Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -231,23 +231,12 @@ default boolean isActualPlayer() {
void setFlying(boolean flying);

/**
* Checks if the player is allowed to fly based on the current game mode and permissions.
* <ul>
* <li>Spectator mode: always allowed to fly (hardcoded)</li>
* <li>Creative mode: allowed unless explicitly denied (FALSE)</li>
* <li>Survival/Adventure mode: denied unless explicitly allowed (TRUE)</li>
* </ul>
* Checks if the player is allowed to fly based on the current game mode and abilities.
*
* @return {@code true} if the player can fly, {@code false} otherwise
*/
default boolean canFly() {
var gameMode = getGameMode();
return switch (gameMode) {
case SPECTATOR -> true;
case CREATIVE -> hasPermission(Permissions.ABILITY_FLY_CREATIVE) != Tristate.FALSE;
case SURVIVAL -> hasPermission(Permissions.ABILITY_FLY_SURVIVAL) == Tristate.TRUE;
case ADVENTURE -> hasPermission(Permissions.ABILITY_FLY_ADVENTURE) == Tristate.TRUE;
};
return isActualPlayer() ? getController().canFly() : false;
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.allaymc.api.eventbus.event.server;

import lombok.Getter;
import org.allaymc.api.annotation.CallerThread;
import org.allaymc.api.annotation.ThreadType;
import org.allaymc.api.player.Player;
import org.allaymc.api.player.PlayerAbility;

import java.util.Collections;
import java.util.EnumSet;
import java.util.Set;

/**
* Called after a player's abilities are changed.
*
* @author zernix2077
*/
@Getter
@CallerThread(ThreadType.WORLD)
public class PlayerAbilitiesUpdateEvent extends ServerPlayerEvent {
protected final Set<PlayerAbility> previous;
protected final Set<PlayerAbility> current;

public PlayerAbilitiesUpdateEvent(Player player, Set<PlayerAbility> previous, Set<PlayerAbility> current) {
super(player);
this.previous = copyAbilities(previous);
this.current = copyAbilities(current);
}

protected static Set<PlayerAbility> copyAbilities(Set<PlayerAbility> abilities) {
return abilities.isEmpty()
? Collections.unmodifiableSet(EnumSet.noneOf(PlayerAbility.class))
: Collections.unmodifiableSet(EnumSet.copyOf(abilities));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.allaymc.api.eventbus.event.server;

import lombok.Getter;
import org.allaymc.api.annotation.CallerThread;
import org.allaymc.api.annotation.ThreadType;
import org.allaymc.api.eventbus.event.CancellableEvent;
import org.allaymc.api.player.Player;
import org.allaymc.api.player.PlayerAbility;

import java.util.Collections;
import java.util.EnumSet;
import java.util.Set;

/**
* Called before an operator's requested ability update is applied to another player.
*
* @author zernix2077
*/
@Getter
@CallerThread(ThreadType.WORLD)
public class PlayerAbilitiesUpdateRequestEvent extends ServerPlayerEvent implements CancellableEvent {
protected final Player target;
protected final Set<PlayerAbility> abilities;

public PlayerAbilitiesUpdateRequestEvent(Player player, Player target, Set<PlayerAbility> abilities) {
super(player);
this.target = target;
this.abilities = abilities.isEmpty()
? Collections.unmodifiableSet(EnumSet.noneOf(PlayerAbility.class))
: Collections.unmodifiableSet(EnumSet.copyOf(abilities));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,9 @@ public record OpPermissionCalculator(Player player) implements PermissionCalcula
Permissions.COMMAND_VERSION
));

/**
* Permissions that should return UNDEFINED even for operators.
*/
public static final Set<String> OP_UNDEFINED_PERMISSIONS = new HashSet<>(Set.of(
Permissions.ABILITY_FLY_SURVIVAL,
Permissions.ABILITY_FLY_CREATIVE,
Permissions.ABILITY_FLY_ADVENTURE
));

@Override
public Tristate calculatePermission(String permission) {
if (Server.getInstance().getPlayerManager().isOperator(player)) {
if (OP_UNDEFINED_PERMISSIONS.contains(permission)) {
return Tristate.UNDEFINED;
}
return Tristate.TRUE;
}

Expand Down
14 changes: 1 addition & 13 deletions api/src/main/java/org/allaymc/api/permission/Permissions.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,6 @@ public interface Permissions {

/* Ability */

/**
* Permission to fly in survival mode. Only TRUE allows flying.
*/
String ABILITY_FLY_SURVIVAL = "ability.fly.survival";
/**
* Permission to fly in creative mode. FALSE denies, otherwise allowed.
*/
String ABILITY_FLY_CREATIVE = "ability.fly.creative";
/**
* Permission to fly in adventure mode. Only TRUE allows flying.
*/
String ABILITY_FLY_ADVENTURE = "ability.fly.adventure";
/**
* The permission to chat.
*/
Expand Down Expand Up @@ -253,4 +241,4 @@ public interface Permissions {
* The permission to use /xp command.
*/
String COMMAND_XP = "allay.command.xp";
}
}
15 changes: 11 additions & 4 deletions api/src/main/java/org/allaymc/api/player/GameMode.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.EnumSet;
import org.allaymc.api.message.MayContainTrKey;
import org.allaymc.api.message.TrKeys;
import org.jetbrains.annotations.UnmodifiableView;

/**
* GameMode represents a game mode that may be assigned to a player. Upon joining the world, players will be
Expand All @@ -19,23 +21,23 @@ public enum GameMode {
* SURVIVAL is the survival game mode: Players with this game mode have limited supplies and can break
* blocks after taking some time.
*/
SURVIVAL(TrKeys.MC_GAMEMODE_SURVIVAL),
SURVIVAL(TrKeys.MC_GAMEMODE_SURVIVAL, EnumSet.noneOf(PlayerAbility.class)),
/**
* CREATIVE represents the creative game mode: Players with this game mode have infinite blocks and
* items and can break blocks instantly. Players with creative mode can also fly.
*/
CREATIVE(TrKeys.MC_GAMEMODE_CREATIVE),
CREATIVE(TrKeys.MC_GAMEMODE_CREATIVE, EnumSet.of(PlayerAbility.MAY_FLY, PlayerAbility.INSTABUILD)),
/**
* ADVENTURE represents the adventure game mode: Players with this game mode cannot edit the world
* (placing or breaking blocks).
*/
ADVENTURE(TrKeys.MC_GAMEMODE_ADVENTURE),
ADVENTURE(TrKeys.MC_GAMEMODE_ADVENTURE, EnumSet.noneOf(PlayerAbility.class)),
/**
* SPECTATOR represents the spectator game mode: Players with this game mode cannot interact with the
* world and cannot be seen by other players. spectator players can fly, like creative mode, and can
* move through blocks.
*/
SPECTATOR(TrKeys.MC_GAMEMODE_SPECTATOR);
SPECTATOR(TrKeys.MC_GAMEMODE_SPECTATOR, EnumSet.of(PlayerAbility.MAY_FLY, PlayerAbility.FLYING, PlayerAbility.NO_CLIP));

private static final GameMode[] VALUES = values();

Expand All @@ -44,6 +46,11 @@ public enum GameMode {
*/
private final @MayContainTrKey String translationKey;

/**
* The default abilities associated with this game mode that should be tracked server-side.
*/
private final @UnmodifiableView EnumSet<PlayerAbility> abilities;
Comment thread
smartcmd marked this conversation as resolved.

/**
* Looks up a game mode by the id passed.
*
Expand Down
Loading
Loading