package admincommands; import java.awt.Color; import java.lang.reflect.Field; import java.nio.channels.SelectionKey; import java.util.Comparator; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; import com.aionemu.commons.network.NioServer; import com.aionemu.gameserver.GameServer; import com.aionemu.gameserver.model.gameobjects.player.Player; import com.aionemu.gameserver.network.aion.AionConnection; import com.aionemu.gameserver.services.player.PlayerService; import com.aionemu.gameserver.utils.ChatUtil; import com.aionemu.gameserver.utils.chathandlers.AdminCommand; /** * @author Neon */ public class Debug extends AdminCommand { public Debug() { super("debug", "Helps fixing runtime problems."); // @formatter:off setSyntaxInfo( " - Displays all connected game clients.", " - Displays information about connected players.", " - Disconnects and attempts to save bugged players." ); // @formatter:on } @Override public void execute(Player admin, String... params) { if (params.length == 0) { sendInfo(admin); return; } if ("connections".equalsIgnoreCase(params[0])) { List connections = findAionConnections(admin); if (connections != null) { sendInfo(admin, "Online clients:\n\t" + connections.stream().map(AionConnection::toString).collect(Collectors.joining("\n\t"))); } } else if ("connectedPlayers".equalsIgnoreCase(params[0])) { List connectedPlayers = findConnectedPlayers(admin); if (connectedPlayers != null) { String message = "Connected players (" + connectedPlayers.size() + "):"; for (Player player : connectedPlayers) { String details = "position: " + player.getPosition().toCoordString() + ", spawned: " + player.isSpawned(); if (!player.isInWorld()) { details += ", " + ChatUtil.color("not in world", Color.RED); } message += "\n\t" + player.getName() + " [" + details + "]"; } sendInfo(admin, message); } } else if ("dcBuggedPlayers".equalsIgnoreCase(params[0])) { List buggedPlayers = findConnectedPlayers(admin).stream().filter(p -> !p.isInWorld()).collect(Collectors.toList()); if (buggedPlayers != null) { if (buggedPlayers.isEmpty()) { sendInfo(admin, "No bugged players found."); } else { for (Player player : buggedPlayers) { player.getController().cancelAllTasks(); // ensure to cancel item update task etc player.getCommonData().setOnline(false); PlayerService.storePlayer(player); player.getClientConnection().setActivePlayer(null); player.getClientConnection().close(); player.setClientConnection(null); } sendInfo(admin, "Saved most data and disconnected the following players:\n" + buggedPlayers); } } } } private List findConnectedPlayers(Player admin) { List connections = findAionConnections(admin); if (connections != null) { return connections.stream().map(AionConnection::getActivePlayer).filter(Objects::nonNull) .sorted(Comparator.comparing(Player::getName)).collect(Collectors.toList()); } return null; } private List findAionConnections(Player admin) { try { Field nioServerField = GameServer.class.getDeclaredField("nioServer"); boolean oldAccessible = nioServerField.isAccessible(); nioServerField.setAccessible(true); NioServer nioServer = (NioServer) nioServerField.get(null); nioServerField.setAccessible(oldAccessible); java.util.Set keys = nioServer.getReadWriteDispatcher().selector().keys(); return keys.stream().map(SelectionKey::attachment).filter(o -> o instanceof AionConnection).map(o -> (AionConnection) o) .collect(Collectors.toList()); } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { sendInfo(admin, e.toString()); return null; } } }