// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . // ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· // ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ // ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ // ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ // Magicbane Emulator Project © 2013 - 2022 // www.magicbane.com package engine.server.login; import engine.Enum.DispatchChannel; import engine.Enum.GameObjectType; import engine.gameManager.DbManager; import engine.gameManager.SessionManager; import engine.job.JobScheduler; import engine.jobs.DisconnectJob; import engine.net.Dispatch; import engine.net.DispatchMessage; import engine.net.NetMsgHandler; import engine.net.client.ClientConnection; import engine.net.client.Protocol; import engine.net.client.msg.ClientNetMsg; import engine.net.client.msg.ServerInfoMsg; import engine.net.client.msg.login.*; import engine.objects.Account; import engine.objects.GuildStatusController; import engine.objects.PlayerCharacter; import engine.server.MBServerStatics; import engine.session.CSSession; import engine.session.Session; import engine.util.ByteUtils; import engine.util.StringUtils; import org.pmw.tinylog.Logger; public class LoginServerMsgHandler implements NetMsgHandler { private final LoginServer server; LoginServerMsgHandler(LoginServer server) { super(); this.server = server; } public static void sendInvalidNameMsg(String firstName, String lastName, int errorCode, ClientConnection clientConnection) { InvalidNameMsg invalidNameMessage; if (firstName.length() > 256 || lastName.length() > 256) invalidNameMessage = new InvalidNameMsg(firstName, lastName, errorCode); else invalidNameMessage = new InvalidNameMsg(firstName, lastName, errorCode); clientConnection.sendMsg(invalidNameMessage); } /* * ========================================================================= * Client Messages * ========================================================================= */ @Override public boolean handleClientMsg(ClientNetMsg clientNetMsg) { if (clientNetMsg == null) { Logger.error("Recieved null msg. Returning."); return false; } ClientConnection origin = (ClientConnection) clientNetMsg.getOrigin(); Protocol protocolMsg = clientNetMsg.getProtocolMsg(); try { switch (protocolMsg) { case SELECTSERVER: this.SendServerInfo(origin); break; case CREATECHAR: this.CommitNewCharacter((CommitNewCharacterMsg) clientNetMsg, origin); break; case REMOVECHAR: this.DeleteCharacter((DeleteCharacterMsg) clientNetMsg, origin); break; case SELECTCHAR: this.RequestGameServer((GameServerIPRequestMsg) clientNetMsg, origin); break; case TARGETOBJECT: // Why is this being sent to login server? break; default: String ocHex = StringUtils.toHexString(protocolMsg.opcode); Logger.error("Cannot not handle Opcode: " + ocHex); return false; } } catch (Exception e) { Logger.error("protocolMsg:" + protocolMsg + e.toString()); return false; } return true; } public static void KickToLogin(int errCode, String message, ClientConnection origin) { LoginErrorMsg msg = new LoginErrorMsg(errCode, message); PlayerCharacter player = origin.getPlayerCharacter(); if (player == null) { origin.sendMsg(msg); } else { Dispatch dispatch = Dispatch.borrow(player, msg); DispatchMessage.dispatchMsgDispatch(dispatch, DispatchChannel.PRIMARY); } Logger.info("Kicking to Login. Message: '" + message + '\''); DisconnectJob dj = new DisconnectJob(origin); JobScheduler.getInstance().scheduleJob(dj, 250); } public static void sendCharacterSelectScreen(Session s) { sendCharacterSelectScreen(s, false); } private static void sendCharacterSelectScreen(Session s, boolean fromCommit) { if (s.getAccount() != null) { CharSelectScreenMsg cssm = new CharSelectScreenMsg(s, fromCommit); s.getConn().sendMsg(cssm); } else { Logger.error("No Account Found: Unable to Send Character Select Screen"); LoginServerMsgHandler.KickToLogin(MBServerStatics.LOGINERROR_UNABLE_TO_LOGIN, "Unable to send Character Select Screen to client.", s.getConn()); } } private void SendServerInfo(ClientConnection conn) { ServerInfoMsg sim = new ServerInfoMsg(); if (!conn.sendMsg(sim)) { Logger.error("Failed to send message"); this.KickToLogin(MBServerStatics.LOGINERROR_UNABLE_TO_LOGIN, "Unable to send ServerInfoMsg to client.", conn); } } private void CommitNewCharacter(CommitNewCharacterMsg commitNewCharacterMessage, ClientConnection clientConnection) { Session session = SessionManager.getSession(clientConnection); if (session.getAccount() == null) return; try { // Check to see if there is an available slot. if (session.getAccount().characterMap.size() >= MBServerStatics.MAX_NUM_OF_CHARACTERS) { this.sendCharacterSelectScreen(session); return; } PlayerCharacter pc = PlayerCharacter.generatePCFromCommitNewCharacterMsg(session.getAccount(), commitNewCharacterMessage, clientConnection); if (pc == null) { Logger.info("Player returned null while creating character."); this.sendCharacterSelectScreen(session, true); return; } PlayerCharacter.initializePlayer(pc); session.getAccount().characterMap.putIfAbsent(pc.getObjectUUID(), pc); // Send back to Character Select Screen this.sendCharacterSelectScreen(session, true); } catch (Exception e) { Logger.error(e); this.sendCharacterSelectScreen(session, true); } } private void DeleteCharacter(DeleteCharacterMsg msg, ClientConnection origin) { try { PlayerCharacter playerCharacter; Session session; session = SessionManager.getSession(origin); playerCharacter = PlayerCharacter.getPlayerCharacter(msg.getCharacterUUID()); if (playerCharacter == null) { Logger.error("Delete Error: PlayerID=" + msg.getCharacterUUID() + " not found."); this.sendCharacterSelectScreen(session); return; } if (session.getAccount() == null) { Logger.error("Delete Error: Account not found."); this.sendCharacterSelectScreen(session); return; } if (playerCharacter.getAccount().equals(session.getAccount()) == false) { Logger.error("Delete Error: Character " + playerCharacter.getName() + " does not belong to account " + origin.getAccount().getUname()); this.sendCharacterSelectScreen(session); return; } //Can't delete as Guild Leader //TODO either find an error or just gdisband. if (GuildStatusController.isGuildLeader(playerCharacter.getGuildStatus())) { this.KickToLogin(MBServerStatics.LOGINERROR_UNABLE_TO_LOGIN, "Cannot delete a guild leader.", origin); return; } // check for active banes if (LoginServer.getActiveBaneQuery(playerCharacter)) { Logger.info("Character " + playerCharacter.getName() + " has unresolved bane"); this.KickToLogin(MBServerStatics.LOGINERROR_UNABLE_TO_LOGIN, "Player has unresolved bane.", origin); return; } playerCharacter.getAccount().characterMap.remove(playerCharacter.getObjectUUID()); playerCharacter.deactivateCharacter(); // TODO Delete Equipment // Resend Character Select Screen. this.sendCharacterSelectScreen(session); } catch (Exception e) { Logger.error(e); } } private void RequestGameServer(GameServerIPRequestMsg gameServerIPRequestMessage, ClientConnection conn) { Session session; PlayerCharacter player; session = SessionManager.getSession(conn); player = (PlayerCharacter) DbManager.getObject(GameObjectType.PlayerCharacter, gameServerIPRequestMessage.getCharacterUUID()); if (player == null) { Logger.info("Unable to find character ID " + gameServerIPRequestMessage.getCharacterUUID()); KickToLogin(MBServerStatics.LOGINERROR_UNABLE_TO_LOGIN, "PlayerCharacter lookup failed in .RequestGameServer().", conn); return; } try { if (!CSSession.updateCrossServerSession(ByteUtils.byteArrayToSafeStringHex(conn.getSecretKeyBytes()), gameServerIPRequestMessage.getCharacterUUID())) { Logger.info("Failed to update Cross server session, Kicking to Login for Character " + player.getObjectUUID()); this.KickToLogin(MBServerStatics.LOGINERROR_UNABLE_TO_LOGIN, "Failed to update Session Information", conn); return; } } catch (Exception e) { Logger.info("Failed to update Cross server session, Kicking to Login for Character " + player.getObjectUUID()); Logger.error(e); } // Set the last character used. Account account = session.getAccount(); account.setLastCharIDUsed(gameServerIPRequestMessage.getCharacterUUID()); GameServerIPResponseMsg gameServerIPResponseMsg = new GameServerIPResponseMsg(); if (!conn.sendMsg(gameServerIPResponseMsg)) { Logger.error("Failed to send message"); this.KickToLogin(MBServerStatics.LOGINERROR_UNABLE_TO_LOGIN, "Unable to send GameServerIPResponseMsg to client.", conn); } } }