package com.supaham.commons.bungee.modules;
import com.google.common.base.Preconditions;
import com.supaham.commons.bungee.CommonTask;
import com.supaham.commons.bungee.modules.framework.CommonModule;
import com.supaham.commons.bungee.modules.framework.Module;
import com.supaham.commons.bungee.modules.framework.ModuleContainer;
import com.supaham.commons.state.State;
import com.supaham.commons.utils.StringUtils;
import com.supaham.commons.utils.TimeUtils;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Plugin;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import javax.annotation.Nonnull;
/**
* Represents a {@link Module} container that allows for registration and removal of modules.
*
* @since 0.3.6
*/
public class Bungee extends CommonModule {
private final Map<UUID, Long> connecting = new HashMap<>();
private final int connectCooldown;
private CommonTask cooldownRemover = new CooldownRemover();
/**
* Constructs a {@link Bungee} instance with a {@link Plugin} as the owner and 2000 milliseconds
* connecting cooldown.
* <br />
* If the {@code connectCooldown} is <b>2000</b> and a player is to be sent to a server, then
* <b>1500</b> ticks later the same player is asked to leave the server again and still hasn't
* left the code terminates.
*
* @param container module container to own this module.
*
* @see #Bungee(ModuleContainer, int)
*/
public Bungee(@Nonnull ModuleContainer container) {
this(container, 2000);
}
/**
* Constructs a {@link Bungee} instance with a {@link Plugin} as the owner.
* <br />
* If the {@code connectCooldown} is <b>40</b> and a player is to be sent to a server, then
* <b>1500</b> ticks later the same player is asked to leave the server again and still hasn't
* left the code terminates.
*
* @param container module container to own this module.
* @param connectCooldown cooldown (in milliseconds) that a player should be able to connect to a
* server.
*/
public Bungee(@Nonnull ModuleContainer container, int connectCooldown) {
super(container);
this.connectCooldown = connectCooldown;
registerTask(this.cooldownRemover);
}
public boolean setState(@Nonnull State state) throws UnsupportedOperationException {
boolean change = super.setState(state);
if (change) {
switch (state) {
case STOPPED:
this.connecting.clear();
break;
}
}
return change;
}
/**
* Sends all online players to a specific bungee server.
*
* @param serverName server to send all online players to
*
* @see #sendPlayerTo(ProxiedPlayer, String)
*/
public void sendAllTo(String serverName) {
for (ProxiedPlayer player : this.plugin.getProxy().getPlayers()) {
sendPlayerTo(player, serverName);
}
}
/**
* Sends a {@link ProxiedPlayer} to a specific bungee server.
* <br />
* The one and only case where the returned boolean would be false is if the {@code player} was
* already being sent within the {@link #getConnectCooldown()} ticks.
*
* @param player player to send
* @param serverName bungee server to send player to
*
* @return whether the player is being sent to the specified {@code serverName}.
*/
public boolean sendPlayerTo(final ProxiedPlayer player, @Nonnull String serverName) {
StringUtils.checkNotNullOrEmpty(serverName, "server name");
Preconditions.checkState(getState().equals(State.ACTIVE), "Bungee module not active.");
ServerInfo serverInfo = this.plugin.getProxy().getServerInfo(serverName);
Preconditions.checkArgument(serverInfo != null, serverName + " is not a valid server.");
Long previous = this.connecting.get(player.getUniqueId());
if (previous != null && !TimeUtils.elapsed(previous, this.connectCooldown)) {
return false;
}
player.connect(serverInfo);
this.connecting.put(player.getUniqueId(), System.currentTimeMillis());
return true;
}
public int getConnectCooldown() {
return connectCooldown;
}
public Set<UUID> getConnecting() {
return Collections.unmodifiableSet(this.connecting.keySet());
}
private final class CooldownRemover extends CommonTask {
public CooldownRemover() {
super(Bungee.this.plugin, 0, 1);
}
@Override public void run() {
Iterator<Long> it = Bungee.this.connecting.values().iterator();
while (it.hasNext()) {
if (it.next() <= System.currentTimeMillis()) {
it.remove();
}
}
}
}
}