#include "precompile.h" #include #include #include "playermgr.h" #include "player.h" #include "cs_proto.pb.h" #include "dbengine.h" #include "WSListener.h" #include "app.h" #include "gamelog.h" #include "IMListener.h" #include "typeconvert.h" #include "perfmonitor.h" #include "asynctaskmgr.h" #include "framework/cpp/utils.h" void PlayerMgr::Init() { } void PlayerMgr::UnInit() { } void PlayerMgr::_SS_WSP_SocketDisconnect(f8::MsgHdr& hdr, const ss::SS_WSP_SocketDisconnect& msg) { OnClientSocketDisconnect(hdr.socket_handle); } void PlayerMgr::_SS_MS_PushUserList(f8::MsgHdr& hdr, const ss::SS_MS_PushUserList& msg) { } void PlayerMgr::_SS_IM_SendChatMsg(f8::MsgHdr& hdr, const ss::SS_IM_SendChatMsg& msg) { Player* hum = GetPlayerByAccountId(msg.target()); if (hum) { cs::SMChatMsgNotify notifymsg; notifymsg.set_sender(msg.context().user_info().base_data().account_id()); notifymsg.set_chat_channel(msg.chat_channel()); notifymsg.set_msg(msg.msg()); hum->SendMsg(notifymsg); } } void PlayerMgr::_SS_IM_SendCustomMsg(f8::MsgHdr& hdr, const ss::SS_IM_SendCustomMsg& msg) { Player* hum = GetPlayerByAccountId(msg.target()); if (hum) { cs::SMCustomMsgNotify notifymsg; notifymsg.set_sender(msg.context().user_info().base_data().account_id()); notifymsg.set_msg(msg.msg()); notifymsg.set_param1(msg.param1()); notifymsg.set_param2(msg.param2()); notifymsg.set_param3(msg.param3()); hum->SendMsg(notifymsg); } } void PlayerMgr::_SS_IM_FriendAgreeRequest(f8::MsgHdr& hdr, const ss::SS_IM_FriendAgreeRequest& msg) { Player* hum = GetPlayerByAccountId(msg.target_id()); if (hum) { hum->_SS_IM_FriendAgreeRequest(hdr, msg); } } void PlayerMgr::_SS_IM_FriendDeleteRequest(f8::MsgHdr& hdr, const ss::SS_IM_FriendDeleteRequest& msg) { Player* hum = GetPlayerByAccountId(msg.target_id()); if (hum) { hum->_SS_IM_FriendDeleteRequest(hdr, msg); } } void PlayerMgr::_SS_IM_FriendApply(f8::MsgHdr& hdr, const ss::SS_IM_FriendApply& msg) { Player* hum = GetPlayerByAccountId(msg.target_id()); if (hum) { hum->_SS_IM_FriendApply(hdr, msg); } } void PlayerMgr::_SS_IM_OnUserOnline(f8::MsgHdr& hdr, const ss::SS_IM_OnUserOnline& msg) { for (auto& account_id : msg.account_ids()) { auto itr = watch_players_.find(account_id); if (itr != watch_players_.end()) { struct Friend *node, *tmp; list_for_each_entry_safe(node, tmp, &itr->second, watch_node) { node->base_data.online = true; node->hum->NotifyUserInfoUpdate(node); } } } } void PlayerMgr::_SS_IM_OnUserOffline(f8::MsgHdr& hdr, const ss::SS_IM_OnUserOffline& msg) { for (auto& account_id : msg.account_ids()) { auto itr = watch_players_.find(account_id); if (itr != watch_players_.end()) { struct Friend *node, *tmp; list_for_each_entry_safe(node, tmp, &itr->second, watch_node) { node->base_data.online = false; node->hum->NotifyUserInfoUpdate(node); } } } } void PlayerMgr::_SS_IM_QueryUserOnlineState(f8::MsgHdr& hdr, const ss::SS_IM_QueryUserOnlineState& msg) { ss::SS_IM_PushUserOnlineState respmsg; for (auto& account_id : msg.account_ids()) { Player* hum = GetPlayerByAccountId(account_id); if (hum) { hum->FillMFUserInfo(respmsg.add_user_infos()); } } IMListener::Instance()->SendMsg(hdr.socket_handle, respmsg); } void PlayerMgr::_SS_IM_PushUserOnlineState(f8::MsgHdr& hdr, const ss::SS_IM_PushUserOnlineState& msg) { AsyncTaskMgr::Instance()->_SS_IM_PushUserOnlineState(hdr, msg); for (auto& user_info : msg.user_infos()) { auto itr = watch_players_.find(user_info.base_data().account_id()); if (itr != watch_players_.end()) { struct Friend *node, *tmp; list_for_each_entry_safe(node, tmp, &itr->second, watch_node) { TypeConvert::Convert(user_info.base_data(), node->base_data); TypeConvert::Convert(user_info.temp_custom_data(), node->temp_custom_data); node->hum->NotifyUserInfoUpdate(node); } } } } void PlayerMgr::_SS_IM_RandomUsersRequest(f8::MsgHdr& hdr, const ss::SS_IM_RandomUsersRequest& msg) { std::set exclude_account_ids; for (auto& account_id : msg.exclude_account_ids()) { exclude_account_ids.insert(account_id); } std::vector human_list; human_list.reserve(100); for (auto& pair : accountid_hash_) { if (pair.second->GetFriendNum() < MAX_FRIEND_NUM && exclude_account_ids.find(pair.second->AccountId()) == exclude_account_ids.end()) { human_list.push_back(pair.second); } } std::random_shuffle(human_list.begin(), human_list.end()); ss::SS_IM_RandomUsersResponse respmsg; *respmsg.mutable_context() = msg.context(); for (size_t i = 0; i < 4; ++i) { if (i < human_list.size()) { human_list[i]->FillMFUserInfo(respmsg.add_user_infos()); } } IMListener::Instance()->SendMsg(hdr.socket_handle, respmsg); } void PlayerMgr::_SS_IM_RandomUsersResponse(f8::MsgHdr& hdr, const ss::SS_IM_RandomUsersResponse& msg) { AsyncTaskMgr::Instance()->_SS_IM_RandomUsersResponse(hdr, msg); } void PlayerMgr::_SS_IM_UpdateUserInfo(f8::MsgHdr& hdr, const ss::SS_IM_UpdateUserInfo& msg) { auto itr = watch_players_.find(msg.user_info().base_data().account_id()); if (itr != watch_players_.end()) { struct Friend *node, *tmp; list_for_each_entry_safe(node, tmp, &itr->second, watch_node) { node->hum->NotifyUserInfoUpdate(node); } } } void PlayerMgr::_CMLogin(f8::MsgHdr& hdr, const cs::CMLogin& msg) { Player* hum = GetPlayerByAccountId(msg.account_id()); if (hum) { hum->ReLogin(hdr, msg); return; } if (GetHdrBySocket(hdr.socket_handle) || GetHdrByAccountId(msg.account_id())) { cs::SMLogin respmsg; respmsg.set_errcode(1); respmsg.set_errmsg("登录失败请重试"); WSListener::Instance()->SendToClient(hdr.socket_handle, 0, respmsg); return; } f8::MsgHdr* new_hdr = hdr.Clone(); new_hdr->user_data = (const void*)a8::XGetTickCount(); pending_socket_hash_[hdr.socket_handle] = std::make_tuple(msg.account_id(), new_hdr); pending_account_hash_[msg.account_id()] = new_hdr; AsyncLogin1(msg); } void PlayerMgr::WatchPlayer(Friend* friend_data) { #ifdef DEBUG if (!list_empty(&friend_data->watch_node)) { abort(); } #endif auto itr = watch_players_.find(friend_data->base_data.account_id); if (itr == watch_players_.end()) { watch_players_[friend_data->base_data.account_id] = list_head(); itr = watch_players_.find(friend_data->base_data.account_id); if (itr == watch_players_.end()) { abort(); } INIT_LIST_HEAD(&itr->second); } list_add(&friend_data->watch_node, &itr->second); } void PlayerMgr::UnWatchPlayer(Friend* friend_data) { if (!list_empty(&friend_data->watch_node)) { list_del_init(&friend_data->watch_node); } } int PlayerMgr::OnlineNum() { return socket_hash_.size(); } void PlayerMgr::Update(long long tick) { for (auto& pair : accountid_hash_) { pair.second->Update(tick); } } Player* PlayerMgr::GetPlayerBySocket(int socket) { auto itr = socket_hash_.find(socket); return itr != socket_hash_.end() ? itr->second : nullptr; } Player* PlayerMgr::GetPlayerByAccountId(const std::string& account_id) { auto itr = accountid_hash_.find(account_id); return itr != accountid_hash_.end() ? itr->second : nullptr; } void PlayerMgr::ReBindSocket(int socket_handle, Player* hum) { socket_hash_.erase(hum->socket_handle); socket_hash_[socket_handle] = hum; hum->socket_handle = socket_handle; } void PlayerMgr::OnWSProxyDisconnect(a8::XParams& param) { int ws_socket = param.sender; std::vector socket_list; for (auto& pair : socket_hash_) { unsigned short parent_socket_handle = (pair.first >> 16) & 0xFFFF; if (parent_socket_handle == ws_socket) { socket_list.push_back(pair.first); } } for (int socket_handle : socket_list) { OnClientSocketDisconnect(socket_handle); } a8::UdpLog::Instance()->Warning ( "OnWSProxyDisconnect %d", { ws_socket }); } void PlayerMgr::OnClientDisconnect(a8::XParams& param) { int gg_socket = param.sender; std::vector socket_list; for (auto& pair : socket_hash_) { unsigned short parent_socket_handle = (pair.first >> 16) & 0xFFFF; if (parent_socket_handle == gg_socket) { socket_list.push_back(pair.first); } } for (int socket_handle : socket_list) { Player* hum = GetPlayerBySocket(socket_handle); if (hum) { RemovePlayerBySocket(socket_handle); } } } void PlayerMgr::RemovePlayerBySocket(int socket_handle) { auto itr = socket_hash_.find(socket_handle); if (itr != socket_hash_.end()) { itr->second->socket_handle = 0; socket_hash_.erase(itr); } } f8::MsgHdr* PlayerMgr::GetHdrBySocket(int socket_handle) { auto itr = pending_socket_hash_.find(socket_handle); return itr != pending_socket_hash_.end() ? std::get<1>(itr->second) : nullptr; } f8::MsgHdr* PlayerMgr::GetHdrByAccountId(const std::string& account_id) { auto itr = pending_account_hash_.find(account_id); return itr != pending_account_hash_.end() ? itr->second : nullptr; } void PlayerMgr::AsyncLogin1(const cs::CMLogin& msg) { auto on_ok = [] (a8::XParams& param, const f8::DataSet* data_set) { cs::CMLogin* msg = (cs::CMLogin*)param.sender.GetUserData(); PlayerMgr::Instance()->AsyncLogin2(*msg); delete msg; }; auto on_error = [] (a8::XParams& param, int error_code, const std::string& error_msg) { cs::CMLogin* msg = (cs::CMLogin*)param.sender.GetUserData(); PlayerMgr::Instance()->AsyncLoginOnError( msg->account_id(), 1, 1, "" ); delete msg; }; cs::CMLogin* msg_copy = new cs::CMLogin(); *msg_copy = msg; a8::XObject conn_info = DBEngine::Instance()->GetConnInfo(msg.account_id()); DBEngine::Instance()->ExecAsyncScript (conn_info, "INSERT INTO `user`(account_id, nickname, avatar_url," " sex, friend_data, createtime, modifytime, registertime)" "VALUES ('%s', '%s', '%s', %d, '', %d, %d, %d)" "ON DUPLICATE KEY UPDATE nickname='%s', avatar_url='%s'," " sex=%d, last_logintime=%d, data_version1=data_version1 + 1;", { msg.account_id(), msg.nickname(), msg.avatar_url(), msg.sex(), App::Instance()->nowtime, App::Instance()->nowtime, f8::ExtractRegisterTimeFromSessionId(msg.session_id()), msg.nickname(), msg.avatar_url(), msg.sex(), App::Instance()->nowtime }, a8::XParams() .SetSender((void*)msg_copy), on_ok, on_error, a8::openssl::Crc32((unsigned char*)msg.account_id().data(), msg.account_id().size()) ); } void PlayerMgr::AsyncLogin2(const cs::CMLogin& msg) { auto on_ok = [] (a8::XParams& param, const f8::DataSet* data_set) { cs::CMLogin* msg = (cs::CMLogin*)param.sender.GetUserData(); if (data_set->empty()) { PlayerMgr::Instance()->AsyncLoginOnError( msg->account_id(), 2, 1, "" ); } else { PlayerMgr::Instance()->AsyncLoginOnOk ( data_set->at(0).at(0), //account_id msg->session_id(), //session_id data_set->at(0).at(1), //nickname data_set->at(0).at(2), //avatar_url a8::XValue(data_set->at(0).at(3)), //sex a8::XValue(data_set->at(0).at(4)), //data_version1 data_set->at(0).at(5), //friend_data a8::XValue(data_set->at(0).at(6)), //user_value1 a8::XValue(data_set->at(0).at(7)), //user_value2 a8::XValue(data_set->at(0).at(8)) //user_value3 ); } delete msg; }; auto on_error = [] (a8::XParams& param, int error_code, const std::string& error_msg) { cs::CMLogin* msg = (cs::CMLogin*)param.sender.GetUserData(); PlayerMgr::Instance()->AsyncLoginOnError( msg->account_id(), 2, 1, "" ); delete msg; }; cs::CMLogin* msg_copy = new cs::CMLogin(); *msg_copy = msg; a8::XObject conn_info = DBEngine::Instance()->GetConnInfo(msg.account_id()); DBEngine::Instance()->ExecAsyncQuery (conn_info, "SELECT account_id, nickname, avatar_url, sex, " " data_version1, friend_data, user_value1, user_value2, user_value3 " "FROM `user` WHERE account_id='%s';", { msg.account_id(), }, a8::XParams() .SetSender((void*)msg_copy), on_ok, on_error, a8::openssl::Crc32((unsigned char*)msg.account_id().data(), msg.account_id().size()) ); } void PlayerMgr::AsyncLoginOnOk(const std::string& account_id, const std::string& session_id, const std::string& nickname, const std::string& avatar_url, int sex, int data_version1, const std::string& friend_data, long long user_value1, long long user_value2, long long user_value3) { f8::MsgHdr* hdr = GetHdrByAccountId(account_id); if (hdr) { Player* hum = GetPlayerByAccountId(account_id); if (hum) { abort(); } hum = GetPlayerBySocket(hdr->socket_handle); if (hum) { abort(); } { hum = new Player(); hum->socket_handle = hdr->socket_handle; hum->ip_saddr = hdr->ip_saddr; hum->myself.base_data.account_id = account_id; hum->myself.base_data.nickname = nickname; hum->myself.base_data.avatar_url = avatar_url; hum->myself.base_data.sex = sex; hum->myself.base_data.base_data_version = data_version1; hum->myself.base_data.user_value1 = user_value1; hum->myself.base_data.user_value2 = user_value2; hum->myself.base_data.user_value3 = user_value3; hum->myself.base_data.online = true; hum->myself.base_data.last_login_time = App::Instance()->nowtime; hum->role_data.session_id = session_id; hum->account_registertime = f8::ExtractRegisterTimeFromSessionId(session_id); { ss::MFUserDB user_db; user_db.ParseFromString(friend_data); hum->Deserialize(user_db); } hum->Init(); socket_hash_[hdr->socket_handle] = hum; accountid_hash_[account_id] = hum; GameLog::Instance()->Login(hum); } pending_socket_hash_.erase(hdr->socket_handle); pending_account_hash_.erase(account_id); { cs::SMLogin respmsg; respmsg.set_errcode(0); respmsg.set_errmsg("ok"); hum->SendMsg(respmsg); } long long login_tick = a8::XGetTickCount() - (long long)hdr->user_data; if (login_tick > PerfMonitor::Instance()->max_login_time) { PerfMonitor::Instance()->max_login_time = login_tick; } f8::MsgHdr::Destroy(hdr); } ++PerfMonitor::Instance()->login_ok_times; } void PlayerMgr::AsyncLoginOnError(const std::string& account_id, int step, int error_code, const std::string& error_msg) { f8::MsgHdr* hdr = GetHdrByAccountId(account_id); if (hdr) { pending_socket_hash_.erase(hdr->socket_handle); pending_account_hash_.erase(account_id); f8::MsgHdr::Destroy(hdr); } ++PerfMonitor::Instance()->login_error_times; } void PlayerMgr::OnClientSocketDisconnect(int socket_handle) { { auto itr = pending_socket_hash_.find(socket_handle); if (itr != pending_socket_hash_.end()) { pending_account_hash_.erase(std::get<0>(itr->second)); f8::MsgHdr::Destroy(std::get<1>(itr->second)); pending_socket_hash_.erase(itr); } } { Player* hum = GetPlayerBySocket(socket_handle); if (hum) { GameLog::Instance()->Logout(hum); hum->NotifyOffline(); hum->UnInit(); socket_hash_.erase(socket_handle); accountid_hash_.erase(hum->myself.base_data.account_id); } } #ifdef DEBUG a8::UdpLog::Instance()->Debug ( "OnClientSocketDisconnect %d", { socket_handle }); #endif }