ProjectAres/Commons/bukkit/src/main/java/tc/oc/commons/bukkit/commands/ServerVisibilityCommands.java

138 lines
6.0 KiB
Java

package tc.oc.commons.bukkit.commands;
import java.util.EnumSet;
import java.util.logging.Logger;
import javax.inject.Inject;
import com.google.common.util.concurrent.ListenableFuture;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import tc.oc.api.docs.Server;
import tc.oc.api.docs.virtual.ServerDoc;
import tc.oc.api.minecraft.MinecraftService;
import tc.oc.minecraft.scheduler.SyncExecutor;
import tc.oc.commons.bukkit.event.WhitelistStateChangeEvent;
import tc.oc.commons.bukkit.whitelist.Whitelist;
import tc.oc.commons.core.commands.CommandFutureCallback;
import tc.oc.commons.core.commands.Commands;
import tc.oc.commons.core.logging.Loggers;
public class ServerVisibilityCommands implements Listener, Commands {
private static final String VISIBILITY_PERMISSION = "server.visibility";
private static final EnumSet<ServerDoc.Visibility> OPTIONS = EnumSet.of(ServerDoc.Visibility.PUBLIC, ServerDoc.Visibility.UNLISTED);
private final Logger logger;
private final MinecraftService minecraftService;
private final SyncExecutor syncExecutor;
private final Whitelist whitelist;
@Inject ServerVisibilityCommands(Loggers loggers, MinecraftService minecraftService, SyncExecutor syncExecutor, Whitelist whitelist) {
this.whitelist = whitelist;
this.logger = loggers.get(getClass());
this.minecraftService = minecraftService;
this.syncExecutor = syncExecutor;
}
private static String coloredVisibility(ServerDoc.Visibility visibility) {
switch(visibility) {
case PRIVATE: return ChatColor.BLUE + "private";
case UNLISTED: return ChatColor.YELLOW + "unlisted";
case PUBLIC: return ChatColor.GREEN + "public";
default: return ChatColor.RED + "unknown";
}
}
private static void reportVisibility(CommandSender sender, ServerDoc.Visibility visibility) {
sender.sendMessage("Server visibility: " + coloredVisibility(visibility));
}
// Too bad Gson refuses to serialize anonymous classes
private static class Info implements ServerDoc.Visible {
private final ServerDoc.Visibility visibility;
public Info(ServerDoc.Visibility visibility) {this.visibility = visibility; }
@Override public ServerDoc.Visibility visibility() { return visibility; }
}
private ListenableFuture<Server> setVisibility(final ServerDoc.Visibility visibility) {
return minecraftService.updateLocalServer(new Info(visibility));
}
@Command(
aliases = { "visibility" },
desc = "Show or change the visibility type of this server",
usage = "[public|unlisted]",
min = 0,
max = 1
)
@CommandPermissions(VISIBILITY_PERMISSION)
public void visibility(final CommandContext args, final CommandSender sender) throws CommandException {
final Server local = minecraftService.getLocalServer();
if(args.argsLength() < 1) {
reportVisibility(sender, local.visibility());
} else {
final ServerDoc.Visibility visibility;
try {
visibility = ServerDoc.Visibility.valueOf(args.getString(0).toUpperCase());
if(!OPTIONS.contains(visibility)) throw new IllegalArgumentException();
} catch(IllegalArgumentException e) {
throw new CommandException("Invalid visibility type '" + args.getString(0) + "'");
}
if(visibility == ServerDoc.Visibility.PUBLIC && whitelist.isEnabled()) {
throw new CommandException("Cannot set visibility to 'public' while whitelist is enabled");
}
syncExecutor.callback(
setVisibility(visibility),
CommandFutureCallback.onSuccess(sender, args, response -> {
logger.info("Server visibility set to " + response.visibility() + " by " + sender.getName());
reportVisibility(sender, response.visibility());
})
);
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void hideAbandonedServer(PlayerQuitEvent event) {
final Server local = minecraftService.getLocalServer();
if(local.startup_visibility() != ServerDoc.Visibility.PUBLIC && // If server was initially not public and
local.visibility() == ServerDoc.Visibility.PUBLIC && // server was made public and
event.getPlayer().hasPermission(VISIBILITY_PERMISSION)) { // someone with perms to do that is leaving...
// ...check if there is still someone online with that permission
for(Player player : event.getPlayer().getServer().getOnlinePlayers()) {
// If someone else with perms is online, we're cool
if(player != event.getPlayer() && player.hasPermission(VISIBILITY_PERMISSION)) return;
}
// If nobody with perms is online, make the server non-public again
logger.info("Reverting server visibility to " + local.startup_visibility() + " because nobody with permissions is online");
setVisibility(local.startup_visibility());
}
}
@EventHandler
public void hideWhitelistedServer(WhitelistStateChangeEvent event) {
final Server local = minecraftService.getLocalServer();
if(local.startup_visibility() != ServerDoc.Visibility.PUBLIC &&
local.visibility() == ServerDoc.Visibility.PUBLIC &&
event.isEnabled()) {
logger.info("Reverting server visibility to " + local.startup_visibility() + " because whitelist is enabled");
setVisibility(local.startup_visibility());
}
}
}