HyCodeYourTale

Permission Checks

Permission Checks

Dokumentace kontroly oprávnění v příkazech a kódu.

---

V Příkazech

requirePermission()

public class AdminCommand extends CommandBase {
public AdminCommand() {
super("admin", "server.commands.admin.desc");

// Vyžaduj oprávnění pro celý příkaz
this.requirePermission(HytalePermissions.fromCommand("admin"));
}

@Override
protected void executeSync(CommandContext context) {
// Hráč už má ověřené oprávnění
context.sendMessage(Message.raw("Admin command executed!"));
}
}

Více Oprávnění

public class ComplexCommand extends CommandBase {
public ComplexCommand() {
super("complex", "server.commands.complex.desc");

// Vyžaduje obě oprávnění
this.requirePermission(HytalePermissions.fromCommand("complex.use"));
this.requirePermission("myplugin.verified");
}
}

Sub-příkazy s Různými Oprávněními

public class WarpCommand extends AbstractCommandCollection {
public WarpCommand() {
super("warp", "server.commands.warp.desc");

// Hlavní příkaz bez oprávnění
this.addUsageVariant(new WarpGoVariantCommand());
this.addSubCommand(new WarpGoCommand());
this.addSubCommand(new WarpSetCommand());
this.addSubCommand(new WarpRemoveCommand());
}
}

class WarpGoCommand extends AbstractPlayerCommand {
WarpGoCommand() {
super("go", "server.commands.warp.go.desc");
// Základní oprávnění pro použití warpu
this.requirePermission(HytalePermissions.fromCommand("warp.go"));
}
}

class WarpSetCommand extends AbstractPlayerCommand {
WarpSetCommand() {
super("set", "server.commands.warp.set.desc");
// Admin oprávnění pro vytvoření warpu
this.requirePermission(HytalePermissions.fromCommand("warp.set"));
}
}

class WarpRemoveCommand extends CommandBase {
WarpRemoveCommand() {
super("remove", "server.commands.warp.remove.desc");
// Admin oprávnění pro smazání warpu
this.requirePermission(HytalePermissions.fromCommand("warp.remove"));
}
}

---

Dynamická Kontrola v Kódu

Přes PlayerRef

public void doAction(PlayerRef playerRef) {
// Základní kontrola
if (!playerRef.hasPermission("myplugin.action")) {
playerRef.sendMessage(Message.raw("Nemáš oprávnění!").color("#FF0000"));
return;
}

// Provést akci
executeAction(playerRef);
}

Přes CommandContext

@Override
protected void executeSync(CommandContext context) {
// Dynamická kontrola uvnitř příkazu
if (context.hasPermission("myplugin.premium")) {
// Premium funkce
context.sendMessage(Message.raw("Premium feature activated!"));
} else {
// Standardní funkce
context.sendMessage(Message.raw("Standard feature"));
}
}

Přes PermissionsModule

public void checkPermission(UUID playerUuid) {
PermissionsModule perms = PermissionsModule.get();

boolean isAdmin = perms.hasPermission(playerUuid, "myplugin.admin");
boolean canEdit = perms.hasPermission(playerUuid, "myplugin.edit", false);

if (isAdmin) {
// Admin funkce
} else if (canEdit) {
// Editor funkce
}
}

---

Permission Eventy

PlayerPermissionChangeEvent

@Override
protected void setup() {
EventRegistry events = getEventRegistry();

// Oprávnění přidána
events.register(PlayerPermissionChangeEvent.PermissionsAdded.class, this::onPermissionsAdded);

// Oprávnění odebrána
events.register(PlayerPermissionChangeEvent.PermissionsRemoved.class, this::onPermissionsRemoved);

// Přidán do skupiny
events.register(PlayerPermissionChangeEvent.GroupAdded.class, this::onGroupAdded);

// Odebrán ze skupiny
events.register(PlayerPermissionChangeEvent.GroupRemoved.class, this::onGroupRemoved);
}

private void onPermissionsAdded(PlayerPermissionChangeEvent.PermissionsAdded event) {
UUID uuid = event.getPlayerUuid();
Set added = event.getAddedPermissions();

getLogger().atInfo().log("Player %s gained permissions: %s", uuid, added);

// Aktualizuj cache nebo UI
refreshPlayerUI(uuid);
}

