-
Notifications
You must be signed in to change notification settings - Fork 0
The basics ‐ Player states
ImIllusion edited this page Jul 22, 2023
·
3 revisions
Player states are simple and short "states" that are applied to any given player. These states can be as simple as being a spectator, or you can put multiple states together to achieve more complex logic.
Let's start by semarating this into 3 classes:
- A player state abstract class, which defines the logical structure
- A player state registry, where we register all our states and event handlers
- A player state tracker, which allows us to know what players have what states
Let's start with our abstract class
public abstract class AbstractPlayerState {
private final PlayerStateTracker tracker;
public AbstractPlayerState(PlayerStateTracker tracker) {
this.tracker = tracker;
}
public abstract String getName(); //
public abstract void apply(Player player);
public abstract void revert(Player player);
public boolean isAppliedTo(Player player) {
return tracker.hasState(getName());
}
public <EventType extends Event> registerEvents(Class<EventType> eventClass, Consumer<EventType> task) {
// Up to you
}
}And a sample player state
public class SpectatorPlayerState extends AbstractPlayerState {
public SpectatorPlayerState(PlayerStateTracker tracker) {
super(tracker);
}
@Override
public String getName() {
return "spectator";
}
@Override
public void apply(Player player) {
player.setGameMode(GameMode.SPECTATOR);
}
@Override
public void revert(Player player) {
player.setGameMode(GameMode.ADVENTURE);
}
}Now that we have a player state, let's quickly do the registry and tracker
public class PlayerStateRegistry {
private final Map<String, AbstractPlayerState> states = new ConcurrentHashMap<>();
public void registerState(AbstractPlayerState state) {
states.put(state.getName(), state);
}
public AbstractPlayerState getState(String name) {
return states.get(name);
}
}public class PlayerStateTracker implements Listener {
private final Map<UUID, List<String>> playerStates = new ConcurrentHashMap<>();
private final PlayerStateRegistry registry;
public PlayerStateTracker(PlayerStateRegistry registry) {
this.registry = registry;
// Register events or something
}
public void addState(Player player, AbstractPlayerState state) {
if(state == null) { // idiot proof
return;
}
UUID playerId = player.getUniqueId();
String stateName = state.getName();
List<String> states = playerStates.computeIfAbsent(playerId, irrelevant -> new ArrayList<>());
// Optional
if(states.contains(stateName)) {
return;
}
// Apply the state and add to the list
states.add(stateName);
state.apply(player);
// Feel free to save this list to PDC in case an instance crashes
}
public void addState(Player player, String stateName) {
addState(player, registry.getState(stateName));
}
public void removeState(Player player, AbstractPlayerState state) {
if(state == null) { // idiot proof
return;
}
UUID playerId = player.getUniqueId();
String stateName = state.getName();
List<String> states = playerStates.getOrDefault(playerId, Collections.EMPTY_LIST);
if(states.isEmpty() || !states.contains(stateName)) {
return;
}
states.remove(stateName);
if(states.isEmpty()) {
playerStates.remove(playerId);
}
state.revert(player);
}
public void removeState(Player player, String stateName) {
removeState(player, registry.getState(stateName));
}
public boolean hasState(Player player, String state) {
return playerStates.getOrDefault(player.getUniqueId(), Collections.EMPTY_LIST).contains(state);
}
public void removeAll(Player player) {
UUID playerId = player.getUniqueId();
List<String> states = this.playerStates.remove(playerId);
if(states == null) {
return;
}
// Apply reverse order just in case
Collections.reverse(states);
for(String state : states) {
AbstractPlayerState abstractState = registry.getState(state);
if(abstractState == null) { // ??
continue;
}
abstractState.revert(player);
}
}
@EventHandler
public void onQuit(PlayerQuitEvent event) {
removeAll(event.getPlayer());
}
}Have fun!