relation/server/imserver/playermgr.cc
2020-10-15 15:23:23 +08:00

672 lines
23 KiB
C++

#include "precompile.h"
#include <a8/openssl.h>
#include <a8/udplog.h>
#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 && !hum->GetBlackListById(msg.context().user_info().base_data().account_id())) {
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)
{
int times = 0;
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);
++times;
if (times > 100) {
a8::UdpLog::Instance()->Warning
("OnUserOnLine watch account_id:%s times:%d ",
{
account_id,
times
});
break;
}
}
}
}
}
void PlayerMgr::_SS_IM_OnUserOffline(f8::MsgHdr& hdr, const ss::SS_IM_OnUserOffline& msg)
{
int times = 0;
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);
++times;
if (times > 100) {
a8::UdpLog::Instance()->Warning
("OnUserOffLine watch account_id:%s times:%d ",
{
account_id,
times
});
break;
}
}
}
}
}
void PlayerMgr::_SS_IM_QueryUserOnlineState(f8::MsgHdr& hdr, const ss::SS_IM_QueryUserOnlineState& msg)
{
ss::SS_IM_PushUserOnlineState respmsg;
*respmsg.mutable_context() = msg.context();
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)
{
int gameid = f8::ExtractGameIdFromAccountId
(msg.context().user_info().base_data().account_id());
std::set<std::string> exclude_account_ids;
for (auto& account_id : msg.exclude_account_ids()) {
exclude_account_ids.insert(account_id);
}
std::vector<Player*> human_list;
human_list.reserve(100);
for (auto& pair : accountid_hash_) {
if (human_list.size() > 100) {
break;
}
if (pair.second->GetFriendNum() < MAX_FRIEND_NUM &&
pair.second->gameid == gameid &&
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_GuildMemberQuitRequest(f8::MsgHdr& hdr, const ss::SS_IM_GuildMemberQuitRequest& msg)
{
Player* hum = GetPlayerByAccountId(msg.target_id());
if (hum) {
hum->UpdateGuildData(0, 0);
hum->SaveToDB(a8::XParams()
.SetSender(hdr.socket_handle)
.SetParam1(msg.seqid()),
[] (a8::XParams& param, const f8::DataSet* data_set)
{
int socket_handle = param.sender;
long long seqid = param.param1;
ss::SS_IM_GuildMemberQuitRequest respmsg;
respmsg.set_seqid(seqid);
IMListener::Instance()->SendMsg(socket_handle, respmsg);
},
[] (a8::XParams& param, int error_code, const std::string& error_msg)
{
});
}
}
void PlayerMgr::_SS_IM_GuildMemberUpdateRequest(f8::MsgHdr& hdr, const ss::SS_IM_GuildMemberUpdateRequest& msg)
{
Player* hum = GetPlayerByAccountId(msg.target_id());
if (hum) {
hum->UpdateGuildData(msg.guild_id(), msg.guild_job());
ss::SS_IM_GuildMemberUpdateRequest respmsg;
respmsg.set_seqid(msg.seqid());
IMListener::Instance()->SendMsg(hdr.socket_handle, respmsg);
}
}
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::_SS_GS_QueryGuildUserOnlineState(f8::MsgHdr& hdr, const ss::SS_GS_QueryGuildUserOnlineState& msg)
{
}
void PlayerMgr::_SS_GS_PushGuildRedPoint(f8::MsgHdr& hdr, const ss::SS_GS_PushGuildRedPoint& msg)
{
Player* hum = GetPlayerByAccountId(msg.account_id());
if (hum) {
hum->UpdateGuildRedPoint(msg.guild_id(), msg.has_apply());
}
}
void PlayerMgr::_SS_GS_ApplyChangeRequest(f8::MsgHdr& hdr, const ss::SS_GS_ApplyChangeRequest& msg)
{
Player* hum = GetPlayerByAccountId(msg.account_id());
if (hum) {
if (msg.is_refuse()) {
hum->RemoveGuildApplyed(msg.guild_id());
} else {
hum->AddGuildApplyed(msg.guild_id());
}
ss::SS_IM_ApplyChangeResponse respmsg;
respmsg.set_seqid(msg.seqid());
IMListener::Instance()->SendMsg(hdr.socket_handle, respmsg);
}
}
void PlayerMgr::_CMLoginOld(f8::MsgHdr& hdr, const cs::CMLoginOld& msg)
{
cs::CMLogin new_msg;
new_msg.set_account_id(msg.account_id());
new_msg.set_session_id(msg.session_id());
new_msg.set_nickname(msg.nickname());
new_msg.set_avatar_url(msg.avatar_url());
new_msg.set_sex(msg.sex());
_CMLogin(hdr, new_msg);
}
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();
}
int PlayerMgr::WatchPlayerNum()
{
return watch_players_.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<int> 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<int> 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
a8::XValue(data_set->at(0).at(9)), //guild_id
a8::XValue(data_set->at(0).at(10)).GetInt() //guild_job
);
}
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, "
" guild_id, guild_job "
"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,
long long guild_id,
int guild_job)
{
f8::MsgHdr* hdr = GetHdrByAccountId(account_id);
if (hdr) {
Player* hum = GetPlayerByAccountId(account_id);
if (hum) {
pending_socket_hash_.erase(hdr->socket_handle);
pending_account_hash_.erase(account_id);
f8::MsgHdr::Destroy(hdr);
return;
}
hum = GetPlayerBySocket(hdr->socket_handle);
if (hum) {
pending_socket_hash_.erase(hdr->socket_handle);
pending_account_hash_.erase(account_id);
f8::MsgHdr::Destroy(hdr);
return;
}
{
hum = new Player();
hum->socket_handle = hdr->socket_handle;
hum->ip_saddr = hdr->ip_saddr;
hum->gameid = f8::ExtractGameIdFromAccountId(account_id);
hum->channel = f8::ExtractChannelIdFromAccountId(account_id);
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.guild_id = guild_id;
hum->myself.base_data.guild_job = guild_job;
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->FillSMLogin(respmsg);
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->myself.base_data.online = false;
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
}