Skip to content

Commit

Permalink
Expand AFK and Exclusion APIs to allow control of logic flow + more
Browse files Browse the repository at this point in the history
Also change examples and remove stafffacilities
  • Loading branch information
aakatz3 committed Mar 28, 2021
1 parent 434dc1a commit 1d627ba
Show file tree
Hide file tree
Showing 11 changed files with 165 additions and 123 deletions.
9 changes: 3 additions & 6 deletions src/main/java/xyz/nkomarn/harbor/Harbor.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import xyz.nkomarn.harbor.command.ForceSkipCommand;
import xyz.nkomarn.harbor.command.HarborCommand;
import xyz.nkomarn.harbor.listener.BedListener;
import xyz.nkomarn.harbor.provider.EssentialsAFKProvider;
import xyz.nkomarn.harbor.task.Checker;
import xyz.nkomarn.harbor.util.Config;
import xyz.nkomarn.harbor.util.Messages;
Expand Down Expand Up @@ -46,16 +45,14 @@ public void onEnable() {
getCommand("harbor").setExecutor(new HarborCommand(this));
getCommand("forceskip").setExecutor(new ForceSkipCommand(this));

registerDefaultProviders();


if (config.getBoolean("metrics")) {
new Metrics(this);
}
}

private void registerDefaultProviders() {

}

