// ----------------------------------------- // Client.cpp // copyright 2001 Sony Online Entertainment // ----------------------------------------- #include "FirstConnectionServer.h" #include "ChatServerConnection.h" #include "CustomerServiceConnection.h" #include "Client.h" #include "ClientConnection.h" #include "serverNetworkMessages/ChatConnectAvatar.h" #include "serverNetworkMessages/ChatDisconnectAvatar.h" #include "serverNetworkMessages/GameConnectionServerMessages.h" #include "sharedGame/PlatformFeatureBits.h" #include "sharedLog/Log.h" #include "sharedMessageDispatch/Transceiver.h" #include "sharedNetworkMessages/ChatEnterRoomById.h" #include "sharedNetworkMessages/ChatServerStatus.h" #include "sharedNetworkMessages/DisconnectPlayerMessage.h" #include "sharedNetworkMessages/GenericValueTypeMessage.h" #include "sharedFoundation/CrcConstexpr.hpp" //---------------------------------------------------------------------- Client::Client(ClientConnection * cconn, const NetworkId& oid) : Receiver(), m_chatConnection(0), m_customerServiceConnection(0), m_clientConnection(cconn), m_deferredChatMessages(), m_hasBeenKicked(false), m_oid(oid), m_gameConnection(0), //m_roomCache(), m_sceneName(), m_skipLoadScreen(false), m_callback(new MessageDispatch::Callback) { static const std::string loginTrace("TRACE_LOGIN"); LOG(loginTrace, ("new Client(%s)", m_oid.getValueString().c_str())); // until/unless a chat server connection is set, the client will // listen for a new chat server coming online. // This handles the case where a client connects and there // are no chat servers currently running (e.g. a crash happens // at the point in time a client is connecting) connectToMessage("ChatServerConnectionOpened"); connectToMessage("CustomerServiceConnectionOpened"); m_callback->connect(*this, &Client::onChatConnectionClosed); } //---------------------------------------------------------------------- Client::~Client() { ConnectionServer::dropClient(m_clientConnection, "Destroying Client Object"); if(m_chatConnection) { m_chatConnection->removeClient(this); m_chatConnection = 0; } if(m_customerServiceConnection) { std::vector v; v.clear(); v.push_back(getNetworkId()); DisconnectPlayerMessage message; GameClientMessage gcm(v, true, message); m_customerServiceConnection->send(gcm, true); m_customerServiceConnection->removeClient(this); m_customerServiceConnection = 0; } if (m_oid != NetworkId::cms_invalid && ConnectionServer::getClient(m_oid)) { WARNING_STRICT_FATAL(true, ("Attempting to delete client %d without removing him from map\n", m_oid.getValueString().c_str())); } m_clientConnection = 0; setGameConnection(0); m_gameConnection = 0; delete m_callback; } //----------------------------------------------------------------------- void Client::onChatConnectionClosed(Connection * closedConnection) { if(m_chatConnection == closedConnection) { m_chatConnection->removeClient(this); m_chatConnection = 0; } } //----------------------------------------------------------------------- void Client::deferChatMessage(const Archive::ByteStream & message) { m_deferredChatMessages.push_back(message); } //----------------------------------------------------------------------- /* void Client::enterRoom(const unsigned int roomId) { IGNORE_RETURN ( m_roomCache.insert(roomId) ); } */ //----------------------------------------------------------------------- void Client::flushChatMessages() { if(m_chatConnection) { std::vector::const_iterator i; for(i = m_deferredChatMessages.begin(); i != m_deferredChatMessages.end(); ++i) { m_chatConnection->Connection::send((*i), true); } m_deferredChatMessages.clear(); } } //------------------------------------------------------------ void Client::handleTransfer(const std::string & sceneName, GameConnection* conn) { NOT_NULL(conn); //Set the new scene name setSceneName(sceneName); //If we are already connected to a game server drop them if (getGameConnection() && getGameConnection() != conn) { DropClient msg(getNetworkId()); getGameConnection()->send(msg, true); } //Set the new game server setGameConnection(conn); m_skipLoadScreen = false; } //----------------------------------------------------------------------- /* void Client::leaveRoom(const unsigned int roomId) { std::set::iterator f = m_roomCache.find(roomId); if(f != m_roomCache.end()) m_roomCache.erase(f); } */ //------------------------------------------------------------ void Client::receiveMessage(const MessageDispatch::Emitter & source, const MessageDispatch::MessageBase & message) { const uint32 messageType = message.getType(); if(messageType == constcrc("GameConnectionClosed")) { // Game server has crashed. With luck, we'll get transferred to a new server shortly // So, clear our connection and put us on a queue. If we don't get transferred in a // reasonable about of time, we'll be dropped. m_gameConnection = 0; ConnectionServer::addRecoveringClient(getNetworkId()); } else if(messageType == constcrc("ChatServerConnectionOpened")) { const ChatServerConnection & chatConnection = static_cast(source); setChatConnection(const_cast(&chatConnection)); } else if(messageType == constcrc("CustomerServiceConnectionOpened")) { const CustomerServiceConnection & customerServiceConnection = static_cast(source); setCustomerServiceConnection(const_cast(&customerServiceConnection)); } } //----------------------------------------------------------------------- void Client::setChatConnection(ChatServerConnection * c) { if(m_chatConnection) { disconnectFromEmitter(*m_chatConnection, "ChatServerConnectionClosed"); // advise the old chat server that this client is disconnecting // from it NOT_NULL(m_clientConnection); ChatDisconnectAvatar m(m_clientConnection->getCharacterId()); m_chatConnection->send(m, true); } else { disconnectFromMessage("ChatServerConnectionOpened"); } m_chatConnection = c; if(c && m_clientConnection) { // advise the new chat server that the client is connecting connectToEmitter(*m_chatConnection, "ChatServerConnectionClosed"); ChatConnectAvatar connectAvatar(m_clientConnection->getCharacterName(), m_clientConnection->getCharacterId(), m_clientConnection->getSUID(), m_clientConnection->getIsSecure(), ((m_clientConnection->getSubscriptionFeatures() & ClientSubscriptionFeature::Base) != 0)); m_chatConnection->send(connectAvatar, true); m_chatConnection->addClient(this); /* std::vector id; id.push_back(getNetworkId()); std::set::const_iterator i; for(i = m_roomCache.begin(); i != m_roomCache.end(); ++i) { ChatEnterRoomById chat(0, (*i)); GameClientMessage gcm(id, true, chat); c->send(gcm, true); } m_roomCache.clear(); */ flushChatMessages(); ChatServerStatus status(true); m_clientConnection->send(status, true); } else { connectToMessage("ChatServerConnectionOpened"); ChatServerStatus status(false); NOT_NULL(m_clientConnection); m_clientConnection->send(status, false); } } //----------------------------------------------------------------------- void Client::setCustomerServiceConnection(CustomerServiceConnection * c) { if(m_customerServiceConnection) { disconnectFromEmitter(*m_customerServiceConnection, "CustomerServiceConnectionClosed"); NOT_NULL(m_clientConnection); } else { disconnectFromMessage("CustomerServiceConnectionOpened"); } m_customerServiceConnection = c; if(c && m_clientConnection) { connectToEmitter(*m_customerServiceConnection, "CustomerServiceConnectionClosed"); m_customerServiceConnection->addClient(this); } else { connectToMessage("CustomerServiceConnectionOpened"); } } //------------------------------------------------------------ void Client::setGameConnection(GameConnection* conn) { if (m_gameConnection != conn) { if (m_gameConnection) { disconnectFromEmitter(*m_gameConnection, "GameConnectionClosed"); } if (conn) { connectToEmitter(*conn, "GameConnectionClosed"); } m_gameConnection = conn; } } //------------------------------------------------------------ void Client::kick(const std::string& reason) { ClientConnection *c = getClientConnection(); ConnectionServer::dropClient(c, reason); m_hasBeenKicked = true; if (getClientConnection()) { LOG("CustomerService", ("Login:%s Dropped Reason: %s. Character: %s (%s). Play time: %s. Active play time: %s", ClientConnection::describeAccount(c).c_str(), reason.c_str(), getClientConnection()->getCharacterName().c_str(), getClientConnection()->getCharacterId().getValueString().c_str(), getClientConnection()->getPlayTimeDuration().c_str(), getClientConnection()->getActivePlayTimeDuration().c_str())); } else { LOG("CustomerService", ("Login: Account unknown (lost client connection) id %s Dropped Reason: %s. Character: . Play time: . Active play time: ", m_oid.getValueString().c_str(), reason.c_str())); } } //------------------------------------------------------------ bool Client::getSkipLoadScreen() const { return m_skipLoadScreen; } //------------------------------------------------------------ void Client::skipLoadScreen() { m_skipLoadScreen = true; } //----------------------------------------------------------------------