Added manual-max-players to the config, which allows you to set a max player count for servers/groups

This commit is contained in:
ajgeiss0702
2023-07-31 17:53:28 -07:00
parent 8d7d56a8c6
commit 6592925c6d
9 changed files with 159 additions and 52 deletions
@@ -61,12 +61,10 @@ public interface Logic {
} }
if(fulljoinPriority > 0) { if(fulljoinPriority > 0) {
if(server.isFull() && (server.canJoinFull(player) || boolean hasMakeRoom = player.hasPermission("ajqueue.make-room") && AjQueueAPI.getInstance().getConfig().getBoolean("enable-make-room-permission");
( if(
player.hasPermission("ajqueue.make-room") && (server.isFull() && (server.canJoinFull(player) || hasMakeRoom)) ||
AjQueueAPI.getInstance().getConfig().getBoolean("enable-make-room-permission") (queueServer.isManuallyFull() && (AdaptedServer.canJoinFull(player, queueServer.getName()) || hasMakeRoom))) {
)
)) {
highest = Math.max(highest, fulljoinPriority); highest = Math.max(highest, fulljoinPriority);
} }
} }
@@ -4,9 +4,7 @@ import com.google.common.collect.ImmutableList;
import us.ajg0702.queue.api.players.AdaptedPlayer; import us.ajg0702.queue.api.players.AdaptedPlayer;
import us.ajg0702.queue.api.players.QueuePlayer; import us.ajg0702.queue.api.players.QueuePlayer;
import us.ajg0702.queue.api.server.AdaptedServer; import us.ajg0702.queue.api.server.AdaptedServer;
import us.ajg0702.queue.api.server.AdaptedServerPing;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@@ -69,6 +67,18 @@ public interface QueueServer {
*/ */
boolean isJoinable(AdaptedPlayer p); boolean isJoinable(AdaptedPlayer p);
/**
* Gets the manually-set max player count for this server/group
* @return The manually-set max player count
*/
int getManualMaxPlayers();
/**
* Checks if the total number of players in this server/group is above the manually-set max player count
* @return If the server is at or above the manually-set player limit
*/
boolean isManuallyFull();
/** /**
* Pauses or unpauses a server * Pauses or unpauses a server
* @param paused true = paused, false = unpaused * @param paused true = paused, false = unpaused
@@ -1,5 +1,6 @@
package us.ajg0702.queue.api.server; package us.ajg0702.queue.api.server;
import us.ajg0702.queue.api.AjQueueAPI;
import us.ajg0702.queue.api.players.AdaptedPlayer; import us.ajg0702.queue.api.players.AdaptedPlayer;
import us.ajg0702.queue.api.util.Handle; import us.ajg0702.queue.api.util.Handle;
import us.ajg0702.queue.api.util.QueueLogger; import us.ajg0702.queue.api.util.QueueLogger;
@@ -52,7 +53,20 @@ public interface AdaptedServer extends Handle {
*/ */
int getOfflineTime(); int getOfflineTime();
boolean canJoinFull(AdaptedPlayer player); default boolean canJoinFull(AdaptedPlayer player) {
return canJoinFull(player, getName());
}
static boolean canJoinFull(AdaptedPlayer player, String serverName) {
if(player == null) return true;
return
player.hasPermission("ajqueue.joinfull") ||
player.hasPermission("ajqueue.joinfullserver." + serverName) ||
player.hasPermission("ajqueue.joinfullandbypassserver." + serverName) ||
player.hasPermission("ajqueue.joinfullandbypass") ||
(AjQueueAPI.getInstance().isPremium() && AjQueueAPI.getInstance().getLogic().getPermissionGetter().hasUniqueFullBypass(player, serverName))
;
}
boolean justWentOnline(); boolean justWentOnline();
@@ -598,9 +598,10 @@ public class QueueManagerImpl implements QueueManager {
final ConcurrentHashMap<AdaptedPlayer, Long> sendingNowAntiSpam = new ConcurrentHashMap<>(); final ConcurrentHashMap<AdaptedPlayer, Long> sendingNowAntiSpam = new ConcurrentHashMap<>();
final Map<QueuePlayer, Integer> sendingAttempts = new WeakHashMap<>(); final Map<QueuePlayer, Integer> sendingAttempts = new WeakHashMap<>();
final Map<QueuePlayer, Long> makeRoomAntispam = new WeakHashMap<>();
@Override @Override
public void sendPlayers(QueueServer queueServer) { public synchronized void sendPlayers(QueueServer queueServer) {
List<QueueServer> sendingServers; List<QueueServer> sendingServers;
if(queueServer == null) { if(queueServer == null) {
sendingServers = new ArrayList<>(servers); sendingServers = new ArrayList<>(servers);
@@ -633,7 +634,10 @@ public class QueueManagerImpl implements QueueManager {
continue; continue;
} }
if(selected.isFull() && !selected.canJoinFull(p.getPlayer())) continue; if(
(selected.isFull() && !selected.canJoinFull(player)) ||
(server.isManuallyFull() && !AdaptedServer.canJoinFull(player, server.getName()))
) continue;
player.sendMessage(msgs.getComponent("status.sending-now", "SERVER:"+server.getAlias())); player.sendMessage(msgs.getComponent("status.sending-now", "SERVER:"+server.getAlias()));
Debug.info("Calling player.connect for " + player.getName() + "(send when back online)"); Debug.info("Calling player.connect for " + player.getName() + "(send when back online)");
@@ -683,23 +687,33 @@ public class QueueManagerImpl implements QueueManager {
if(!server.canAccess(nextPlayer)) continue; if(!server.canAccess(nextPlayer)) continue;
if( if(
selected.isFull() && (
!selected.canJoinFull(nextPlayer) && (selected.isFull() && !selected.canJoinFull(nextPlayer)) ||
(server.isManuallyFull() && !AdaptedServer.canJoinFull(nextPlayer, server.getName()))
) &&
!( !(
nextPlayer.hasPermission("ajqueue.make-room") && nextPlayer.hasPermission("ajqueue.make-room") &&
main.getConfig().getBoolean("enable-make-room-permission") main.getConfig().getBoolean("enable-make-room-permission") &&
(!server.isGroup() || server.isManuallyFull()) // only use make-room on groups if the server is manually full
) )
) continue; ) continue;
// ajqueue.make-room logic // ajqueue.make-room logic
if( if(
selected.isFull() && (
!selected.canJoinFull(nextPlayer) && (selected.isFull() && !selected.canJoinFull(nextPlayer)) ||
(server.isManuallyFull() && !AdaptedServer.canJoinFull(nextPlayer, server.getName()))
) &&
main.getConfig().getBoolean("enable-make-room-permission") && main.getConfig().getBoolean("enable-make-room-permission") &&
nextPlayer.hasPermission("ajqueue.make-room") && nextPlayer.hasPermission("ajqueue.make-room") &&
!server.isGroup() (!server.isGroup() || server.isManuallyFull()) && // only use make-room on groups if the server is manually full
( // don't make room more than the minimum ping time
System.currentTimeMillis() - makeRoomAntispam.getOrDefault(nextQueuePlayer, 0L)
>= (main.getConfig().getDouble("minimum-ping-time") * 1e3)
)
) { ) {
makeRoomAntispam.put(nextQueuePlayer, System.currentTimeMillis());
List<AdaptedPlayer> players = selected.getPlayers(); List<AdaptedPlayer> players = selected.getPlayers();
// first, we need to find what the lowest priority on the server is // first, we need to find what the lowest priority on the server is
@@ -11,14 +11,13 @@ import us.ajg0702.queue.api.server.AdaptedServerPing;
import us.ajg0702.queue.common.QueueMain; import us.ajg0702.queue.common.QueueMain;
import us.ajg0702.queue.common.players.QueuePlayerImpl; import us.ajg0702.queue.common.players.QueuePlayerImpl;
import us.ajg0702.queue.common.queues.balancers.DefaultBalancer; import us.ajg0702.queue.common.queues.balancers.DefaultBalancer;
import us.ajg0702.queue.common.queues.balancers.FirstBalancer;
import us.ajg0702.queue.common.queues.balancers.MinigameBalancer; import us.ajg0702.queue.common.queues.balancers.MinigameBalancer;
import us.ajg0702.queue.common.utils.Debug; import us.ajg0702.queue.common.utils.Debug;
import us.ajg0702.utils.common.Messages; import us.ajg0702.utils.common.Messages;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
public class QueueServerImpl implements QueueServer { public class QueueServerImpl implements QueueServer {
@@ -38,6 +37,9 @@ public class QueueServerImpl implements QueueServer {
private long lastSentTime = 0; private long lastSentTime = 0;
private int manualMaxPlayers = Integer.MAX_VALUE;
public QueueServerImpl(String name, QueueMain main, AdaptedServer server, List<QueuePlayer> previousPlayers) { public QueueServerImpl(String name, QueueMain main, AdaptedServer server, List<QueuePlayer> previousPlayers) {
this(name, main, Collections.singletonList(server), previousPlayers); this(name, main, Collections.singletonList(server), previousPlayers);
} }
@@ -55,11 +57,13 @@ public class QueueServerImpl implements QueueServer {
String balancerType = type.substring(colon+1); String balancerType = type.substring(colon+1);
if(groupName.equals(name)) { if(groupName.equals(name)) {
//noinspection SwitchStatementWithTooFewBranches
switch(balancerType.toLowerCase(Locale.ROOT)) { switch(balancerType.toLowerCase(Locale.ROOT)) {
case "minigame": case "minigame":
balancer = new MinigameBalancer(this, main); balancer = new MinigameBalancer(this, main);
break; break;
case "first":
balancer = new FirstBalancer(this, main);
break;
default: default:
balancerType = "default"; balancerType = "default";
balancer = new DefaultBalancer(this, main); balancer = new DefaultBalancer(this, main);
@@ -73,6 +77,26 @@ public class QueueServerImpl implements QueueServer {
Debug.info("Using default balancer for "+name); Debug.info("Using default balancer for "+name);
} }
List<String> manualLimits = main.getConfig().getStringList("manual-max-players");
for (String manualLimit : manualLimits) {
String[] parts = manualLimit.split(":");
if(parts.length != 2) {
main.getLogger().warn("Invalid manual limit: " + manualLimit);
continue;
}
String limitFor = parts[0];
if(!limitFor.equals(name)) continue;
String limitStr = parts[1];
try {
manualMaxPlayers = Integer.parseInt(limitStr);
} catch(NumberFormatException e) {
main.getLogger().warn("Invalid limit number for " + limitFor);
}
break;
}
for(QueuePlayer queuePlayer : previousPlayers) { for(QueuePlayer queuePlayer : previousPlayers) {
if(queuePlayer.getPlayer() == null) { if(queuePlayer.getPlayer() == null) {
addPlayer( addPlayer(
@@ -123,7 +147,7 @@ public class QueueServerImpl implements QueueServer {
return msgs.getString("status.offline.whitelisted"); return msgs.getString("status.offline.whitelisted");
} }
if(server.isFull() && !server.canJoinFull(p)) { if((server.isFull() && !server.canJoinFull(p)) || (isManuallyFull() && !AdaptedServer.canJoinFull(p, getName()))) {
return msgs.getString("status.offline.full"); return msgs.getString("status.offline.full");
} }
@@ -159,7 +183,7 @@ public class QueueServerImpl implements QueueServer {
return "whitelisted"; return "whitelisted";
} }
if(server.isFull() && !server.canJoinFull(p)) { if(((server.isFull() && !server.canJoinFull(p)) || (isManuallyFull() && !AdaptedServer.canJoinFull(p, getName())))) {
return "full"; return "full";
} }
@@ -186,11 +210,31 @@ public class QueueServerImpl implements QueueServer {
@Override @Override
public boolean isJoinable(AdaptedPlayer p) { public boolean isJoinable(AdaptedPlayer p) {
if(isManuallyFull() && !AdaptedServer.canJoinFull(p, getName())) return false;
AdaptedServer server = getIdealServer(p); AdaptedServer server = getIdealServer(p);
if(server == null) return false; if(server == null) return false;
return server.isJoinable(p) && !isPaused(); return server.isJoinable(p) && !isPaused();
} }
@Override
public int getManualMaxPlayers() {
return manualMaxPlayers;
}
@Override
public boolean isManuallyFull() {
int total = 0;
for (AdaptedServer server : servers) {
Optional<AdaptedServerPing> lastPing = server.getLastPing();
if(!lastPing.isPresent()) continue;
total += lastPing.get().getPlayerCount();
}
// Debug.info(total + " >= " + getManualMaxPlayers() + " = " + (total >= getManualMaxPlayers()));
return total >= getManualMaxPlayers();
}
@Override @Override
public synchronized void setPaused(boolean paused) { public synchronized void setPaused(boolean paused) {
this.paused = paused; this.paused = paused;
@@ -272,6 +316,11 @@ public class QueueServerImpl implements QueueServer {
return ImmutableList.copyOf(names); return ImmutableList.copyOf(names);
} }
@Override
public boolean isOnline() {
return QueueServer.super.isOnline();
}
@Override @Override
public boolean isGroup() { public boolean isGroup() {
return servers.size() > 1; return servers.size() > 1;
@@ -0,0 +1,37 @@
package us.ajg0702.queue.common.queues.balancers;
import org.jetbrains.annotations.Nullable;
import us.ajg0702.queue.api.players.AdaptedPlayer;
import us.ajg0702.queue.api.queues.Balancer;
import us.ajg0702.queue.api.queues.QueueServer;
import us.ajg0702.queue.api.server.AdaptedServer;
import us.ajg0702.queue.common.QueueMain;
public class FirstBalancer implements Balancer {
private final QueueServer server;
private final QueueMain main;
public FirstBalancer(QueueServer server, QueueMain main) {
this.server = server;
this.main = main;
}
@Override
public AdaptedServer getIdealServer(@Nullable AdaptedPlayer player) {
AdaptedServer alreadyConnected;
if(player == null) {
alreadyConnected = null;
} else {
alreadyConnected = player.getCurrentServer();
}
for (AdaptedServer sv : server.getServers()) {
if(!sv.isOnline()) continue;
if(sv.equals(alreadyConnected)) continue;
if(!sv.isJoinable(player)) continue;
return sv;
}
// If all servers are unavailable, just select the first one
return server.getServers().get(0);
}
}
+15 -5
View File
@@ -91,6 +91,14 @@ queue-servers:
# Default: true # Default: true
kick-kicked-players: true kick-kicked-players: true
# This option allows you to manually set player caps for servers
# Note that this does NOT override the player cap returned by the server.
# Format: - '<server>:<max-players>'
# Example: - 'lobbys:50'
# The example above will limit the lobbys group to have a total of 50 players.
# This works on both groups and individual servers
manual-max-players: []
# Server groups are a group of servers that you can queue for. It will send you to the server that is the least full. # Server groups are a group of servers that you can queue for. It will send you to the server that is the least full.
# If all servers in the group are full, it will act the same as it would when a single server is full. # If all servers in the group are full, it will act the same as it would when a single server is full.
@@ -101,10 +109,12 @@ server-groups:
# What balancer should we use for groups? # What balancer should we use for groups?
# If a group is not specified here, then the default one is used # If a group is not specified here, then the default one is used
# Example entry: - "bedwars:minigame" # Example: - "bedwars:minigame"
# The example above will set the bedwars group to use the minigame balancer
# Balancers: # Balancers:
# default - Will send the player to the server in the group with the least number of players # default - Will send the player to the server in the group with the least number of players
# minigame - Will send the player to the server with the most players, until that server is full, which it will then send to the next server # minigame - Will send the player to the server with the most players, until that server is full, which it will then send to the next server
# first - Will send the player to the first available server in the group (as long as it is joinable)
balancer-types: balancer-types:
- "bedwars:minigame" - "bedwars:minigame"
@@ -211,12 +221,12 @@ wait-to-load-servers: false
# How long should we wait after the server finishes loading to load the server list? # How long should we wait after the server finishes loading to load the server list?
# Only works if the above is enabled. # Only works if the above is enabled.
# This is in miliseconds so 1000 = 1 second # This is in milliseconds so 1000 = 1 second
# Default: 500 # Default: 500
wait-to-load-servers-delay: 500 wait-to-load-servers-delay: 500
# How often (in seconds) we should check for new servers to add queues for. # How often (in seconds) we should check for new servers to add queues for.
# If you dynamicly add servers, set this to something other than 0. # If you dynamically add servers, set this to something other than 0.
# To disable, set to 0 # To disable, set to 0
# Default: 0 # Default: 0
reload-servers-interval: 0 reload-servers-interval: 0
@@ -296,7 +306,7 @@ make-room-kick-to: lobby
# For the make-room permission, players with the lowest priority are kicked first. # For the make-room permission, players with the lowest priority are kicked first.
# Of those players, this option decides which to kick. # Of those players, this option decides which to kick.
# true - kick players who have been on the server the longest # true - kick players who have been on the server the longest
# false - kick players who have been on nthe server the shortest # false - kick players who have been on the server the shortest
# Default: true # Default: true
make-room-kick-longest-playtime: true make-room-kick-longest-playtime: true
@@ -367,7 +377,7 @@ debug: false
# Don't touch this number please # Don't touch this number please
config-version: 41 config-version: 42
# This is ONLY here so that they can be moved to messages.yml. Please edit these in messages.yml! # This is ONLY here so that they can be moved to messages.yml. Please edit these in messages.yml!
@@ -106,17 +106,6 @@ public class BungeeServer implements AdaptedServer {
return offlineTime; return offlineTime;
} }
@Override
public boolean canJoinFull(AdaptedPlayer player) {
if(player == null) return true;
return
player.hasPermission("ajqueue.joinfull") ||
player.hasPermission("ajqueue.joinfullserver."+getName()) ||
player.hasPermission("ajqueue.joinfullandbypassserver."+getName()) ||
player.hasPermission("ajqueue.joinfullandbypass") ||
(AjQueueAPI.getInstance().isPremium() && AjQueueAPI.getInstance().getLogic().getPermissionGetter().hasUniqueFullBypass(player, getName()))
;
}
@Override @Override
public boolean justWentOnline() { public boolean justWentOnline() {
@@ -9,7 +9,6 @@ import us.ajg0702.queue.api.server.AdaptedServer;
import us.ajg0702.queue.api.server.AdaptedServerInfo; import us.ajg0702.queue.api.server.AdaptedServerInfo;
import us.ajg0702.queue.api.server.AdaptedServerPing; import us.ajg0702.queue.api.server.AdaptedServerPing;
import us.ajg0702.queue.api.util.QueueLogger; import us.ajg0702.queue.api.util.QueueLogger;
import us.ajg0702.queue.common.utils.Debug;
import us.ajg0702.queue.platforms.velocity.players.VelocityPlayer; import us.ajg0702.queue.platforms.velocity.players.VelocityPlayer;
import java.util.ArrayList; import java.util.ArrayList;
@@ -113,19 +112,6 @@ public class VelocityServer implements AdaptedServer {
return offlineTime; return offlineTime;
} }
@Override
public boolean canJoinFull(AdaptedPlayer player) {
if(player == null) return true;
Debug.info("on "+getName());
return
player.hasPermission("ajqueue.joinfull") ||
player.hasPermission("ajqueue.joinfullserver."+getName()) ||
player.hasPermission("ajqueue.joinfullandbypassserver."+getName()) ||
player.hasPermission("ajqueue.joinfullandbypass") ||
(AjQueueAPI.getInstance().isPremium() && AjQueueAPI.getInstance().getLogic().getPermissionGetter().hasUniqueFullBypass(player, getName()))
;
}
@Override @Override
public boolean justWentOnline() { public boolean justWentOnline() {
return System.currentTimeMillis()-lastOffline <= (AjQueueAPI.getInstance().getConfig().getDouble("wait-time") * 2 * 1000) && isOnline(); return System.currentTimeMillis()-lastOffline <= (AjQueueAPI.getInstance().getConfig().getDouble("wait-time") * 2 * 1000) && isOnline();