private void onPermissionsRemoved(PlayerPermissionChangeEvent.PermissionsRemoved event) {
UUID uuid = event.getPlayerUuid();
Set removed = event.getRemovedPermissions();

getLogger().atInfo().log("Player %s lost permissions: %s", uuid, removed);
}

private void onGroupAdded(PlayerPermissionChangeEvent.GroupAdded event) {
UUID uuid = event.getPlayerUuid();
String group = event.getGroupName();

getLogger().atInfo().log("Player %s added to group: %s", uuid, group);
}

private void onGroupRemoved(PlayerPermissionChangeEvent.GroupRemoved event) {
UUID uuid = event.getPlayerUuid();
String group = event.getGroupName();

getLogger().atInfo().log("Player %s removed from group: %s", uuid, group);
}

PlayerGroupEvent

@Override
protected void setup() {
EventRegistry events = getEventRegistry();

events.register(PlayerGroupEvent.Added.class, event -> {
UUID uuid = event.getPlayerUuid();
String group = event.getGroup();

// Hráč přidán do skupiny
if ("vip".equals(group)) {
giveVIPRewards(uuid);
}
});

events.register(PlayerGroupEvent.Removed.class, event -> {
UUID uuid = event.getPlayerUuid();
String group = event.getGroup();

// Hráč odebrán ze skupiny
if ("vip".equals(group)) {
removeVIPBenefits(uuid);
}
});
}

GroupPermissionChangeEvent

@Override
protected void setup() {
EventRegistry events = getEventRegistry();

events.register(GroupPermissionChangeEvent.Added.class, event -> {
String group = event.getGroup();
Set permissions = event.getPermissions();

getLogger().atInfo().log("Group %s gained: %s", group, permissions);

// Aktualizuj všechny hráče ve skupině
refreshGroupMembers(group);
});

events.register(GroupPermissionChangeEvent.Removed.class, event -> {
String group = event.getGroup();
Set permissions = event.getPermissions();

getLogger().atInfo().log("Group %s lost: %s", group, permissions);
});
}

---

Vzory Kontroly

Feature Flags

public class FeatureManager {
private final PermissionsModule perms = PermissionsModule.get();

public boolean canUseFeature(UUID uuid, String feature) {
return perms.hasPermission(uuid, "myplugin.feature." + feature, false);
}

public boolean isPremium(UUID uuid) {
return perms.hasPermission(uuid, "myplugin.premium");
}

public boolean isAdmin(UUID uuid) {
return perms.hasPermission(uuid, "myplugin.admin");
}

public int getMaxSlots(UUID uuid) {
if (isAdmin(uuid)) return Integer.MAX_VALUE;
if (isPremium(uuid)) return 100;
return 10;
}
}

Hierarchická Oprávnění

public class CommandWithLevels extends AbstractPlayerCommand {
public CommandWithLevels() {
super("mycommand", "server.commands.mycommand.desc");
// Základní oprávnění pro použití
this.requirePermission("myplugin.mycommand.use");
}

@Override
protected void execute(CommandContext context, ...) {
PlayerRef playerRef = context.getPlayerRef();

// Úroveň 3 - plný přístup
if (playerRef.hasPermission("myplugin.mycommand.admin")) {
executeAdmin(context);
return;
}

// Úroveň 2 - rozšířený přístup
if (playerRef.hasPermission("myplugin.mycommand.extended")) {
executeExtended(context);
return;
}

// Úroveň 1 - základní přístup
executeBasic(context);
}
}

Cache Oprávnění

public class PermissionCache {
private final Map cache = new ConcurrentHashMap<>();
private final PermissionsModule perms = PermissionsModule.get();

public boolean hasPermission(UUID uuid, String permission) {
CachedPermissions cached = cache.computeIfAbsent(uuid, this::loadPermissions);
return cached.has(permission);
}

private CachedPermissions loadPermissions(UUID uuid) {
Set groups = perms.getGroupsForUser(uuid);
return new CachedPermissions(uuid, groups);
}

public void invalidate(UUID uuid) {
cache.remove(uuid);
}

// Invalidace při změně oprávnění
@Override
protected void setup() {
getEventRegistry().register(PlayerPermissionChangeEvent.class, event -> {
invalidate(event.getPlayerUuid());
});
}
}