@Override
public void onDisable() {
Expand Down Expand Up @@ -108,11 +105,11 @@ public void addExclusionProvider(ExclusionProvider provider) {
* @param provider An external implementation of an {@link AFKProvider}, provided by an implementing plugin
*
* @see AFKProvider
* @see PlayerManager#addAFKProvider(AFKProvider)
* @see PlayerManager#addAfkProvider(AFKProvider, LogicType)
*/
@SuppressWarnings("unused")
public void addAFKProvider(AFKProvider provider, LogicType type) {
playerManager.addAFKProvider(provider);
playerManager.addAfkProvider(provider, type);
}

@NotNull
Expand Down
1 change: 1 addition & 0 deletions src/main/java/xyz/nkomarn/harbor/api/AFKProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public interface AFKProvider {
* Tests if a {@link Player} is AFK
*
* @param player The {@link Player} that is being checked
*
* @return If the player is afk (true) or not (false)
*/
boolean isAFK(Player player);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public interface ExclusionProvider {
* Tests if a {@link Player} is excluded from the sleep checks for Harbor
*
* @param player The {@link Player} that is being checked
*
* @return If the player is excluded (true) or not (false)
*/
boolean isExcluded(Player player);
Expand Down
22 changes: 9 additions & 13 deletions src/main/java/xyz/nkomarn/harbor/api/LogicType.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
package xyz.nkomarn.harbor.api;

import java.util.function.BiFunction;
import org.bukkit.configuration.Configuration;
import org.jetbrains.annotations.NotNull;

public enum LogicType implements BiFunction<Boolean, Boolean, Boolean> {
AND, OR, XOR;
/**
* An enum to represent the type of logic to be used when combining multiple Providers
*/
public enum LogicType {
AND, OR;

@Override
public Boolean apply(Boolean a, Boolean b) {
if(this.equals(AND))
return a && b;
else if(this.equals(OR))
return a || b;
else if(this.equals(XOR))
return a ^ b;
else
throw new UnsupportedOperationException("Unsupported logic type");
public static LogicType fromConfig(@NotNull Configuration configuration, String path, LogicType defaultType) {
return valueOf(configuration.getString(path, defaultType.toString()).toUpperCase().trim());
}
}
22 changes: 14 additions & 8 deletions src/main/java/xyz/nkomarn/harbor/listener/AfkListeners.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,34 +9,34 @@
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.scheduler.BukkitRunnable;
import xyz.nkomarn.harbor.provider.DefaultAFKProvider;
import xyz.nkomarn.harbor.util.PlayerManager;

import java.util.ArrayDeque;
import java.util.Queue;

public final class AfkListeners extends BukkitRunnable implements Listener {

private final PlayerManager playerManager;
private final DefaultAFKProvider afkProvider;
private double checksToMake = 0;
private final Queue<AfkPlayer> players = new ArrayDeque<>();

public AfkListeners(PlayerManager playerManager) {
this.playerManager = playerManager;
public AfkListeners(DefaultAFKProvider afkProvider) {
this.afkProvider = afkProvider;
}

@EventHandler(ignoreCancelled = true)
public void onChat(AsyncPlayerChatEvent event) {
playerManager.updateActivity(event.getPlayer());
afkProvider.updateActivity(event.getPlayer());
}

@EventHandler(ignoreCancelled = true)
public void onCommand(PlayerCommandPreprocessEvent event) {
playerManager.updateActivity(event.getPlayer());
afkProvider.updateActivity(event.getPlayer());
}

@EventHandler(ignoreCancelled = true)
public void onInventoryClick(InventoryClickEvent event) {
playerManager.updateActivity((Player) event.getWhoClicked());
afkProvider.updateActivity((Player) event.getWhoClicked());
}

@EventHandler
Expand All @@ -62,13 +62,18 @@ public void run() {
while (System.currentTimeMillis() - start < 20 && checksToMake > 0) {
AfkPlayer afkPlayer = players.poll();
if (afkPlayer.changed()) {
playerManager.updateActivity(afkPlayer.player);
afkProvider.updateActivity(afkPlayer.player);
}
players.add(afkPlayer);
checksToMake--;
}
}

@Override
public void cancel() {
super.cancel();
}

private static class AfkPlayer {
private final Player player;
private int hash;
Expand All @@ -79,6 +84,7 @@ public AfkPlayer(Player player) {

/**
* Check if the player changed its position since the last check
*
* @return true if the position changed
*/
private boolean changed() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,85 @@
package xyz.nkomarn.harbor.provider;

import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import org.jetbrains.annotations.NotNull;
import xyz.nkomarn.harbor.Harbor;
import xyz.nkomarn.harbor.api.AFKProvider;
import xyz.nkomarn.harbor.listener.AfkListeners;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class DefaultAFKProvider implements AFKProvider, Listener {
private final Harbor harbor;
private final boolean enabled;
private final Map<UUID, Instant> playerActivity;
private final AfkListeners listeners;

public DefaultAFKProvider(@NotNull Harbor harbor) {
this.harbor = harbor;
playerActivity = new HashMap<>();
if (enabled = (harbor.getConfig().getBoolean("afk-detection.fallback-enabled", true))) {
harbor.getLogger().info("Registering fallback AFK detection system.");
listeners = new AfkListeners(this);
harbor.getServer().getPluginManager().registerEvents(this, harbor);
} else {
harbor.getLogger().info("Not registering fallback AFK detection system.");
listeners = null;
}
}

@Override
public boolean isAFK(Player player) {
return false;
if (!enabled || !playerActivity.containsKey(player.getUniqueId())) {
return false;
}

long minutes = playerActivity.get(player.getUniqueId()).until(Instant.now(), ChronoUnit.MINUTES);
return minutes >= harbor.getConfiguration().getInteger("afk-detection.timeout");
}

/**
* Sets the given player's last activity to the current timestamp.
*
* @param player The player to update.
*/
public void updateActivity(@NotNull Player player) {
playerActivity.put(player.getUniqueId(), Instant.now());
}


/**
* Enables Harbor's fallback listeners for AFK detection if other AFKProviders are not present.
*/
public void enableListeners() {
if (enabled) {
listeners.runTaskTimer(harbor, 1, 1);
harbor.getServer().getPluginManager().registerEvents(listeners, harbor);
}
}

/**
* Disables Harbor's fallback listeners for AFK detection if other AFKProviders are present.
*/

public void disableListeners() {
if (enabled) {
listeners.cancel();
harbor.getLogger().info("Unregistering fallback AFK detection system.");
}
}

@EventHandler
public void onQuit(PlayerQuitEvent event) {
playerActivity.remove(event.getPlayer().getUniqueId());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,18 @@

import com.earth2me.essentials.Essentials;
import com.earth2me.essentials.User;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import xyz.nkomarn.harbor.Harbor;
import xyz.nkomarn.harbor.api.AFKProvider;

import java.util.Optional;

/**
* An {@link AFKProvider} that uses Essentials; can be used as an example of how external
* plugins can implement an {@link AFKProvider}
*/
public class EssentialsAFKProvider implements AFKProvider {
private final Essentials essentials;

private EssentialsAFKProvider(@NotNull Essentials essentials) {
public EssentialsAFKProvider(@NotNull Essentials essentials) {
this.essentials = essentials;
}

Expand All @@ -28,15 +24,4 @@ public boolean isAFK(Player player) {
return user != null && user.isAfk();
}

public static void registerEssentials(Harbor harbor) {
ConfigurationSection afk = harbor.getConfig().getConfigurationSection("afk-detection");
if(afk != null && afk.getBoolean("essentials-enabled")) {
if(harbor.getEssentials().isPresent()) {
EssentialsAFKProvider provider = new EssentialsAFKProvider(harbor.getEssentials().get());
} else {
harbor.getLogger().info("Essentials not present- skipping registering Essentials AFK detection");
}
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@
import java.util.HashMap;
import java.util.Map;

public class GameModeExclusionProvider extends HarborProvider implements ExclusionProvider {
public class GameModeExclusionProvider implements ExclusionProvider {
private final Map<GameMode, Boolean> exclusionMap;

public GameModeExclusionProvider(@NotNull Harbor harbor) {
super(harbor);
ConfigurationSection exclusions = harbor.getConfig().getConfigurationSection("exclusions");
if(exclusions != null) {
if (exclusions != null) {
exclusionMap = new HashMap<>();
exclusionMap.put(GameMode.ADVENTURE, exclusions.getBoolean("exclude-adventure", false));
exclusionMap.put(GameMode.CREATIVE, exclusions.getBoolean("exclude-creative", false));
Expand All @@ -28,6 +28,6 @@ public GameModeExclusionProvider(@NotNull Harbor harbor) {

@Override
public boolean isExcluded(Player player) {
return exclusionMap != null ? exclusionMap.get(player.getGameMode()) : false;
return exclusionMap != null ? exclusionMap.getOrDefault(player.getGameMode(), false) : false;
}
}
47 changes: 20 additions & 27 deletions src/main/java/xyz/nkomarn/harbor/task/Checker.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import xyz.nkomarn.harbor.Harbor;
import xyz.nkomarn.harbor.api.AFKProvider;
import xyz.nkomarn.harbor.api.ExclusionProvider;
import xyz.nkomarn.harbor.provider.GameModeExclusionProvider;
import xyz.nkomarn.harbor.util.Config;
import xyz.nkomarn.harbor.util.Messages;

Expand All @@ -28,17 +29,29 @@
import static java.util.stream.Collectors.toList;

public class Checker extends BukkitRunnable {

private final Set<ExclusionProvider> providers;
private final Harbor harbor;
private final Set<UUID> skippingWorlds;
private final List<ExclusionProvider> exclusionProviders;

public Checker(@NotNull Harbor harbor) {
this.harbor = harbor;
this.skippingWorlds = new HashSet<>();
this.exclusionProviders = new ArrayList<>();
this.providers = new HashSet<>();

ConfigurationSection exclusions = harbor.getConfig().getConfigurationSection("exclusions");


if(exclusions != null) {
// Add inbuilt exclusions
providers.add(new GameModeExclusionProvider(harbor));
if(exclusions.getBoolean("ignored-permission", false))
providers.add(player -> player.hasPermission("harbor.ignored"));
if(exclusions.getBoolean("exclude-vanished", false))
providers.add(Checker::isVanished);
if(exclusions.getBoolean("exclude-afk", false))
providers.add(player -> harbor.getPlayerManager().isAfk(player));
}

runTaskTimerAsynchronously(harbor, 0L, harbor.getConfiguration().getInteger("interval") * 20);
}

Expand Down Expand Up @@ -139,7 +152,7 @@ public boolean isBlacklisted(@NotNull World world) {
* @param player The player to check.
* @return Whether the provided player is vanished.
*/
public boolean isVanished(@NotNull Player player) {
public static boolean isVanished(@NotNull Player player) {
for (MetadataValue meta : player.getMetadata("vanished")) {
if (meta.asBoolean()) {
return true;
Expand Down Expand Up @@ -213,27 +226,7 @@ private List<Player> getExcluded(@NotNull World world) {
* @return Whether the given player is excluded.
*/
private boolean isExcluded(@NotNull Player player) {
ConfigurationSection exclusions = harbor.getConfig().getConfigurationSection("exclusions");

if (exclusions == null) {
return false;
}

boolean excludedByAdventure = exclusions.getBoolean("exclude-adventure", false) && player.getGameMode() == GameMode.ADVENTURE;
boolean excludedByCreative = exclusions.getBoolean("exclude-creative", false) && player.getGameMode() == GameMode.CREATIVE;
boolean excludedBySpectator = exclusions.getBoolean("exclude-spectator", false) && player.getGameMode() == GameMode.SPECTATOR;
boolean excludedByPermission = exclusions.getBoolean("ignored-permission", false) && player.hasPermission("harbor.ignored");
boolean excludedByVanish = exclusions.getBoolean("exclude-vanished", false) && isVanished(player);
boolean excludedByAfk = exclusions.getBoolean("exclude-afk", false) && harbor.getPlayerManager().isAfk(player);
boolean excludedByProvider = exclusionProviders.stream().anyMatch(provider -> provider.isExcluded(player));

return excludedByAdventure
|| excludedByCreative
|| excludedBySpectator
|| excludedByPermission
|| excludedByVanish
|| excludedByAfk
|| excludedByProvider;
return providers.stream().anyMatch(provider -> provider.isExcluded(player));
}

/**
Expand Down Expand Up @@ -314,10 +307,10 @@ public void ensureMain(@NotNull Runnable runnable) {
}

/**
* Adds an {@link ExclusionProvider}, which will be checked as a condition
* Adds an {@link ExclusionProvider}, which will be checked as a condition. All Exclusions will be ORed together
* on which to exclude a given player
*/
public void addExclusionProvider(ExclusionProvider provider) {
exclusionProviders.add(provider);
providers.add(provider);
}
}
Loading

0 comments on commit 1d627ba

Please sign in to comment.