Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
99c3d68d3a | ||
|
|
59f3866e36 | ||
|
|
d45d9a295b | ||
|
|
b13a74c61e | ||
|
|
0fe85ed6ff | ||
|
|
bc15e348f5 | ||
|
|
1b3b9b5c62 | ||
|
|
fe80ba6cc4 | ||
|
|
65751cd56b | ||
|
|
ee79f53612 | ||
|
|
d3029a8467 | ||
|
|
f61d9ff9f0 | ||
|
|
a53c9fad00 | ||
|
|
4de7448394 | ||
|
|
6781c1fb51 | ||
|
|
acdc259771 | ||
|
|
d319d8dc52 | ||
|
|
419d711fb6 | ||
|
|
2d662cbab9 | ||
|
|
ae93c9768b | ||
|
|
664cad21a9 | ||
|
|
8cc126f711 | ||
|
|
9c0874162b | ||
|
|
f35a9b6a09 | ||
|
|
fa17404133 | ||
|
|
64bd8b5eaf | ||
|
|
e227d96cbf | ||
|
|
6e07d6ad36 | ||
|
|
d6c810aa71 | ||
|
|
10f698b70f | ||
|
|
594f50bee7 | ||
|
|
9204848ffb | ||
|
|
272d289d4a | ||
|
|
c9d4c7dac7 | ||
|
|
848fc353d4 | ||
|
|
f896ed723d | ||
|
|
00b62d7cd9 | ||
|
|
f84f425817 | ||
|
|
9c5a43b487 | ||
|
|
b2c76aca7d | ||
|
|
04bb035a83 | ||
|
|
2cf77db8b6 | ||
|
|
d1cb644712 | ||
|
|
4e2807cff5 | ||
|
|
5735e0ef44 | ||
|
|
9cd33d26f2 | ||
|
|
062fca3f75 | ||
|
|
a182768cfa | ||
|
|
93683c3a2f | ||
|
|
ba522597a8 | ||
|
|
b232cb94b4 | ||
|
|
ee6aa47d99 | ||
|
|
b3ebf202fd | ||
|
|
0fa3095241 | ||
|
|
433272518f | ||
|
|
26de6d3a78 | ||
|
|
5ea2aee2f4 | ||
|
|
5a377e713e | ||
|
|
cfb298f69b | ||
|
|
563b5be9b2 | ||
|
|
fb36bd0ced | ||
|
|
979c80d9ee | ||
|
|
4598435dd4 | ||
|
|
51202924af | ||
|
|
8ae70990ad | ||
|
|
a63be102cf | ||
|
|
044deccd22 | ||
|
|
ad49508b74 | ||
|
|
05c9ca5951 | ||
|
|
f5cdb98b01 | ||
|
|
228687b741 | ||
|
|
7ebbfcf0d2 | ||
|
|
49c17c4a18 | ||
|
|
7c42b9aeca | ||
|
|
1511193e58 | ||
|
|
528d668bc6 | ||
|
|
71896a75bf | ||
|
|
931d61e2ed | ||
|
|
b87b1c7123 | ||
|
|
fed5a0fd87 | ||
|
|
9d4f278117 | ||
|
|
1d465aa800 | ||
|
|
8741e8259f | ||
|
|
98adb046ee | ||
|
|
a68a5d91c4 | ||
|
|
0808392353 | ||
|
|
07f672ae1f | ||
|
|
e219237e44 | ||
|
|
c533446ab0 | ||
|
|
82488140ee | ||
|
|
327ccec02f | ||
|
|
46efe0ef93 | ||
|
|
c2231bcc2e |
No files matched your search
@@ -1,40 +0,0 @@
|
||||
---
|
||||
name: 🐛 Bug report
|
||||
about: Report an issue or problem with the way LuckPerms is functioning.
|
||||
title: ''
|
||||
labels: 'type: issue'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!-- Before going any further, please check to see if your problem is fixed by updating to a newer version. The latest development builds can be obtained from https://luckperms.net/download -->
|
||||
|
||||
### Description
|
||||
<!-- Please provide a short description of the issue in the space below. -->
|
||||
|
||||
|
||||
### Reproduction steps
|
||||
<!-- Please provide a clear list of steps we should follow in order to reproduce your issue in the space below. -->
|
||||
|
||||
1. Open the config.yml file and set example to true.
|
||||
2. Restart the server
|
||||
3. Run /lp user example permission set x from the console
|
||||
4. See error
|
||||
|
||||
|
||||
### Expected behaviour
|
||||
<!-- Please provide a description of what you expected to happen. -->
|
||||
|
||||
|
||||
### Environment details
|
||||
<!-- Please provide details of your server environment in the space below. -->
|
||||
|
||||
* Server type/version: `ExampleSpigot` running version `1.12.2` build `???`
|
||||
* LuckPerms version: `v???`
|
||||
|
||||
<!-- If you think it would be helpful, please also include a "pastebin" of any relevant config files or log output. You should use https://gist.github.com/ to upload, then include the link below. -->
|
||||
|
||||
|
||||
### Any other relevant details
|
||||
<!-- Please include any other relevant details in the space below. -->
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
name: 🐛 Bug report
|
||||
description: Report an issue or problem with the way LuckPerms is functioning.
|
||||
labels: ["type: issue"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "Before going any further, please check to see if your problem is fixed by updating to a newer version. The latest development builds can be obtained from https://luckperms.net/download"
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: Please provide a short description of the issue in the space below.
|
||||
placeholder: Description goes here!
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reproduction-steps
|
||||
attributes:
|
||||
label: Reproduction Steps
|
||||
description: Please provide a clear list of steps we should follow in order to reproduce your issue in the space below.
|
||||
placeholder: List reproduction steps here, please!
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected-behaviour
|
||||
attributes:
|
||||
label: Expected Behaviour
|
||||
description: Please provide a description of what you expected to happen.
|
||||
placeholder: Describe what you expected to happen here.
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: server-info
|
||||
attributes:
|
||||
label: Server Details
|
||||
description: Please provide a description of the server details, including type and specific version number.
|
||||
placeholder: 'git-Paper-124 (MC: 1.17.1)'
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: luckperms-version
|
||||
attributes:
|
||||
label: LuckPerms Version
|
||||
description: Please provide the specific, precise version number of LuckPerms you are using to reproduce this bug.
|
||||
placeholder: v5.3.70
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Logs and Configs
|
||||
description: If you think it would be helpful, please also include a pastebin of any relevant config files or log output. You should use https://gist.github.com/ to upload, then include the link below.
|
||||
placeholder: https://gist.github.com/HelpfulBugReporter/ThisIsAVeryUsefulLogOutput
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: extra-info
|
||||
attributes:
|
||||
label: Extra Details
|
||||
description: Please include any other relevant details in the space below.
|
||||
placeholder: I was able to reproduce this only at the end of a rainbow.
|
||||
validations:
|
||||
required: false
|
||||
@@ -1,16 +0,0 @@
|
||||
---
|
||||
name: 💡 Suggestion
|
||||
about: Suggest an idea for an improvement or change to LuckPerms.
|
||||
title: ''
|
||||
labels: 'type: suggestion'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Description
|
||||
<!-- Please provide a short description of the suggestion in the space below. -->
|
||||
|
||||
|
||||
### Proposed behaviour
|
||||
<!-- Please provide a short explanation of how the feature should work / be changed, and how this will effect the project. -->
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
name: 💡 Suggestion
|
||||
description: Suggest an idea for an improvement or change to LuckPerms.
|
||||
labels: ["type: suggestion"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "Before going any further, please check to see if your suggestion has already been added by checking the [wiki](https://luckperms.net/wiki/Home). The latest development builds can be obtained from https://luckperms.net/download"
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: Please provide a short description of your suggestion in the space below.
|
||||
placeholder: Hello, perhaps you should...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: proposed-behaviour
|
||||
attributes:
|
||||
label: Proposed Behaviour
|
||||
description: Please provide a short explanation of how the feature should work / be changed, and how this will affect the project.
|
||||
placeholder: It would...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: extra-info
|
||||
attributes:
|
||||
label: Extra Details
|
||||
description: Please include any other relevant details in the space below.
|
||||
placeholder: I think this should only function at the end of a rainbow.
|
||||
validations:
|
||||
required: false
|
||||
@@ -1,4 +1,4 @@
|
||||

|
||||

|
||||
# LuckPerms
|
||||
[](https://ci.lucko.me/job/LuckPerms/)
|
||||
[](https://javadoc.io/doc/net.luckperms/api)
|
||||
|
||||
+52
-39
@@ -2,7 +2,7 @@ group = 'net.luckperms'
|
||||
project.version = '5.3'
|
||||
|
||||
dependencies {
|
||||
compileOnly 'org.checkerframework:checker-qual:3.8.0'
|
||||
compileOnly 'org.checkerframework:checker-qual:3.12.0'
|
||||
compileOnly 'org.jetbrains:annotations:20.1.0'
|
||||
}
|
||||
|
||||
@@ -17,11 +17,17 @@ if (project.hasProperty('sonatypeUsername') && project.hasProperty('sonatypePass
|
||||
options.encoding = 'UTF-8'
|
||||
options.charSet = 'UTF-8'
|
||||
options.links(
|
||||
'https://docs.oracle.com/javase/8/docs/api/',
|
||||
'https://checkerframework.org/api/',
|
||||
'https://javadoc.io/static/org.jetbrains/annotations/20.1.0/'
|
||||
)
|
||||
options.addStringOption('Xdoclint:none', '-quiet')
|
||||
|
||||
if (JavaVersion.current() > JavaVersion.VERSION_1_8) {
|
||||
options.addBooleanOption('-no-module-directories', true)
|
||||
options.links.add('https://docs.oracle.com/en/java/javase/11/docs/api/')
|
||||
} else {
|
||||
options.links.add('https://docs.oracle.com/javase/8/docs/api/')
|
||||
}
|
||||
}
|
||||
|
||||
task javadocJar(type: Jar, dependsOn: javadoc) {
|
||||
@@ -44,56 +50,63 @@ if (project.hasProperty('sonatypeUsername') && project.hasProperty('sonatypePass
|
||||
sign configurations.archives
|
||||
}
|
||||
|
||||
uploadArchives {
|
||||
publishing {
|
||||
repositories {
|
||||
mavenDeployer {
|
||||
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
|
||||
maven {
|
||||
def releasesRepoUrl = 'https://oss.sonatype.org/service/local/staging/deploy/maven2/'
|
||||
def snapshotsRepoUrl = 'https://oss.sonatype.org/content/repositories/snapshots/'
|
||||
url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
|
||||
|
||||
repository(url: 'https://oss.sonatype.org/service/local/staging/deploy/maven2/') {
|
||||
authentication(userName: sonatypeUsername, password: sonatypePassword)
|
||||
credentials {
|
||||
username sonatypeUsername
|
||||
password sonatypePassword
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
snapshotRepository(url: 'https://oss.sonatype.org/content/repositories/snapshots/') {
|
||||
authentication(userName: sonatypeUsername, password: sonatypePassword)
|
||||
}
|
||||
publications {
|
||||
mavenJava(MavenPublication) {
|
||||
artifactId = 'api'
|
||||
|
||||
from components.java
|
||||
artifact sourcesJar
|
||||
artifact javadocJar
|
||||
|
||||
pom {
|
||||
project {
|
||||
name 'LuckPerms API'
|
||||
description 'A permissions plugin for Minecraft servers.'
|
||||
url 'https://luckperms.net'
|
||||
name 'LuckPerms API'
|
||||
description 'A permissions plugin for Minecraft servers.'
|
||||
url 'https://luckperms.net'
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name 'MIT'
|
||||
url 'https://opensource.org/licenses/MIT'
|
||||
}
|
||||
licenses {
|
||||
license {
|
||||
name 'MIT'
|
||||
url 'https://opensource.org/licenses/MIT'
|
||||
}
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
id 'lucko'
|
||||
name 'Luck'
|
||||
url 'https://lucko.me'
|
||||
email 'git@lucko.me'
|
||||
}
|
||||
developers {
|
||||
developer {
|
||||
id 'lucko'
|
||||
name 'Luck'
|
||||
url 'https://lucko.me'
|
||||
email 'git@lucko.me'
|
||||
}
|
||||
}
|
||||
|
||||
scm {
|
||||
connection 'scm:git:https://github.com/lucko/LuckPerms.git'
|
||||
developerConnection 'scm:git:git@github.com:lucko/LuckPerms.git'
|
||||
url 'https://github.com/lucko/LuckPerms'
|
||||
}
|
||||
scm {
|
||||
connection 'scm:git:https://github.com/lucko/LuckPerms.git'
|
||||
developerConnection 'scm:git:git@github.com:lucko/LuckPerms.git'
|
||||
url 'https://github.com/lucko/LuckPerms'
|
||||
}
|
||||
|
||||
ciManagement {
|
||||
system 'Jenkins'
|
||||
url 'https://ci.lucko.me/job/LuckPerms'
|
||||
}
|
||||
ciManagement {
|
||||
system 'Jenkins'
|
||||
url 'https://ci.lucko.me/job/LuckPerms'
|
||||
}
|
||||
|
||||
issueManagement {
|
||||
system 'GitHub'
|
||||
url 'https://github.com/lucko/LuckPerms/issues'
|
||||
}
|
||||
issueManagement {
|
||||
system 'GitHub'
|
||||
url 'https://github.com/lucko/LuckPerms/issues'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ public final class LuckPermsProvider {
|
||||
* @throws IllegalStateException if the API is not loaded yet
|
||||
*/
|
||||
public static @NonNull LuckPerms get() {
|
||||
LuckPerms instance = LuckPermsProvider.instance;
|
||||
if (instance == null) {
|
||||
throw new NotLoadedException();
|
||||
}
|
||||
@@ -76,9 +77,9 @@ public final class LuckPermsProvider {
|
||||
private static final String MESSAGE = "The LuckPerms API isn't loaded yet!\n" +
|
||||
"This could be because:\n" +
|
||||
" a) the LuckPerms plugin is not installed or it failed to enable\n" +
|
||||
" b) your plugin does not declare a dependency on LuckPerms\n" +
|
||||
" c) you are attempting to use the API before plugins reach the 'enable' phase\n" +
|
||||
" (call the #get method in onEnable, not in your plugin constructor!)\n";
|
||||
" b) the plugin in the stacktrace does not declare a dependency on LuckPerms\n" +
|
||||
" c) the plugin in the stacktrace is retrieving the API before the plugin 'enable' phase\n" +
|
||||
" (call the #get method in onEnable, not the constructor!)\n";
|
||||
|
||||
NotLoadedException() {
|
||||
super(MESSAGE);
|
||||
|
||||
@@ -31,6 +31,10 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
/**
|
||||
* Holds cached lookup data for a given set of query options.
|
||||
*
|
||||
* <p>All calls will account for inheritance, as well as any default data
|
||||
* provided by the platform. These calls are heavily cached and are therefore
|
||||
* fast.</p>
|
||||
*/
|
||||
public interface CachedData {
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ import java.util.concurrent.CompletableFuture;
|
||||
* Holds cached permission and meta lookup data for a {@link PermissionHolder}.
|
||||
*
|
||||
* <p>All calls will account for inheritance, as well as any default data
|
||||
* provided by the platform. This calls are heavily cached and are therefore
|
||||
* provided by the platform. These calls are heavily cached and are therefore
|
||||
* fast.</p>
|
||||
*/
|
||||
public interface CachedDataManager {
|
||||
@@ -81,11 +81,10 @@ public interface CachedDataManager {
|
||||
* <p>For {@link User}s, the most appropriate query options will be their
|
||||
* {@link ContextManager#getQueryOptions(User) current active query options} if the
|
||||
* corresponding player is online, and otherwise, will fallback to
|
||||
* {@link ContextManager#getStaticQueryOptions() the current static query options}
|
||||
* if they are offline.</p>
|
||||
* {@link ContextManager#getStaticQueryOptions() the current static query options}.</p>
|
||||
*
|
||||
* <p>For {@link Group}s, the most appropriate query options will always be
|
||||
* {@link ContextManager#getStaticQueryOptions()} the current static query options.</p>
|
||||
* {@link ContextManager#getStaticQueryOptions() the current static query options}.</p>
|
||||
*
|
||||
* @return a permission data instance
|
||||
* @since 5.1
|
||||
@@ -99,11 +98,10 @@ public interface CachedDataManager {
|
||||
* <p>For {@link User}s, the most appropriate query options will be their
|
||||
* {@link ContextManager#getQueryOptions(User) current active query options} if the
|
||||
* corresponding player is online, and otherwise, will fallback to
|
||||
* {@link ContextManager#getStaticQueryOptions() the current static query options}
|
||||
* if they are offline.</p>
|
||||
* {@link ContextManager#getStaticQueryOptions() the current static query options}.</p>
|
||||
*
|
||||
* <p>For {@link Group}s, the most appropriate query options will always be
|
||||
* {@link ContextManager#getStaticQueryOptions()} the current static query options.</p>
|
||||
* {@link ContextManager#getStaticQueryOptions() the current static query options}.</p>
|
||||
*
|
||||
* @return a meta data instance
|
||||
* @since 5.1
|
||||
@@ -118,7 +116,7 @@ public interface CachedDataManager {
|
||||
void invalidate();
|
||||
|
||||
/**
|
||||
* Invalidates all of the underlying Permission calculators.
|
||||
* Invalidates all underlying permission calculators.
|
||||
*
|
||||
* <p>Can be called to allow for an update in defaults.</p>
|
||||
*/
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
package net.luckperms.api.cacheddata;
|
||||
|
||||
import net.luckperms.api.metastacking.MetaStackDefinition;
|
||||
import net.luckperms.api.node.types.MetaNode;
|
||||
import net.luckperms.api.node.types.PrefixNode;
|
||||
import net.luckperms.api.node.types.SuffixNode;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
@@ -39,16 +42,40 @@ import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Holds cached meta lookup data for a specific set of contexts.
|
||||
*
|
||||
* <p>Meta data refers to {@link PrefixNode prefixes}, {@link SuffixNode suffixes} and
|
||||
* {@link MetaNode meta (options)} held by a permission holder.</p>
|
||||
*
|
||||
* <p>All calls will account for inheritance, as well as any default data
|
||||
* provided by the platform. These calls are heavily cached and are therefore
|
||||
* fast.</p>
|
||||
*/
|
||||
public interface CachedMetaData extends CachedData {
|
||||
|
||||
/**
|
||||
* Query a meta value for the given {@code key}.
|
||||
*
|
||||
* <p>This method will always return a {@link Result}, but the
|
||||
* {@link Result#result() inner result} {@link String} will be null if a value
|
||||
* for the given key was not found.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @return a result containing the value
|
||||
* @since 5.4
|
||||
*/
|
||||
@NonNull Result<String, MetaNode> queryMetaValue(@NonNull String key);
|
||||
|
||||
/**
|
||||
* Gets a value for the given meta key.
|
||||
*
|
||||
* <p>If no such meta value exists for the given key, {@code null} is returned.</p>
|
||||
*
|
||||
* @param key the key
|
||||
* @return the value
|
||||
*/
|
||||
@Nullable String getMetaValue(@NonNull String key);
|
||||
default @Nullable String getMetaValue(@NonNull String key) {
|
||||
return queryMetaValue(key).result();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value for the given meta key, and runs it through the given {@code transformer}.
|
||||
@@ -81,37 +108,97 @@ public interface CachedMetaData extends CachedData {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the holder's highest priority prefix, or null if the holder has no prefixes
|
||||
* Query for a prefix.
|
||||
*
|
||||
* <p>This method uses the rules defined by the {@link #getPrefixStackDefinition() prefix stack}
|
||||
* to produce a {@link String} output.</p>
|
||||
*
|
||||
* <p>Assuming the default configuration is used, this will usually be the value of the
|
||||
* holder's highest priority prefix node.</p>
|
||||
*
|
||||
* <p>This method will always return a {@link Result}, but the
|
||||
* {@link Result#result() inner result} {@link String} will be null if
|
||||
* a the resultant prefix stack contained no elements.</p>
|
||||
*
|
||||
* @return a result containing the prefix
|
||||
* @since 5.4
|
||||
*/
|
||||
@NonNull Result<String, PrefixNode> queryPrefix();
|
||||
|
||||
/**
|
||||
* Gets the prefix.
|
||||
*
|
||||
* <p>This method uses the rules defined by the {@link #getPrefixStackDefinition() prefix stack}
|
||||
* to produce a {@link String} output.</p>
|
||||
*
|
||||
* <p>Assuming the default configuration is used, this will usually be the value of the
|
||||
* holder's highest priority prefix node.</p>
|
||||
*
|
||||
* <p>If the resultant prefix stack contained no elements, {@code null} is returned.</p>
|
||||
*
|
||||
* @return a prefix string, or null
|
||||
*/
|
||||
@Nullable String getPrefix();
|
||||
default @Nullable String getPrefix() {
|
||||
return queryPrefix().result();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the holder's highest priority suffix, or null if the holder has no suffixes
|
||||
* Query for a suffix.
|
||||
*
|
||||
* <p>This method uses the rules defined by the {@link #getSuffixStackDefinition() suffix stack}
|
||||
* to produce a {@link String} output.</p>
|
||||
*
|
||||
* <p>Assuming the default configuration is used, this will usually be the value of the
|
||||
* holder's highest priority suffix node.</p>
|
||||
*
|
||||
* <p>This method will always return a {@link Result}, but the
|
||||
* {@link Result#result() inner result} {@link String} will be null if
|
||||
* a the resultant suffix stack contained no elements.</p>
|
||||
*
|
||||
* @return a result containing the suffix
|
||||
* @since 5.4
|
||||
*/
|
||||
@NonNull Result<String, SuffixNode> querySuffix();
|
||||
|
||||
/**
|
||||
* Gets the suffix.
|
||||
*
|
||||
* <p>This method uses the rules defined by the {@link #getSuffixStackDefinition() suffix stack}
|
||||
* to produce a {@link String} output.</p>
|
||||
*
|
||||
* <p>Assuming the default configuration is used, this will usually be the value of the
|
||||
* holder's highest priority suffix node.</p>
|
||||
*
|
||||
* <p>If the resultant suffix stack contained no elements, {@code null} is returned.</p>
|
||||
*
|
||||
* @return a suffix string, or null
|
||||
*/
|
||||
@Nullable String getSuffix();
|
||||
default @Nullable String getSuffix() {
|
||||
return querySuffix().result();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an immutable copy of the meta this holder has.
|
||||
* Gets a map of all accumulated {@link MetaNode meta}.
|
||||
*
|
||||
* @return an immutable map of meta
|
||||
* <p>Prefer using the {@link #getMetaValue(String)} method for querying values.</p>
|
||||
*
|
||||
* @return a map of meta
|
||||
*/
|
||||
@NonNull @Unmodifiable Map<String, List<String>> getMeta();
|
||||
|
||||
/**
|
||||
* Gets an immutable sorted map of all of the prefixes the holder has, whereby the first
|
||||
* value is the highest priority prefix.
|
||||
* Gets a sorted map of all accumulated {@link PrefixNode prefixes}.
|
||||
*
|
||||
* <p>Prefer using the {@link #getPrefix()} method for querying.</p>
|
||||
*
|
||||
* @return a sorted map of prefixes
|
||||
*/
|
||||
@NonNull @Unmodifiable SortedMap<Integer, String> getPrefixes();
|
||||
|
||||
/**
|
||||
* Gets an immutable sorted map of all of the suffixes the holder has, whereby the first
|
||||
* value is the highest priority suffix.
|
||||
* Gets a sorted map of all accumulated {@link SuffixNode suffixes}.
|
||||
*
|
||||
* <p>Prefer using the {@link #getSuffix()} method for querying.</p>
|
||||
*
|
||||
* @return a sorted map of suffixes
|
||||
*/
|
||||
@@ -128,14 +215,14 @@ public interface CachedMetaData extends CachedData {
|
||||
@Nullable String getPrimaryGroup();
|
||||
|
||||
/**
|
||||
* Gets the definition used for the prefix stack
|
||||
* Gets the definition used for the prefix stack.
|
||||
*
|
||||
* @return the definition used for the prefix stack
|
||||
*/
|
||||
@NonNull MetaStackDefinition getPrefixStackDefinition();
|
||||
|
||||
/**
|
||||
* Gets the definition used for the suffix stack
|
||||
* Gets the definition used for the suffix stack.
|
||||
*
|
||||
* @return the definition used for the suffix stack
|
||||
*/
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
package net.luckperms.api.cacheddata;
|
||||
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.util.Tristate;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
@@ -34,17 +35,39 @@ import java.util.Map;
|
||||
|
||||
/**
|
||||
* Holds cached permission lookup data for a specific set of contexts.
|
||||
*
|
||||
* <p>All calls will account for inheritance, as well as any default data
|
||||
* provided by the platform. These calls are heavily cached and are therefore
|
||||
* fast.</p>
|
||||
*/
|
||||
public interface CachedPermissionData extends CachedData {
|
||||
|
||||
/**
|
||||
* Gets a permission check result for the given permission node.
|
||||
* Performs a permission check for the given {@code permission} node.
|
||||
*
|
||||
* <p>This check is equivalent to the "hasPermission" method call on most platforms.
|
||||
* You can use {@link Tristate#asBoolean()} if you need a truthy result.</p>
|
||||
*
|
||||
* @param permission the permission node
|
||||
* @return a result containing the tristate
|
||||
* @throws NullPointerException if permission is null
|
||||
* @since 5.4
|
||||
*/
|
||||
@NonNull Result<Tristate, Node> queryPermission(@NonNull String permission);
|
||||
|
||||
/**
|
||||
* Performs a permission check for the given {@code permission} node.
|
||||
*
|
||||
* <p>This check is equivalent to the "hasPermission" method call on most platforms.
|
||||
* You can use {@link Tristate#asBoolean()} if you need a truthy result.</p>
|
||||
*
|
||||
* @param permission the permission node
|
||||
* @return a tristate result
|
||||
* @throws NullPointerException if permission is null
|
||||
*/
|
||||
@NonNull Tristate checkPermission(@NonNull String permission);
|
||||
default @NonNull Tristate checkPermission(@NonNull String permission) {
|
||||
return queryPermission(permission).result();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates the underlying permission calculator cache.
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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 net.luckperms.api.cacheddata;
|
||||
|
||||
import net.luckperms.api.node.Node;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* Represents the result of a cached data lookup.
|
||||
*
|
||||
* <p>You can find "the holder that has the node that caused this result"
|
||||
* using the following code:</p>
|
||||
* <p></p>
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* public static {@link net.luckperms.api.model.PermissionHolder.Identifier} holderThatHasTheNodeThatCausedTheResult(Result<?, ?> result) {
|
||||
* {@link Node} node = result.node();
|
||||
* if (node == null) {
|
||||
* return null;
|
||||
* }
|
||||
* {@link net.luckperms.api.node.metadata.types.InheritanceOriginMetadata} origin = node.getMetadata(InheritanceOriginMetadata.KEY).orElse(null);
|
||||
* if (origin == null) {
|
||||
* return null;
|
||||
* }
|
||||
* return origin.getOrigin();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>Combined with the node itself, this is all the information needed to determine
|
||||
* the root cause of the result.</p>
|
||||
* </blockquote>
|
||||
*
|
||||
* <p>The nullability of {@link #result()} is purposely undefined to allow the
|
||||
* flexibility for methods using {@link Result} to declare it. In general, if the {@code T} type
|
||||
* has a nullable/undefined value, then the return of {@link #result()} will be non-null,
|
||||
* and if not, it will be nullable.</p>
|
||||
*
|
||||
* @param <T> the result type
|
||||
* @param <N> the node type
|
||||
* @since 5.4
|
||||
*/
|
||||
public interface Result<T, N extends Node> {
|
||||
|
||||
/**
|
||||
* Gets the underlying result.
|
||||
*
|
||||
* @return the underlying result
|
||||
*/
|
||||
T result();
|
||||
|
||||
/**
|
||||
* Gets the node that caused the result.
|
||||
*
|
||||
* @return the causing node
|
||||
*/
|
||||
@Nullable N node();
|
||||
|
||||
}
|
||||
@@ -24,7 +24,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* CachedData lookup API for {@link net.luckperms.api.model.user.User}s and
|
||||
* Caches permission checks and meta lookups for {@link net.luckperms.api.model.user.User}s and
|
||||
* {@link net.luckperms.api.model.group.Group}s.
|
||||
*/
|
||||
package net.luckperms.api.cacheddata;
|
||||
@@ -119,7 +119,7 @@ public interface ImmutableContextSet extends ContextSet {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds of of the contexts in another {@link ContextSet} to the set.
|
||||
* Adds all the contexts in another {@link ContextSet} to the set.
|
||||
*
|
||||
* @param contextSet the set to add from
|
||||
* @return the builder
|
||||
|
||||
@@ -94,7 +94,7 @@ public interface MutableContextSet extends ContextSet {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds of of the contexts in another {@link ContextSet} to this set.
|
||||
* Adds all the contexts in another {@link ContextSet} to this set.
|
||||
*
|
||||
* @param contextSet the set to add from
|
||||
* @throws NullPointerException if the contextSet is null
|
||||
|
||||
+16
@@ -56,6 +56,22 @@ public interface UniqueIdDetermineTypeEvent extends LuckPermsEvent, ResultEvent<
|
||||
*/
|
||||
String TYPE_UNAUTHENTICATED = "unauthenticated";
|
||||
|
||||
/**
|
||||
* The players UUID most likely belongs to a NPC (non-player character).
|
||||
*
|
||||
* <p>Usually indicated by the UUID being {@link UUID#version() version} 2.</p>
|
||||
*
|
||||
* @since 5.4
|
||||
*/
|
||||
String TYPE_NPC = "npc";
|
||||
|
||||
/**
|
||||
* Unknown UUID type.
|
||||
*
|
||||
* @since 5.4
|
||||
*/
|
||||
String TYPE_UNKNOWN = "unknown";
|
||||
|
||||
/**
|
||||
* Gets the {@link UUID unique id} being queried.
|
||||
*
|
||||
|
||||
@@ -31,6 +31,8 @@ import net.luckperms.api.node.types.SuffixNode;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Represents a type of chat meta
|
||||
*/
|
||||
@@ -70,7 +72,7 @@ public enum ChatMetaType {
|
||||
private final NodeType<? extends ChatMetaNode<?, ?>> nodeType;
|
||||
|
||||
ChatMetaType(NodeType<? extends ChatMetaNode<?, ?>> nodeType) {
|
||||
this.name = nodeType.name().toLowerCase();
|
||||
this.name = nodeType.name().toLowerCase(Locale.ROOT);
|
||||
this.nodeType = nodeType;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ package net.luckperms.api.node.metadata;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
final class SimpleNodeMetadataKey<T> implements NodeMetadataKey<T> {
|
||||
@@ -34,7 +35,7 @@ final class SimpleNodeMetadataKey<T> implements NodeMetadataKey<T> {
|
||||
private final Class<T> type;
|
||||
|
||||
SimpleNodeMetadataKey(String name, Class<T> type) {
|
||||
this.name = name.toLowerCase();
|
||||
this.name = name.toLowerCase(Locale.ROOT);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
+10
@@ -26,6 +26,7 @@
|
||||
package net.luckperms.api.node.metadata.types;
|
||||
|
||||
import net.luckperms.api.model.PermissionHolder;
|
||||
import net.luckperms.api.model.data.DataType;
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.node.metadata.NodeMetadataKey;
|
||||
|
||||
@@ -56,6 +57,15 @@ public interface InheritanceOriginMetadata {
|
||||
*/
|
||||
PermissionHolder.@NonNull Identifier getOrigin();
|
||||
|
||||
/**
|
||||
* Gets the {@link DataType type} of the {@link net.luckperms.api.model.data.NodeMap}
|
||||
* the node was inherited from.
|
||||
*
|
||||
* @return the type of the NodeMap the node was inherited from.
|
||||
* @since 5.4
|
||||
*/
|
||||
@NonNull DataType getDataType();
|
||||
|
||||
/**
|
||||
* Gets whether the associated node was inherited from another holder.
|
||||
*
|
||||
|
||||
@@ -27,6 +27,7 @@ package net.luckperms.api.query;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
final class SimpleOptionKey<T> implements OptionKey<T> {
|
||||
@@ -35,7 +36,7 @@ final class SimpleOptionKey<T> implements OptionKey<T> {
|
||||
private final int hashCode;
|
||||
|
||||
SimpleOptionKey(String name, Class<T> type) {
|
||||
this.name = name.toLowerCase();
|
||||
this.name = name.toLowerCase(Locale.ROOT);
|
||||
this.type = type;
|
||||
this.hashCode = Objects.hash(this.name, this.type); // cache hashcode
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
package net.luckperms.api.query.meta;
|
||||
|
||||
import net.luckperms.api.cacheddata.Result;
|
||||
import net.luckperms.api.node.types.MetaNode;
|
||||
import net.luckperms.api.query.OptionKey;
|
||||
|
||||
@@ -54,6 +55,6 @@ public interface MetaValueSelector {
|
||||
* @param values the values, in the order in which they were accumulated.
|
||||
* @return the selected value
|
||||
*/
|
||||
@NonNull String selectValue(@NonNull String key, @NonNull List<String> values);
|
||||
@NonNull Result<String, MetaNode> selectValue(@NonNull String key, @NonNull List<? extends Result<String, MetaNode>> values);
|
||||
|
||||
}
|
||||
+6
-12
@@ -1,22 +1,16 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
maven { url 'https://plugins.gradle.org/m2' }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'gradle.plugin.net.minecrell:licenser:0.4.1'
|
||||
}
|
||||
plugins {
|
||||
id 'org.cadixdev.licenser' version '0.6.1' apply false
|
||||
}
|
||||
|
||||
defaultTasks 'licenseFormat', 'build'
|
||||
|
||||
subprojects {
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'maven'
|
||||
apply plugin: 'net.minecrell.licenser'
|
||||
apply plugin: 'maven-publish'
|
||||
apply plugin: 'org.cadixdev.licenser'
|
||||
|
||||
group = 'me.lucko.luckperms'
|
||||
version = '5.3-SNAPSHOT'
|
||||
version = '5.4-SNAPSHOT'
|
||||
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
@@ -45,7 +39,7 @@ subprojects {
|
||||
}
|
||||
|
||||
project.ext.majorVersion = '5'
|
||||
project.ext.minorVersion = '3'
|
||||
project.ext.minorVersion = '4'
|
||||
project.ext.patchVersion = determinePatchVersion()
|
||||
project.ext.apiVersion = project.ext.majorVersion + '.' + project.ext.minorVersion
|
||||
project.ext.fullVersion = project.ext.apiVersion + '.' + project.ext.patchVersion
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
plugins {
|
||||
id 'com.github.johnrengelman.shadow' version '2.0.4'
|
||||
id 'com.github.johnrengelman.shadow' version '7.0.0'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':bukkit')
|
||||
compile 'com.google.code.gson:gson:2.7'
|
||||
compile 'com.google.guava:guava:19.0'
|
||||
implementation project(':bukkit')
|
||||
implementation 'com.google.code.gson:gson:2.7'
|
||||
implementation 'com.google.guava:guava:19.0'
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
archiveName = 'luckperms-bukkitlegacy.jarinjar'
|
||||
archiveFileName = 'luckperms-bukkitlegacy.jarinjar'
|
||||
|
||||
dependencies {
|
||||
include(dependency('me.lucko.luckperms:.*'))
|
||||
@@ -41,4 +41,4 @@ shadowJar {
|
||||
|
||||
artifacts {
|
||||
archives shadowJar
|
||||
}
|
||||
}
|
||||
@@ -9,19 +9,18 @@ repositories {
|
||||
dependencies {
|
||||
compileOnly 'com.destroystokyo.paper:paper-api:1.15.2-R0.1-SNAPSHOT'
|
||||
|
||||
compile project(':api')
|
||||
compile project(':common:loader-utils')
|
||||
implementation project(':api')
|
||||
implementation project(':common:loader-utils')
|
||||
}
|
||||
|
||||
processResources {
|
||||
from(sourceSets.main.resources.srcDirs) {
|
||||
filesMatching('plugin.yml') {
|
||||
expand 'pluginVersion': project.ext.fullVersion
|
||||
include 'plugin.yml'
|
||||
}
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
archiveName = "LuckPerms-Bukkit-Legacy-${project.ext.fullVersion}.jar"
|
||||
archiveFileName = "LuckPerms-Bukkit-Legacy-${project.ext.fullVersion}.jar"
|
||||
|
||||
from {
|
||||
project(':bukkit-legacy').tasks.shadowJar.archiveFile
|
||||
@@ -30,4 +29,4 @@ shadowJar {
|
||||
|
||||
artifacts {
|
||||
archives shadowJar
|
||||
}
|
||||
}
|
||||
+11
-7
@@ -1,5 +1,5 @@
|
||||
plugins {
|
||||
id 'com.github.johnrengelman.shadow' version '2.0.4'
|
||||
id 'com.github.johnrengelman.shadow' version '7.0.0'
|
||||
}
|
||||
|
||||
repositories {
|
||||
@@ -8,20 +8,24 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':common')
|
||||
implementation project(':common')
|
||||
compileOnly project(':common:loader-utils')
|
||||
|
||||
compileOnly 'com.destroystokyo.paper:paper-api:1.15.2-R0.1-SNAPSHOT'
|
||||
compileOnly 'me.lucko:adventure-platform-bukkit:4.0.0' // re: this artifact - see note in common/build.gradle
|
||||
compileOnly 'me.lucko:commodore:1.7'
|
||||
compileOnly('net.milkbowl.vault:VaultAPI:1.6') {
|
||||
compileOnly('me.lucko:adventure-platform-bukkit:4.9.4') {
|
||||
exclude(module: 'adventure-bom')
|
||||
exclude(module: 'adventure-api')
|
||||
exclude(module: 'adventure-nbt')
|
||||
}
|
||||
compileOnly 'me.lucko:commodore:1.12'
|
||||
compileOnly('net.milkbowl.vault:VaultAPI:1.7') {
|
||||
exclude(module: 'bukkit')
|
||||
}
|
||||
compileOnly 'lilypad.client.connect:api:0.0.1-SNAPSHOT'
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
archiveName = 'luckperms-bukkit.jarinjar'
|
||||
archiveFileName = 'luckperms-bukkit.jarinjar'
|
||||
|
||||
dependencies {
|
||||
include(dependency('me.lucko.luckperms:.*'))
|
||||
@@ -48,4 +52,4 @@ shadowJar {
|
||||
|
||||
artifacts {
|
||||
archives shadowJar
|
||||
}
|
||||
}
|
||||
@@ -9,19 +9,18 @@ repositories {
|
||||
dependencies {
|
||||
compileOnly 'com.destroystokyo.paper:paper-api:1.15.2-R0.1-SNAPSHOT'
|
||||
|
||||
compile project(':api')
|
||||
compile project(':common:loader-utils')
|
||||
implementation project(':api')
|
||||
implementation project(':common:loader-utils')
|
||||
}
|
||||
|
||||
processResources {
|
||||
from(sourceSets.main.resources.srcDirs) {
|
||||
filesMatching('plugin.yml') {
|
||||
expand 'pluginVersion': project.ext.fullVersion
|
||||
include 'plugin.yml'
|
||||
}
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
archiveName = "LuckPerms-Bukkit-${project.ext.fullVersion}.jar"
|
||||
archiveFileName = "LuckPerms-Bukkit-${project.ext.fullVersion}.jar"
|
||||
|
||||
from {
|
||||
project(':bukkit').tasks.shadowJar.archiveFile
|
||||
@@ -30,4 +29,4 @@ shadowJar {
|
||||
|
||||
artifacts {
|
||||
archives shadowJar
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ package me.lucko.luckperms.bukkit;
|
||||
|
||||
import me.lucko.luckperms.bukkit.util.NullSafeConsoleCommandSender;
|
||||
import me.lucko.luckperms.common.loader.LoaderBootstrap;
|
||||
import me.lucko.luckperms.common.plugin.bootstrap.BootstrappedWithLoader;
|
||||
import me.lucko.luckperms.common.plugin.bootstrap.LuckPermsBootstrap;
|
||||
import me.lucko.luckperms.common.plugin.classpath.ClassPathAppender;
|
||||
import me.lucko.luckperms.common.plugin.classpath.JarInJarClassPathAppender;
|
||||
@@ -56,7 +57,7 @@ import java.util.logging.Logger;
|
||||
/**
|
||||
* Bootstrap plugin for LuckPerms running on Bukkit.
|
||||
*/
|
||||
public class LPBukkitBootstrap implements LuckPermsBootstrap, LoaderBootstrap {
|
||||
public class LPBukkitBootstrap implements LuckPermsBootstrap, LoaderBootstrap, BootstrappedWithLoader {
|
||||
private final JavaPlugin loader;
|
||||
|
||||
/**
|
||||
@@ -111,6 +112,7 @@ public class LPBukkitBootstrap implements LuckPermsBootstrap, LoaderBootstrap {
|
||||
|
||||
// provide adapters
|
||||
|
||||
@Override
|
||||
public JavaPlugin getLoader() {
|
||||
return this.loader;
|
||||
}
|
||||
|
||||
@@ -60,8 +60,6 @@ import me.lucko.luckperms.common.model.manager.user.StandardUserManager;
|
||||
import me.lucko.luckperms.common.plugin.AbstractLuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.plugin.util.AbstractConnectionListener;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
import me.lucko.luckperms.common.tasks.CacheHousekeepingTask;
|
||||
import me.lucko.luckperms.common.tasks.ExpireTemporaryTask;
|
||||
|
||||
import net.luckperms.api.LuckPerms;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
@@ -79,7 +77,6 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
@@ -125,6 +122,7 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
dependencies.add(Dependency.ADVENTURE_PLATFORM_BUKKIT);
|
||||
if (isBrigadierSupported()) {
|
||||
dependencies.add(Dependency.COMMODORE);
|
||||
dependencies.add(Dependency.COMMODORE_FILE);
|
||||
}
|
||||
return dependencies;
|
||||
}
|
||||
@@ -258,12 +256,6 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
this.bootstrap.getServer().getServicesManager().register(LuckPerms.class, api, this.bootstrap.getLoader(), ServicePriority.Normal);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerHousekeepingTasks() {
|
||||
this.bootstrap.getScheduler().asyncRepeating(new ExpireTemporaryTask(this), 3, TimeUnit.SECONDS);
|
||||
this.bootstrap.getScheduler().asyncRepeating(new CacheHousekeepingTask(this), 2, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performFinalSetup() {
|
||||
// register permissions
|
||||
@@ -304,7 +296,7 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
this.bootstrap.getScheduler().executeSync(() -> {
|
||||
try {
|
||||
LuckPermsPermissible lpPermissible = new LuckPermsPermissible(player, user, this);
|
||||
PermissibleInjector.inject(player, lpPermissible);
|
||||
PermissibleInjector.inject(player, lpPermissible, getLogger());
|
||||
} catch (Throwable t) {
|
||||
getLogger().severe("Exception thrown when setting up permissions for " +
|
||||
player.getUniqueId() + " - " + player.getName(), t);
|
||||
@@ -357,7 +349,7 @@ public class LPBukkitPlugin extends AbstractLuckPermsPlugin {
|
||||
try {
|
||||
Class.forName(className);
|
||||
return true;
|
||||
} catch (ClassNotFoundException var1) {
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -52,7 +52,7 @@ public class BukkitCalculatorFactory implements CalculatorFactory {
|
||||
|
||||
@Override
|
||||
public PermissionCalculator build(QueryOptions queryOptions, CacheMetadata metadata) {
|
||||
List<PermissionProcessor> processors = new ArrayList<>(7);
|
||||
List<PermissionProcessor> processors = new ArrayList<>(8);
|
||||
|
||||
processors.add(new DirectProcessor());
|
||||
|
||||
@@ -75,7 +75,8 @@ public class BukkitCalculatorFactory implements CalculatorFactory {
|
||||
boolean op = queryOptions.option(BukkitContextManager.OP_OPTION).orElse(false);
|
||||
if (metadata.getHolderType() == HolderType.USER && this.plugin.getConfiguration().get(ConfigKeys.APPLY_BUKKIT_DEFAULT_PERMISSIONS)) {
|
||||
boolean overrideWildcards = this.plugin.getConfiguration().get(ConfigKeys.APPLY_DEFAULT_NEGATIONS_BEFORE_WILDCARDS);
|
||||
processors.add(new DefaultsProcessor(this.plugin, overrideWildcards, op));
|
||||
processors.add(new DefaultPermissionMapProcessor(this.plugin, op));
|
||||
processors.add(new PermissionMapProcessor(this.plugin, overrideWildcards, op));
|
||||
}
|
||||
|
||||
if (op) {
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
package me.lucko.luckperms.bukkit.calculator;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.calculator.processor.AbstractPermissionProcessor;
|
||||
import me.lucko.luckperms.common.cacheddata.result.TristateResult;
|
||||
import me.lucko.luckperms.common.calculator.processor.AbstractSourceBasedProcessor;
|
||||
import me.lucko.luckperms.common.calculator.processor.PermissionProcessor;
|
||||
import me.lucko.luckperms.common.calculator.result.TristateResult;
|
||||
|
||||
import net.luckperms.api.util.Tristate;
|
||||
|
||||
@@ -40,7 +40,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
/**
|
||||
* Permission Processor for Bukkits "child" permission system.
|
||||
*/
|
||||
public class ChildProcessor extends AbstractPermissionProcessor implements PermissionProcessor {
|
||||
public class ChildProcessor extends AbstractSourceBasedProcessor implements PermissionProcessor {
|
||||
private static final TristateResult.Factory RESULT_FACTORY = new TristateResult.Factory(ChildProcessor.class);
|
||||
|
||||
private final LPBukkitPlugin plugin;
|
||||
@@ -62,10 +62,10 @@ public class ChildProcessor extends AbstractPermissionProcessor implements Permi
|
||||
@Override
|
||||
public void refresh() {
|
||||
Map<String, TristateResult> childPermissions = new HashMap<>();
|
||||
this.sourceMap.forEach((key, value) -> {
|
||||
Map<String, Boolean> children = this.plugin.getPermissionMap().getChildPermissions(key, value);
|
||||
this.sourceMap.forEach((key, node) -> {
|
||||
Map<String, Boolean> children = this.plugin.getPermissionMap().getChildPermissions(key, node.getValue());
|
||||
children.forEach((childKey, childValue) -> {
|
||||
childPermissions.put(childKey, RESULT_FACTORY.result(Tristate.of(childValue), "parent: " + key));
|
||||
childPermissions.put(childKey, RESULT_FACTORY.resultWithOverride(node, Tristate.of(childValue)));
|
||||
});
|
||||
});
|
||||
this.childPermissions = childPermissions;
|
||||
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.bukkit.calculator;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.cacheddata.result.TristateResult;
|
||||
import me.lucko.luckperms.common.calculator.processor.AbstractPermissionProcessor;
|
||||
import me.lucko.luckperms.common.calculator.processor.PermissionProcessor;
|
||||
|
||||
import net.luckperms.api.util.Tristate;
|
||||
|
||||
/**
|
||||
* Permission Processor for Bukkits "default" permission system.
|
||||
*/
|
||||
public class DefaultPermissionMapProcessor extends AbstractPermissionProcessor implements PermissionProcessor {
|
||||
private static final TristateResult.Factory RESULT_FACTORY = new TristateResult.Factory(DefaultPermissionMapProcessor.class);
|
||||
|
||||
private final LPBukkitPlugin plugin;
|
||||
private final boolean isOp;
|
||||
|
||||
public DefaultPermissionMapProcessor(LPBukkitPlugin plugin, boolean isOp) {
|
||||
this.plugin = plugin;
|
||||
this.isOp = isOp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TristateResult hasPermission(String permission) {
|
||||
Tristate t = this.plugin.getDefaultPermissionMap().lookupDefaultPermission(permission, this.isOp);
|
||||
if (t != Tristate.UNDEFINED) {
|
||||
return RESULT_FACTORY.result(t);
|
||||
}
|
||||
|
||||
return TristateResult.UNDEFINED;
|
||||
}
|
||||
}
|
||||
@@ -1,90 +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.bukkit.calculator;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.calculator.processor.PermissionProcessor;
|
||||
import me.lucko.luckperms.common.calculator.processor.SpongeWildcardProcessor;
|
||||
import me.lucko.luckperms.common.calculator.processor.WildcardProcessor;
|
||||
import me.lucko.luckperms.common.calculator.result.TristateResult;
|
||||
|
||||
import net.luckperms.api.util.Tristate;
|
||||
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.permissions.PermissionDefault;
|
||||
|
||||
/**
|
||||
* Permission Processor for Bukkits "default" permission system.
|
||||
*/
|
||||
public class DefaultsProcessor implements PermissionProcessor {
|
||||
private static final TristateResult.Factory DEFAULT_PERMISSION_MAP_RESULT_FACTORY = new TristateResult.Factory(DefaultsProcessor.class, "default permission map");
|
||||
private static final TristateResult.Factory PERMISSION_MAP_RESULT_FACTORY = new TristateResult.Factory(DefaultsProcessor.class, "permission map");
|
||||
|
||||
private final LPBukkitPlugin plugin;
|
||||
private final boolean overrideWildcards;
|
||||
private final boolean isOp;
|
||||
|
||||
public DefaultsProcessor(LPBukkitPlugin plugin, boolean overrideWildcards, boolean isOp) {
|
||||
this.plugin = plugin;
|
||||
this.overrideWildcards = overrideWildcards;
|
||||
this.isOp = isOp;
|
||||
}
|
||||
|
||||
private boolean canOverrideWildcard(TristateResult prev) {
|
||||
return this.overrideWildcards &&
|
||||
(prev.processorClass() == WildcardProcessor.class || prev.processorClass() == SpongeWildcardProcessor.class) &&
|
||||
prev.result() == Tristate.TRUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TristateResult hasPermission(TristateResult prev, String permission) {
|
||||
if (prev != TristateResult.UNDEFINED) {
|
||||
// Check to see if the result should be overridden
|
||||
if (canOverrideWildcard(prev)) {
|
||||
Permission defPerm = this.plugin.getPermissionMap().get(permission);
|
||||
if (defPerm != null) {
|
||||
PermissionDefault def = defPerm.getDefault();
|
||||
if (def == PermissionDefault.FALSE || this.isOp && def == PermissionDefault.NOT_OP) {
|
||||
return PERMISSION_MAP_RESULT_FACTORY.result(Tristate.FALSE, "permission map (overriding wildcard): " + prev.cause());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
Tristate t = this.plugin.getDefaultPermissionMap().lookupDefaultPermission(permission, this.isOp);
|
||||
if (t != Tristate.UNDEFINED) {
|
||||
return DEFAULT_PERMISSION_MAP_RESULT_FACTORY.result(t);
|
||||
}
|
||||
|
||||
Permission defPerm = this.plugin.getPermissionMap().get(permission);
|
||||
if (defPerm == null) {
|
||||
return TristateResult.UNDEFINED;
|
||||
}
|
||||
return PERMISSION_MAP_RESULT_FACTORY.result(Tristate.of(defPerm.getDefault().getValue(this.isOp)));
|
||||
}
|
||||
}
|
||||
@@ -25,8 +25,9 @@
|
||||
|
||||
package me.lucko.luckperms.bukkit.calculator;
|
||||
|
||||
import me.lucko.luckperms.common.cacheddata.result.TristateResult;
|
||||
import me.lucko.luckperms.common.calculator.processor.AbstractPermissionProcessor;
|
||||
import me.lucko.luckperms.common.calculator.processor.PermissionProcessor;
|
||||
import me.lucko.luckperms.common.calculator.result.TristateResult;
|
||||
|
||||
import net.luckperms.api.util.Tristate;
|
||||
|
||||
@@ -34,7 +35,7 @@ import net.luckperms.api.util.Tristate;
|
||||
* Permission Processor which is added for opped users, to simply return true if
|
||||
* no other processors match.
|
||||
*/
|
||||
public final class OpProcessor implements PermissionProcessor {
|
||||
public final class OpProcessor extends AbstractPermissionProcessor implements PermissionProcessor {
|
||||
private static final TristateResult TRUE_RESULT = new TristateResult.Factory(OpProcessor.class).result(Tristate.TRUE);
|
||||
|
||||
public static final OpProcessor INSTANCE = new OpProcessor();
|
||||
@@ -44,10 +45,7 @@ public final class OpProcessor implements PermissionProcessor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TristateResult hasPermission(TristateResult prev, String permission) {
|
||||
if (prev != TristateResult.UNDEFINED) {
|
||||
return prev;
|
||||
}
|
||||
public TristateResult hasPermission(String permission) {
|
||||
return TRUE_RESULT;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.bukkit.calculator;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.cacheddata.result.TristateResult;
|
||||
import me.lucko.luckperms.common.calculator.processor.AbstractOverrideWildcardProcessor;
|
||||
import me.lucko.luckperms.common.calculator.processor.PermissionProcessor;
|
||||
|
||||
import net.luckperms.api.util.Tristate;
|
||||
|
||||
import org.bukkit.permissions.Permission;
|
||||
|
||||
/**
|
||||
* Permission Processor for Bukkits "default" permission system.
|
||||
*/
|
||||
public class PermissionMapProcessor extends AbstractOverrideWildcardProcessor implements PermissionProcessor {
|
||||
private static final TristateResult.Factory RESULT_FACTORY = new TristateResult.Factory(PermissionMapProcessor.class);
|
||||
|
||||
private final LPBukkitPlugin plugin;
|
||||
private final boolean isOp;
|
||||
|
||||
public PermissionMapProcessor(LPBukkitPlugin plugin, boolean overrideWildcards, boolean isOp) {
|
||||
super(overrideWildcards);
|
||||
this.plugin = plugin;
|
||||
this.isOp = isOp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TristateResult hasPermission(String permission) {
|
||||
Permission defPerm = this.plugin.getPermissionMap().get(permission);
|
||||
if (defPerm == null) {
|
||||
return TristateResult.UNDEFINED;
|
||||
}
|
||||
return RESULT_FACTORY.result(Tristate.of(defPerm.getDefault().getValue(this.isOp)));
|
||||
}
|
||||
}
|
||||
@@ -30,8 +30,8 @@ import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.cache.LoadingMap;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.context.ContextManager;
|
||||
import me.lucko.luckperms.common.context.QueryOptionsCache;
|
||||
import me.lucko.luckperms.common.context.manager.ContextManager;
|
||||
import me.lucko.luckperms.common.context.manager.QueryOptionsCache;
|
||||
import me.lucko.luckperms.common.util.CaffeineFactory;
|
||||
|
||||
import net.luckperms.api.context.ImmutableContextSet;
|
||||
|
||||
@@ -29,7 +29,7 @@ import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.context.contextset.ImmutableContextSetImpl;
|
||||
import me.lucko.luckperms.common.context.ImmutableContextSetImpl;
|
||||
import me.lucko.luckperms.common.util.EnumNamer;
|
||||
|
||||
import net.luckperms.api.context.Context;
|
||||
|
||||
+8
-8
@@ -29,13 +29,13 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.bukkit.calculator.DefaultsProcessor;
|
||||
import me.lucko.luckperms.bukkit.calculator.OpProcessor;
|
||||
import me.lucko.luckperms.common.calculator.result.TristateResult;
|
||||
import me.lucko.luckperms.bukkit.calculator.PermissionMapProcessor;
|
||||
import me.lucko.luckperms.common.cacheddata.result.TristateResult;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.context.QueryOptionsCache;
|
||||
import me.lucko.luckperms.common.context.manager.QueryOptionsCache;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.verbose.event.PermissionCheckEvent;
|
||||
import me.lucko.luckperms.common.verbose.event.CheckOrigin;
|
||||
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
import net.luckperms.api.util.Tristate;
|
||||
@@ -143,13 +143,13 @@ public class LuckPermsPermissible extends PermissibleBase {
|
||||
}
|
||||
|
||||
QueryOptions queryOptions = this.queryOptionsSupplier.getQueryOptions();
|
||||
TristateResult result = this.user.getCachedData().getPermissionData(queryOptions).checkPermission(permission, PermissionCheckEvent.Origin.PLATFORM_LOOKUP_CHECK);
|
||||
TristateResult result = this.user.getCachedData().getPermissionData(queryOptions).checkPermission(permission, CheckOrigin.PLATFORM_API_HAS_PERMISSION_SET);
|
||||
if (result.result() == Tristate.UNDEFINED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ignore matches made from looking up in the permission map (replicate bukkit behaviour)
|
||||
if (result.processorClass() == DefaultsProcessor.class && "permission map".equals(result.cause())) {
|
||||
if (result.processorClass() == PermissionMapProcessor.class) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ public class LuckPermsPermissible extends PermissibleBase {
|
||||
}
|
||||
|
||||
QueryOptions queryOptions = this.queryOptionsSupplier.getQueryOptions();
|
||||
return this.user.getCachedData().getPermissionData(queryOptions).checkPermission(permission, PermissionCheckEvent.Origin.PLATFORM_PERMISSION_CHECK).result().asBoolean();
|
||||
return this.user.getCachedData().getPermissionData(queryOptions).checkPermission(permission, CheckOrigin.PLATFORM_API_HAS_PERMISSION).result().asBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -183,7 +183,7 @@ public class LuckPermsPermissible extends PermissibleBase {
|
||||
}
|
||||
|
||||
QueryOptions queryOptions = this.queryOptionsSupplier.getQueryOptions();
|
||||
TristateResult result = this.user.getCachedData().getPermissionData(queryOptions).checkPermission(permission.getName(), PermissionCheckEvent.Origin.PLATFORM_PERMISSION_CHECK);
|
||||
TristateResult result = this.user.getCachedData().getPermissionData(queryOptions).checkPermission(permission.getName(), CheckOrigin.PLATFORM_API_HAS_PERMISSION);
|
||||
|
||||
// override default op handling using the Permission class we have
|
||||
if (result.processorClass() == OpProcessor.class && this.plugin.getConfiguration().get(ConfigKeys.APPLY_BUKKIT_DEFAULT_PERMISSIONS)) {
|
||||
|
||||
+3
-2
@@ -46,6 +46,7 @@ import java.lang.reflect.Field;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
@@ -239,7 +240,7 @@ public class LuckPermsPermissionAttachment extends PermissionAttachment {
|
||||
Objects.requireNonNull(name, "name is null");
|
||||
Preconditions.checkArgument(!name.isEmpty(), "name is empty");
|
||||
|
||||
String permission = name.toLowerCase();
|
||||
String permission = name.toLowerCase(Locale.ROOT);
|
||||
|
||||
Boolean previous = this.perms.put(permission, value);
|
||||
if (previous != null && previous == value) {
|
||||
@@ -264,7 +265,7 @@ public class LuckPermsPermissionAttachment extends PermissionAttachment {
|
||||
Objects.requireNonNull(name, "name is null");
|
||||
Preconditions.checkArgument(!name.isEmpty(), "name is empty");
|
||||
|
||||
String permission = name.toLowerCase();
|
||||
String permission = name.toLowerCase(Locale.ROOT);
|
||||
|
||||
Boolean previous = this.perms.remove(permission);
|
||||
if (previous == null) {
|
||||
|
||||
+11
-10
@@ -25,11 +25,12 @@
|
||||
|
||||
package me.lucko.luckperms.bukkit.inject.permissible;
|
||||
|
||||
import me.lucko.luckperms.common.calculator.result.TristateResult;
|
||||
import me.lucko.luckperms.common.cacheddata.result.TristateResult;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.query.QueryOptionsImpl;
|
||||
import me.lucko.luckperms.common.verbose.VerboseCheckTarget;
|
||||
import me.lucko.luckperms.common.verbose.VerboseHandler;
|
||||
import me.lucko.luckperms.common.verbose.event.PermissionCheckEvent;
|
||||
import me.lucko.luckperms.common.verbose.event.CheckOrigin;
|
||||
|
||||
import net.luckperms.api.util.Tristate;
|
||||
|
||||
@@ -51,7 +52,7 @@ import java.util.Set;
|
||||
public class MonitoredPermissibleBase extends PermissibleBase {
|
||||
final LuckPermsPlugin plugin;
|
||||
private final PermissibleBase delegate;
|
||||
private final String name;
|
||||
private final VerboseCheckTarget verboseCheckTarget;
|
||||
|
||||
// remains false until the object has been constructed
|
||||
// necessary to catch the superclass call to #recalculatePermissions on init
|
||||
@@ -64,12 +65,12 @@ public class MonitoredPermissibleBase extends PermissibleBase {
|
||||
|
||||
this.plugin = plugin;
|
||||
this.delegate = delegate;
|
||||
this.name = name;
|
||||
this.verboseCheckTarget = VerboseCheckTarget.internal(name);
|
||||
this.initialised = true;
|
||||
}
|
||||
|
||||
private void logCheck(PermissionCheckEvent.Origin origin, String permission, boolean result) {
|
||||
this.plugin.getVerboseHandler().offerPermissionCheckEvent(origin, this.name, QueryOptionsImpl.DEFAULT_CONTEXTUAL, permission, TristateResult.of(Tristate.of(result)));
|
||||
private void logCheck(CheckOrigin origin, String permission, boolean result) {
|
||||
this.plugin.getVerboseHandler().offerPermissionCheckEvent(origin, this.verboseCheckTarget, QueryOptionsImpl.DEFAULT_CONTEXTUAL, permission, TristateResult.forMonitoredResult(Tristate.of(result)));
|
||||
this.plugin.getPermissionRegistry().offer(permission);
|
||||
}
|
||||
|
||||
@@ -84,7 +85,7 @@ public class MonitoredPermissibleBase extends PermissibleBase {
|
||||
}
|
||||
|
||||
final boolean result = this.delegate.isPermissionSet(permission);
|
||||
logCheck(PermissionCheckEvent.Origin.PLATFORM_LOOKUP_CHECK, permission, result);
|
||||
logCheck(CheckOrigin.PLATFORM_API_HAS_PERMISSION_SET, permission, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -95,7 +96,7 @@ public class MonitoredPermissibleBase extends PermissibleBase {
|
||||
}
|
||||
|
||||
final boolean result = this.delegate.isPermissionSet(permission);
|
||||
logCheck(PermissionCheckEvent.Origin.PLATFORM_LOOKUP_CHECK, permission.getName(), result);
|
||||
logCheck(CheckOrigin.PLATFORM_API_HAS_PERMISSION_SET, permission.getName(), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -106,7 +107,7 @@ public class MonitoredPermissibleBase extends PermissibleBase {
|
||||
}
|
||||
|
||||
final boolean result = this.delegate.hasPermission(permission);
|
||||
logCheck(PermissionCheckEvent.Origin.PLATFORM_PERMISSION_CHECK, permission, result);
|
||||
logCheck(CheckOrigin.PLATFORM_API_HAS_PERMISSION, permission, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -117,7 +118,7 @@ public class MonitoredPermissibleBase extends PermissibleBase {
|
||||
}
|
||||
|
||||
final boolean result = this.delegate.hasPermission(permission);
|
||||
logCheck(PermissionCheckEvent.Origin.PLATFORM_PERMISSION_CHECK, permission.getName(), result);
|
||||
logCheck(CheckOrigin.PLATFORM_API_HAS_PERMISSION, permission.getName(), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
+32
-1
@@ -26,6 +26,7 @@
|
||||
package me.lucko.luckperms.bukkit.inject.permissible;
|
||||
|
||||
import me.lucko.luckperms.bukkit.util.CraftBukkitImplementation;
|
||||
import me.lucko.luckperms.common.plugin.logging.PluginLogger;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.PermissibleBase;
|
||||
@@ -84,9 +85,10 @@ public final class PermissibleInjector {
|
||||
*
|
||||
* @param player the player to inject into
|
||||
* @param newPermissible the permissible to inject
|
||||
* @param logger the plugin logger
|
||||
* @throws Exception propagates any exceptions which were thrown during injection
|
||||
*/
|
||||
public static void inject(Player player, LuckPermsPermissible newPermissible) throws Exception {
|
||||
public static void inject(Player player, LuckPermsPermissible newPermissible, PluginLogger logger) throws Exception {
|
||||
|
||||
// get the existing PermissibleBase held by the player
|
||||
PermissibleBase oldPermissible = (PermissibleBase) HUMAN_ENTITY_PERMISSIBLE_FIELD.get(player);
|
||||
@@ -96,6 +98,15 @@ public final class PermissibleInjector {
|
||||
throw new IllegalStateException("LPPermissible already injected into player " + player.toString());
|
||||
}
|
||||
|
||||
Class<? extends PermissibleBase> oldClass = oldPermissible.getClass();
|
||||
if (!PermissibleBase.class.equals(oldClass)) {
|
||||
logger.warn("Player " + player.getName() + " already has a custom permissible (" + oldClass.getName() + ")!\n" +
|
||||
"This is probably because you have multiple permission plugins installed.\n" +
|
||||
"Please make sure that LuckPerms is the only permission plugin installed on your server!\n" +
|
||||
"(unless you're performing a migration, in which case, just remember to remove your old " +
|
||||
"permission plugin once you're done!)");
|
||||
}
|
||||
|
||||
// Move attachments over from the old permissible
|
||||
|
||||
//noinspection unchecked
|
||||
@@ -151,4 +162,24 @@ public final class PermissibleInjector {
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkInjected(Player player, PluginLogger logger) {
|
||||
PermissibleBase permissibleBase;
|
||||
try {
|
||||
permissibleBase = (PermissibleBase) HUMAN_ENTITY_PERMISSIBLE_FIELD.get(player);
|
||||
} catch (IllegalAccessException e) {
|
||||
return; // ignore
|
||||
}
|
||||
|
||||
if (permissibleBase instanceof LuckPermsPermissible) {
|
||||
return; // all gucci
|
||||
}
|
||||
|
||||
Class<? extends PermissibleBase> clazz = permissibleBase.getClass();
|
||||
logger.warn("Player " + player.getName() + " has a non-LuckPerms permissible (" + clazz.getName() + ")!\n" +
|
||||
"This is probably because you have multiple permission plugins installed.\n" +
|
||||
"Please make sure that LuckPerms is the only permission plugin installed on your server!\n" +
|
||||
"(unless you're performing a migration, in which case, just remember to remove your old " +
|
||||
"permission plugin once you're done!)");
|
||||
}
|
||||
|
||||
}
|
||||
+2
-1
@@ -43,6 +43,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -140,7 +141,7 @@ public final class LuckPermsDefaultsMap implements Map<Boolean, Set<Permission>>
|
||||
protected @NonNull Map<String, Boolean> supply() {
|
||||
Map<String, Boolean> builder = new HashMap<>();
|
||||
for (Permission perm : LuckPermsDefaultsMap.this.get(this.op)) {
|
||||
String name = perm.getName().toLowerCase();
|
||||
String name = perm.getName().toLowerCase(Locale.ROOT);
|
||||
builder.put(name, true);
|
||||
for (Map.Entry<String, Boolean> child : LuckPermsDefaultsMap.this.plugin.getPermissionMap().getChildPermissions(name, true).entrySet()) {
|
||||
builder.putIfAbsent(child.getKey(), child.getValue());
|
||||
|
||||
+10
-1
@@ -40,6 +40,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -180,7 +181,7 @@ public final class LuckPermsPermissionMap extends ForwardingMap<String, Permissi
|
||||
continue;
|
||||
}
|
||||
|
||||
String key = e.getKey().toLowerCase();
|
||||
String key = e.getKey().toLowerCase(Locale.ROOT);
|
||||
|
||||
if (accumulator.containsKey(key)) {
|
||||
continue; // Prevent infinite loops
|
||||
@@ -241,6 +242,10 @@ public final class LuckPermsPermissionMap extends ForwardingMap<String, Permissi
|
||||
|
||||
NotifyingChildrenMap(Map<String, Boolean> delegate) {
|
||||
this.delegate = delegate;
|
||||
|
||||
for (String key : this.delegate.keySet()) {
|
||||
LuckPermsPermissionMap.this.plugin.getPermissionRegistry().insert(key);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -251,6 +256,7 @@ public final class LuckPermsPermissionMap extends ForwardingMap<String, Permissi
|
||||
@Override
|
||||
public Boolean put(@NonNull String key, @NonNull Boolean value) {
|
||||
Boolean ret = super.put(key, value);
|
||||
LuckPermsPermissionMap.this.plugin.getPermissionRegistry().insert(key);
|
||||
LuckPermsPermissionMap.this.update();
|
||||
return ret;
|
||||
}
|
||||
@@ -258,6 +264,9 @@ public final class LuckPermsPermissionMap extends ForwardingMap<String, Permissi
|
||||
@Override
|
||||
public void putAll(@NonNull Map<? extends String, ? extends Boolean> map) {
|
||||
super.putAll(map);
|
||||
for (String key : map.keySet()) {
|
||||
LuckPermsPermissionMap.this.plugin.getPermissionRegistry().insert(key);
|
||||
}
|
||||
LuckPermsPermissionMap.this.update();
|
||||
}
|
||||
|
||||
|
||||
+73
-157
@@ -25,10 +25,7 @@
|
||||
|
||||
package me.lucko.luckperms.bukkit.inject.server;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.util.ImmutableCollectors;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.Permissible;
|
||||
@@ -40,10 +37,8 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* A replacement map for the 'permSubs' instance in Bukkit's SimplePluginManager.
|
||||
@@ -67,15 +62,17 @@ import java.util.function.Function;
|
||||
*
|
||||
* Injected by {@link InjectorSubscriptionMap}.
|
||||
*/
|
||||
public final class LuckPermsSubscriptionMap extends HashMap<String, Map<Permissible, Boolean>> {
|
||||
public final class LuckPermsSubscriptionMap implements Map<String, Map<Permissible, Boolean>> {
|
||||
|
||||
// the plugin instance
|
||||
final LPBukkitPlugin plugin;
|
||||
|
||||
private final Map<Permissible, Set<String>> subscriptions = Collections.synchronizedMap(new WeakHashMap<>());
|
||||
|
||||
public LuckPermsSubscriptionMap(LPBukkitPlugin plugin, Map<String, Map<Permissible, Boolean>> existingData) {
|
||||
this.plugin = plugin;
|
||||
for (Entry<String, Map<Permissible, Boolean>> entry : existingData.entrySet()) {
|
||||
super.put(entry.getKey(), new LPSubscriptionValueMap(entry.getKey(), entry.getValue()));
|
||||
entry.getValue().keySet().forEach(permissible -> subscribe(permissible, entry.getKey()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,61 +81,55 @@ public final class LuckPermsSubscriptionMap extends HashMap<String, Map<Permissi
|
||||
* we override it to always return a value - which means the null check in
|
||||
* subscribeToDefaultPerms always fails - soo, we don't have to worry too much
|
||||
* about implementing #put.
|
||||
*
|
||||
* we also ensure all returns are LPSubscriptionValueMaps. this extension
|
||||
* will also delegate checks to online players - meaning we don't ever
|
||||
* have to register their subscriptions with the plugin manager.
|
||||
*/
|
||||
@Override
|
||||
public Map<Permissible, Boolean> get(Object key) {
|
||||
if (key == null || !(key instanceof String)) {
|
||||
return null;
|
||||
return new ValueMap((String) key);
|
||||
}
|
||||
|
||||
public void subscribe(Permissible permissible, String permission) {
|
||||
// don't allow players to be put into this map
|
||||
if (permissible instanceof Player) {
|
||||
return;
|
||||
}
|
||||
|
||||
String permission = (String) key;
|
||||
Set<String> perms = this.subscriptions.computeIfAbsent(permissible, x -> Collections.synchronizedSet(new HashSet<>()));
|
||||
perms.add(permission);
|
||||
}
|
||||
|
||||
LPSubscriptionValueMap result = (LPSubscriptionValueMap) super.get(key);
|
||||
if (result == null) {
|
||||
// calculate a new map - always!
|
||||
result = new LPSubscriptionValueMap(permission);
|
||||
super.put(permission, result);
|
||||
public boolean unsubscribe(Permissible permissible, String permission) {
|
||||
if (permissible instanceof Player) {
|
||||
return false; // ignore calls for players
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
Set<String> perms = this.subscriptions.get(permissible);
|
||||
|
||||
@Override
|
||||
public Map<Permissible, Boolean> put(String key, Map<Permissible, Boolean> value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException("Map value cannot be null");
|
||||
if (perms == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ensure values are LP subscription maps
|
||||
if (!(value instanceof LPSubscriptionValueMap)) {
|
||||
value = new LPSubscriptionValueMap(key, value);
|
||||
return perms.remove(permission);
|
||||
}
|
||||
|
||||
public @NonNull Set<Permissible> subscribers(String permission) {
|
||||
Collection<? extends Player> onlinePlayers = this.plugin.getBootstrap().getServer().getOnlinePlayers();
|
||||
Set<Permissible> set = new HashSet<>(onlinePlayers.size() + this.subscriptions.size());
|
||||
|
||||
// add permissibles from the subscriptions map
|
||||
this.subscriptions.forEach((permissible, perms) -> {
|
||||
if (perms.contains(permission)) {
|
||||
set.add(permissible);
|
||||
}
|
||||
});
|
||||
|
||||
// add any online players who meet requirements
|
||||
for (Player player : onlinePlayers) {
|
||||
if (player.hasPermission(permission) || player.isPermissionSet(permission)) {
|
||||
set.add(player);
|
||||
}
|
||||
}
|
||||
return super.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(Map<? extends String, ? extends Map<Permissible, Boolean>> m) {
|
||||
m.forEach(this::put);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Permissible, Boolean> putIfAbsent(String key, Map<Permissible, Boolean> value) {
|
||||
return get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Permissible, Boolean> computeIfAbsent(String key, Function<? super String, ? extends Map<Permissible, Boolean>> mappingFunction) {
|
||||
return get(key);
|
||||
}
|
||||
|
||||
// if the key isn't null and is a string, #get will always return a value for it
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return key != null && key instanceof String;
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,109 +139,53 @@ public final class LuckPermsSubscriptionMap extends HashMap<String, Map<Permissi
|
||||
*/
|
||||
public Map<String, Map<Permissible, Boolean>> detach() {
|
||||
Map<String, Map<Permissible, Boolean>> map = new HashMap<>();
|
||||
for (Map.Entry<String, Map<Permissible, Boolean>> ent : entrySet()) {
|
||||
map.put(ent.getKey(), new WeakHashMap<>(((LPSubscriptionValueMap) ent.getValue()).backing));
|
||||
}
|
||||
this.subscriptions.forEach((permissible, perms) -> {
|
||||
for (String perm : perms) {
|
||||
map.computeIfAbsent(perm, x -> new WeakHashMap<>()).put(permissible, true);
|
||||
}
|
||||
});
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override public Map<Permissible, Boolean> put(String key, Map<Permissible, Boolean> value) { throw new UnsupportedOperationException(); }
|
||||
@Override public Map<Permissible, Boolean> remove(Object key) { throw new UnsupportedOperationException(); }
|
||||
@Override public void putAll(Map<? extends String, ? extends Map<Permissible, Boolean>> m) { throw new UnsupportedOperationException(); }
|
||||
@Override public void clear() { throw new UnsupportedOperationException(); }
|
||||
@Override public Set<String> keySet() { throw new UnsupportedOperationException(); }
|
||||
@Override public Collection<Map<Permissible, Boolean>> values() { throw new UnsupportedOperationException(); }
|
||||
@Override public Set<Entry<String, Map<Permissible, Boolean>>> entrySet() { throw new UnsupportedOperationException(); }
|
||||
@Override public int size() { return 0; }
|
||||
@Override public boolean isEmpty() { throw new UnsupportedOperationException(); }
|
||||
@Override public boolean containsKey(Object key) { throw new UnsupportedOperationException(); }
|
||||
@Override public boolean containsValue(Object value) { throw new UnsupportedOperationException(); }
|
||||
|
||||
/**
|
||||
* Value map extension which includes LP objects in Permissible related queries.
|
||||
*/
|
||||
public final class LPSubscriptionValueMap implements Map<Permissible, Boolean> {
|
||||
public final class ValueMap implements Map<Permissible, Boolean> {
|
||||
|
||||
// the permission being mapped to this value map
|
||||
private final String permission;
|
||||
|
||||
// the backing map
|
||||
private final Map<Permissible, Boolean> backing;
|
||||
|
||||
private LPSubscriptionValueMap(String permission, Map<Permissible, Boolean> backing) {
|
||||
public ValueMap(String permission) {
|
||||
this.permission = permission;
|
||||
this.backing = Collections.synchronizedMap(new WeakHashMap<>(backing));
|
||||
|
||||
// remove all players from the map
|
||||
this.backing.keySet().removeIf(p -> p instanceof Player);
|
||||
}
|
||||
|
||||
public LPSubscriptionValueMap(String permission) {
|
||||
this.permission = permission;
|
||||
this.backing = Collections.synchronizedMap(new WeakHashMap<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean get(Object key) {
|
||||
boolean isPlayer = key instanceof Player;
|
||||
|
||||
// if the key is a player, check their LPPermissible first
|
||||
if (isPlayer) {
|
||||
Permissible p = (Permissible) key;
|
||||
if (p.hasPermission(this.permission)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// then try the map
|
||||
Boolean result = this.backing.get(key);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// then try the permissible, if we haven't already
|
||||
if (!isPlayer && key instanceof Permissible) {
|
||||
Permissible p = (Permissible) key;
|
||||
if (p.hasPermission(this.permission)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// no result
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean put(Permissible key, Boolean value) {
|
||||
// don't allow players to be put into this map
|
||||
if (key instanceof Player) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.backing.put(key, value);
|
||||
subscribe(key, this.permission);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
// delegate through the get method
|
||||
return get(key) != null;
|
||||
public Boolean remove(Object k) {
|
||||
Permissible key = (Permissible) k;
|
||||
return unsubscribe(key, this.permission) ? true : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Set<Permissible> keySet() {
|
||||
// start with the backing set
|
||||
Set<Permissible> set;
|
||||
synchronized (this.backing) {
|
||||
set = new HashSet<>(this.backing.keySet());
|
||||
}
|
||||
|
||||
// add any online players who meet requirements
|
||||
for (Player player : LuckPermsSubscriptionMap.this.plugin.getBootstrap().getServer().getOnlinePlayers()) {
|
||||
if (player.hasPermission(this.permission) || player.isPermissionSet(this.permission)) {
|
||||
set.add(player);
|
||||
}
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Set<Entry<Permissible, Boolean>> entrySet() {
|
||||
return keySet().stream()
|
||||
.map(key -> {
|
||||
Boolean value = get(key);
|
||||
return value != null ? Maps.immutableEntry(key, value) : null;
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(ImmutableCollectors.toSet());
|
||||
return subscribers(this.permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -262,34 +197,15 @@ public final class LuckPermsSubscriptionMap extends HashMap<String, Map<Permissi
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return Math.max(1, this.backing.size());
|
||||
return 1;
|
||||
}
|
||||
|
||||
// just delegate to the backing map
|
||||
|
||||
@Override
|
||||
public Boolean remove(Object key) {
|
||||
return this.backing.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return this.backing.containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(@NonNull Map<? extends Permissible, ? extends Boolean> m) {
|
||||
this.backing.putAll(m);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.backing.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Collection<Boolean> values() {
|
||||
return this.backing.values();
|
||||
}
|
||||
@Override public void putAll(Map<? extends Permissible, ? extends Boolean> m) { throw new UnsupportedOperationException(); }
|
||||
@Override public void clear() { throw new UnsupportedOperationException(); }
|
||||
@Override public Collection<Boolean> values() { throw new UnsupportedOperationException(); }
|
||||
@Override public Set<Entry<Permissible, Boolean>> entrySet() { throw new UnsupportedOperationException(); }
|
||||
@Override public boolean containsKey(Object key) { throw new UnsupportedOperationException(); }
|
||||
@Override public boolean containsValue(Object value) { throw new UnsupportedOperationException(); }
|
||||
@Override public Boolean get(Object key) { throw new UnsupportedOperationException(); }
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -203,7 +203,7 @@ public class BukkitConnectionListener extends AbstractConnectionListener impleme
|
||||
LuckPermsPermissible lpPermissible = new LuckPermsPermissible(player, user, this.plugin);
|
||||
|
||||
// Inject into the player
|
||||
PermissibleInjector.inject(player, lpPermissible);
|
||||
PermissibleInjector.inject(player, lpPermissible, this.plugin.getLogger());
|
||||
|
||||
} catch (Throwable t) {
|
||||
this.plugin.getLogger().warn("Exception thrown when setting up permissions for " +
|
||||
@@ -230,6 +230,8 @@ public class BukkitConnectionListener extends AbstractConnectionListener impleme
|
||||
e.disallow(PlayerLoginEvent.Result.KICK_OTHER, "");
|
||||
}
|
||||
}
|
||||
|
||||
PermissibleInjector.checkInjected(e.getPlayer(), this.plugin.getLogger());
|
||||
}
|
||||
|
||||
// Wait until the last priority to unload, so plugins can still perform permission checks on this event
|
||||
|
||||
+4
-3
@@ -38,6 +38,7 @@ import org.bukkit.event.server.PluginEnableEvent;
|
||||
import org.bukkit.event.server.RemoteServerCommandEvent;
|
||||
import org.bukkit.event.server.ServerCommandEvent;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class BukkitPlatformListener implements Listener {
|
||||
@@ -51,17 +52,17 @@ public class BukkitPlatformListener implements Listener {
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onPlayerCommand(PlayerCommandPreprocessEvent e) {
|
||||
handleCommand(e.getPlayer(), e.getMessage().toLowerCase(), e);
|
||||
handleCommand(e.getPlayer(), e.getMessage().toLowerCase(Locale.ROOT), e);
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onServerCommand(ServerCommandEvent e) {
|
||||
handleCommand(e.getSender(), e.getCommand().toLowerCase(), e);
|
||||
handleCommand(e.getSender(), e.getCommand().toLowerCase(Locale.ROOT), e);
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onRemoteServerCommand(RemoteServerCommandEvent e) {
|
||||
handleCommand(e.getSender(), e.getCommand().toLowerCase(), e);
|
||||
handleCommand(e.getSender(), e.getCommand().toLowerCase(Locale.ROOT), e);
|
||||
}
|
||||
|
||||
private void handleCommand(CommandSender sender, String cmdLine, Cancellable event) {
|
||||
|
||||
@@ -79,6 +79,8 @@ public abstract class AbstractVaultPermission extends Permission {
|
||||
public abstract boolean userHasPermission(String world, UUID uuid, String permission);
|
||||
public abstract boolean userAddPermission(String world, UUID uuid, String permission);
|
||||
public abstract boolean userRemovePermission(String world, UUID uuid, String permission);
|
||||
public abstract boolean userAddTransient(String world, UUID uuid, String permission);
|
||||
public abstract boolean userRemoveTransient(String world, UUID uuid, String permission);
|
||||
public abstract boolean userInGroup(String world, UUID uuid, String group);
|
||||
public abstract boolean userAddGroup(String world, UUID uuid, String group);
|
||||
public abstract boolean userRemoveGroup(String world, UUID uuid, String group);
|
||||
@@ -181,7 +183,7 @@ public abstract class AbstractVaultPermission extends Permission {
|
||||
public final boolean playerAdd(Player player, String permission) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return userAddPermission(convertWorld(player), ((OfflinePlayer) player).getUniqueId(), permission);
|
||||
return userAddPermission(convertWorld(player), player.getUniqueId(), permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -209,7 +211,63 @@ public abstract class AbstractVaultPermission extends Permission {
|
||||
public final boolean playerRemove(Player player, String permission) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return userRemovePermission(convertWorld(player), ((OfflinePlayer) player).getUniqueId(), permission);
|
||||
return userRemovePermission(convertWorld(player), player.getUniqueId(), permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean playerAddTransient(OfflinePlayer player, String permission) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return userAddTransient(null, player.getUniqueId(), permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerAddTransient(Player player, String permission) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return userAddTransient(convertWorld(player), player.getUniqueId(), permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerAddTransient(String world, OfflinePlayer player, String permission) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return userAddTransient(convertWorld(world), player.getUniqueId(), permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerAddTransient(String world, Player player, String permission) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return userAddTransient(convertWorld(world), player.getUniqueId(), permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean playerRemoveTransient(OfflinePlayer player, String permission) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return userRemoveTransient(null, player.getUniqueId(), permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerRemoveTransient(Player player, String permission) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return userRemoveTransient(convertWorld(player), player.getUniqueId(), permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerRemoveTransient(String world, OfflinePlayer player, String permission) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return userRemoveTransient(convertWorld(world), player.getUniqueId(), permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean playerRemoveTransient(String world, Player player, String permission) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
return userRemoveTransient(convertWorld(world), player.getUniqueId(), permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -279,7 +337,7 @@ public abstract class AbstractVaultPermission extends Permission {
|
||||
public final boolean playerInGroup(Player player, String group) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(group, "group");
|
||||
return userInGroup(convertWorld(player), ((OfflinePlayer) player).getUniqueId(), group);
|
||||
return userInGroup(convertWorld(player), player.getUniqueId(), group);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -307,7 +365,7 @@ public abstract class AbstractVaultPermission extends Permission {
|
||||
public final boolean playerAddGroup(Player player, String group) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
Objects.requireNonNull(group, "group");
|
||||
return userAddGroup(convertWorld(player), ((OfflinePlayer) player).getUniqueId(), group);
|
||||
return userAddGroup(convertWorld(player), player.getUniqueId(), group);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -334,7 +392,7 @@ public abstract class AbstractVaultPermission extends Permission {
|
||||
@Override
|
||||
public final boolean playerRemoveGroup(Player player, String group) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
return userRemoveGroup(convertWorld(player), ((OfflinePlayer) player).getUniqueId(), group);
|
||||
return userRemoveGroup(convertWorld(player), player.getUniqueId(), group);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -358,7 +416,7 @@ public abstract class AbstractVaultPermission extends Permission {
|
||||
@Override
|
||||
public final String[] getPlayerGroups(Player player) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
return userGetGroups(convertWorld(player), ((OfflinePlayer) player).getUniqueId());
|
||||
return userGetGroups(convertWorld(player), player.getUniqueId());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -382,7 +440,7 @@ public abstract class AbstractVaultPermission extends Permission {
|
||||
@Override
|
||||
public final String getPrimaryGroup(Player player) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
return userGetPrimaryGroup(convertWorld(player), ((OfflinePlayer) player).getUniqueId());
|
||||
return userGetPrimaryGroup(convertWorld(player), player.getUniqueId());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,14 +30,15 @@ import com.google.common.base.Strings;
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.cacheddata.type.MetaAccumulator;
|
||||
import me.lucko.luckperms.common.cacheddata.type.MetaCache;
|
||||
import me.lucko.luckperms.common.context.contextset.ImmutableContextSetImpl;
|
||||
import me.lucko.luckperms.common.cacheddata.type.MonitoredMetaCache;
|
||||
import me.lucko.luckperms.common.context.ImmutableContextSetImpl;
|
||||
import me.lucko.luckperms.common.model.Group;
|
||||
import me.lucko.luckperms.common.model.PermissionHolder;
|
||||
import me.lucko.luckperms.common.node.types.Meta;
|
||||
import me.lucko.luckperms.common.node.types.Prefix;
|
||||
import me.lucko.luckperms.common.node.types.Suffix;
|
||||
import me.lucko.luckperms.common.query.QueryOptionsImpl;
|
||||
import me.lucko.luckperms.common.verbose.event.MetaCheckEvent;
|
||||
import me.lucko.luckperms.common.verbose.event.CheckOrigin;
|
||||
|
||||
import net.luckperms.api.context.DefaultContextKeys;
|
||||
import net.luckperms.api.context.ImmutableContextSet;
|
||||
@@ -49,6 +50,7 @@ import net.luckperms.api.query.Flag;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
import net.milkbowl.vault.chat.Chat;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -96,7 +98,7 @@ public class LuckPermsVaultChat extends AbstractVaultChat {
|
||||
PermissionHolder user = this.vaultPermission.lookupUser(uuid);
|
||||
QueryOptions queryOptions = this.vaultPermission.getQueryOptions(uuid, world);
|
||||
MetaCache metaData = user.getCachedData().getMetaData(queryOptions);
|
||||
return Strings.nullToEmpty(metaData.getPrefix(MetaCheckEvent.Origin.THIRD_PARTY_API));
|
||||
return Strings.nullToEmpty(metaData.getPrefix(CheckOrigin.THIRD_PARTY_API).result());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -106,7 +108,7 @@ public class LuckPermsVaultChat extends AbstractVaultChat {
|
||||
PermissionHolder user = this.vaultPermission.lookupUser(uuid);
|
||||
QueryOptions queryOptions = this.vaultPermission.getQueryOptions(uuid, world);
|
||||
MetaCache metaData = user.getCachedData().getMetaData(queryOptions);
|
||||
return Strings.nullToEmpty(metaData.getSuffix(MetaCheckEvent.Origin.THIRD_PARTY_API));
|
||||
return Strings.nullToEmpty(metaData.getSuffix(CheckOrigin.THIRD_PARTY_API).result());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -138,8 +140,8 @@ public class LuckPermsVaultChat extends AbstractVaultChat {
|
||||
|
||||
PermissionHolder user = this.vaultPermission.lookupUser(uuid);
|
||||
QueryOptions queryOptions = this.vaultPermission.getQueryOptions(uuid, world);
|
||||
MetaCache metaData = user.getCachedData().getMetaData(queryOptions);
|
||||
return metaData.getMetaValue(key, MetaCheckEvent.Origin.THIRD_PARTY_API);
|
||||
MonitoredMetaCache metaData = user.getCachedData().getMetaData(queryOptions);
|
||||
return metaData.getMetaValue(key, CheckOrigin.THIRD_PARTY_API).result();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -157,21 +159,21 @@ public class LuckPermsVaultChat extends AbstractVaultChat {
|
||||
@Override
|
||||
public String getGroupChatPrefix(String world, String name) {
|
||||
Objects.requireNonNull(name, "name");
|
||||
MetaCache metaData = getGroupMetaCache(name, world);
|
||||
MonitoredMetaCache metaData = getGroupMetaCache(name, world);
|
||||
if (metaData == null) {
|
||||
return null;
|
||||
}
|
||||
return Strings.nullToEmpty(metaData.getPrefix(MetaCheckEvent.Origin.THIRD_PARTY_API));
|
||||
return Strings.nullToEmpty(metaData.getPrefix(CheckOrigin.THIRD_PARTY_API).result());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroupChatSuffix(String world, String name) {
|
||||
Objects.requireNonNull(name, "name");
|
||||
MetaCache metaData = getGroupMetaCache(name, world);
|
||||
MonitoredMetaCache metaData = getGroupMetaCache(name, world);
|
||||
if (metaData == null) {
|
||||
return null;
|
||||
}
|
||||
return Strings.nullToEmpty(metaData.getSuffix(MetaCheckEvent.Origin.THIRD_PARTY_API));
|
||||
return Strings.nullToEmpty(metaData.getSuffix(CheckOrigin.THIRD_PARTY_API).result());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -198,11 +200,11 @@ public class LuckPermsVaultChat extends AbstractVaultChat {
|
||||
public String getGroupMeta(String world, String name, String key) {
|
||||
Objects.requireNonNull(name, "name");
|
||||
Objects.requireNonNull(key, "key");
|
||||
MetaCache metaData = getGroupMetaCache(name, world);
|
||||
MonitoredMetaCache metaData = getGroupMetaCache(name, world);
|
||||
if (metaData == null) {
|
||||
return null;
|
||||
}
|
||||
return metaData.getMetaValue(key, MetaCheckEvent.Origin.THIRD_PARTY_API);
|
||||
return metaData.getMetaValue(key, CheckOrigin.THIRD_PARTY_API).result();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -222,7 +224,7 @@ public class LuckPermsVaultChat extends AbstractVaultChat {
|
||||
return this.plugin.getGroupManager().getByDisplayName(name);
|
||||
}
|
||||
|
||||
private MetaCache getGroupMetaCache(String name, String world) {
|
||||
private MonitoredMetaCache getGroupMetaCache(String name, String world) {
|
||||
Group group = getGroup(name);
|
||||
if (group == null) {
|
||||
return null;
|
||||
@@ -254,7 +256,7 @@ public class LuckPermsVaultChat extends AbstractVaultChat {
|
||||
|
||||
private void setMeta(PermissionHolder holder, String key, Object value, String world) {
|
||||
if (key.equalsIgnoreCase(Prefix.NODE_KEY) || key.equalsIgnoreCase(Suffix.NODE_KEY)) {
|
||||
setChatMeta(holder, ChatMetaType.valueOf(key.toUpperCase()), value == null ? null : value.toString(), world);
|
||||
setChatMeta(holder, ChatMetaType.valueOf(key.toUpperCase(Locale.ROOT)), value == null ? null : value.toString(), world);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -277,7 +279,7 @@ public class LuckPermsVaultChat extends AbstractVaultChat {
|
||||
private QueryOptions createQueryOptionsForWorldSet(String world) {
|
||||
ImmutableContextSet.Builder context = new ImmutableContextSetImpl.BuilderImpl();
|
||||
if (world != null && !world.isEmpty() && !world.equalsIgnoreCase("global")) {
|
||||
context.add(DefaultContextKeys.WORLD_KEY, world.toLowerCase());
|
||||
context.add(DefaultContextKeys.WORLD_KEY, world.toLowerCase(Locale.ROOT));
|
||||
}
|
||||
context.add(DefaultContextKeys.SERVER_KEY, this.vaultPermission.getVaultServer());
|
||||
|
||||
|
||||
+59
-24
@@ -29,10 +29,10 @@ import com.google.common.base.Preconditions;
|
||||
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.bukkit.context.BukkitContextManager;
|
||||
import me.lucko.luckperms.common.cacheddata.type.MetaCache;
|
||||
import me.lucko.luckperms.common.cacheddata.result.TristateResult;
|
||||
import me.lucko.luckperms.common.cacheddata.type.MonitoredMetaCache;
|
||||
import me.lucko.luckperms.common.cacheddata.type.PermissionCache;
|
||||
import me.lucko.luckperms.common.calculator.processor.DirectProcessor;
|
||||
import me.lucko.luckperms.common.calculator.result.TristateResult;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.model.Group;
|
||||
import me.lucko.luckperms.common.model.HolderType;
|
||||
@@ -44,9 +44,9 @@ import me.lucko.luckperms.common.node.types.Inheritance;
|
||||
import me.lucko.luckperms.common.query.QueryOptionsImpl;
|
||||
import me.lucko.luckperms.common.util.UniqueIdType;
|
||||
import me.lucko.luckperms.common.util.Uuids;
|
||||
import me.lucko.luckperms.common.verbose.event.MetaCheckEvent;
|
||||
import me.lucko.luckperms.common.verbose.event.PermissionCheckEvent;
|
||||
import me.lucko.luckperms.common.verbose.event.CheckOrigin;
|
||||
|
||||
import net.luckperms.api.context.ContextSet;
|
||||
import net.luckperms.api.context.DefaultContextKeys;
|
||||
import net.luckperms.api.context.MutableContextSet;
|
||||
import net.luckperms.api.model.data.DataType;
|
||||
@@ -59,6 +59,7 @@ import net.milkbowl.vault.permission.Permission;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
@@ -173,7 +174,7 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
PermissionHolder user = lookupUser(uuid);
|
||||
QueryOptions queryOptions = getQueryOptions(uuid, world);
|
||||
PermissionCache permissionData = user.getCachedData().getPermissionData(queryOptions);
|
||||
return permissionData.checkPermission(permission, PermissionCheckEvent.Origin.THIRD_PARTY_API).result().asBoolean();
|
||||
return permissionData.checkPermission(permission, CheckOrigin.THIRD_PARTY_API).result().asBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -185,7 +186,7 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
if (user instanceof Group) {
|
||||
throw new UnsupportedOperationException("Unable to modify the permissions of NPC players");
|
||||
}
|
||||
return holderAddPermission(user, permission, world);
|
||||
return holderAddPermission(user, permission, world, DataType.NORMAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -197,7 +198,31 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
if (user instanceof Group) {
|
||||
throw new UnsupportedOperationException("Unable to modify the permissions of NPC players");
|
||||
}
|
||||
return holderRemovePermission(user, permission, world);
|
||||
return holderRemovePermission(user, permission, world, DataType.NORMAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean userAddTransient(String world, UUID uuid, String permission) {
|
||||
Objects.requireNonNull(uuid, "uuid");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
|
||||
PermissionHolder user = lookupUser(uuid);
|
||||
if (user instanceof Group) {
|
||||
throw new UnsupportedOperationException("Unable to modify the permissions of NPC players");
|
||||
}
|
||||
return holderAddPermission(user, permission, world, DataType.TRANSIENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean userRemoveTransient(String world, UUID uuid, String permission) {
|
||||
Objects.requireNonNull(uuid, "uuid");
|
||||
Objects.requireNonNull(permission, "permission");
|
||||
|
||||
PermissionHolder user = lookupUser(uuid);
|
||||
if (user instanceof Group) {
|
||||
throw new UnsupportedOperationException("Unable to modify the permissions of NPC players");
|
||||
}
|
||||
return holderRemovePermission(user, permission, world, DataType.TRANSIENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -209,7 +234,7 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
QueryOptions queryOptions = getQueryOptions(uuid, world);
|
||||
PermissionCache permissionData = user.getCachedData().getPermissionData(queryOptions);
|
||||
|
||||
TristateResult result = permissionData.checkPermission(Inheritance.key(rewriteGroupName(group)), PermissionCheckEvent.Origin.THIRD_PARTY_API);
|
||||
TristateResult result = permissionData.checkPermission(Inheritance.key(rewriteGroupName(group)), CheckOrigin.THIRD_PARTY_API);
|
||||
return result.processorClass() == DirectProcessor.class && result.result().asBoolean();
|
||||
}
|
||||
|
||||
@@ -252,8 +277,11 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
}
|
||||
|
||||
QueryOptions queryOptions = getQueryOptions(uuid, world);
|
||||
MetaCache metaData = user.getCachedData().getMetaData(queryOptions);
|
||||
String value = metaData.getPrimaryGroup(MetaCheckEvent.Origin.THIRD_PARTY_API);
|
||||
MonitoredMetaCache metaData = user.getCachedData().getMetaData(queryOptions);
|
||||
String value = metaData.getPrimaryGroup(CheckOrigin.THIRD_PARTY_API);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Group group = getGroup(value);
|
||||
return group != null ? groupName(group) : value;
|
||||
@@ -271,7 +299,7 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
|
||||
QueryOptions queryOptions = getQueryOptions(null, world);
|
||||
PermissionCache permissionData = group.getCachedData().getPermissionData(queryOptions);
|
||||
return permissionData.checkPermission(permission, PermissionCheckEvent.Origin.THIRD_PARTY_API).result().asBoolean();
|
||||
return permissionData.checkPermission(permission, CheckOrigin.THIRD_PARTY_API).result().asBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -284,7 +312,7 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
return false;
|
||||
}
|
||||
|
||||
return holderAddPermission(group, permission, world);
|
||||
return holderAddPermission(group, permission, world, DataType.NORMAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -297,7 +325,7 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
return false;
|
||||
}
|
||||
|
||||
return holderRemovePermission(group, permission, world);
|
||||
return holderRemovePermission(group, permission, world, DataType.NORMAL);
|
||||
}
|
||||
|
||||
// utility methods for getting user and group instances
|
||||
@@ -328,13 +356,13 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
|
||||
// utility method for getting a contexts instance for a given vault lookup.
|
||||
QueryOptions getQueryOptions(@Nullable UUID uuid, @Nullable String world) {
|
||||
MutableContextSet context;
|
||||
ContextSet context;
|
||||
|
||||
Player player = Optional.ofNullable(uuid).flatMap(u -> this.plugin.getBootstrap().getPlayer(u)).orElse(null);
|
||||
if (player != null) {
|
||||
context = this.plugin.getContextManager().getContext(player).mutableCopy();
|
||||
context = this.plugin.getContextManager().getContext(player);
|
||||
} else {
|
||||
context = this.plugin.getContextManager().getStaticContext().mutableCopy();
|
||||
context = this.plugin.getContextManager().getStaticContext();
|
||||
}
|
||||
|
||||
String playerWorld = player == null ? null : player.getWorld().getName();
|
||||
@@ -342,20 +370,26 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
// if world is null, we want to do a lookup in the players current context
|
||||
// if world is not null, we want to do a lookup in that specific world
|
||||
if (world != null && !world.isEmpty() && !world.equalsIgnoreCase(playerWorld)) {
|
||||
MutableContextSet mutContext = context.mutableCopy();
|
||||
context = mutContext;
|
||||
|
||||
// remove already accumulated worlds
|
||||
context.removeAll(DefaultContextKeys.WORLD_KEY);
|
||||
mutContext.removeAll(DefaultContextKeys.WORLD_KEY);
|
||||
// add the vault world
|
||||
context.add(DefaultContextKeys.WORLD_KEY, world.toLowerCase());
|
||||
mutContext.add(DefaultContextKeys.WORLD_KEY, world.toLowerCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
// if we're using a special vault server
|
||||
if (useVaultServer()) {
|
||||
MutableContextSet mutContext = context instanceof MutableContextSet ? (MutableContextSet) context : context.mutableCopy();
|
||||
context = mutContext;
|
||||
|
||||
// remove the normal server context from the set
|
||||
context.remove(DefaultContextKeys.SERVER_KEY, getServer());
|
||||
mutContext.remove(DefaultContextKeys.SERVER_KEY, getServer());
|
||||
|
||||
// add the vault specific server
|
||||
if (!getVaultServer().equals("global")) {
|
||||
context.add(DefaultContextKeys.SERVER_KEY, getVaultServer());
|
||||
mutContext.add(DefaultContextKeys.SERVER_KEY, getVaultServer());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,7 +411,7 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
|
||||
// utility methods for modifying the state of PermissionHolders
|
||||
|
||||
private boolean holderAddPermission(PermissionHolder holder, String permission, String world) {
|
||||
private boolean holderAddPermission(PermissionHolder holder, String permission, String world, DataType type) {
|
||||
Objects.requireNonNull(permission, "permission is null");
|
||||
Preconditions.checkArgument(!permission.isEmpty(), "permission is an empty string");
|
||||
|
||||
@@ -386,13 +420,13 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
.withContext(DefaultContextKeys.WORLD_KEY, world == null ? "global" : world)
|
||||
.build();
|
||||
|
||||
if (holder.setNode(DataType.NORMAL, node, true).wasSuccessful()) {
|
||||
if (holder.setNode(type, node, true).wasSuccessful()) {
|
||||
return holderSave(holder);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean holderRemovePermission(PermissionHolder holder, String permission, String world) {
|
||||
private boolean holderRemovePermission(PermissionHolder holder, String permission, String world, DataType type) {
|
||||
Objects.requireNonNull(permission, "permission is null");
|
||||
Preconditions.checkArgument(!permission.isEmpty(), "permission is an empty string");
|
||||
|
||||
@@ -401,7 +435,7 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
.withContext(DefaultContextKeys.WORLD_KEY, world == null ? "global" : world)
|
||||
.build();
|
||||
|
||||
if (holder.unsetNode(DataType.NORMAL, node).wasSuccessful()) {
|
||||
if (holder.unsetNode(type, node).wasSuccessful()) {
|
||||
return holderSave(holder);
|
||||
}
|
||||
return false;
|
||||
@@ -450,4 +484,5 @@ public class LuckPermsVaultPermission extends AbstractVaultPermission {
|
||||
private boolean useVaultServer() {
|
||||
return this.plugin.getConfiguration().get(ConfigKeys.USE_VAULT_SERVER);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -154,15 +154,25 @@ data:
|
||||
#verifyServerCertificate: false
|
||||
|
||||
# The prefix for all LuckPerms SQL tables.
|
||||
#
|
||||
# - This only applies for remote SQL storage types (MySQL, MariaDB, etc).
|
||||
# - Change this if you want to use different tables for different servers.
|
||||
table-prefix: 'luckperms_'
|
||||
|
||||
# The prefix to use for all LuckPerms collections. Change this if you want to use different
|
||||
# collections for different servers. The default is no prefix.
|
||||
# The prefix to use for all LuckPerms MongoDB collections.
|
||||
#
|
||||
# - This only applies for the MongoDB storage type.
|
||||
# - Change this if you want to use different collections for different servers. The default is no
|
||||
# prefix.
|
||||
mongodb-collection-prefix: ''
|
||||
|
||||
# MongoDB ClientConnectionURI for use with replica sets and custom connection options
|
||||
# - See https://docs.mongodb.com/manual/reference/connection-string/
|
||||
# The connection string URI to use to connect to the MongoDB instance.
|
||||
#
|
||||
# - When configured, this setting will override anything defined in the address, database,
|
||||
# username or password fields above.
|
||||
# - If you have a connection string that starts with 'mongodb://' or 'mongodb+srv://', enter it
|
||||
# below.
|
||||
# - For more information, please see https://docs.mongodb.com/manual/reference/connection-string/
|
||||
mongodb-connection-uri: ''
|
||||
|
||||
# Define settings for a "split" storage setup.
|
||||
@@ -231,6 +241,7 @@ watch-files: true
|
||||
# below.
|
||||
# => rabbitmq Uses RabbitMQ pub-sub to push changes. Your server connection info must be
|
||||
# configured below.
|
||||
# => custom Uses a messaging service provided using the LuckPerms API.
|
||||
# => auto Attempts to automatically setup a messaging service using redis or sql.
|
||||
messaging-service: auto
|
||||
|
||||
@@ -252,6 +263,7 @@ broadcast-received-log-entries: true
|
||||
redis:
|
||||
enabled: false
|
||||
address: localhost
|
||||
username: ''
|
||||
password: ''
|
||||
|
||||
# Settings for RabbitMQ.
|
||||
@@ -540,6 +552,13 @@ apply-bukkit-attachment-permissions: true
|
||||
# | Extra settings | #
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
|
||||
# A list of context calculators which will be skipped when calculating contexts.
|
||||
#
|
||||
# - You can disable context calculators by either:
|
||||
# => specifying the Java class name used by the calculator (e.g. com.example.ExampleCalculator)
|
||||
# => specifying a sub-section of the Java package used by the calculator (e.g. com.example)
|
||||
disabled-context-calculators: []
|
||||
|
||||
# Allows you to set "aliases" for the worlds sent forward for context calculation.
|
||||
#
|
||||
# - These aliases are provided in addition to the real world name. Applied recursively.
|
||||
@@ -575,7 +594,8 @@ group-weight:
|
||||
# Controls whether server operators should exist at all.
|
||||
#
|
||||
# - When set to 'false', all players will be de-opped, and the /op and /deop commands will be
|
||||
# disabled.
|
||||
# disabled. Note that vanilla features like the spawn-protection require an operator on the
|
||||
# server to work.
|
||||
enable-ops: true
|
||||
|
||||
# Enables or disables a special permission based system in LuckPerms for controlling OP status.
|
||||
@@ -660,6 +680,20 @@ debug-logins: false
|
||||
# or less.
|
||||
allow-invalid-usernames: false
|
||||
|
||||
# If LuckPerms should not require users to confirm bulkupdate operations.
|
||||
#
|
||||
# - When set to true, operations will be executed immediately.
|
||||
# - This is not recommended, as bulkupdate has the potential to irreversibly delete large amounts of
|
||||
# data, and is not designed to be executed automatically.
|
||||
# - If automation is needed, users should prefer using the LuckPerms API.
|
||||
skip-bulkupdate-confirmation: false
|
||||
|
||||
# If LuckPerms should prevent bulkupdate operations.
|
||||
#
|
||||
# - When set to true, bulkupdate operations (the /lp bulkupdate command) will not work.
|
||||
# - When set to false, bulkupdate operations will be allowed via the console.
|
||||
disable-bulkupdate: false
|
||||
|
||||
# If LuckPerms should allow a users primary group to be removed with the 'parent remove' command.
|
||||
#
|
||||
# - When this happens, the plugin will set their primary group back to default.
|
||||
|
||||
@@ -54,6 +54,12 @@ luckperms {
|
||||
translations {
|
||||
install;
|
||||
}
|
||||
applyedits {
|
||||
code brigadier:string single_word;
|
||||
}
|
||||
trusteditor {
|
||||
id brigadier:string single_word;
|
||||
}
|
||||
creategroup {
|
||||
name brigadier:string single_word {
|
||||
weight brigadier:integer {
|
||||
@@ -62,9 +68,13 @@ luckperms {
|
||||
}
|
||||
}
|
||||
deletegroup {
|
||||
name brigadier:string single_word;
|
||||
name brigadier:string single_word {
|
||||
flags brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
listgroups {
|
||||
page brigadier:integer;
|
||||
}
|
||||
listgroups;
|
||||
createtrack {
|
||||
name brigadier:string single_word;
|
||||
}
|
||||
@@ -546,7 +556,9 @@ luckperms {
|
||||
context brigadier:string greedy_phrase;
|
||||
}
|
||||
rename {
|
||||
newname brigadier:string single_word;
|
||||
newname brigadier:string single_word {
|
||||
flags brigadier:string greedy_phrase;
|
||||
}
|
||||
}
|
||||
clone {
|
||||
newname brigadier:string single_word;
|
||||
|
||||
+9
-5
@@ -1,18 +1,22 @@
|
||||
plugins {
|
||||
id 'com.github.johnrengelman.shadow' version '2.0.4'
|
||||
id 'com.github.johnrengelman.shadow' version '7.0.0'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':common')
|
||||
implementation project(':common')
|
||||
compileOnly project(':common:loader-utils')
|
||||
|
||||
compileOnly 'net.md-5:bungeecord-api:1.15-SNAPSHOT'
|
||||
compileOnly 'me.lucko:adventure-platform-bungeecord:4.0.0' // re: this artifact - see note in common/build.gradle
|
||||
compileOnly 'net.md-5:bungeecord-api:1.16-R0.4'
|
||||
compileOnly('me.lucko:adventure-platform-bungeecord:4.9.4') {
|
||||
exclude(module: 'adventure-bom')
|
||||
exclude(module: 'adventure-api')
|
||||
exclude(module: 'adventure-nbt')
|
||||
}
|
||||
compileOnly 'com.imaginarycode.minecraft:RedisBungee:0.4'
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
archiveName = 'luckperms-bungee.jarinjar'
|
||||
archiveFileName = 'luckperms-bungee.jarinjar'
|
||||
|
||||
dependencies {
|
||||
include(dependency('me.lucko.luckperms:.*'))
|
||||
|
||||
@@ -5,19 +5,18 @@ plugins {
|
||||
dependencies {
|
||||
compileOnly 'net.md-5:bungeecord-api:1.15-SNAPSHOT'
|
||||
|
||||
compile project(':api')
|
||||
compile project(':common:loader-utils')
|
||||
implementation project(':api')
|
||||
implementation project(':common:loader-utils')
|
||||
}
|
||||
|
||||
processResources {
|
||||
from(sourceSets.main.resources.srcDirs) {
|
||||
filesMatching('plugin.yml') {
|
||||
expand 'pluginVersion': project.ext.fullVersion
|
||||
include 'plugin.yml'
|
||||
}
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
archiveName = "LuckPerms-Bungee-${project.ext.fullVersion}.jar"
|
||||
archiveFileName = "LuckPerms-Bungee-${project.ext.fullVersion}.jar"
|
||||
|
||||
from {
|
||||
project(':bungee').tasks.shadowJar.archiveFile
|
||||
@@ -26,4 +25,4 @@ shadowJar {
|
||||
|
||||
artifacts {
|
||||
archives shadowJar
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ package me.lucko.luckperms.bungee;
|
||||
|
||||
import me.lucko.luckperms.bungee.util.RedisBungeeUtil;
|
||||
import me.lucko.luckperms.common.loader.LoaderBootstrap;
|
||||
import me.lucko.luckperms.common.plugin.bootstrap.BootstrappedWithLoader;
|
||||
import me.lucko.luckperms.common.plugin.bootstrap.LuckPermsBootstrap;
|
||||
import me.lucko.luckperms.common.plugin.classpath.ClassPathAppender;
|
||||
import me.lucko.luckperms.common.plugin.classpath.JarInJarClassPathAppender;
|
||||
@@ -56,7 +57,7 @@ import java.util.logging.Logger;
|
||||
/**
|
||||
* Bootstrap plugin for LuckPerms running on BungeeCord.
|
||||
*/
|
||||
public class LPBungeeBootstrap implements LuckPermsBootstrap, LoaderBootstrap {
|
||||
public class LPBungeeBootstrap implements LuckPermsBootstrap, LoaderBootstrap, BootstrappedWithLoader {
|
||||
private final Plugin loader;
|
||||
|
||||
/**
|
||||
@@ -101,6 +102,7 @@ public class LPBungeeBootstrap implements LuckPermsBootstrap, LoaderBootstrap {
|
||||
|
||||
// provide adapters
|
||||
|
||||
@Override
|
||||
public Plugin getLoader() {
|
||||
return this.loader;
|
||||
}
|
||||
|
||||
@@ -47,8 +47,6 @@ import me.lucko.luckperms.common.model.manager.user.StandardUserManager;
|
||||
import me.lucko.luckperms.common.plugin.AbstractLuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.plugin.util.AbstractConnectionListener;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
import me.lucko.luckperms.common.tasks.CacheHousekeepingTask;
|
||||
import me.lucko.luckperms.common.tasks.ExpireTemporaryTask;
|
||||
|
||||
import net.luckperms.api.LuckPerms;
|
||||
import net.luckperms.api.context.DefaultContextKeys;
|
||||
@@ -57,7 +55,6 @@ import net.md_5.bungee.api.plugin.Plugin;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
@@ -170,12 +167,6 @@ public class LPBungeePlugin extends AbstractLuckPermsPlugin {
|
||||
// BungeeCord doesn't have a services manager
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerHousekeepingTasks() {
|
||||
this.bootstrap.getScheduler().asyncRepeating(new ExpireTemporaryTask(this), 3, TimeUnit.SECONDS);
|
||||
this.bootstrap.getScheduler().asyncRepeating(new CacheHousekeepingTask(this), 2, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performFinalSetup() {
|
||||
|
||||
|
||||
@@ -28,8 +28,9 @@ package me.lucko.luckperms.bungee.context;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
|
||||
import me.lucko.luckperms.bungee.LPBungeePlugin;
|
||||
import me.lucko.luckperms.common.context.ContextManager;
|
||||
import me.lucko.luckperms.common.context.QueryOptionsSupplier;
|
||||
import me.lucko.luckperms.common.context.manager.ContextManager;
|
||||
import me.lucko.luckperms.common.context.manager.InlineQueryOptionsSupplier;
|
||||
import me.lucko.luckperms.common.context.manager.QueryOptionsSupplier;
|
||||
import me.lucko.luckperms.common.util.CaffeineFactory;
|
||||
|
||||
import net.luckperms.api.context.ImmutableContextSet;
|
||||
@@ -60,9 +61,10 @@ public class BungeeContextManager extends ContextManager<ProxiedPlayer, ProxiedP
|
||||
throw new NullPointerException("subject");
|
||||
}
|
||||
|
||||
return new InlineQueryOptionsSupplier(subject, this.contextsCache);
|
||||
return new InlineQueryOptionsSupplier<>(subject, this.contextsCache);
|
||||
}
|
||||
|
||||
// override getContext, getQueryOptions and invalidateCache to skip the QueryOptionsSupplier
|
||||
@Override
|
||||
public ImmutableContextSet getContext(ProxiedPlayer subject) {
|
||||
return getQueryOptions(subject).context();
|
||||
@@ -83,18 +85,4 @@ public class BungeeContextManager extends ContextManager<ProxiedPlayer, ProxiedP
|
||||
return formQueryOptions(contextSet);
|
||||
}
|
||||
|
||||
private static final class InlineQueryOptionsSupplier implements QueryOptionsSupplier {
|
||||
private final ProxiedPlayer key;
|
||||
private final LoadingCache<ProxiedPlayer, QueryOptions> cache;
|
||||
|
||||
private InlineQueryOptionsSupplier(ProxiedPlayer key, LoadingCache<ProxiedPlayer, QueryOptions> cache) {
|
||||
this.key = key;
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryOptions getQueryOptions() {
|
||||
return this.cache.get(this.key);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ package me.lucko.luckperms.bungee.context;
|
||||
|
||||
import me.lucko.luckperms.bungee.LPBungeePlugin;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.context.contextset.ImmutableContextSetImpl;
|
||||
import me.lucko.luckperms.common.context.ImmutableContextSetImpl;
|
||||
|
||||
import net.luckperms.api.context.ContextCalculator;
|
||||
import net.luckperms.api.context.ContextConsumer;
|
||||
|
||||
@@ -28,7 +28,7 @@ package me.lucko.luckperms.bungee.context;
|
||||
import com.imaginarycode.minecraft.redisbungee.RedisBungee;
|
||||
import com.imaginarycode.minecraft.redisbungee.RedisBungeeAPI;
|
||||
|
||||
import me.lucko.luckperms.common.context.contextset.ImmutableContextSetImpl;
|
||||
import me.lucko.luckperms.common.context.ImmutableContextSetImpl;
|
||||
|
||||
import net.luckperms.api.context.ContextConsumer;
|
||||
import net.luckperms.api.context.ContextSet;
|
||||
|
||||
+9
-7
@@ -27,10 +27,12 @@ package me.lucko.luckperms.bungee.listeners;
|
||||
|
||||
import me.lucko.luckperms.bungee.LPBungeePlugin;
|
||||
import me.lucko.luckperms.bungee.event.TristateCheckEvent;
|
||||
import me.lucko.luckperms.common.calculator.result.TristateResult;
|
||||
import me.lucko.luckperms.common.cacheddata.result.TristateResult;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.query.QueryOptionsImpl;
|
||||
import me.lucko.luckperms.common.verbose.VerboseCheckTarget;
|
||||
import me.lucko.luckperms.common.verbose.event.CheckOrigin;
|
||||
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
import net.luckperms.api.util.Tristate;
|
||||
@@ -70,7 +72,7 @@ public class BungeePermissionCheckListener implements Listener {
|
||||
}
|
||||
|
||||
QueryOptions queryOptions = this.plugin.getContextManager().getQueryOptions(player);
|
||||
Tristate result = user.getCachedData().getPermissionData(queryOptions).checkPermission(e.getPermission(), me.lucko.luckperms.common.verbose.event.PermissionCheckEvent.Origin.PLATFORM_PERMISSION_CHECK).result();
|
||||
Tristate result = user.getCachedData().getPermissionData(queryOptions).checkPermission(e.getPermission(), CheckOrigin.PLATFORM_API_HAS_PERMISSION).result();
|
||||
if (result == Tristate.UNDEFINED && this.plugin.getConfiguration().get(ConfigKeys.APPLY_BUNGEE_CONFIG_PERMISSIONS)) {
|
||||
return; // just use the result provided by the proxy when the event was created
|
||||
}
|
||||
@@ -99,7 +101,7 @@ public class BungeePermissionCheckListener implements Listener {
|
||||
}
|
||||
|
||||
QueryOptions queryOptions = this.plugin.getContextManager().getQueryOptions(player);
|
||||
Tristate result = user.getCachedData().getPermissionData(queryOptions).checkPermission(e.getPermission(), me.lucko.luckperms.common.verbose.event.PermissionCheckEvent.Origin.PLATFORM_LOOKUP_CHECK).result();
|
||||
Tristate result = user.getCachedData().getPermissionData(queryOptions).checkPermission(e.getPermission(), CheckOrigin.PLATFORM_API_HAS_PERMISSION_SET).result();
|
||||
if (result == Tristate.UNDEFINED && this.plugin.getConfiguration().get(ConfigKeys.APPLY_BUNGEE_CONFIG_PERMISSIONS)) {
|
||||
return; // just use the result provided by the proxy when the event was created
|
||||
}
|
||||
@@ -118,9 +120,9 @@ public class BungeePermissionCheckListener implements Listener {
|
||||
|
||||
String permission = e.getPermission();
|
||||
Tristate result = Tristate.of(e.hasPermission());
|
||||
String name = "internal/" + e.getSender().getName();
|
||||
VerboseCheckTarget target = VerboseCheckTarget.internal(e.getSender().getName());
|
||||
|
||||
this.plugin.getVerboseHandler().offerPermissionCheckEvent(me.lucko.luckperms.common.verbose.event.PermissionCheckEvent.Origin.PLATFORM_PERMISSION_CHECK, name, QueryOptionsImpl.DEFAULT_CONTEXTUAL, permission, TristateResult.of(result));
|
||||
this.plugin.getVerboseHandler().offerPermissionCheckEvent(CheckOrigin.PLATFORM_API_HAS_PERMISSION, target, QueryOptionsImpl.DEFAULT_CONTEXTUAL, permission, TristateResult.forMonitoredResult(result));
|
||||
this.plugin.getPermissionRegistry().offer(permission);
|
||||
}
|
||||
|
||||
@@ -135,9 +137,9 @@ public class BungeePermissionCheckListener implements Listener {
|
||||
|
||||
String permission = e.getPermission();
|
||||
Tristate result = e.getResult();
|
||||
String name = "internal/" + e.getSender().getName();
|
||||
VerboseCheckTarget target = VerboseCheckTarget.internal(e.getSender().getName());
|
||||
|
||||
this.plugin.getVerboseHandler().offerPermissionCheckEvent(me.lucko.luckperms.common.verbose.event.PermissionCheckEvent.Origin.PLATFORM_LOOKUP_CHECK, name, QueryOptionsImpl.DEFAULT_CONTEXTUAL, permission, TristateResult.of(result));
|
||||
this.plugin.getVerboseHandler().offerPermissionCheckEvent(CheckOrigin.PLATFORM_API_HAS_PERMISSION_SET, target, QueryOptionsImpl.DEFAULT_CONTEXTUAL, permission, TristateResult.forMonitoredResult(result));
|
||||
this.plugin.getPermissionRegistry().offer(permission);
|
||||
}
|
||||
}
|
||||
@@ -151,15 +151,25 @@ data:
|
||||
#verifyServerCertificate: false
|
||||
|
||||
# The prefix for all LuckPerms SQL tables.
|
||||
#
|
||||
# - This only applies for remote SQL storage types (MySQL, MariaDB, etc).
|
||||
# - Change this if you want to use different tables for different servers.
|
||||
table-prefix: 'luckperms_'
|
||||
|
||||
# The prefix to use for all LuckPerms collections. Change this if you want to use different
|
||||
# collections for different servers. The default is no prefix.
|
||||
# The prefix to use for all LuckPerms MongoDB collections.
|
||||
#
|
||||
# - This only applies for the MongoDB storage type.
|
||||
# - Change this if you want to use different collections for different servers. The default is no
|
||||
# prefix.
|
||||
mongodb-collection-prefix: ''
|
||||
|
||||
# MongoDB ClientConnectionURI for use with replica sets and custom connection options
|
||||
# - See https://docs.mongodb.com/manual/reference/connection-string/
|
||||
# The connection string URI to use to connect to the MongoDB instance.
|
||||
#
|
||||
# - When configured, this setting will override anything defined in the address, database,
|
||||
# username or password fields above.
|
||||
# - If you have a connection string that starts with 'mongodb://' or 'mongodb+srv://', enter it
|
||||
# below.
|
||||
# - For more information, please see https://docs.mongodb.com/manual/reference/connection-string/
|
||||
mongodb-connection-uri: ''
|
||||
|
||||
# Define settings for a "split" storage setup.
|
||||
@@ -229,6 +239,7 @@ watch-files: true
|
||||
# the RedisBungee plugin installed.
|
||||
# => rabbitmq Uses RabbitMQ pub-sub to push changes. Your server connection info must be
|
||||
# configured below.
|
||||
# => custom Uses a messaging service provided using the LuckPerms API.
|
||||
# => auto Attempts to automatically setup a messaging service using redis or sql.
|
||||
messaging-service: auto
|
||||
|
||||
@@ -250,6 +261,7 @@ broadcast-received-log-entries: false
|
||||
redis:
|
||||
enabled: false
|
||||
address: localhost
|
||||
username: ''
|
||||
password: ''
|
||||
|
||||
# Settings for RabbitMQ.
|
||||
@@ -520,6 +532,13 @@ apply-bungee-config-permissions: false
|
||||
# | Extra settings | #
|
||||
# +----------------------------------------------------------------------------------------------+ #
|
||||
|
||||
# A list of context calculators which will be skipped when calculating contexts.
|
||||
#
|
||||
# - You can disable context calculators by either:
|
||||
# => specifying the Java class name used by the calculator (e.g. com.example.ExampleCalculator)
|
||||
# => specifying a sub-section of the Java package used by the calculator (e.g. com.example)
|
||||
disabled-context-calculators: []
|
||||
|
||||
# Allows you to set "aliases" for the worlds sent forward for context calculation.
|
||||
#
|
||||
# - These aliases are provided in addition to the real world name. Applied recursively.
|
||||
@@ -563,6 +582,20 @@ debug-logins: false
|
||||
# or less.
|
||||
allow-invalid-usernames: false
|
||||
|
||||
# If LuckPerms should not require users to confirm bulkupdate operations.
|
||||
#
|
||||
# - When set to true, operations will be executed immediately.
|
||||
# - This is not recommended, as bulkupdate has the potential to irreversibly delete large amounts of
|
||||
# data, and is not designed to be executed automatically.
|
||||
# - If automation is needed, users should prefer using the LuckPerms API.
|
||||
skip-bulkupdate-confirmation: false
|
||||
|
||||
# If LuckPerms should prevent bulkupdate operations.
|
||||
#
|
||||
# - When set to true, bulkupdate operations (the /lp bulkupdate command) will not work.
|
||||
# - When set to false, bulkupdate operations will be allowed via the console.
|
||||
disable-bulkupdate: false
|
||||
|
||||
# If LuckPerms should allow a users primary group to be removed with the 'parent remove' command.
|
||||
#
|
||||
# - When this happens, the plugin will set their primary group back to default.
|
||||
|
||||
+54
-36
@@ -1,3 +1,7 @@
|
||||
plugins {
|
||||
id 'java-library'
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform {
|
||||
excludeTags 'dependency_checksum'
|
||||
@@ -5,55 +9,69 @@ test {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testCompile 'org.junit.jupiter:junit-jupiter-api:5.7.0'
|
||||
testCompile 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
|
||||
|
||||
compile project(':api')
|
||||
compile 'org.checkerframework:checker-qual:3.8.0'
|
||||
api project(':api')
|
||||
api 'org.checkerframework:checker-qual:3.12.0'
|
||||
|
||||
compileOnly project(':common:loader-utils')
|
||||
|
||||
compileOnly 'org.slf4j:slf4j-api:1.7.30'
|
||||
compileOnly 'org.apache.logging.log4j:log4j-api:2.14.0'
|
||||
|
||||
// This is a special re-packaged version of 'net.kyori:adventure-*' for our own use.
|
||||
// Don't use it in other projects, you want the net.kyori version instead.
|
||||
// See here for more info: https://github.com/KyoriPowered/adventure
|
||||
compile('me.lucko:adventure-api:4.0.0') {
|
||||
api('net.kyori:adventure-api:4.9.3') {
|
||||
exclude(module: 'adventure-bom')
|
||||
exclude(module: 'checker-qual')
|
||||
exclude(module: 'annotations')
|
||||
}
|
||||
|
||||
compile('net.kyori:event-api:3.0.0') {
|
||||
exclude(module: 'checker-qual')
|
||||
exclude(module: 'guava')
|
||||
}
|
||||
compile 'com.google.code.gson:gson:2.7'
|
||||
compile 'com.google.guava:guava:19.0'
|
||||
compile 'com.github.ben-manes.caffeine:caffeine:2.8.4'
|
||||
compile 'com.squareup.okhttp3:okhttp:3.14.7'
|
||||
compile 'com.squareup.okio:okio:1.17.5'
|
||||
compile 'net.bytebuddy:byte-buddy:1.10.9'
|
||||
compile('org.spongepowered:configurate-core:3.7') {
|
||||
exclude(module: 'checker-qual')
|
||||
exclude(module: 'guava')
|
||||
}
|
||||
compile('org.spongepowered:configurate-yaml:3.7') {
|
||||
exclude(module: 'checker-qual')
|
||||
exclude(module: 'snakeyaml')
|
||||
}
|
||||
compile('org.spongepowered:configurate-gson:3.7') {
|
||||
exclude(module: 'checker-qual')
|
||||
api('net.kyori:adventure-text-serializer-gson:4.9.3') {
|
||||
exclude(module: 'adventure-bom')
|
||||
exclude(module: 'adventure-api')
|
||||
exclude(module: 'gson')
|
||||
}
|
||||
compile ('org.spongepowered:configurate-hocon:3.7') {
|
||||
|
||||
api('net.kyori:adventure-text-serializer-legacy:4.9.3') {
|
||||
exclude(module: 'adventure-bom')
|
||||
exclude(module: 'adventure-api')
|
||||
}
|
||||
|
||||
api('net.kyori:adventure-text-serializer-plain:4.9.3') {
|
||||
exclude(module: 'adventure-bom')
|
||||
exclude(module: 'adventure-api')
|
||||
}
|
||||
|
||||
api('net.kyori:event-api:3.0.0') {
|
||||
exclude(module: 'checker-qual')
|
||||
exclude(module: 'guava')
|
||||
}
|
||||
compile('me.lucko.configurate:configurate-toml:3.7') {
|
||||
exclude(module: 'toml4j')
|
||||
|
||||
api 'com.google.code.gson:gson:2.7'
|
||||
api 'com.google.guava:guava:19.0'
|
||||
|
||||
api 'com.github.ben-manes.caffeine:caffeine:2.9.0'
|
||||
api 'com.squareup.okhttp3:okhttp:3.14.9'
|
||||
api 'com.squareup.okio:okio:1.17.5'
|
||||
api 'net.bytebuddy:byte-buddy:1.10.22'
|
||||
api('org.spongepowered:configurate-core:3.7.2') {
|
||||
transitive = false
|
||||
}
|
||||
compile 'com.zaxxer:HikariCP:4.0.2'
|
||||
compile 'redis.clients:jedis:3.3.0'
|
||||
compile 'com.rabbitmq:amqp-client:5.10.0'
|
||||
compile 'org.mongodb:mongo-java-driver:3.12.2'
|
||||
compile 'org.yaml:snakeyaml:1.23'
|
||||
api('org.spongepowered:configurate-yaml:3.7.2') {
|
||||
transitive = false
|
||||
}
|
||||
api('org.spongepowered:configurate-gson:3.7.2') {
|
||||
transitive = false
|
||||
}
|
||||
api('org.spongepowered:configurate-hocon:3.7.2') {
|
||||
transitive = false
|
||||
}
|
||||
api('me.lucko.configurate:configurate-toml:3.7') {
|
||||
transitive = false
|
||||
}
|
||||
api 'com.zaxxer:HikariCP:4.0.3'
|
||||
api 'redis.clients:jedis:3.5.2'
|
||||
api 'com.rabbitmq:amqp-client:5.12.0'
|
||||
api 'org.mongodb:mongo-java-driver:3.12.8'
|
||||
api 'org.yaml:snakeyaml:1.28'
|
||||
}
|
||||
+15
@@ -33,6 +33,7 @@ import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
||||
/**
|
||||
@@ -64,6 +65,20 @@ public class JarInJarClassLoader extends URLClassLoader {
|
||||
addURL(url);
|
||||
}
|
||||
|
||||
public void deleteJarResource() {
|
||||
URL[] urls = getURLs();
|
||||
if (urls.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Path path = Paths.get(urls[0].toURI());
|
||||
Files.deleteIfExists(path);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new plugin instance.
|
||||
*
|
||||
|
||||
@@ -47,6 +47,7 @@ import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
@@ -126,10 +127,10 @@ public class LoggedAction implements Action {
|
||||
}
|
||||
|
||||
public boolean matchesSearch(String query) {
|
||||
query = Objects.requireNonNull(query, "query").toLowerCase();
|
||||
return this.source.name.toLowerCase().contains(query) ||
|
||||
this.target.name.toLowerCase().contains(query) ||
|
||||
this.description.toLowerCase().contains(query);
|
||||
query = Objects.requireNonNull(query, "query").toLowerCase(Locale.ROOT);
|
||||
return this.source.name.toLowerCase(Locale.ROOT).contains(query) ||
|
||||
this.target.name.toLowerCase(Locale.ROOT).contains(query) ||
|
||||
this.description.toLowerCase(Locale.ROOT).contains(query);
|
||||
}
|
||||
|
||||
public void submit(LuckPermsPlugin plugin, Sender sender) {
|
||||
|
||||
@@ -31,6 +31,7 @@ import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.storage.misc.DataConstraints;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public final class ApiUtils {
|
||||
@@ -55,7 +56,7 @@ public final class ApiUtils {
|
||||
}
|
||||
|
||||
Preconditions.checkArgument(DataConstraints.GROUP_NAME_TEST.test(s), "Invalid name entry: " + s);
|
||||
return s.toLowerCase();
|
||||
return s.toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -41,8 +41,12 @@ import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.event.AbstractEventBus;
|
||||
import me.lucko.luckperms.common.messaging.LuckPermsMessagingService;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.plugin.bootstrap.BootstrappedWithLoader;
|
||||
import me.lucko.luckperms.common.plugin.bootstrap.LuckPermsBootstrap;
|
||||
import me.lucko.luckperms.common.plugin.logging.PluginLogger;
|
||||
|
||||
import net.luckperms.api.LuckPerms;
|
||||
import net.luckperms.api.LuckPermsProvider;
|
||||
import net.luckperms.api.actionlog.ActionLogger;
|
||||
import net.luckperms.api.context.ContextManager;
|
||||
import net.luckperms.api.messaging.MessagingService;
|
||||
@@ -93,6 +97,37 @@ public class LuckPermsApiProvider implements LuckPerms {
|
||||
this.metaStackFactory = new ApiMetaStackFactory(plugin);
|
||||
}
|
||||
|
||||
public void ensureApiWasLoadedByPlugin() {
|
||||
LuckPermsBootstrap bootstrap = this.plugin.getBootstrap();
|
||||
ClassLoader pluginClassLoader;
|
||||
if (bootstrap instanceof BootstrappedWithLoader) {
|
||||
pluginClassLoader = ((BootstrappedWithLoader) bootstrap).getLoader().getClass().getClassLoader();
|
||||
} else {
|
||||
pluginClassLoader = bootstrap.getClass().getClassLoader();
|
||||
}
|
||||
|
||||
for (Class<?> apiClass : new Class[]{LuckPerms.class, LuckPermsProvider.class}) {
|
||||
ClassLoader apiClassLoader = apiClass.getClassLoader();
|
||||
|
||||
if (!apiClassLoader.equals(pluginClassLoader)) {
|
||||
String guilty = "unknown";
|
||||
try {
|
||||
guilty = bootstrap.identifyClassLoader(apiClassLoader);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
PluginLogger logger = this.plugin.getLogger();
|
||||
logger.warn("It seems that the LuckPerms API has been (class)loaded by a plugin other than LuckPerms!");
|
||||
logger.warn("The API was loaded by " + apiClassLoader + " (" + guilty + ") and the " +
|
||||
"LuckPerms plugin was loaded by " + pluginClassLoader.toString() + ".");
|
||||
logger.warn("This indicates that the other plugin has incorrectly \"shaded\" the " +
|
||||
"LuckPerms API into its jar file. This can cause errors at runtime and should be fixed.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull String getServerName() {
|
||||
return this.plugin.getConfiguration().get(ConfigKeys.SERVER);
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
package me.lucko.luckperms.common.api.implementation;
|
||||
|
||||
import me.lucko.luckperms.common.context.ContextManager;
|
||||
import me.lucko.luckperms.common.context.manager.ContextManager;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.query.QueryOptionsBuilderImpl;
|
||||
|
||||
|
||||
+2
-2
@@ -25,8 +25,8 @@
|
||||
|
||||
package me.lucko.luckperms.common.api.implementation;
|
||||
|
||||
import me.lucko.luckperms.common.context.contextset.ImmutableContextSetImpl;
|
||||
import me.lucko.luckperms.common.context.contextset.MutableContextSetImpl;
|
||||
import me.lucko.luckperms.common.context.ImmutableContextSetImpl;
|
||||
import me.lucko.luckperms.common.context.MutableContextSetImpl;
|
||||
|
||||
import net.luckperms.api.context.ContextSetFactory;
|
||||
import net.luckperms.api.context.ImmutableContextSet;
|
||||
|
||||
+4
-2
@@ -25,7 +25,7 @@
|
||||
|
||||
package me.lucko.luckperms.common.api.implementation;
|
||||
|
||||
import me.lucko.luckperms.common.context.ContextManager;
|
||||
import me.lucko.luckperms.common.context.manager.ContextManager;
|
||||
import me.lucko.luckperms.common.model.manager.user.UserManager;
|
||||
|
||||
import net.luckperms.api.context.ImmutableContextSet;
|
||||
@@ -57,7 +57,9 @@ public class ApiPlayerAdapter<S, P extends S> implements PlayerAdapter<P> {
|
||||
public @NonNull User getUser(@NonNull P player) {
|
||||
Objects.requireNonNull(player, "player");
|
||||
me.lucko.luckperms.common.model.User user = this.userManager.getIfLoaded(this.contextManager.getUniqueId(checkType(player)));
|
||||
Objects.requireNonNull(user, "user");
|
||||
if (user == null) {
|
||||
throw new IllegalStateException("Unable to get a user for " + player);
|
||||
}
|
||||
return user.getApiProxy();
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ import com.google.common.base.Preconditions;
|
||||
import me.lucko.luckperms.common.cacheddata.UserCachedDataManager;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.node.types.Inheritance;
|
||||
import me.lucko.luckperms.common.verbose.event.MetaCheckEvent;
|
||||
import me.lucko.luckperms.common.verbose.event.CheckOrigin;
|
||||
|
||||
import net.luckperms.api.model.data.DataMutateResult;
|
||||
import net.luckperms.api.model.data.DataType;
|
||||
@@ -38,6 +38,7 @@ import net.luckperms.api.node.NodeEqualityPredicate;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -71,7 +72,7 @@ public class ApiUser extends ApiPermissionHolder implements net.luckperms.api.mo
|
||||
|
||||
@Override
|
||||
public @NonNull String getPrimaryGroup() {
|
||||
String value = this.handle.getCachedData().getMetaData(this.handle.getQueryOptions()).getPrimaryGroup(MetaCheckEvent.Origin.LUCKPERMS_API);
|
||||
String value = this.handle.getCachedData().getMetaData(this.handle.getQueryOptions()).getPrimaryGroup(CheckOrigin.LUCKPERMS_API);
|
||||
Objects.requireNonNull(value, "value"); // assert nonnull
|
||||
return value;
|
||||
}
|
||||
@@ -79,15 +80,15 @@ public class ApiUser extends ApiPermissionHolder implements net.luckperms.api.mo
|
||||
@Override
|
||||
public @NonNull DataMutateResult setPrimaryGroup(@NonNull String group) {
|
||||
Objects.requireNonNull(group, "group");
|
||||
if (getPrimaryGroup().equalsIgnoreCase(group)) {
|
||||
if (group.equalsIgnoreCase(this.handle.getPrimaryGroup().getStoredValue().orElse(null))) {
|
||||
return DataMutateResult.FAIL_ALREADY_HAS;
|
||||
}
|
||||
|
||||
if (!this.handle.hasNode(DataType.NORMAL, Inheritance.builder(group.toLowerCase()).build(), NodeEqualityPredicate.IGNORE_EXPIRY_TIME_AND_VALUE).asBoolean()) {
|
||||
if (!this.handle.hasNode(DataType.NORMAL, Inheritance.builder(group.toLowerCase(Locale.ROOT)).build(), NodeEqualityPredicate.IGNORE_EXPIRY_TIME_AND_VALUE).asBoolean()) {
|
||||
return DataMutateResult.FAIL;
|
||||
}
|
||||
|
||||
this.handle.getPrimaryGroup().setStoredValue(group.toLowerCase());
|
||||
this.handle.getPrimaryGroup().setStoredValue(group.toLowerCase(Locale.ROOT));
|
||||
return DataMutateResult.SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
+14
-8
@@ -63,17 +63,20 @@ public class ApiUserManager extends ApiAbstractManager<User, net.luckperms.api.m
|
||||
return internal == null ? null : internal.getApiProxy();
|
||||
}
|
||||
|
||||
private net.luckperms.api.model.user.User proxyAndRegisterUsage(User internal) {
|
||||
if (internal != null) {
|
||||
this.plugin.getUserManager().getHouseKeeper().registerApiUsage(internal.getUniqueId());
|
||||
}
|
||||
return proxy(internal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull CompletableFuture<net.luckperms.api.model.user.User> loadUser(@NonNull UUID uniqueId, @Nullable String username) {
|
||||
Objects.requireNonNull(uniqueId, "uuid");
|
||||
ApiUtils.checkUsername(username, this.plugin);
|
||||
|
||||
if (this.plugin.getUserManager().getIfLoaded(uniqueId) == null) {
|
||||
this.plugin.getUserManager().getHouseKeeper().registerApiUsage(uniqueId);
|
||||
}
|
||||
|
||||
return this.plugin.getStorage().loadUser(uniqueId, username)
|
||||
.thenApply(this::proxy);
|
||||
.thenApply(this::proxyAndRegisterUsage);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -105,7 +108,10 @@ public class ApiUserManager extends ApiAbstractManager<User, net.luckperms.api.m
|
||||
action.accept(user.getApiProxy());
|
||||
return user;
|
||||
}, this.plugin.getBootstrap().getScheduler().async())
|
||||
.thenCompose(user -> this.plugin.getStorage().saveUser(user));
|
||||
.thenCompose(user -> {
|
||||
this.plugin.getUserManager().giveDefaultIfNeeded(user);
|
||||
return this.plugin.getStorage().saveUser(user);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -151,13 +157,13 @@ public class ApiUserManager extends ApiAbstractManager<User, net.luckperms.api.m
|
||||
@Override
|
||||
public net.luckperms.api.model.user.User getUser(@NonNull UUID uniqueId) {
|
||||
Objects.requireNonNull(uniqueId, "uuid");
|
||||
return proxy(this.handle.getIfLoaded(uniqueId));
|
||||
return proxyAndRegisterUsage(this.handle.getIfLoaded(uniqueId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public net.luckperms.api.model.user.User getUser(@NonNull String username) {
|
||||
Objects.requireNonNull(username, "name");
|
||||
return proxy(this.handle.getByUsername(username));
|
||||
return proxyAndRegisterUsage(this.handle.getByUsername(username));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -38,6 +38,7 @@ import me.lucko.luckperms.common.node.utils.NodeJsonSerializer;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
import me.lucko.luckperms.common.storage.Storage;
|
||||
import me.lucko.luckperms.common.util.CompletableFutures;
|
||||
import me.lucko.luckperms.common.util.gson.GsonProvider;
|
||||
import me.lucko.luckperms.common.util.gson.JArray;
|
||||
import me.lucko.luckperms.common.util.gson.JObject;
|
||||
@@ -193,7 +194,7 @@ public abstract class Exporter implements Runnable {
|
||||
}
|
||||
|
||||
// all of the threads have been scheduled now and are running. we just need to wait for them all to complete
|
||||
CompletableFuture<Void> overallFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
|
||||
CompletableFuture<Void> overallFuture = CompletableFutures.allOf(futures);
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
|
||||
@@ -39,6 +39,7 @@ import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.node.utils.NodeJsonSerializer;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.sender.Sender;
|
||||
import me.lucko.luckperms.common.util.CompletableFutures;
|
||||
import me.lucko.luckperms.common.util.Uuids;
|
||||
|
||||
import net.luckperms.api.event.cause.CreationCause;
|
||||
@@ -50,6 +51,7 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
@@ -167,7 +169,7 @@ public class Importer implements Runnable {
|
||||
for (JsonElement holderElement : holdersArray) {
|
||||
JsonObject jsonData = holderElement.getAsJsonObject();
|
||||
|
||||
HolderType type = HolderType.valueOf(jsonData.get("type").getAsString().toUpperCase());
|
||||
HolderType type = HolderType.valueOf(jsonData.get("type").getAsString().toUpperCase(Locale.ROOT));
|
||||
String id = jsonData.get("id").getAsString();
|
||||
|
||||
if (type == HolderType.GROUP) {
|
||||
@@ -259,7 +261,7 @@ public class Importer implements Runnable {
|
||||
}
|
||||
|
||||
// all of the threads have been scheduled now and are running. we just need to wait for them all to complete
|
||||
CompletableFuture<Void> overallFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
|
||||
CompletableFuture<Void> overallFuture = CompletableFutures.allOf(futures);
|
||||
|
||||
this.notify.forEach(s -> Message.IMPORT_INFO.send(s, "All data entries have been processed and scheduled for import - now waiting for the execution to complete."));
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
package me.lucko.luckperms.common.bulkupdate.query;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Represents a field being used in an update
|
||||
*/
|
||||
@@ -38,7 +40,7 @@ public enum QueryField {
|
||||
|
||||
public static QueryField of(String s) {
|
||||
try {
|
||||
return valueOf(s.toUpperCase());
|
||||
return valueOf(s.toUpperCase(Locale.ROOT));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
+13
-24
@@ -27,12 +27,13 @@ package me.lucko.luckperms.common.cacheddata;
|
||||
|
||||
import me.lucko.luckperms.common.cache.LoadingMap;
|
||||
import me.lucko.luckperms.common.cacheddata.type.MetaAccumulator;
|
||||
import me.lucko.luckperms.common.cacheddata.type.MetaCache;
|
||||
import me.lucko.luckperms.common.cacheddata.type.MonitoredMetaCache;
|
||||
import me.lucko.luckperms.common.cacheddata.type.PermissionCache;
|
||||
import me.lucko.luckperms.common.calculator.CalculatorFactory;
|
||||
import me.lucko.luckperms.common.calculator.PermissionCalculator;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.util.CaffeineFactory;
|
||||
import me.lucko.luckperms.common.util.CompletableFutures;
|
||||
|
||||
import net.luckperms.api.cacheddata.CachedData;
|
||||
import net.luckperms.api.cacheddata.CachedDataManager;
|
||||
@@ -40,6 +41,7 @@ import net.luckperms.api.cacheddata.CachedMetaData;
|
||||
import net.luckperms.api.cacheddata.CachedPermissionData;
|
||||
import net.luckperms.api.metastacking.MetaStackDefinition;
|
||||
import net.luckperms.api.node.ChatMetaType;
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
@@ -59,7 +61,7 @@ import java.util.function.IntFunction;
|
||||
public abstract class AbstractCachedDataManager implements CachedDataManager {
|
||||
private final LuckPermsPlugin plugin;
|
||||
private final AbstractContainer<PermissionCache, CachedPermissionData> permission;
|
||||
private final AbstractContainer<MetaCache, CachedMetaData> meta;
|
||||
private final AbstractContainer<MonitoredMetaCache, CachedMetaData> meta;
|
||||
|
||||
protected AbstractCachedDataManager(LuckPermsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
@@ -87,7 +89,7 @@ public abstract class AbstractCachedDataManager implements CachedDataManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull MetaCache getMetaData(@NonNull QueryOptions queryOptions) {
|
||||
public @NonNull MonitoredMetaCache getMetaData(@NonNull QueryOptions queryOptions) {
|
||||
return this.meta.get(queryOptions);
|
||||
}
|
||||
|
||||
@@ -97,7 +99,7 @@ public abstract class AbstractCachedDataManager implements CachedDataManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull MetaCache getMetaData() {
|
||||
public @NonNull MonitoredMetaCache getMetaData() {
|
||||
return getMetaData(getQueryOptions());
|
||||
}
|
||||
|
||||
@@ -139,7 +141,7 @@ public abstract class AbstractCachedDataManager implements CachedDataManager {
|
||||
* @param <M> the map type
|
||||
* @return the resolved permissions
|
||||
*/
|
||||
protected abstract <M extends Map<String, Boolean>> M resolvePermissions(IntFunction<M> mapFactory, QueryOptions queryOptions);
|
||||
protected abstract <M extends Map<String, Node>> M resolvePermissions(IntFunction<M> mapFactory, QueryOptions queryOptions);
|
||||
|
||||
/**
|
||||
* Resolves the owners meta data for the given {@link QueryOptions}.
|
||||
@@ -153,18 +155,18 @@ public abstract class AbstractCachedDataManager implements CachedDataManager {
|
||||
Objects.requireNonNull(queryOptions, "queryOptions");
|
||||
CacheMetadata metadata = getMetadataForQueryOptions(queryOptions);
|
||||
|
||||
ConcurrentHashMap<String, Boolean> sourcePermissions = resolvePermissions(ConcurrentHashMap::new, queryOptions);
|
||||
ConcurrentHashMap<String, Node> sourcePermissions = resolvePermissions(ConcurrentHashMap::new, queryOptions);
|
||||
return new PermissionCache(queryOptions, metadata, getCalculatorFactory(), sourcePermissions);
|
||||
}
|
||||
|
||||
private MetaCache calculateMeta(QueryOptions queryOptions) {
|
||||
private MonitoredMetaCache calculateMeta(QueryOptions queryOptions) {
|
||||
Objects.requireNonNull(queryOptions, "queryOptions");
|
||||
CacheMetadata metadata = getMetadataForQueryOptions(queryOptions);
|
||||
|
||||
MetaAccumulator accumulator = newAccumulator(queryOptions);
|
||||
resolveMeta(accumulator, queryOptions);
|
||||
|
||||
return new MetaCache(this.plugin, queryOptions, metadata, accumulator);
|
||||
return new MonitoredMetaCache(this.plugin, queryOptions, metadata, accumulator);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -240,7 +242,7 @@ public abstract class AbstractCachedDataManager implements CachedDataManager {
|
||||
@Override
|
||||
public @NonNull CompletableFuture<Void> reload() {
|
||||
Set<QueryOptions> keys = this.cache.keySet();
|
||||
return CompletableFuture.allOf(keys.stream().map(this::reload).toArray(CompletableFuture[]::new));
|
||||
return CompletableFutures.allOf(keys.stream().map(this::reload));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -254,24 +256,11 @@ public abstract class AbstractCachedDataManager implements CachedDataManager {
|
||||
this.cache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private MetaStackDefinition getMetaStackDefinition(QueryOptions queryOptions, ChatMetaType type) {
|
||||
MetaStackDefinition stack = queryOptions.option(type == ChatMetaType.PREFIX ?
|
||||
MetaStackDefinition.PREFIX_STACK_KEY :
|
||||
MetaStackDefinition.SUFFIX_STACK_KEY
|
||||
).orElse(null);
|
||||
|
||||
if (stack == null) {
|
||||
stack = getDefaultMetaStackDefinition(type);
|
||||
}
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
private MetaAccumulator newAccumulator(QueryOptions queryOptions) {
|
||||
return new MetaAccumulator(
|
||||
getMetaStackDefinition(queryOptions, ChatMetaType.PREFIX),
|
||||
getMetaStackDefinition(queryOptions, ChatMetaType.SUFFIX)
|
||||
queryOptions.option(MetaStackDefinition.PREFIX_STACK_KEY).orElseGet(() -> getDefaultMetaStackDefinition(ChatMetaType.PREFIX)),
|
||||
queryOptions.option(MetaStackDefinition.SUFFIX_STACK_KEY).orElseGet(() -> getDefaultMetaStackDefinition(ChatMetaType.SUFFIX))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
package me.lucko.luckperms.common.cacheddata;
|
||||
|
||||
import me.lucko.luckperms.common.model.HolderType;
|
||||
import me.lucko.luckperms.common.verbose.VerboseCheckTarget;
|
||||
|
||||
import net.luckperms.api.cacheddata.CachedData;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
@@ -41,18 +42,18 @@ public class CacheMetadata {
|
||||
private final HolderType holderType;
|
||||
|
||||
/**
|
||||
* The name of the object which owns the cache
|
||||
* The information about the holder for verbose checks
|
||||
*/
|
||||
private final String objectName;
|
||||
private final VerboseCheckTarget verboseCheckInfo;
|
||||
|
||||
/**
|
||||
* The query options
|
||||
*/
|
||||
private final QueryOptions queryOptions;
|
||||
|
||||
public CacheMetadata(HolderType holderType, String objectName, QueryOptions queryOptions) {
|
||||
public CacheMetadata(HolderType holderType, VerboseCheckTarget verboseCheckInfo, QueryOptions queryOptions) {
|
||||
this.holderType = holderType;
|
||||
this.objectName = objectName;
|
||||
this.verboseCheckInfo = verboseCheckInfo;
|
||||
this.queryOptions = queryOptions;
|
||||
}
|
||||
|
||||
@@ -60,8 +61,8 @@ public class CacheMetadata {
|
||||
return this.holderType;
|
||||
}
|
||||
|
||||
public String getObjectName() {
|
||||
return this.objectName;
|
||||
public VerboseCheckTarget getVerboseCheckInfo() {
|
||||
return this.verboseCheckInfo;
|
||||
}
|
||||
|
||||
public QueryOptions getQueryOptions() {
|
||||
|
||||
+2
-1
@@ -27,6 +27,7 @@ package me.lucko.luckperms.common.cacheddata;
|
||||
|
||||
import me.lucko.luckperms.common.model.Group;
|
||||
import me.lucko.luckperms.common.model.HolderType;
|
||||
import me.lucko.luckperms.common.verbose.VerboseCheckTarget;
|
||||
|
||||
import net.luckperms.api.cacheddata.CachedDataManager;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
@@ -42,7 +43,7 @@ public class GroupCachedDataManager extends HolderCachedDataManager<Group> imple
|
||||
|
||||
@Override
|
||||
protected CacheMetadata getMetadataForQueryOptions(QueryOptions queryOptions) {
|
||||
return new CacheMetadata(HolderType.GROUP, this.holder.getPlainDisplayName(), queryOptions);
|
||||
return new CacheMetadata(HolderType.GROUP, VerboseCheckTarget.group(this.holder), queryOptions);
|
||||
}
|
||||
|
||||
}
|
||||
+2
-1
@@ -32,6 +32,7 @@ import me.lucko.luckperms.common.model.PermissionHolder;
|
||||
|
||||
import net.luckperms.api.metastacking.MetaStackDefinition;
|
||||
import net.luckperms.api.node.ChatMetaType;
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
|
||||
import java.util.Map;
|
||||
@@ -75,7 +76,7 @@ public abstract class HolderCachedDataManager<T extends PermissionHolder> extend
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <M extends Map<String, Boolean>> M resolvePermissions(IntFunction<M> mapFactory, QueryOptions queryOptions) {
|
||||
protected <M extends Map<String, Node>> M resolvePermissions(IntFunction<M> mapFactory, QueryOptions queryOptions) {
|
||||
return this.holder.exportPermissions(mapFactory, queryOptions, true, getPlugin().getConfiguration().get(ConfigKeys.APPLYING_SHORTHAND));
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -27,6 +27,7 @@ package me.lucko.luckperms.common.cacheddata;
|
||||
|
||||
import me.lucko.luckperms.common.model.HolderType;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.verbose.VerboseCheckTarget;
|
||||
|
||||
import net.luckperms.api.cacheddata.CachedDataManager;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
@@ -42,7 +43,7 @@ public class UserCachedDataManager extends HolderCachedDataManager<User> impleme
|
||||
|
||||
@Override
|
||||
protected CacheMetadata getMetadataForQueryOptions(QueryOptions queryOptions) {
|
||||
return new CacheMetadata(HolderType.USER, this.holder.getPlainDisplayName(), queryOptions);
|
||||
return new CacheMetadata(HolderType.USER, VerboseCheckTarget.user(this.holder), queryOptions);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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.common.cacheddata.result;
|
||||
|
||||
import net.luckperms.api.cacheddata.Result;
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.node.types.ChatMetaNode;
|
||||
import net.luckperms.api.node.types.MetaNode;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* Represents the result of a meta lookup
|
||||
*
|
||||
* @param <N> the node type
|
||||
*/
|
||||
public final class StringResult<N extends Node> implements Result<String, N> {
|
||||
|
||||
/** The result, nullable */
|
||||
private final String result;
|
||||
/** The node that caused the result */
|
||||
private final N node;
|
||||
/** A reference to another result that this one overrides */
|
||||
private StringResult<N> overriddenResult;
|
||||
|
||||
public StringResult(String result, N node, StringResult<N> overriddenResult) {
|
||||
this.result = result;
|
||||
this.node = node;
|
||||
this.overriddenResult = overriddenResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String result() {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable N node() {
|
||||
return this.node;
|
||||
}
|
||||
|
||||
public @Nullable StringResult<N> overriddenResult() {
|
||||
return this.overriddenResult;
|
||||
}
|
||||
|
||||
public void setOverriddenResult(StringResult<N> overriddenResult) {
|
||||
this.overriddenResult = overriddenResult;
|
||||
}
|
||||
|
||||
public StringResult<N> copy() {
|
||||
return new StringResult<>(this.result, this.node, this.overriddenResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StringResult(" +
|
||||
"result=" + this.result + ", " +
|
||||
"node=" + this.node + ", " +
|
||||
"overriddenResult=" + this.overriddenResult + ')';
|
||||
}
|
||||
|
||||
private static final StringResult<?> NULL_RESULT = new StringResult<>(null, null, null);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <N extends Node> StringResult<N> nullResult() {
|
||||
return (StringResult<N>) NULL_RESULT;
|
||||
}
|
||||
|
||||
public static <N extends Node> StringResult<N> of(String result) {
|
||||
return new StringResult<>(result, null, null);
|
||||
}
|
||||
|
||||
public static <N extends Node> StringResult<N> of(String result, N node) {
|
||||
return new StringResult<>(result, node, null);
|
||||
}
|
||||
|
||||
public static StringResult<MetaNode> of(MetaNode node) {
|
||||
return new StringResult<>(node.getMetaValue(), node, null);
|
||||
}
|
||||
|
||||
public static <N extends ChatMetaNode<?, ?>> StringResult<N> of(N node) {
|
||||
return new StringResult<>(node.getMetaValue(), node, null);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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.common.cacheddata.result;
|
||||
|
||||
import me.lucko.luckperms.common.calculator.PermissionCalculator;
|
||||
import me.lucko.luckperms.common.calculator.processor.PermissionProcessor;
|
||||
|
||||
import net.luckperms.api.cacheddata.Result;
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.util.Tristate;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* Represents the result of a {@link PermissionCalculator} lookup.
|
||||
*/
|
||||
public final class TristateResult implements Result<Tristate, Node> {
|
||||
|
||||
/** The result */
|
||||
private final Tristate result;
|
||||
/** The node that caused the result */
|
||||
private final Node node;
|
||||
/** The permission processor that provided the result */
|
||||
private final Class<? extends PermissionProcessor> processorClass;
|
||||
/** A reference to another result that this one overrides */
|
||||
private TristateResult overriddenResult;
|
||||
|
||||
private TristateResult(Tristate result, Node node, Class<? extends PermissionProcessor> processorClass) {
|
||||
this.result = result;
|
||||
this.node = node;
|
||||
this.processorClass = processorClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Tristate result() {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Node node() {
|
||||
return this.node;
|
||||
}
|
||||
|
||||
public @Nullable Class<? extends PermissionProcessor> processorClass() {
|
||||
return this.processorClass;
|
||||
}
|
||||
|
||||
public @Nullable String processorClassFriendly() {
|
||||
if (this.processorClass == null) {
|
||||
return null;
|
||||
} else if (this.processorClass.getName().startsWith("me.lucko.luckperms.")) {
|
||||
String simpleName = this.processorClass.getSimpleName();
|
||||
String platform = this.processorClass.getName().split("\\.")[3];
|
||||
return platform + "." + simpleName;
|
||||
} else {
|
||||
return this.processorClass.getName();
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable TristateResult overriddenResult() {
|
||||
return this.overriddenResult;
|
||||
}
|
||||
|
||||
public void setOverriddenResult(TristateResult overriddenResult) {
|
||||
this.overriddenResult = overriddenResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TristateResult(" +
|
||||
"result=" + this.result + ", " +
|
||||
"node=" + this.node + ", " +
|
||||
"processorClass=" + this.processorClass + ", " +
|
||||
"overriddenResult=" + this.overriddenResult + ')';
|
||||
}
|
||||
|
||||
private static final TristateResult TRUE = new TristateResult(Tristate.TRUE, null,null);
|
||||
private static final TristateResult FALSE = new TristateResult(Tristate.FALSE, null,null);
|
||||
public static final TristateResult UNDEFINED = new TristateResult(Tristate.UNDEFINED, null,null);
|
||||
|
||||
public static TristateResult forMonitoredResult(Tristate result) {
|
||||
switch (result) {
|
||||
case TRUE:
|
||||
return TRUE;
|
||||
case FALSE:
|
||||
return FALSE;
|
||||
case UNDEFINED:
|
||||
return UNDEFINED;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Factory {
|
||||
private final Class<? extends PermissionProcessor> processorClass;
|
||||
|
||||
public Factory(Class<? extends PermissionProcessor> processorClass) {
|
||||
this.processorClass = processorClass;
|
||||
}
|
||||
|
||||
public TristateResult result(Tristate result) {
|
||||
switch (result) {
|
||||
case TRUE:
|
||||
case FALSE:
|
||||
return new TristateResult(result, null, this.processorClass);
|
||||
case UNDEFINED:
|
||||
return UNDEFINED;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
public TristateResult result(@Nullable Node node) {
|
||||
if (node == null) {
|
||||
return UNDEFINED;
|
||||
}
|
||||
return new TristateResult(Tristate.of(node.getValue()), node, this.processorClass);
|
||||
}
|
||||
|
||||
public TristateResult resultWithOverride(@Nullable Node node, @NonNull Tristate result) {
|
||||
if (result == Tristate.UNDEFINED) {
|
||||
return UNDEFINED;
|
||||
}
|
||||
return new TristateResult(result, node, this.processorClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
-25
@@ -28,6 +28,7 @@ package me.lucko.luckperms.common.cacheddata.type;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
|
||||
import me.lucko.luckperms.common.cacheddata.result.StringResult;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.node.types.Weight;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
@@ -35,13 +36,16 @@ import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import net.luckperms.api.metastacking.MetaStackDefinition;
|
||||
import net.luckperms.api.node.ChatMetaType;
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.node.types.ChatMetaNode;
|
||||
import net.luckperms.api.node.types.MetaNode;
|
||||
import net.luckperms.api.node.types.PrefixNode;
|
||||
import net.luckperms.api.node.types.SuffixNode;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
@@ -73,16 +77,18 @@ public class MetaAccumulator {
|
||||
|
||||
private final AtomicReference<State> state = new AtomicReference<>(State.ACCUMULATING);
|
||||
|
||||
private final ListMultimap<String, String> meta;
|
||||
private final SortedMap<Integer, String> prefixes;
|
||||
private final SortedMap<Integer, String> suffixes;
|
||||
private final ListMultimap<String, StringResult<MetaNode>> meta;
|
||||
private final SortedMap<Integer, StringResult<PrefixNode>> prefixes;
|
||||
private final SortedMap<Integer, StringResult<SuffixNode>> suffixes;
|
||||
private int weight = 0;
|
||||
private String primaryGroup;
|
||||
|
||||
private Set<String> seenNodeKeys = new HashSet<>();
|
||||
|
||||
private final MetaStackDefinition prefixDefinition;
|
||||
private final MetaStackDefinition suffixDefinition;
|
||||
private final MetaStackAccumulator prefixAccumulator;
|
||||
private final MetaStackAccumulator suffixAccumulator;
|
||||
private final MetaStackAccumulator<PrefixNode> prefixAccumulator;
|
||||
private final MetaStackAccumulator<SuffixNode> suffixAccumulator;
|
||||
|
||||
public MetaAccumulator(MetaStackDefinition prefixDefinition, MetaStackDefinition suffixDefinition) {
|
||||
Objects.requireNonNull(prefixDefinition, "prefixDefinition");
|
||||
@@ -92,8 +98,8 @@ public class MetaAccumulator {
|
||||
this.suffixes = new TreeMap<>(Comparator.reverseOrder());
|
||||
this.prefixDefinition = prefixDefinition;
|
||||
this.suffixDefinition = suffixDefinition;
|
||||
this.prefixAccumulator = new MetaStackAccumulator(this.prefixDefinition, ChatMetaType.PREFIX);
|
||||
this.suffixAccumulator = new MetaStackAccumulator(this.suffixDefinition, ChatMetaType.SUFFIX);
|
||||
this.prefixAccumulator = new MetaStackAccumulator<>(this.prefixDefinition, ChatMetaType.PREFIX);
|
||||
this.suffixAccumulator = new MetaStackAccumulator<>(this.suffixDefinition, ChatMetaType.SUFFIX);
|
||||
}
|
||||
|
||||
private void ensureState(State state) {
|
||||
@@ -115,11 +121,12 @@ public class MetaAccumulator {
|
||||
|
||||
// perform final changes
|
||||
if (!this.meta.containsKey(Weight.NODE_KEY) && this.weight != 0) {
|
||||
this.meta.put(Weight.NODE_KEY, String.valueOf(this.weight));
|
||||
this.meta.put(Weight.NODE_KEY, StringResult.of(String.valueOf(this.weight)));
|
||||
}
|
||||
if (this.primaryGroup != null && !this.meta.containsKey("primarygroup")) {
|
||||
this.meta.put("primarygroup", this.primaryGroup);
|
||||
this.meta.put("primarygroup", StringResult.of(this.primaryGroup));
|
||||
}
|
||||
this.seenNodeKeys = null; // free up for GC
|
||||
|
||||
this.state.set(State.COMPLETE);
|
||||
}
|
||||
@@ -129,29 +136,34 @@ public class MetaAccumulator {
|
||||
public void accumulateNode(Node n) {
|
||||
ensureState(State.ACCUMULATING);
|
||||
|
||||
// only process distinct nodes once, allows inheritance to be
|
||||
// "cancelled out" by assigning a false copy.
|
||||
if (!this.seenNodeKeys.add(n.getKey())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!n.getValue()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (n instanceof MetaNode) {
|
||||
MetaNode mn = (MetaNode) n;
|
||||
this.meta.put(mn.getMetaKey(), mn.getMetaValue());
|
||||
this.meta.put(mn.getMetaKey(), StringResult.of(mn));
|
||||
}
|
||||
|
||||
if (n instanceof PrefixNode) {
|
||||
PrefixNode pn = (PrefixNode) n;
|
||||
this.prefixes.putIfAbsent(pn.getPriority(), pn.getMetaValue());
|
||||
this.prefixes.putIfAbsent(pn.getPriority(), StringResult.of(pn));
|
||||
this.prefixAccumulator.offer(pn);
|
||||
}
|
||||
|
||||
if (n instanceof SuffixNode) {
|
||||
SuffixNode pn = (SuffixNode) n;
|
||||
this.suffixes.putIfAbsent(pn.getPriority(), pn.getMetaValue());
|
||||
this.suffixes.putIfAbsent(pn.getPriority(), StringResult.of(pn));
|
||||
this.suffixAccumulator.offer(pn);
|
||||
}
|
||||
}
|
||||
|
||||
public void accumulateMeta(String key, String value) {
|
||||
ensureState(State.ACCUMULATING);
|
||||
this.meta.put(key, value);
|
||||
}
|
||||
|
||||
public void accumulateWeight(int weight) {
|
||||
ensureState(State.ACCUMULATING);
|
||||
this.weight = Math.max(this.weight, weight);
|
||||
@@ -164,22 +176,22 @@ public class MetaAccumulator {
|
||||
|
||||
// read methods
|
||||
|
||||
public ListMultimap<String, String> getMeta() {
|
||||
public ListMultimap<String, StringResult<MetaNode>> getMeta() {
|
||||
ensureState(State.COMPLETE);
|
||||
return this.meta;
|
||||
}
|
||||
|
||||
public Map<Integer, String> getChatMeta(ChatMetaType type) {
|
||||
public Map<Integer, ? extends StringResult<? extends ChatMetaNode<?, ?>>> getChatMeta(ChatMetaType type) {
|
||||
ensureState(State.COMPLETE);
|
||||
return type == ChatMetaType.PREFIX ? this.prefixes : this.suffixes;
|
||||
}
|
||||
|
||||
public SortedMap<Integer, String> getPrefixes() {
|
||||
public SortedMap<Integer, StringResult<PrefixNode>> getPrefixes() {
|
||||
ensureState(State.COMPLETE);
|
||||
return this.prefixes;
|
||||
}
|
||||
|
||||
public SortedMap<Integer, String> getSuffixes() {
|
||||
public SortedMap<Integer, StringResult<SuffixNode>> getSuffixes() {
|
||||
ensureState(State.COMPLETE);
|
||||
return this.suffixes;
|
||||
}
|
||||
@@ -204,14 +216,14 @@ public class MetaAccumulator {
|
||||
return this.suffixDefinition;
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
public StringResult<PrefixNode> getPrefix() {
|
||||
ensureState(State.COMPLETE);
|
||||
return this.prefixAccumulator.toFormattedString();
|
||||
return this.prefixAccumulator.toResult();
|
||||
}
|
||||
|
||||
public String getSuffix() {
|
||||
public StringResult<SuffixNode> getSuffix() {
|
||||
ensureState(State.COMPLETE);
|
||||
return this.suffixAccumulator.toFormattedString();
|
||||
return this.suffixAccumulator.toResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -26,112 +26,213 @@
|
||||
package me.lucko.luckperms.common.cacheddata.type;
|
||||
|
||||
import com.google.common.collect.ForwardingMap;
|
||||
import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimaps;
|
||||
|
||||
import me.lucko.luckperms.common.cacheddata.CacheMetadata;
|
||||
import me.lucko.luckperms.common.model.HolderType;
|
||||
import me.lucko.luckperms.common.node.types.Prefix;
|
||||
import me.lucko.luckperms.common.node.types.Suffix;
|
||||
import me.lucko.luckperms.common.cacheddata.UsageTracked;
|
||||
import me.lucko.luckperms.common.cacheddata.result.StringResult;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.verbose.event.MetaCheckEvent;
|
||||
import me.lucko.luckperms.common.verbose.event.CheckOrigin;
|
||||
|
||||
import net.luckperms.api.cacheddata.CachedMetaData;
|
||||
import net.luckperms.api.cacheddata.Result;
|
||||
import net.luckperms.api.metastacking.MetaStackDefinition;
|
||||
import net.luckperms.api.node.types.MetaNode;
|
||||
import net.luckperms.api.node.types.PrefixNode;
|
||||
import net.luckperms.api.node.types.SuffixNode;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
import net.luckperms.api.query.meta.MetaValueSelector;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.SortedMap;
|
||||
|
||||
/**
|
||||
* Holds cached meta for a given context
|
||||
*/
|
||||
public class MetaCache extends SimpleMetaCache implements CachedMetaData {
|
||||
public class MetaCache extends UsageTracked implements CachedMetaData {
|
||||
|
||||
/** The plugin instance */
|
||||
private final LuckPermsPlugin plugin;
|
||||
|
||||
/** The metadata for this cache */
|
||||
private final CacheMetadata metadata;
|
||||
/** The query options this container is holding data for */
|
||||
private final QueryOptions queryOptions;
|
||||
|
||||
/** The object name passed to the verbose handler when checks are made */
|
||||
private final String verboseCheckTarget;
|
||||
/* The data */
|
||||
private final Map<String, List<StringResult<MetaNode>>> meta;
|
||||
private final Map<String, StringResult<MetaNode>> flattenedMeta;
|
||||
private final SortedMap<Integer, StringResult<PrefixNode>> prefixes;
|
||||
private final SortedMap<Integer, StringResult<SuffixNode>> suffixes;
|
||||
private final int weight;
|
||||
private final String primaryGroup;
|
||||
private final MetaStackDefinition prefixDefinition;
|
||||
private final MetaStackDefinition suffixDefinition;
|
||||
private final StringResult<PrefixNode> prefix;
|
||||
private final StringResult<SuffixNode> suffix;
|
||||
|
||||
public MetaCache(LuckPermsPlugin plugin, QueryOptions queryOptions, CacheMetadata metadata, MetaAccumulator sourceMeta) {
|
||||
super(plugin, queryOptions, sourceMeta);
|
||||
public MetaCache(LuckPermsPlugin plugin, QueryOptions queryOptions, MetaAccumulator sourceMeta) {
|
||||
this.plugin = plugin;
|
||||
this.metadata = metadata;
|
||||
this.queryOptions = queryOptions;
|
||||
|
||||
if (this.metadata.getHolderType() == HolderType.GROUP) {
|
||||
this.verboseCheckTarget = "group/" + this.metadata.getObjectName();
|
||||
} else {
|
||||
this.verboseCheckTarget = this.metadata.getObjectName();
|
||||
Map<String, List<StringResult<MetaNode>>> meta = Multimaps.asMap(ImmutableListMultimap.copyOf(sourceMeta.getMeta()));
|
||||
|
||||
MetaValueSelector metaValueSelector = this.queryOptions.option(MetaValueSelector.KEY)
|
||||
.orElseGet(() -> this.plugin.getConfiguration().get(ConfigKeys.META_VALUE_SELECTOR));
|
||||
|
||||
ImmutableMap.Builder<String, StringResult<MetaNode>> builder = ImmutableMap.builder();
|
||||
for (Map.Entry<String, List<StringResult<MetaNode>>> e : meta.entrySet()) {
|
||||
if (e.getValue().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Result<String, MetaNode> selected = metaValueSelector.selectValue(e.getKey(), e.getValue());
|
||||
if (selected == null) {
|
||||
throw new NullPointerException(metaValueSelector + " returned null");
|
||||
}
|
||||
|
||||
builder.put(e.getKey(), (StringResult<MetaNode>) selected);
|
||||
}
|
||||
this.flattenedMeta = builder.build();
|
||||
this.meta = new LowerCaseMetaMap(meta);
|
||||
|
||||
this.prefixes = ImmutableSortedMap.copyOfSorted(sourceMeta.getPrefixes());
|
||||
this.suffixes = ImmutableSortedMap.copyOfSorted(sourceMeta.getSuffixes());
|
||||
this.weight = sourceMeta.getWeight();
|
||||
this.primaryGroup = sourceMeta.getPrimaryGroup();
|
||||
this.prefixDefinition = sourceMeta.getPrefixDefinition();
|
||||
this.suffixDefinition = sourceMeta.getSuffixDefinition();
|
||||
this.prefix = sourceMeta.getPrefix();
|
||||
this.suffix = sourceMeta.getSuffix();
|
||||
}
|
||||
|
||||
public @NonNull StringResult<MetaNode> getMetaValue(String key, CheckOrigin origin) {
|
||||
Objects.requireNonNull(key, "key");
|
||||
return this.flattenedMeta.getOrDefault(key.toLowerCase(Locale.ROOT), StringResult.nullResult());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMetaValue(String key, MetaCheckEvent.Origin origin) {
|
||||
String value = super.getMetaValue(key, origin);
|
||||
this.plugin.getVerboseHandler().offerMetaCheckEvent(origin, this.verboseCheckTarget, this.metadata.getQueryOptions(), key, String.valueOf(value));
|
||||
return value;
|
||||
public final @NonNull Result<String, MetaNode> queryMetaValue(@NonNull String key) {
|
||||
return getMetaValue(key, CheckOrigin.LUCKPERMS_API);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefix(MetaCheckEvent.Origin origin) {
|
||||
String value = super.getPrefix(origin);
|
||||
this.plugin.getVerboseHandler().offerMetaCheckEvent(origin, this.verboseCheckTarget, this.metadata.getQueryOptions(), Prefix.NODE_KEY, String.valueOf(value));
|
||||
return value;
|
||||
public final @Nullable String getMetaValue(@NonNull String key) {
|
||||
return getMetaValue(key, CheckOrigin.LUCKPERMS_API).result();
|
||||
}
|
||||
|
||||
public @NonNull StringResult<PrefixNode> getPrefix(CheckOrigin origin) {
|
||||
return this.prefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSuffix(MetaCheckEvent.Origin origin) {
|
||||
String value = super.getSuffix(origin);
|
||||
this.plugin.getVerboseHandler().offerMetaCheckEvent(origin, this.verboseCheckTarget, this.metadata.getQueryOptions(), Suffix.NODE_KEY, String.valueOf(value));
|
||||
return value;
|
||||
public final @NonNull Result<String, PrefixNode> queryPrefix() {
|
||||
return getPrefix(CheckOrigin.LUCKPERMS_API);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> getMeta(MetaCheckEvent.Origin origin) {
|
||||
return new MonitoredMetaMap(super.getMeta(origin), origin);
|
||||
public final @Nullable String getPrefix() {
|
||||
return getPrefix(CheckOrigin.LUCKPERMS_API).result();
|
||||
}
|
||||
|
||||
public @NonNull StringResult<SuffixNode> getSuffix(CheckOrigin origin) {
|
||||
return this.suffix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWeight(MetaCheckEvent.Origin origin) {
|
||||
int value = super.getWeight(origin);
|
||||
this.plugin.getVerboseHandler().offerMetaCheckEvent(origin, this.verboseCheckTarget, this.metadata.getQueryOptions(), "weight", String.valueOf(value));
|
||||
return value;
|
||||
public final @NonNull Result<String, SuffixNode> querySuffix() {
|
||||
return getSuffix(CheckOrigin.LUCKPERMS_API);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getPrimaryGroup(MetaCheckEvent.Origin origin) {
|
||||
String value = super.getPrimaryGroup(origin);
|
||||
this.plugin.getVerboseHandler().offerMetaCheckEvent(origin, this.verboseCheckTarget, this.metadata.getQueryOptions(), "primarygroup", String.valueOf(value));
|
||||
return value;
|
||||
public final @Nullable String getSuffix() {
|
||||
return getSuffix(CheckOrigin.LUCKPERMS_API).result();
|
||||
}
|
||||
|
||||
private final class MonitoredMetaMap extends ForwardingMap<String, List<String>> {
|
||||
private final Map<String, List<String>> delegate;
|
||||
private final MetaCheckEvent.Origin origin;
|
||||
protected Map<String, List<StringResult<MetaNode>>> getMetaResults(CheckOrigin origin) {
|
||||
return this.meta;
|
||||
}
|
||||
|
||||
private MonitoredMetaMap(Map<String, List<String>> delegate, MetaCheckEvent.Origin origin) {
|
||||
public final Map<String, List<String>> getMeta(CheckOrigin origin) {
|
||||
return Maps.transformValues(getMetaResults(origin), list -> Lists.transform(list, StringResult::result));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final @NonNull Map<String, List<String>> getMeta() {
|
||||
return getMeta(CheckOrigin.LUCKPERMS_API);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull SortedMap<Integer, String> getPrefixes() {
|
||||
return Maps.transformValues(this.prefixes, StringResult::result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull SortedMap<Integer, String> getSuffixes() {
|
||||
return Maps.transformValues(this.suffixes, StringResult::result);
|
||||
}
|
||||
|
||||
public int getWeight(CheckOrigin origin) {
|
||||
return this.weight;
|
||||
}
|
||||
|
||||
//@Override - not actually exposed in the API atm
|
||||
public final int getWeight() {
|
||||
return getWeight(CheckOrigin.LUCKPERMS_API);
|
||||
}
|
||||
|
||||
public @Nullable String getPrimaryGroup(CheckOrigin origin) {
|
||||
return this.primaryGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final @Nullable String getPrimaryGroup() {
|
||||
return getPrimaryGroup(CheckOrigin.LUCKPERMS_API);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull MetaStackDefinition getPrefixStackDefinition() {
|
||||
return this.prefixDefinition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull MetaStackDefinition getSuffixStackDefinition() {
|
||||
return this.suffixDefinition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull QueryOptions getQueryOptions() {
|
||||
return this.queryOptions;
|
||||
}
|
||||
|
||||
private static final class LowerCaseMetaMap extends ForwardingMap<String, List<StringResult<MetaNode>>> {
|
||||
private final Map<String, List<StringResult<MetaNode>>> delegate;
|
||||
|
||||
private LowerCaseMetaMap(Map<String, List<StringResult<MetaNode>>> delegate) {
|
||||
this.delegate = delegate;
|
||||
this.origin = origin;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, List<String>> delegate() {
|
||||
protected Map<String, List<StringResult<MetaNode>>> delegate() {
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> get(Object k) {
|
||||
public List<StringResult<MetaNode>> get(Object k) {
|
||||
if (k == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String key = (String) k;
|
||||
List<String> values = super.get(key);
|
||||
MetaCache.this.plugin.getVerboseHandler().offerMetaCheckEvent(this.origin, MetaCache.this.verboseCheckTarget, MetaCache.this.metadata.getQueryOptions(), key, String.valueOf(values));
|
||||
return values;
|
||||
return super.get(key.toLowerCase(Locale.ROOT));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+51
-11
@@ -25,6 +25,8 @@
|
||||
|
||||
package me.lucko.luckperms.common.cacheddata.type;
|
||||
|
||||
import me.lucko.luckperms.common.cacheddata.result.StringResult;
|
||||
|
||||
import net.luckperms.api.metastacking.MetaStackDefinition;
|
||||
import net.luckperms.api.metastacking.MetaStackElement;
|
||||
import net.luckperms.api.node.ChatMetaType;
|
||||
@@ -36,10 +38,12 @@ import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class MetaStackAccumulator {
|
||||
public class MetaStackAccumulator<N extends ChatMetaNode<N, ?>> {
|
||||
private final MetaStackDefinition definition;
|
||||
private final List<Entry> entries;
|
||||
private final List<Entry<N>> entries;
|
||||
|
||||
public MetaStackAccumulator(MetaStackDefinition definition, ChatMetaType targetType) {
|
||||
this.definition = definition;
|
||||
@@ -47,20 +51,27 @@ public class MetaStackAccumulator {
|
||||
List<MetaStackElement> elements = definition.getElements();
|
||||
this.entries = new ArrayList<>(elements.size());
|
||||
for (MetaStackElement element : elements) {
|
||||
this.entries.add(new Entry(element, targetType));
|
||||
this.entries.add(new Entry<>(element, targetType));
|
||||
}
|
||||
}
|
||||
|
||||
public void offer(ChatMetaNode<?, ?> node) {
|
||||
for (Entry entry : this.entries) {
|
||||
public void offer(N node) {
|
||||
for (Entry<N> entry : this.entries) {
|
||||
entry.offer(node);
|
||||
}
|
||||
}
|
||||
|
||||
public List<N> getElements() {
|
||||
return this.entries.stream()
|
||||
.map(Entry::getNode)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public String toFormattedString() {
|
||||
List<String> elements = new LinkedList<>();
|
||||
for (Entry entry : this.entries) {
|
||||
ChatMetaNode<?, ?> node = entry.getNode();
|
||||
for (Entry<N> entry : this.entries) {
|
||||
N node = entry.getNode();
|
||||
if (node != null) {
|
||||
elements.add(node.getMetaValue());
|
||||
}
|
||||
@@ -94,22 +105,51 @@ public class MetaStackAccumulator {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static final class Entry {
|
||||
public StringResult<N> toResult() {
|
||||
String formatted = toFormattedString();
|
||||
if (formatted == null) {
|
||||
return StringResult.nullResult();
|
||||
}
|
||||
|
||||
List<N> elements = getElements();
|
||||
|
||||
switch (elements.size()) {
|
||||
case 0:
|
||||
throw new AssertionError();
|
||||
case 1:
|
||||
return StringResult.of(formatted, elements.get(0));
|
||||
default: {
|
||||
Iterator<N> it = elements.iterator();
|
||||
StringResult<N> result = StringResult.of(formatted, it.next());
|
||||
|
||||
StringResult<N> root = result;
|
||||
while (it.hasNext()) {
|
||||
StringResult<N> nested = StringResult.of(it.next());
|
||||
root.setOverriddenResult(nested);
|
||||
root = nested;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Entry<N extends ChatMetaNode<?, ?>> {
|
||||
private final MetaStackElement element;
|
||||
private final ChatMetaType type;
|
||||
|
||||
private @Nullable ChatMetaNode<?, ?> current = null;
|
||||
private @Nullable N current = null;
|
||||
|
||||
Entry(MetaStackElement element, ChatMetaType type) {
|
||||
this.element = element;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public ChatMetaNode<?, ?> getNode() {
|
||||
public N getNode() {
|
||||
return this.current;
|
||||
}
|
||||
|
||||
public boolean offer(ChatMetaNode<?, ?> node) {
|
||||
public boolean offer(N node) {
|
||||
if (this.element.shouldAccumulate(this.type, node, this.current)) {
|
||||
this.current = node;
|
||||
return true;
|
||||
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* 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.common.cacheddata.type;
|
||||
|
||||
import com.google.common.collect.ForwardingMap;
|
||||
|
||||
import me.lucko.luckperms.common.cacheddata.CacheMetadata;
|
||||
import me.lucko.luckperms.common.cacheddata.result.StringResult;
|
||||
import me.lucko.luckperms.common.node.types.Prefix;
|
||||
import me.lucko.luckperms.common.node.types.Suffix;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.verbose.event.CheckOrigin;
|
||||
|
||||
import net.luckperms.api.cacheddata.CachedMetaData;
|
||||
import net.luckperms.api.node.types.MetaNode;
|
||||
import net.luckperms.api.node.types.PrefixNode;
|
||||
import net.luckperms.api.node.types.SuffixNode;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Holds cached meta for a given context
|
||||
*/
|
||||
public class MonitoredMetaCache extends MetaCache implements CachedMetaData {
|
||||
|
||||
/** The plugin instance */
|
||||
private final LuckPermsPlugin plugin;
|
||||
|
||||
/** The metadata for this cache */
|
||||
private final CacheMetadata metadata;
|
||||
|
||||
public MonitoredMetaCache(LuckPermsPlugin plugin, QueryOptions queryOptions, CacheMetadata metadata, MetaAccumulator sourceMeta) {
|
||||
super(plugin, queryOptions, sourceMeta);
|
||||
this.plugin = plugin;
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public StringResult<MetaNode> getMetaValue(String key, CheckOrigin origin) {
|
||||
StringResult<MetaNode> value = super.getMetaValue(key, origin);
|
||||
this.plugin.getVerboseHandler().offerMetaCheckEvent(origin, this.metadata.getVerboseCheckInfo(), this.metadata.getQueryOptions(), key, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public StringResult<PrefixNode> getPrefix(CheckOrigin origin) {
|
||||
StringResult<PrefixNode> value = super.getPrefix(origin);
|
||||
this.plugin.getVerboseHandler().offerMetaCheckEvent(origin, this.metadata.getVerboseCheckInfo(), this.metadata.getQueryOptions(), Prefix.NODE_KEY, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public StringResult<SuffixNode> getSuffix(CheckOrigin origin) {
|
||||
StringResult<SuffixNode> value = super.getSuffix(origin);
|
||||
this.plugin.getVerboseHandler().offerMetaCheckEvent(origin, this.metadata.getVerboseCheckInfo(), this.metadata.getQueryOptions(), Suffix.NODE_KEY, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, List<StringResult<MetaNode>>> getMetaResults(CheckOrigin origin) {
|
||||
return new MonitoredMetaMap(super.getMetaResults(origin), origin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWeight(CheckOrigin origin) {
|
||||
int value = super.getWeight(origin);
|
||||
this.plugin.getVerboseHandler().offerMetaCheckEvent(origin, this.metadata.getVerboseCheckInfo(), this.metadata.getQueryOptions(), "weight", StringResult.of(String.valueOf(value)));
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getPrimaryGroup(CheckOrigin origin) {
|
||||
String value = super.getPrimaryGroup(origin);
|
||||
this.plugin.getVerboseHandler().offerMetaCheckEvent(origin, this.metadata.getVerboseCheckInfo(), this.metadata.getQueryOptions(), "primarygroup", StringResult.of(value));
|
||||
return value;
|
||||
}
|
||||
|
||||
private final class MonitoredMetaMap extends ForwardingMap<String, List<StringResult<MetaNode>>> {
|
||||
private final Map<String, List<StringResult<MetaNode>>> delegate;
|
||||
private final CheckOrigin origin;
|
||||
|
||||
private MonitoredMetaMap(Map<String, List<StringResult<MetaNode>>> delegate, CheckOrigin origin) {
|
||||
this.delegate = delegate;
|
||||
this.origin = origin;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, List<StringResult<MetaNode>>> delegate() {
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StringResult<MetaNode>> get(Object k) {
|
||||
if (k == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String key = (String) k;
|
||||
List<StringResult<MetaNode>> values = super.get(key);
|
||||
|
||||
if (values == null || values.isEmpty()) {
|
||||
MonitoredMetaCache.this.plugin.getVerboseHandler().offerMetaCheckEvent(this.origin, MonitoredMetaCache.this.metadata.getVerboseCheckInfo(), MonitoredMetaCache.this.metadata.getQueryOptions(), key, StringResult.nullResult());
|
||||
} else {
|
||||
Iterator<StringResult<MetaNode>> it = values.iterator();
|
||||
StringResult<MetaNode> result = it.next().copy();
|
||||
|
||||
StringResult<MetaNode> root = result;
|
||||
while (it.hasNext()) {
|
||||
StringResult<MetaNode> nested = it.next().copy();
|
||||
root.setOverriddenResult(nested);
|
||||
root = nested;
|
||||
}
|
||||
|
||||
MonitoredMetaCache.this.plugin.getVerboseHandler().offerMetaCheckEvent(this.origin, MonitoredMetaCache.this.metadata.getVerboseCheckInfo(), MonitoredMetaCache.this.metadata.getQueryOptions(), key, result);
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+19
-10
@@ -25,14 +25,18 @@
|
||||
|
||||
package me.lucko.luckperms.common.cacheddata.type;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import me.lucko.luckperms.common.cacheddata.CacheMetadata;
|
||||
import me.lucko.luckperms.common.cacheddata.UsageTracked;
|
||||
import me.lucko.luckperms.common.cacheddata.result.TristateResult;
|
||||
import me.lucko.luckperms.common.calculator.CalculatorFactory;
|
||||
import me.lucko.luckperms.common.calculator.PermissionCalculator;
|
||||
import me.lucko.luckperms.common.calculator.result.TristateResult;
|
||||
import me.lucko.luckperms.common.verbose.event.PermissionCheckEvent;
|
||||
import me.lucko.luckperms.common.verbose.event.CheckOrigin;
|
||||
|
||||
import net.luckperms.api.cacheddata.CachedPermissionData;
|
||||
import net.luckperms.api.cacheddata.Result;
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
import net.luckperms.api.util.Tristate;
|
||||
|
||||
@@ -55,12 +59,12 @@ public class PermissionCache extends UsageTracked implements CachedPermissionDat
|
||||
/**
|
||||
* The raw set of permission strings.
|
||||
*/
|
||||
private final Map<String, Boolean> permissions;
|
||||
private final Map<String, Node> permissions;
|
||||
|
||||
/**
|
||||
* An immutable copy of {@link #permissions}
|
||||
* A string->boolean view of {@link #permissions}
|
||||
*/
|
||||
private final Map<String, Boolean> permissionsUnmodifiable;
|
||||
private final Map<String, Boolean> permissionsView;
|
||||
|
||||
/**
|
||||
* The calculator instance responsible for resolving the raw permission strings in the permission map.
|
||||
@@ -69,10 +73,10 @@ public class PermissionCache extends UsageTracked implements CachedPermissionDat
|
||||
*/
|
||||
private final PermissionCalculator calculator;
|
||||
|
||||
public PermissionCache(QueryOptions queryOptions, CacheMetadata metadata, CalculatorFactory calculatorFactory, ConcurrentHashMap<String, Boolean> sourcePermissions) {
|
||||
public PermissionCache(QueryOptions queryOptions, CacheMetadata metadata, CalculatorFactory calculatorFactory, ConcurrentHashMap<String, Node> sourcePermissions) {
|
||||
this.queryOptions = queryOptions;
|
||||
this.permissions = sourcePermissions;
|
||||
this.permissionsUnmodifiable = Collections.unmodifiableMap(this.permissions);
|
||||
this.permissionsView = Collections.unmodifiableMap(Maps.transformValues(this.permissions, Node::getValue));
|
||||
|
||||
this.calculator = calculatorFactory.build(queryOptions, metadata);
|
||||
this.calculator.setSourcePermissions(this.permissions);
|
||||
@@ -89,19 +93,24 @@ public class PermissionCache extends UsageTracked implements CachedPermissionDat
|
||||
|
||||
@Override
|
||||
public @NonNull Map<String, Boolean> getPermissionMap() {
|
||||
return this.permissionsUnmodifiable;
|
||||
return this.permissionsView;
|
||||
}
|
||||
|
||||
public TristateResult checkPermission(String permission, PermissionCheckEvent.Origin origin) {
|
||||
public TristateResult checkPermission(String permission, CheckOrigin origin) {
|
||||
if (permission == null) {
|
||||
throw new NullPointerException("permission");
|
||||
}
|
||||
return this.calculator.checkPermission(permission, origin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Result<Tristate, Node> queryPermission(@NonNull String permission) {
|
||||
return checkPermission(permission, CheckOrigin.LUCKPERMS_API);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Tristate checkPermission(@NonNull String permission) {
|
||||
return checkPermission(permission, PermissionCheckEvent.Origin.LUCKPERMS_API).result();
|
||||
return checkPermission(permission, CheckOrigin.LUCKPERMS_API).result();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,212 +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.common.cacheddata.type;
|
||||
|
||||
import com.google.common.collect.ForwardingMap;
|
||||
import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.common.collect.Multimaps;
|
||||
|
||||
import me.lucko.luckperms.common.cacheddata.UsageTracked;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.verbose.event.MetaCheckEvent;
|
||||
|
||||
import net.luckperms.api.cacheddata.CachedMetaData;
|
||||
import net.luckperms.api.metastacking.MetaStackDefinition;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
import net.luckperms.api.query.meta.MetaValueSelector;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.SortedMap;
|
||||
|
||||
/**
|
||||
* Holds cached meta for a given context
|
||||
*/
|
||||
public class SimpleMetaCache extends UsageTracked implements CachedMetaData {
|
||||
|
||||
private final LuckPermsPlugin plugin;
|
||||
|
||||
/** The query options this container is holding data for */
|
||||
private final QueryOptions queryOptions;
|
||||
|
||||
/* The data */
|
||||
protected final Map<String, List<String>> meta;
|
||||
protected final Map<String, String> flattenedMeta;
|
||||
protected final SortedMap<Integer, String> prefixes;
|
||||
protected final SortedMap<Integer, String> suffixes;
|
||||
protected final int weight;
|
||||
protected final String primaryGroup;
|
||||
private final MetaStackDefinition prefixDefinition;
|
||||
private final MetaStackDefinition suffixDefinition;
|
||||
private final String prefix;
|
||||
private final String suffix;
|
||||
|
||||
public SimpleMetaCache(LuckPermsPlugin plugin, QueryOptions queryOptions, MetaAccumulator sourceMeta) {
|
||||
this.plugin = plugin;
|
||||
this.queryOptions = queryOptions;
|
||||
|
||||
Map<String, List<String>> meta = Multimaps.asMap(ImmutableListMultimap.copyOf(sourceMeta.getMeta()));
|
||||
|
||||
MetaValueSelector metaValueSelector = this.queryOptions.option(MetaValueSelector.KEY)
|
||||
.orElseGet(() -> this.plugin.getConfiguration().get(ConfigKeys.META_VALUE_SELECTOR));
|
||||
|
||||
ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
|
||||
for (Map.Entry<String, List<String>> e : meta.entrySet()) {
|
||||
if (e.getValue().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String selected = metaValueSelector.selectValue(e.getKey(), e.getValue());
|
||||
if (selected == null) {
|
||||
throw new NullPointerException(metaValueSelector + " returned null");
|
||||
}
|
||||
|
||||
builder.put(e.getKey(), selected);
|
||||
}
|
||||
this.flattenedMeta = builder.build();
|
||||
this.meta = new LowerCaseMetaMap(meta);
|
||||
|
||||
this.prefixes = ImmutableSortedMap.copyOfSorted(sourceMeta.getPrefixes());
|
||||
this.suffixes = ImmutableSortedMap.copyOfSorted(sourceMeta.getSuffixes());
|
||||
this.weight = sourceMeta.getWeight();
|
||||
this.primaryGroup = sourceMeta.getPrimaryGroup();
|
||||
this.prefixDefinition = sourceMeta.getPrefixDefinition();
|
||||
this.suffixDefinition = sourceMeta.getSuffixDefinition();
|
||||
this.prefix = sourceMeta.getPrefix();
|
||||
this.suffix = sourceMeta.getSuffix();
|
||||
}
|
||||
|
||||
public String getMetaValue(String key, MetaCheckEvent.Origin origin) {
|
||||
Objects.requireNonNull(key, "key");
|
||||
return this.flattenedMeta.get(key.toLowerCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getMetaValue(@NonNull String key) {
|
||||
return getMetaValue(key, MetaCheckEvent.Origin.LUCKPERMS_API);
|
||||
}
|
||||
|
||||
public String getPrefix(MetaCheckEvent.Origin origin) {
|
||||
return this.prefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getPrefix() {
|
||||
return getPrefix(MetaCheckEvent.Origin.LUCKPERMS_API);
|
||||
}
|
||||
|
||||
public String getSuffix(MetaCheckEvent.Origin origin) {
|
||||
return this.suffix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getSuffix() {
|
||||
return getSuffix(MetaCheckEvent.Origin.LUCKPERMS_API);
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getMeta(MetaCheckEvent.Origin origin) {
|
||||
return this.meta;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final @NonNull Map<String, List<String>> getMeta() {
|
||||
return getMeta(MetaCheckEvent.Origin.LUCKPERMS_API);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull SortedMap<Integer, String> getPrefixes() {
|
||||
return this.prefixes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull SortedMap<Integer, String> getSuffixes() {
|
||||
return this.suffixes;
|
||||
}
|
||||
|
||||
public int getWeight(MetaCheckEvent.Origin origin) {
|
||||
return this.weight;
|
||||
}
|
||||
|
||||
//@Override - not actually exposed in the API atm
|
||||
public final int getWeight() {
|
||||
return getWeight(MetaCheckEvent.Origin.LUCKPERMS_API);
|
||||
}
|
||||
|
||||
public @Nullable String getPrimaryGroup(MetaCheckEvent.Origin origin) {
|
||||
return this.primaryGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final @Nullable String getPrimaryGroup() {
|
||||
return getPrimaryGroup(MetaCheckEvent.Origin.LUCKPERMS_API);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull MetaStackDefinition getPrefixStackDefinition() {
|
||||
return this.prefixDefinition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull MetaStackDefinition getSuffixStackDefinition() {
|
||||
return this.suffixDefinition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull QueryOptions getQueryOptions() {
|
||||
return this.queryOptions;
|
||||
}
|
||||
|
||||
private static final class LowerCaseMetaMap extends ForwardingMap<String, List<String>> {
|
||||
private final Map<String, List<String>> delegate;
|
||||
|
||||
private LowerCaseMetaMap(Map<String, List<String>> delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, List<String>> delegate() {
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> get(Object k) {
|
||||
if (k == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String key = (String) k;
|
||||
return super.get(key.toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+14
-11
@@ -25,11 +25,14 @@
|
||||
|
||||
package me.lucko.luckperms.common.cacheddata.type;
|
||||
|
||||
import net.luckperms.api.cacheddata.Result;
|
||||
import net.luckperms.api.node.types.MetaNode;
|
||||
import net.luckperms.api.query.meta.MetaValueSelector;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public class SimpleMetaValueSelector implements MetaValueSelector {
|
||||
@@ -42,7 +45,7 @@ public class SimpleMetaValueSelector implements MetaValueSelector {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull String selectValue(@NonNull String key, @NonNull List<String> values) {
|
||||
public @NonNull Result<String, MetaNode> selectValue(@NonNull String key, @NonNull List<? extends Result<String, MetaNode>> values) {
|
||||
switch (values.size()) {
|
||||
case 0:
|
||||
throw new IllegalArgumentException("values is empty");
|
||||
@@ -56,7 +59,7 @@ public class SimpleMetaValueSelector implements MetaValueSelector {
|
||||
public enum Strategy {
|
||||
INHERITANCE {
|
||||
@Override
|
||||
public String select(List<String> values) {
|
||||
public Result<String, MetaNode> select(List<? extends Result<String, MetaNode>> values) {
|
||||
return values.get(0);
|
||||
}
|
||||
},
|
||||
@@ -64,7 +67,7 @@ public class SimpleMetaValueSelector implements MetaValueSelector {
|
||||
private final DoubleSelectionPredicate selection = (value, current) -> value > current;
|
||||
|
||||
@Override
|
||||
public String select(List<String> values) {
|
||||
public Result<String, MetaNode> select(List<? extends Result<String, MetaNode>> values) {
|
||||
return selectNumber(values, this.selection);
|
||||
}
|
||||
},
|
||||
@@ -72,16 +75,16 @@ public class SimpleMetaValueSelector implements MetaValueSelector {
|
||||
private final DoubleSelectionPredicate selection = (value, current) -> value < current;
|
||||
|
||||
@Override
|
||||
public String select(List<String> values) {
|
||||
public Result<String, MetaNode> select(List<? extends Result<String, MetaNode>> values) {
|
||||
return selectNumber(values, this.selection);
|
||||
}
|
||||
};
|
||||
|
||||
public abstract String select(List<String> values);
|
||||
public abstract Result<String, MetaNode> select(List<? extends Result<String, MetaNode>> values);
|
||||
|
||||
public static Strategy parse(String s) {
|
||||
try {
|
||||
return Strategy.valueOf(s.replace('-', '_').toUpperCase());
|
||||
return Strategy.valueOf(s.replace('-', '_').toUpperCase(Locale.ROOT));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
@@ -93,15 +96,15 @@ public class SimpleMetaValueSelector implements MetaValueSelector {
|
||||
boolean shouldSelect(double value, double current);
|
||||
}
|
||||
|
||||
private static String selectNumber(List<String> values, DoubleSelectionPredicate selection) {
|
||||
private static Result<String, MetaNode> selectNumber(List<? extends Result<String, MetaNode>> values, DoubleSelectionPredicate selection) {
|
||||
double current = 0;
|
||||
String selected = null;
|
||||
Result<String, MetaNode> selected = null;
|
||||
|
||||
for (String value : values) {
|
||||
for (Result<String, MetaNode> result : values) {
|
||||
try {
|
||||
double parse = Double.parseDouble(value);
|
||||
double parse = Double.parseDouble(result.result());
|
||||
if (selected == null || selection.shouldSelect(parse, current)) {
|
||||
selected = value;
|
||||
selected = result;
|
||||
current = parse;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
|
||||
@@ -1,145 +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.common.calculator;
|
||||
|
||||
import net.luckperms.api.util.Tristate;
|
||||
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* The LuckPerms Luckiness Calculator (tm)
|
||||
*/
|
||||
public final class LuckyPerms {
|
||||
|
||||
/** A sequence of the first 1000 lucky numbers. */
|
||||
private static final Set<Integer> LUCKY_NUMBERS = generateLuckyNumbers(1000);
|
||||
/** Is it an unlucky day? */
|
||||
private static final boolean UNLUCKY_DAY;
|
||||
/** The unlucky number. */
|
||||
private static final int UNLUCKY_NUMBER = 666;
|
||||
/** The lucky number */
|
||||
private static final int LUCKY_NUMBER;
|
||||
|
||||
static {
|
||||
LocalDate date = LocalDate.now();
|
||||
UNLUCKY_DAY = date.getDayOfWeek() == DayOfWeek.FRIDAY && date.getDayOfMonth() == 13;
|
||||
|
||||
if (Locale.getDefault().getLanguage().equals(Locale.CHINESE.getLanguage())) {
|
||||
// https://en.wikipedia.org/wiki/Chinese_numerology#Eight
|
||||
LUCKY_NUMBER = 8;
|
||||
} else {
|
||||
// https://en.wikipedia.org/wiki/7
|
||||
LUCKY_NUMBER = 7;
|
||||
}
|
||||
}
|
||||
|
||||
/** A ~magical~ counter used when determining luckiness. */
|
||||
private final AtomicInteger counter;
|
||||
|
||||
public LuckyPerms() {
|
||||
this.counter = new AtomicInteger();
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses highly advanced, patented LuckPerms(tm) calculations to determine
|
||||
* the current luckiness measure.
|
||||
*
|
||||
* <p>Returns {@link Tristate#TRUE} if lucky, {@link Tristate#FALSE} if unlucky,
|
||||
* and {@link Tristate#UNDEFINED} if unable to determine.</p>
|
||||
*
|
||||
* @return the calculated luckiness measure
|
||||
*/
|
||||
public Tristate calculateLuckiness() {
|
||||
int i = this.counter.incrementAndGet();
|
||||
|
||||
// is the counter divisible by the unlucky number? oh no.. that's not a good sign!
|
||||
if (i % UNLUCKY_NUMBER == 0) {
|
||||
return Tristate.FALSE;
|
||||
}
|
||||
|
||||
// got lucky on a dice roll & the counter is in the lucky numbers set? must be lucky!
|
||||
if (isEven(rollDice()) && LUCKY_NUMBERS.contains(i % 1000)) {
|
||||
return Tristate.TRUE;
|
||||
}
|
||||
|
||||
// is it Friday 13th? I sure hope not.
|
||||
if (UNLUCKY_DAY) {
|
||||
return Tristate.FALSE;
|
||||
}
|
||||
|
||||
// is the current system time divisible by the lucky number? sounds promising?!
|
||||
if ((System.currentTimeMillis() / 1000) % LUCKY_NUMBER == 0) {
|
||||
return Tristate.TRUE;
|
||||
}
|
||||
|
||||
// well, this is embarrassing.
|
||||
return Tristate.UNDEFINED;
|
||||
}
|
||||
|
||||
// Roll a 6-sided fair dice.
|
||||
private static int rollDice() {
|
||||
return ThreadLocalRandom.current().nextInt(6) + 1;
|
||||
}
|
||||
|
||||
// Is the number even?
|
||||
private static boolean isEven(int i) {
|
||||
return i % 2 == 0;
|
||||
}
|
||||
|
||||
// Generates 'lucky numbers'
|
||||
// see: https://en.wikipedia.org/wiki/Lucky_number
|
||||
private static Set<Integer> generateLuckyNumbers(int n) {
|
||||
// generate a sequence 1..n
|
||||
List<Integer> sequence = new ArrayList<>(n);
|
||||
for (int i = 1; i <= n; i++) {
|
||||
sequence.add(i);
|
||||
}
|
||||
|
||||
int j = 1; // the index of the value being considered as the next step
|
||||
int step = 2; // the step to use when deleting
|
||||
|
||||
// delete sequence[j]th elements in the list
|
||||
while (step < sequence.size()) {
|
||||
int idx = step - 1;
|
||||
while (idx < sequence.size()) {
|
||||
sequence.remove(idx);
|
||||
idx += (step - 1);
|
||||
}
|
||||
step = sequence.get(j++);
|
||||
}
|
||||
|
||||
return new HashSet<>(sequence);
|
||||
}
|
||||
|
||||
}
|
||||
+8
-27
@@ -27,17 +27,17 @@ package me.lucko.luckperms.common.calculator;
|
||||
|
||||
import me.lucko.luckperms.common.cache.LoadingMap;
|
||||
import me.lucko.luckperms.common.cacheddata.CacheMetadata;
|
||||
import me.lucko.luckperms.common.cacheddata.result.TristateResult;
|
||||
import me.lucko.luckperms.common.calculator.processor.PermissionProcessor;
|
||||
import me.lucko.luckperms.common.calculator.result.TristateResult;
|
||||
import me.lucko.luckperms.common.model.HolderType;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.verbose.event.PermissionCheckEvent;
|
||||
import me.lucko.luckperms.common.verbose.event.CheckOrigin;
|
||||
|
||||
import net.luckperms.api.util.Tristate;
|
||||
import net.luckperms.api.node.Node;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
@@ -55,25 +55,13 @@ public class PermissionCalculator implements Function<String, TristateResult> {
|
||||
/** The processors which back this calculator */
|
||||
private final PermissionProcessor[] processors;
|
||||
|
||||
/** The LuckPerms Luckiness Calculator */
|
||||
private final LuckyPerms feelingLucky = new LuckyPerms();
|
||||
|
||||
/** Loading cache for permission checks */
|
||||
private final LoadingMap<String, TristateResult> lookupCache = LoadingMap.of(this);
|
||||
|
||||
/** The object name passed to the verbose handler when checks are made */
|
||||
private final String verboseCheckTarget;
|
||||
|
||||
public PermissionCalculator(LuckPermsPlugin plugin, CacheMetadata metadata, Collection<PermissionProcessor> processors) {
|
||||
this.plugin = plugin;
|
||||
this.metadata = metadata;
|
||||
this.processors = processors.toArray(new PermissionProcessor[0]);
|
||||
|
||||
if (this.metadata.getHolderType() == HolderType.GROUP) {
|
||||
this.verboseCheckTarget = "group/" + this.metadata.getObjectName();
|
||||
} else {
|
||||
this.verboseCheckTarget = this.metadata.getObjectName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,19 +73,12 @@ public class PermissionCalculator implements Function<String, TristateResult> {
|
||||
* @param origin marks where this check originated from
|
||||
* @return the result
|
||||
*/
|
||||
public TristateResult checkPermission(String permission, PermissionCheckEvent.Origin origin) {
|
||||
// check the luckiness calculator before anything else.
|
||||
// if unable to determine luckiness, fallback to checking permissions data *sigh*
|
||||
Tristate luckiness = this.feelingLucky.calculateLuckiness();
|
||||
if (luckiness != Tristate.UNDEFINED) {
|
||||
return TristateResult.of(luckiness);
|
||||
}
|
||||
|
||||
public TristateResult checkPermission(String permission, CheckOrigin origin) {
|
||||
// get the result
|
||||
TristateResult result = this.lookupCache.get(permission);
|
||||
|
||||
// log this permission lookup to the verbose handler
|
||||
this.plugin.getVerboseHandler().offerPermissionCheckEvent(origin, this.verboseCheckTarget, this.metadata.getQueryOptions(), permission, result);
|
||||
this.plugin.getVerboseHandler().offerPermissionCheckEvent(origin, this.metadata.getVerboseCheckInfo(), this.metadata.getQueryOptions(), permission, result);
|
||||
|
||||
// return the result
|
||||
return result;
|
||||
@@ -107,7 +88,7 @@ public class PermissionCalculator implements Function<String, TristateResult> {
|
||||
public TristateResult apply(@NonNull String permission) {
|
||||
// convert the permission to lowercase, as all values in the backing map are also lowercase.
|
||||
// this allows fast case insensitive lookups
|
||||
permission = permission.toLowerCase();
|
||||
permission = permission.toLowerCase(Locale.ROOT);
|
||||
|
||||
// offer the permission to the permission vault
|
||||
// we only need to do this once per permission, so it doesn't matter
|
||||
@@ -127,7 +108,7 @@ public class PermissionCalculator implements Function<String, TristateResult> {
|
||||
*
|
||||
* @param sourceMap the source map
|
||||
*/
|
||||
public synchronized void setSourcePermissions(Map<String, Boolean> sourceMap) {
|
||||
public synchronized void setSourcePermissions(Map<String, Node> sourceMap) {
|
||||
for (PermissionProcessor processor : this.processors) {
|
||||
processor.setSource(sourceMap);
|
||||
processor.refresh();
|
||||
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.common.calculator.processor;
|
||||
|
||||
import me.lucko.luckperms.common.cacheddata.result.TristateResult;
|
||||
|
||||
import net.luckperms.api.util.Tristate;
|
||||
|
||||
public abstract class AbstractOverrideWildcardProcessor extends AbstractPermissionProcessor implements PermissionProcessor {
|
||||
private final boolean overrideWildcards;
|
||||
|
||||
public AbstractOverrideWildcardProcessor(boolean overrideWildcards) {
|
||||
this.overrideWildcards = overrideWildcards;
|
||||
}
|
||||
|
||||
private boolean canOverrideWildcard(TristateResult prev) {
|
||||
return this.overrideWildcards &&
|
||||
(prev.processorClass() == WildcardProcessor.class || prev.processorClass() == SpongeWildcardProcessor.class) &&
|
||||
prev.result() == Tristate.TRUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TristateResult hasPermissionOverride(TristateResult prev, String permission) {
|
||||
if (canOverrideWildcard(prev)) {
|
||||
TristateResult override = hasPermission(permission);
|
||||
if (override.result() == Tristate.FALSE) {
|
||||
override.setOverriddenResult(prev);
|
||||
return override;
|
||||
}
|
||||
}
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
}
|
||||
+15
-13
@@ -25,26 +25,28 @@
|
||||
|
||||
package me.lucko.luckperms.common.calculator.processor;
|
||||
|
||||
import me.lucko.luckperms.common.calculator.result.TristateResult;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import me.lucko.luckperms.common.cacheddata.result.TristateResult;
|
||||
|
||||
/**
|
||||
* Abstract implementation of {@link PermissionProcessor} that splits behaviour for normal
|
||||
* permission checks and override checks into two separate methods.
|
||||
*/
|
||||
public abstract class AbstractPermissionProcessor implements PermissionProcessor {
|
||||
protected Map<String, Boolean> sourceMap = Collections.emptyMap();
|
||||
|
||||
@Override
|
||||
public void setSource(Map<String, Boolean> sourceMap) {
|
||||
this.sourceMap = sourceMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TristateResult hasPermission(TristateResult prev, String permission) {
|
||||
public final TristateResult hasPermission(TristateResult prev, String permission) {
|
||||
if (prev != TristateResult.UNDEFINED) {
|
||||
return prev;
|
||||
return hasPermissionOverride(prev, permission);
|
||||
}
|
||||
return hasPermission(permission);
|
||||
}
|
||||
|
||||
public abstract TristateResult hasPermission(String permission);
|
||||
// Performs a regular permission check
|
||||
protected abstract TristateResult hasPermission(String permission);
|
||||
|
||||
// Performs an override permission check
|
||||
protected TristateResult hasPermissionOverride(TristateResult prev, String permission) {
|
||||
return prev;
|
||||
}
|
||||
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.common.calculator.processor;
|
||||
|
||||
import net.luckperms.api.node.Node;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class AbstractSourceBasedProcessor extends AbstractPermissionProcessor implements PermissionProcessor {
|
||||
protected Map<String, Node> sourceMap = Collections.emptyMap();
|
||||
|
||||
@Override
|
||||
public void setSource(Map<String, Node> sourceMap) {
|
||||
this.sourceMap = sourceMap;
|
||||
}
|
||||
|
||||
}
|
||||
+3
-5
@@ -25,16 +25,14 @@
|
||||
|
||||
package me.lucko.luckperms.common.calculator.processor;
|
||||
|
||||
import me.lucko.luckperms.common.calculator.result.TristateResult;
|
||||
import me.lucko.luckperms.common.cacheddata.result.TristateResult;
|
||||
|
||||
import net.luckperms.api.util.Tristate;
|
||||
|
||||
public class DirectProcessor extends AbstractPermissionProcessor implements PermissionProcessor {
|
||||
public class DirectProcessor extends AbstractSourceBasedProcessor implements PermissionProcessor {
|
||||
private static final TristateResult.Factory RESULT_FACTORY = new TristateResult.Factory(DirectProcessor.class);
|
||||
|
||||
@Override
|
||||
public TristateResult hasPermission(String permission) {
|
||||
return RESULT_FACTORY.result(Tristate.of(this.sourceMap.get(permission)));
|
||||
return RESULT_FACTORY.result(this.sourceMap.get(permission));
|
||||
}
|
||||
|
||||
}
|
||||
+4
-2
@@ -25,8 +25,10 @@
|
||||
|
||||
package me.lucko.luckperms.common.calculator.processor;
|
||||
|
||||
import me.lucko.luckperms.common.cacheddata.result.TristateResult;
|
||||
import me.lucko.luckperms.common.calculator.PermissionCalculator;
|
||||
import me.lucko.luckperms.common.calculator.result.TristateResult;
|
||||
|
||||
import net.luckperms.api.node.Node;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -52,7 +54,7 @@ public interface PermissionProcessor {
|
||||
*
|
||||
* @param sourceMap the source map
|
||||
*/
|
||||
default void setSource(Map<String, Boolean> sourceMap) {
|
||||
default void setSource(Map<String, Node> sourceMap) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -28,17 +28,17 @@ package me.lucko.luckperms.common.calculator.processor;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import me.lucko.luckperms.common.calculator.result.TristateResult;
|
||||
import me.lucko.luckperms.common.cacheddata.result.TristateResult;
|
||||
import me.lucko.luckperms.common.node.types.RegexPermission;
|
||||
|
||||
import net.luckperms.api.util.Tristate;
|
||||
import net.luckperms.api.node.Node;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class RegexProcessor extends AbstractPermissionProcessor implements PermissionProcessor {
|
||||
public class RegexProcessor extends AbstractSourceBasedProcessor implements PermissionProcessor {
|
||||
private static final TristateResult.Factory RESULT_FACTORY = new TristateResult.Factory(RegexProcessor.class);
|
||||
|
||||
private List<Map.Entry<Pattern, TristateResult>> regexPermissions = Collections.emptyList();
|
||||
@@ -56,7 +56,7 @@ public class RegexProcessor extends AbstractPermissionProcessor implements Permi
|
||||
@Override
|
||||
public void refresh() {
|
||||
ImmutableList.Builder<Map.Entry<Pattern, TristateResult>> builder = ImmutableList.builder();
|
||||
for (Map.Entry<String, Boolean> e : this.sourceMap.entrySet()) {
|
||||
for (Map.Entry<String, Node> e : this.sourceMap.entrySet()) {
|
||||
RegexPermission.Builder regexPerm = RegexPermission.parse(e.getKey());
|
||||
if (regexPerm == null) {
|
||||
continue;
|
||||
@@ -67,7 +67,7 @@ public class RegexProcessor extends AbstractPermissionProcessor implements Permi
|
||||
continue;
|
||||
}
|
||||
|
||||
TristateResult value = RESULT_FACTORY.result(Tristate.of(e.getValue()), "pattern: " + pattern.pattern());
|
||||
TristateResult value = RESULT_FACTORY.result(e.getValue());
|
||||
builder.add(Maps.immutableEntry(pattern, value));
|
||||
}
|
||||
this.regexPermissions = builder.build();
|
||||
|
||||
+6
-6
@@ -25,12 +25,12 @@
|
||||
|
||||
package me.lucko.luckperms.common.calculator.processor;
|
||||
|
||||
import me.lucko.luckperms.common.calculator.result.TristateResult;
|
||||
import me.lucko.luckperms.common.cacheddata.result.TristateResult;
|
||||
import me.lucko.luckperms.common.node.AbstractNode;
|
||||
|
||||
import net.luckperms.api.util.Tristate;
|
||||
import net.luckperms.api.node.Node;
|
||||
|
||||
public class SpongeWildcardProcessor extends AbstractPermissionProcessor implements PermissionProcessor {
|
||||
public class SpongeWildcardProcessor extends AbstractSourceBasedProcessor implements PermissionProcessor {
|
||||
private static final TristateResult.Factory RESULT_FACTORY = new TristateResult.Factory(SpongeWildcardProcessor.class);
|
||||
|
||||
@Override
|
||||
@@ -45,9 +45,9 @@ public class SpongeWildcardProcessor extends AbstractPermissionProcessor impleme
|
||||
|
||||
node = node.substring(0, endIndex);
|
||||
if (!node.isEmpty()) {
|
||||
Tristate t = Tristate.of(this.sourceMap.get(node));
|
||||
if (t != Tristate.UNDEFINED) {
|
||||
return RESULT_FACTORY.result(t, "match: " + node);
|
||||
Node n = this.sourceMap.get(node);
|
||||
if (n != null) {
|
||||
return RESULT_FACTORY.result(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-8
@@ -27,15 +27,16 @@ package me.lucko.luckperms.common.calculator.processor;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import me.lucko.luckperms.common.calculator.result.TristateResult;
|
||||
import me.lucko.luckperms.common.cacheddata.result.TristateResult;
|
||||
import me.lucko.luckperms.common.node.AbstractNode;
|
||||
|
||||
import net.luckperms.api.node.Node;
|
||||
import net.luckperms.api.util.Tristate;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
public class WildcardProcessor extends AbstractPermissionProcessor implements PermissionProcessor {
|
||||
public class WildcardProcessor extends AbstractSourceBasedProcessor implements PermissionProcessor {
|
||||
private static final TristateResult.Factory RESULT_FACTORY = new TristateResult.Factory(WildcardProcessor.class);
|
||||
|
||||
public static final String WILDCARD_SUFFIX = ".*";
|
||||
@@ -78,22 +79,22 @@ public class WildcardProcessor extends AbstractPermissionProcessor implements Pe
|
||||
@Override
|
||||
public void refresh() {
|
||||
ImmutableMap.Builder<String, TristateResult> builder = ImmutableMap.builder();
|
||||
for (Map.Entry<String, Boolean> e : this.sourceMap.entrySet()) {
|
||||
for (Map.Entry<String, Node> e : this.sourceMap.entrySet()) {
|
||||
String key = e.getKey();
|
||||
if (!key.endsWith(WILDCARD_SUFFIX) || key.length() <= 2) {
|
||||
continue;
|
||||
}
|
||||
key = key.substring(0, key.length() - 2);
|
||||
|
||||
TristateResult value = RESULT_FACTORY.result(Tristate.of(e.getValue()), "match: " + key);
|
||||
TristateResult value = RESULT_FACTORY.result(e.getValue());
|
||||
builder.put(key, value);
|
||||
}
|
||||
this.wildcardPermissions = builder.build();
|
||||
|
||||
Tristate state = Tristate.of(this.sourceMap.get(ROOT_WILDCARD));
|
||||
if (state == Tristate.UNDEFINED) {
|
||||
state = Tristate.of(this.sourceMap.get(ROOT_WILDCARD_WITH_QUOTES));
|
||||
Node rootWildcard = this.sourceMap.get(ROOT_WILDCARD);
|
||||
if (rootWildcard == null) {
|
||||
rootWildcard = this.sourceMap.get(ROOT_WILDCARD_WITH_QUOTES);
|
||||
}
|
||||
this.rootWildcardState = RESULT_FACTORY.result(state, "root");
|
||||
this.rootWildcardState = rootWildcard == null ? TristateResult.UNDEFINED : RESULT_FACTORY.result(rootWildcard);
|
||||
}
|
||||
}
|
||||
@@ -1,112 +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.common.calculator.result;
|
||||
|
||||
import me.lucko.luckperms.common.calculator.PermissionCalculator;
|
||||
import me.lucko.luckperms.common.calculator.processor.PermissionProcessor;
|
||||
|
||||
import net.luckperms.api.util.Tristate;
|
||||
|
||||
/**
|
||||
* Represents the result of a {@link PermissionCalculator} lookup.
|
||||
*/
|
||||
public final class TristateResult {
|
||||
|
||||
private static final Factory NULL_FACTORY = new Factory(null, null);
|
||||
public static final TristateResult UNDEFINED = new TristateResult(Tristate.UNDEFINED, null, null);
|
||||
|
||||
public static TristateResult of(Tristate result) {
|
||||
return NULL_FACTORY.result(result);
|
||||
}
|
||||
|
||||
private final Tristate result;
|
||||
private final Class<? extends PermissionProcessor> processorClass;
|
||||
private final String cause;
|
||||
|
||||
private TristateResult(Tristate result, Class<? extends PermissionProcessor> processorClass, String cause) {
|
||||
this.result = result;
|
||||
this.processorClass = processorClass;
|
||||
this.cause = cause;
|
||||
}
|
||||
|
||||
public Tristate result() {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
public Class<? extends PermissionProcessor> processorClass() {
|
||||
return this.processorClass;
|
||||
}
|
||||
|
||||
public String cause() {
|
||||
return this.cause;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TristateResult(" +
|
||||
"result=" + this.result + ", " +
|
||||
"processorClass=" + this.processorClass + ", " +
|
||||
"cause=" + this.cause + ')';
|
||||
}
|
||||
|
||||
public static final class Factory {
|
||||
private final Class<? extends PermissionProcessor> processorClass;
|
||||
|
||||
private final TristateResult trueResult;
|
||||
private final TristateResult falseResult;
|
||||
|
||||
public Factory(Class<? extends PermissionProcessor> processorClass, String defaultCause) {
|
||||
this.processorClass = processorClass;
|
||||
|
||||
this.trueResult = new TristateResult(Tristate.TRUE, processorClass, defaultCause);
|
||||
this.falseResult = new TristateResult(Tristate.FALSE, processorClass, defaultCause);
|
||||
}
|
||||
|
||||
public Factory(Class<? extends PermissionProcessor> processorClass) {
|
||||
this(processorClass, null);
|
||||
}
|
||||
|
||||
public TristateResult result(Tristate result) {
|
||||
switch (result) {
|
||||
case TRUE:
|
||||
return this.trueResult;
|
||||
case FALSE:
|
||||
return this.falseResult;
|
||||
case UNDEFINED:
|
||||
return UNDEFINED;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
public TristateResult result(Tristate result, String cause) {
|
||||
if (result == Tristate.UNDEFINED) {
|
||||
return UNDEFINED;
|
||||
}
|
||||
return new TristateResult(result, this.processorClass, cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,7 @@ import me.lucko.luckperms.common.commands.misc.SearchCommand;
|
||||
import me.lucko.luckperms.common.commands.misc.SyncCommand;
|
||||
import me.lucko.luckperms.common.commands.misc.TranslationsCommand;
|
||||
import me.lucko.luckperms.common.commands.misc.TreeCommand;
|
||||
import me.lucko.luckperms.common.commands.misc.TrustEditorCommand;
|
||||
import me.lucko.luckperms.common.commands.misc.VerboseCommand;
|
||||
import me.lucko.luckperms.common.commands.track.CreateTrack;
|
||||
import me.lucko.luckperms.common.commands.track.DeleteTrack;
|
||||
@@ -75,6 +76,7 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
@@ -122,6 +124,7 @@ public class CommandManager {
|
||||
.add(new BulkUpdateCommand())
|
||||
.add(new TranslationsCommand())
|
||||
.add(new ApplyEditsCommand())
|
||||
.add(new TrustEditorCommand())
|
||||
.add(new CreateGroup())
|
||||
.add(new DeleteGroup())
|
||||
.add(new ListGroups())
|
||||
@@ -130,7 +133,7 @@ public class CommandManager {
|
||||
.add(new ListTracks())
|
||||
.build()
|
||||
.stream()
|
||||
.collect(ImmutableCollectors.toMap(c -> c.getName().toLowerCase(), Function.identity()));
|
||||
.collect(ImmutableCollectors.toMap(c -> c.getName().toLowerCase(Locale.ROOT), Function.identity()));
|
||||
}
|
||||
|
||||
public LuckPermsPlugin getPlugin() {
|
||||
@@ -141,7 +144,7 @@ public class CommandManager {
|
||||
return this.tabCompletions;
|
||||
}
|
||||
|
||||
public CompletableFuture<CommandResult> executeCommand(Sender sender, String label, List<String> args) {
|
||||
public CompletableFuture<Void> executeCommand(Sender sender, String label, List<String> args) {
|
||||
SchedulerAdapter scheduler = this.plugin.getBootstrap().getScheduler();
|
||||
List<String> argsCopy = new ArrayList<>(args);
|
||||
|
||||
@@ -156,18 +159,17 @@ public class CommandManager {
|
||||
AtomicReference<SchedulerTask> timeoutTask = new AtomicReference<>();
|
||||
|
||||
// schedule the actual execution of the command using the command executor service
|
||||
CompletableFuture<CommandResult> future = CompletableFuture.supplyAsync(() -> {
|
||||
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
|
||||
// set flags
|
||||
executorThread.set(Thread.currentThread());
|
||||
this.executingCommand.set(true);
|
||||
|
||||
// actually try to execute the command
|
||||
try {
|
||||
return execute(sender, label, args);
|
||||
execute(sender, label, args);
|
||||
} catch (Throwable e) {
|
||||
// catch any exception
|
||||
this.plugin.getLogger().severe("Exception whilst executing command: " + args, e);
|
||||
return null;
|
||||
} finally {
|
||||
// unset flags
|
||||
this.executingCommand.set(false);
|
||||
@@ -207,7 +209,7 @@ public class CommandManager {
|
||||
return this.mainCommands.values().stream().anyMatch(c -> c.shouldDisplay() && c.isAuthorized(sender));
|
||||
}
|
||||
|
||||
private CommandResult execute(Sender sender, String label, List<String> arguments) {
|
||||
private void execute(Sender sender, String label, List<String> arguments) {
|
||||
applyConvenienceAliases(arguments, true);
|
||||
|
||||
// Handle no arguments
|
||||
@@ -223,7 +225,7 @@ public class CommandManager {
|
||||
|
||||
if (hasPermissionForAny(sender)) {
|
||||
Message.VIEW_AVAILABLE_COMMANDS_PROMPT.send(sender, label);
|
||||
return CommandResult.SUCCESS;
|
||||
return;
|
||||
}
|
||||
|
||||
Collection<? extends Group> groups = this.plugin.getGroupManager().getAll().values();
|
||||
@@ -232,22 +234,22 @@ public class CommandManager {
|
||||
} else {
|
||||
Message.NO_PERMISSION_FOR_SUBCOMMANDS.send(sender);
|
||||
}
|
||||
return CommandResult.NO_PERMISSION;
|
||||
return;
|
||||
}
|
||||
|
||||
// Look for the main command.
|
||||
Command<?> main = this.mainCommands.get(arguments.get(0).toLowerCase());
|
||||
Command<?> main = this.mainCommands.get(arguments.get(0).toLowerCase(Locale.ROOT));
|
||||
|
||||
// Main command not found
|
||||
if (main == null) {
|
||||
sendCommandUsage(sender, label);
|
||||
return CommandResult.INVALID_ARGS;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the Sender has permission to use the main command.
|
||||
if (!main.isAuthorized(sender)) {
|
||||
sendCommandUsage(sender, label);
|
||||
return CommandResult.NO_PERMISSION;
|
||||
return;
|
||||
}
|
||||
|
||||
arguments.remove(0); // remove the main command arg.
|
||||
@@ -255,21 +257,17 @@ public class CommandManager {
|
||||
// Check the correct number of args were given for the main command
|
||||
if (main.getArgumentCheck().test(arguments.size())) {
|
||||
main.sendDetailedUsage(sender, label);
|
||||
return CommandResult.INVALID_ARGS;
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to execute the command.
|
||||
CommandResult result;
|
||||
try {
|
||||
result = main.execute(this.plugin, sender, null, new ArgumentList(arguments), label);
|
||||
main.execute(this.plugin, sender, null, new ArgumentList(arguments), label);
|
||||
} catch (CommandException e) {
|
||||
result = e.handle(sender, label, main);
|
||||
e.handle(sender, label, main);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
result = CommandResult.FAILURE;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<String> tabCompleteCommand(Sender sender, List<String> arguments) {
|
||||
@@ -281,7 +279,7 @@ public class CommandManager {
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return TabCompleter.create()
|
||||
.at(0, CompletionSupplier.startsWith(() -> mains.stream().map(c -> c.getName().toLowerCase())))
|
||||
.at(0, CompletionSupplier.startsWith(() -> mains.stream().map(c -> c.getName().toLowerCase(Locale.ROOT))))
|
||||
.from(1, partial -> mains.stream()
|
||||
.filter(m -> m.getName().equalsIgnoreCase(arguments.get(0)))
|
||||
.findFirst()
|
||||
@@ -338,7 +336,7 @@ public class CommandManager {
|
||||
// '/lp user Luck p set --> /lp user Luck permission set' etc
|
||||
// ^ ^^^^^^^^^^
|
||||
if (args.size() >= 3 && (rewriteLastArgument || args.size() >= 4)) {
|
||||
String arg0 = args.get(0).toLowerCase();
|
||||
String arg0 = args.get(0).toLowerCase(Locale.ROOT);
|
||||
if (arg0.equals("user") || arg0.equals("group")) {
|
||||
replaceArgs(args, 2, arg -> {
|
||||
switch (arg) {
|
||||
@@ -358,7 +356,7 @@ public class CommandManager {
|
||||
// '/lp user Luck permission i' --> '/lp user Luck permission info' etc
|
||||
// ^ ^^^^
|
||||
if (args.size() >= 4 && (rewriteLastArgument || args.size() >= 5)) {
|
||||
String arg2 = args.get(2).toLowerCase();
|
||||
String arg2 = args.get(2).toLowerCase(Locale.ROOT);
|
||||
if (arg2.equals("permission") || arg2.equals("parent") || arg2.equals("meta")) {
|
||||
replaceArgs(args, 3, arg -> arg.equals("i") ? "info" : null);
|
||||
}
|
||||
@@ -368,7 +366,7 @@ public class CommandManager {
|
||||
}
|
||||
|
||||
private static void replaceArgs(List<String> args, int i, Function<String, String> rewrites) {
|
||||
String arg = args.get(i).toLowerCase();
|
||||
String arg = args.get(i).toLowerCase(Locale.ROOT);
|
||||
String rewrite = rewrites.apply(arg);
|
||||
if (rewrite != null) {
|
||||
args.remove(i);
|
||||
|
||||
+2
-1
@@ -36,6 +36,7 @@ import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -58,7 +59,7 @@ public abstract class ChildCommand<T> extends Command<T> {
|
||||
TextComponent.Builder builder = Component.text()
|
||||
.append(Component.text('>', NamedTextColor.DARK_AQUA))
|
||||
.append(Component.space())
|
||||
.append(Component.text(getName().toLowerCase(), NamedTextColor.GREEN));
|
||||
.append(Component.text(getName().toLowerCase(Locale.ROOT), NamedTextColor.GREEN));
|
||||
|
||||
if (getArgs().isPresent()) {
|
||||
List<Component> argUsages = getArgs().get().stream()
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
package me.lucko.luckperms.common.command.abstraction;
|
||||
|
||||
import me.lucko.luckperms.common.command.CommandResult;
|
||||
import me.lucko.luckperms.common.command.access.CommandPermission;
|
||||
import me.lucko.luckperms.common.command.spec.Argument;
|
||||
import me.lucko.luckperms.common.command.spec.CommandSpec;
|
||||
@@ -148,7 +147,7 @@ public abstract class Command<T> {
|
||||
}
|
||||
|
||||
// Main execution method for the command.
|
||||
public abstract CommandResult execute(LuckPermsPlugin plugin, Sender sender, T target, ArgumentList args, String label) throws CommandException;
|
||||
public abstract void execute(LuckPermsPlugin plugin, Sender sender, T target, ArgumentList args, String label) throws CommandException;
|
||||
|
||||
// Tab completion method - default implementation is provided as some commands do not provide tab completions.
|
||||
public List<String> tabComplete(LuckPermsPlugin plugin, Sender sender, ArgumentList args) {
|
||||
|
||||
Loaded 100 of 441 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user