---

Příklad: Kompletní Příkaz

public class HomeCommand extends AbstractPlayerCommand {
private static final Message NO_PERMISSION = Message.translation("server.commands.errors.noPermission");
private static final Message HOME_TELEPORTED = Message.translation("server.commands.home.teleported");
private static final Message HOME_SET = Message.translation("server.commands.home.set");
private static final Message HOME_DELETE_CONFIRM = Message.translation("server.commands.home.deleteConfirm");

public HomeCommand() {
super("home", "server.commands.home.desc");

// Základní oprávnění pro /home
this.requirePermission(HytalePermissions.fromCommand("home"));

// Sub-příkazy
this.addSubCommand(new HomeSetCommand());
this.addSubCommand(new HomeDeleteCommand());
this.addSubCommand(new HomeListCommand());
}

@Override
protected void execute(
CommandContext context,
Store store,
Ref ref,
PlayerRef playerRef,
World world
) {
// Teleport na výchozí home
teleportToHome(context, playerRef, "default");
}

// /home set [name]
private static class HomeSetCommand extends AbstractPlayerCommand {
private final OptionalArg nameArg;

HomeSetCommand() {
super("set", "server.commands.home.set.desc");
this.requirePermission(HytalePermissions.fromCommand("home.set"));
this.nameArg = this.withOptionalArg("name", "server.commands.home.name.desc", ArgTypes.STRING);
}

@Override
protected void execute(CommandContext context, ...) {
String homeName = nameArg.provided(context) ? nameArg.get(context) : "default";
PlayerRef playerRef = context.getPlayerRef();

// Kontrola limitu homes
int maxHomes = getMaxHomes(playerRef);
int currentHomes = getHomeCount(playerRef.getUuid());

if (currentHomes >= maxHomes) {
context.sendMessage(Message.translation("server.commands.home.limitReached")
.param("max", maxHomes));
return;
}

setHome(playerRef, homeName);
context.sendMessage(HOME_SET.param("name", homeName));
}

private int getMaxHomes(PlayerRef playerRef) {
if (playerRef.hasPermission("myplugin.home.unlimited")) return Integer.MAX_VALUE;
if (playerRef.hasPermission("myplugin.home.vip")) return 10;
return 3;
}
}

// /home delete
private static class HomeDeleteCommand extends CommandBase {
private final RequiredArg nameArg;

HomeDeleteCommand() {
super("delete", "server.commands.home.delete.desc");
this.requirePermission(HytalePermissions.fromCommand("home.delete"));
this.nameArg = this.withRequiredArg("name", "server.commands.home.name.desc", ArgTypes.STRING);
}

@Override
protected void executeSync(CommandContext context) {
String homeName = nameArg.get(context);

// Admin může mazat i cizí homes
if (context.hasPermission("myplugin.home.delete.others")) {
// Rozšířená funkcionalita
}

deleteHome(context.getPlayerRef(), homeName);
context.sendMessage(HOME_DELETE_CONFIRM.param("name", homeName));
}
}

// /home list
private static class HomeListCommand extends CommandBase {
HomeListCommand() {
super("list", "server.commands.home.list.desc");
// Žádné speciální oprávnění - dědí od parent
}
}
}

---

Shrnutí

| Metoda | Kde | Použití |
|--------|-----|---------|
| requirePermission(perm) | Konstruktor | Vyžadovat oprávnění pro příkaz |
| context.hasPermission(perm) | executeSync | Dynamická kontrola |
| playerRef.hasPermission(perm) | Kdekoliv | Kontrola přes PlayerRef |
| perms.hasPermission(uuid, perm) | Kdekoliv | Kontrola přes UUID |

| Event | Kdy |
|-------|-----|
| PlayerPermissionChangeEvent.PermissionsAdded | Přidána oprávnění |
| PlayerPermissionChangeEvent.PermissionsRemoved | Odebrána oprávnění |
| PlayerPermissionChangeEvent.GroupAdded | Přidán do skupiny |
| PlayerPermissionChangeEvent.GroupRemoved | Odebrán ze skupiny |
| GroupPermissionChangeEvent.Added | Skupina získala oprávnění |
| GroupPermissionChangeEvent.Removed | Skupina ztratila oprávnění |

Last updated: 20. ledna 2026