Package dev.polv.taleapi.permission


package dev.polv.taleapi.permission
Extensible Permission System for TaleAPI.

Overview

This package provides a modern, high-performance permission system built on the Service Provider Interface (SPI) pattern. It supports dynamic values, contextual permissions, and efficient O(k) lookups using a Radix Tree.

Architecture

                ┌──────────────────────┐
                │  PermissionService   │  ← Public API
                │    (Singleton)       │
                └──────────┬───────────┘
                           │
                ┌──────────▼───────────┐
                │  PermissionProvider  │  ← SPI Interface
                │    (Pluggable)       │
                └──────────┬───────────┘
                           │
            ┌──────────────┴──────────────┐
            ▼                             ▼
    ┌───────────────┐             ┌───────────────┐
    │DefaultProvider│             │ Custom Plugin │
    │   (JSON)      │             │   Provider    │
    └───────────────┘             └───────────────┘
 

Key Features

  • Tristate: ALLOW, DENY, or UNDEFINED (not just boolean)
  • Dynamic Values: Permissions can carry payloads (integers, strings, etc.)
  • Context: Permissions can be conditional (world, gamemode, server)
  • Wildcards: Instant O(1) wildcard matching via Radix Tree
  • Events: Hook into permission checks to temporarily override results

Quick Start


 // Get the permission service
 PermissionService perms = PermissionService.getInstance();

 // Query a boolean permission
 if (perms.query(player, "plots.claim").isAllowed()) {
   // Player can claim plots
 }

 // Query a permission with a dynamic value
 int maxPlots = perms.query(player, "plots.limit").asInt(1);

 // Context-aware query
 ContextSet context = ContextSet.of(ContextKey.WORLD, "nether");
 if (perms.query(player, "ability.fly", context).isAllowed()) {
   // Player can fly in the nether
 }
 

Hooking Permission Checks


 // Temporarily deny teleport during a minigame
 PermissionCheckCallback.EVENT.register((player, key, ctx, result) -> {
   if (matchManager.isInMatch(player) && key.startsWith("cmd.teleport")) {
     return CheckResult.deny();
   }
   return CheckResult.unmodified();
 });
 
See Also: