-
Notifications
You must be signed in to change notification settings - Fork 522
Implement Fabric Permission API #5226
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Patbox
wants to merge
25
commits into
FabricMC:26.1
Choose a base branch
from
Patbox:permission-api
base: 26.1
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 22 commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
ca75625
Create Fabric Permission API
Patbox 63f2ba3
Improve javadocs, move from interface to a final class, safer Command…
Patbox 4b87796
Merge branch '26.1' into permission-api
Patbox 5f31c28
Merge branch '26.1' into permission-api
Patbox 98e6e08
Async permission check utility methods, mention possible slowness of …
Patbox 07cc1e1
Provide better support for async permission checks on provider side
Patbox a83a17b
Merge branch '26.1' into permission-api
Patbox 13d5cda
Fix async check (oops)
Patbox 2bf037a
Wrap permission key and codec into a single object, swap from tristat…
Patbox 050baef
Write package-info, test key serialization
Patbox e002854
Intern keys, don't use supply async
Patbox ee133e5
Fix interner being initialized too late
Patbox 60cc5eb
a
Patbox b9d0c87
Mark as experimental
Patbox 77f1229
Merge branch '26.1' into permission-api
Patbox 703a71e
Merge remote-tracking branch 'origin/permission-api' into permission-api
Patbox 1d1cfc3
Drop serializable context keys for now
Patbox 73eab46
Merge branch '26.1' into permission-api
Patbox 9d52cb9
Rework how permissions are resolved, remove async methods, add server…
Patbox 856cf52
Merge branch '26.1' into permission-api
Patbox 49648a4
Checkstyle fix
Patbox cbeeb1a
Fix not being marked as experimental in fabric.mod.json
Patbox f301395
Add a callback for context modification
Patbox 2ea07c3
Revert accidental DefaultItemComponentEvents changes
Patbox 3aef4b8
Drop interner, javadoc fixes
Patbox File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| version = getSubprojectVersion(project) | ||
|
|
||
| loom { | ||
| accessWidenerPath = file('src/main/resources/fabric-permission-api-v1.classtweaker') | ||
| } | ||
|
|
||
| moduleDependencies(project, [ | ||
| ":fabric-api-base" | ||
| ]) | ||
|
|
||
| testDependencies(project, [ | ||
| ":fabric-command-api-v2", | ||
| ":fabric-lifecycle-events-v1" | ||
| ]) |
26 changes: 26 additions & 0 deletions
26
...-api-v1/src/main/java/net/fabricmc/fabric/api/permission/v1/MutablePermissionContext.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| /* | ||
| * Copyright (c) 2016, 2017, 2018, 2019 FabricMC | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package net.fabricmc.fabric.api.permission.v1; | ||
|
|
||
| import org.jspecify.annotations.Nullable; | ||
|
|
||
| /** | ||
| * Mutable version of {@link PermissionContext}, intended for creation of custom context conditions. | ||
| */ | ||
| public interface MutablePermissionContext extends PermissionContext { | ||
| <T> MutablePermissionContext set(PermissionContext.Key<T> key, @Nullable T value); | ||
| } |
247 changes: 247 additions & 0 deletions
247
...mission-api-v1/src/main/java/net/fabricmc/fabric/api/permission/v1/PermissionContext.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,247 @@ | ||
| /* | ||
| * Copyright (c) 2016, 2017, 2018, 2019 FabricMC | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package net.fabricmc.fabric.api.permission.v1; | ||
|
|
||
| import java.util.Objects; | ||
| import java.util.Set; | ||
| import java.util.UUID; | ||
| import java.util.concurrent.CompletableFuture; | ||
|
|
||
| import org.jetbrains.annotations.ApiStatus; | ||
| import org.jspecify.annotations.Nullable; | ||
|
|
||
| import net.minecraft.commands.CommandSourceStack; | ||
| import net.minecraft.core.BlockPos; | ||
| import net.minecraft.resources.Identifier; | ||
| import net.minecraft.server.MinecraftServer; | ||
| import net.minecraft.server.permissions.PermissionLevel; | ||
| import net.minecraft.server.players.NameAndId; | ||
| import net.minecraft.world.entity.Entity; | ||
| import net.minecraft.world.level.Level; | ||
| import net.minecraft.world.phys.Vec3; | ||
|
|
||
| import net.fabricmc.fabric.impl.permission.CustomPermissionContext; | ||
| import net.fabricmc.fabric.impl.permission.OverriddenPermissionContext; | ||
| import net.fabricmc.fabric.impl.permission.PermissionContextKey; | ||
|
|
||
| /** | ||
| * Interface representing context object used for permission checks, providing both required | ||
| * and additional values. | ||
| * | ||
| * <p>Permission checks should be applied by calling methods defined in {@link PermissionContextOwner} | ||
| * For command checks, you can use {@link PermissionPredicates}. | ||
| */ | ||
| public interface PermissionContext extends PermissionContextOwner { | ||
| /** | ||
| * Represents name attached to the permission context. | ||
| * There is no requirement for it to be unique, as it might be changed by external factors. | ||
| * Mainly used to help with identifying system-type contexts or context with shared/nil uuid. | ||
| * For entities, it defaults to the plain name, based on either custom name or entity type name. | ||
| */ | ||
| Key<String> NAME = PermissionContextKey.NAME; | ||
|
|
||
| /** | ||
| * Represents position current position in which permission check is applied. | ||
| */ | ||
| Key<Vec3> POSITION = PermissionContextKey.POSITION; | ||
|
|
||
| /** | ||
| * Represents position current block position in which permission check is applied. | ||
| */ | ||
| Key<BlockPos> BLOCK_POSITION = PermissionContextKey.BLOCK_POSITION; | ||
|
|
||
| /** | ||
| * Represents entity for which permission check is applied. | ||
| */ | ||
| Key<Entity> ENTITY = PermissionContextKey.ENTITY; | ||
|
|
||
| /** | ||
| * Represents command source stack for which permission check is applied. | ||
| */ | ||
| Key<CommandSourceStack> COMMAND_SOURCE_STACK = PermissionContextKey.COMMAND_SOURCE_STACK; | ||
|
|
||
| /** | ||
| * Represents level for which permission check is applied. | ||
| */ | ||
| Key<Level> LEVEL = PermissionContextKey.LEVEL; | ||
|
|
||
| /** | ||
| * Represents the server to which this context is attached to. | ||
| */ | ||
| Key<MinecraftServer> SERVER = PermissionContextKey.SERVER; | ||
|
|
||
| /** | ||
| * Creates a custom context, without any optional values. | ||
| * | ||
| * @param uuid the uuid connected to this context | ||
| * @param type type of the context | ||
| * @param permissionLevel base permission level | ||
| * @return mutable permission context | ||
| */ | ||
| static MutablePermissionContext create(UUID uuid, Type type, PermissionLevel permissionLevel) { | ||
| Objects.requireNonNull(uuid, "uuid cannot be null"); | ||
| Objects.requireNonNull(type, "type cannot be null"); | ||
| Objects.requireNonNull(permissionLevel, "permissionLevel cannot be null"); | ||
|
|
||
| return new CustomPermissionContext(uuid, type, permissionLevel); | ||
| } | ||
|
|
||
| /** | ||
| * Creates a context of offline player. | ||
| * Do note that depending on the backing implementation, the check for offline players | ||
| * might be noticeably slower, so using async check methods or checking them on non-main threads | ||
| * is encouraged. | ||
| * | ||
| * @param uuid player's uuid | ||
| * @param server the currently running server instance | ||
| * @return mutable permission context | ||
| */ | ||
| static CompletableFuture<MutablePermissionContext> offlinePlayer(UUID uuid, MinecraftServer server) { | ||
| Objects.requireNonNull(uuid, "uuid cannot be null"); | ||
| Objects.requireNonNull(server, "server cannot be null"); | ||
|
|
||
| PermissionLevel permissionLevel = server.getProfilePermissions(new NameAndId(uuid, "")).level(); | ||
| var ctx = new CustomPermissionContext(uuid, Type.PLAYER, permissionLevel); | ||
| ctx.set(PermissionContext.SERVER, server); | ||
|
|
||
| return PermissionEvents.PREPARE_OFFLINE_PLAYER.invoker().prepareOfflinePlayer(ctx, server).thenApply(_ -> ctx); | ||
| } | ||
|
|
||
| /** | ||
| * Creates a context of offline player. | ||
| * Do note that depending on the backing implementation, the check for offline players | ||
| * might be noticeably slower, so using async check methods or checking them on non-main threads | ||
| * is encouraged. | ||
| * | ||
| * @param nameAndId player's name and uuid | ||
| * @param server the currently running server instance | ||
| * @return mutable permission context | ||
| */ | ||
| static CompletableFuture<MutablePermissionContext> offlinePlayer(NameAndId nameAndId, MinecraftServer server) { | ||
| Objects.requireNonNull(nameAndId, "nameAndId cannot be null"); | ||
| Objects.requireNonNull(server, "server cannot be null"); | ||
|
|
||
| PermissionLevel permissionLevel = server.getProfilePermissions(nameAndId).level(); | ||
| var ctx = new CustomPermissionContext(nameAndId.id(), Type.PLAYER, permissionLevel); | ||
| ctx.set(PermissionContext.NAME, nameAndId.name()); | ||
| ctx.set(PermissionContext.SERVER, server); | ||
|
|
||
| return PermissionEvents.PREPARE_OFFLINE_PLAYER.invoker().prepareOfflinePlayer(ctx, server).thenApply(_ -> ctx); | ||
| } | ||
|
|
||
| /** | ||
| * Creates a unique key, indented for attaching additional context data. | ||
| * This key/value can't be serialized. | ||
| * | ||
| * @param identifier unique identifier | ||
| * @param <T> type of attached | ||
| * @return unique key | ||
| */ | ||
| static <T> Key<T> key(Identifier identifier) { | ||
| Objects.requireNonNull(identifier, "identifier cannot be null"); | ||
|
|
||
| return PermissionContextKey.getOrCreateKey(identifier); | ||
| } | ||
|
|
||
| /** | ||
| * UUID connected to this context. | ||
| */ | ||
| UUID uuid(); | ||
|
|
||
| /** | ||
| * The type of the context. | ||
| */ | ||
| Type type(); | ||
|
|
||
| /** | ||
| * Returns optional value attached to this context. | ||
| * | ||
| * @param key unique key | ||
| * @param <T> type of value | ||
| * @return stored value if it's present, null otherwise | ||
| */ | ||
| @Nullable | ||
| <T> T get(Key<T> key); | ||
|
|
||
| /** | ||
| * Returns optional value attached to this context, with a fallback. | ||
| * | ||
| * @param key unique key | ||
| * @param defaultValue fallback value, if it's not present | ||
|
||
| * @param <T> type of value | ||
| * @return stored value if it's present, otherwise defaultValue | ||
| */ | ||
| default <T> T orElse(Key<T> key, T defaultValue) { | ||
| T value = get(key); | ||
|
|
||
| return value != null ? value : defaultValue; | ||
| } | ||
|
|
||
| /** | ||
| * Creates a mutable copy of this context. | ||
| * | ||
| * @return a new mutable permission context. | ||
| */ | ||
| default MutablePermissionContext mutable() { | ||
| return new OverriddenPermissionContext(this); | ||
| } | ||
|
|
||
| /** | ||
| * Provides the vanilla permission level of the context. | ||
| * | ||
| * @return permission level of the context. | ||
| */ | ||
| PermissionLevel permissionLevel(); | ||
|
|
||
| /** | ||
| * Provides a set of defined permission context keys. | ||
| * | ||
| * @return unmodifiable set of permission keys. | ||
| */ | ||
| Set<Key<?>> keys(); | ||
|
|
||
| @Override | ||
| default PermissionContext getPermissionContext() { | ||
| return this; | ||
| } | ||
|
|
||
| /** | ||
| * Identifies the owner type of the permission context. | ||
| */ | ||
| enum Type { | ||
| PLAYER, | ||
| ENTITY, | ||
| SYSTEM, | ||
| OTHER | ||
| } | ||
|
|
||
| /** | ||
| * Key used to represent additional permission context. | ||
| * The context itself might be serializable, however it's not a strict requirement. | ||
| * | ||
| * @param <T> type of the context | ||
| */ | ||
| @ApiStatus.NonExtendable | ||
| interface Key<T> { | ||
| /** | ||
| * Identifier representing this context. | ||
| * | ||
| * @return id of this key | ||
| */ | ||
| Identifier id(); | ||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indented