#include "precompile.h" #include #include #include #include #include #include #include #include #include #include "framework/cpp/netmsghandler.h" #include "app.h" #include "jsondatamgr.h" #include "handlermgr.h" #include "metamgr.h" #include "roommgr.h" #include "player.h" #include "playermgr.h" #include "mapmgr.h" #include "entityfactory.h" #include "perfmonitor.h" #include "killmgr.h" #include "ss_msgid.pb.h" #include "ss_proto.pb.h" #include "framework/cpp/msgqueue.h" #include "framework/cpp/tglog.h" #include "framework/cpp/httpclientpool.h" #include "collider.h" struct MsgNode { SocketFrom_e sockfrom; int sockhandle; unsigned short msgid; unsigned int seqid; long ip_saddr; char* buf; int buflen; MsgNode* next; }; struct IMMsgNode { unsigned short msgid; a8::XParams params; IMMsgNode* next = nullptr; }; const char* const PROJ_LOG_ROOT_FMT = "/data/logs/%s/logs"; const char* const PROJ_LOG_FILENAME_FMT = "log_$pid_%Y%m%d.log"; static void SavePerfLog() { a8::UdpLog::Instance()->Info ("max_rundelay:%d room_num:%d player_num:%d online_num:%d alive_count:%d " "sys_request_delay:%d user_request_delay:%d http_pending_num:%d real_alive_count:%d " "account_num:%d level0_num:%d level1_num:%d", { PerfMonitor::Instance()->max_run_delay_time, RoomMgr::Instance()->RoomNum(), PerfMonitor::Instance()->entity_num[ET_Player], PlayerMgr::Instance()->OnlineNum(), PerfMonitor::Instance()->alive_count, f8::HttpClientPool::Instance()->max_sys_request_delay, f8::HttpClientPool::Instance()->max_user_request_delay, f8::HttpClientPool::Instance()->GetPendingNum(), PerfMonitor::Instance()->real_alive_count, PlayerMgr::Instance()->GetAccountNum(), PerfMonitor::Instance()->room_num[RT_NewBrid], PerfMonitor::Instance()->room_num[RT_MidBrid] }); PerfMonitor::Instance()->max_run_delay_time = 0; PerfMonitor::Instance()->max_dispatchmsg_time = 0; PerfMonitor::Instance()->max_timer_idle = 0; PerfMonitor::Instance()->grid_chg_times = 0; PerfMonitor::Instance()->test_times = 0; PerfMonitor::Instance()->params[0] = 0, PerfMonitor::Instance()->params[1] = 0, PerfMonitor::Instance()->params[2] = 0, PerfMonitor::Instance()->params[3] = 0, PerfMonitor::Instance()->params[4] = 0, PerfMonitor::Instance()->params[5] = 0, PerfMonitor::Instance()->params[6] = 0, f8::HttpClientPool::Instance()->max_sys_request_delay = 0; f8::HttpClientPool::Instance()->max_user_request_delay = 0; } bool App::Init(int argc, char* argv[]) { #if 0 { AabbCollider a_collider; AabbCollider b_collider; a8::Vec2 new_pos; bool ret = a_collider.CalcSafePoint(&b_collider, new_pos); int i = 0; } #endif signal(SIGPIPE, SIG_IGN); this->argc = argc; this->argv = argv; if (!ParseOpt()) { if (node_id <= 0) { a8::XPrintf("gameserver启动失败,缺少-n参数\n", {}); } else if (node_id > MAX_NODE_ID) { a8::XPrintf("gameserver启动失败,-n参数不能大于%d\n", {MAX_NODE_ID}); } else if (instance_id <= 0) { a8::XPrintf("gameserver启动失败,缺少-i参数\n", {}); } else if (instance_id > MAX_INSTANCE_ID) { a8::XPrintf("gameserver启动失败,-i参数不能大于%d\n", {MAX_INSTANCE_ID}); } return false; } int debug_mode = 0; #ifdef DEBUG debug_mode = 1; #endif a8::XPrintf("gameserver starting node_id: %d instance_id:%d pid:%d game_id:%d debug_mode:%d\n", { node_id, instance_id, getpid(), GAME_ID, debug_mode }); loop_mutex_ = new std::mutex(); loop_cond_ = new std::condition_variable(); msg_mutex_ = new std::mutex(); im_msg_mutex_ = new std::mutex(); srand(time(nullptr)); InitLog(); PerfMonitor::Instance()->Init(); HandlerMgr::Instance()->Init(); a8::Timer::Instance()->Init(); f8::MsgQueue::Instance()->Init(); f8::TGLog::Instance()->Init(a8::Format(PROJ_NAME_FMT, {GAME_ID}), false); f8::HttpClientPool::Instance()->Init(MAX_ALL_HTTP_NUM, MAX_SYS_HTTP_NUM, MAX_USER_HTTP_NUM); JsonDataMgr::Instance()->Init(); MetaMgr::Instance()->Init(); EntityFactory::Instance()->Init(); uuid.SetMachineId((node_id - 1) * MAX_NODE_ID + instance_id); KillMgr::Instance()->Init(); RoomMgr::Instance()->Init(); MapMgr::Instance()->Init(); PlayerMgr::Instance()->Init(); GGListener::Instance()->Init(); a8::UdpLog::Instance()->Info("gameserver starting instance_id:%d pid:%d debug_mode:%d channel:%d", { instance_id, getpid(), debug_mode, JsonDataMgr::Instance()->channel }); { int perf_log_time = 1000 * 30; a8::Timer::Instance()->AddRepeatTimer(perf_log_time, a8::XParams(), [] (const a8::XParams& param) { SavePerfLog(); }); } if (HasFlag(7)) { a8::Timer::Instance()->AddDeadLineTimer( 1000 * 60 * 1, a8::XParams(), [] (const a8::XParams& param) { App::Instance()->terminated = true; } ); } return true; } void App::UnInit() { GGListener::Instance()->UnInit(); PlayerMgr::Instance()->UnInit(); MapMgr::Instance()->UnInit(); RoomMgr::Instance()->UnInit(); KillMgr::Instance()->UnInit(); EntityFactory::Instance()->UnInit(); MetaMgr::Instance()->UnInit(); JsonDataMgr::Instance()->UnInit(); f8::HttpClientPool::Instance()->UnInit(); f8::MsgQueue::Instance()->UnInit(); a8::Timer::Instance()->UnInit(); HandlerMgr::Instance()->UnInit(); PerfMonitor::Instance()->UnInit(); f8::TGLog::Instance()->UnInit(); UnInitLog(); FreeSocketMsgQueue(); FreeIMMsgQueue(); A8_SAFE_DELETE(im_msg_mutex_); A8_SAFE_DELETE(msg_mutex_); A8_SAFE_DELETE(loop_cond_); A8_SAFE_DELETE(loop_mutex_); } int App::Run() { int ret = 0; a8::UdpLog::Instance()->Info("gameserver running", {}); last_run_tick_ = a8::XGetTickCount(); int delta_time = 0; while (!terminated) { a8::tick_t begin_tick = a8::XGetTickCount(); Global::g_nowtime = time(nullptr); QuickExecute(delta_time); SlowerExecute(delta_time); Schedule(); a8::tick_t end_tick = a8::XGetTickCount(); if (end_tick - begin_tick > PerfMonitor::Instance()->max_run_delay_time) { PerfMonitor::Instance()->max_run_delay_time = end_tick - begin_tick; } delta_time = end_tick - begin_tick; } return ret; } void App::AddSocketMsg(SocketFrom_e sockfrom, int sockhandle, long ip_saddr, unsigned short msgid, unsigned int seqid, const char *msgbody, int bodylen) { MsgNode *p = (MsgNode*) malloc(sizeof(MsgNode)); memset(p, 0, sizeof(MsgNode)); p->sockfrom = sockfrom; p->ip_saddr = ip_saddr; p->sockhandle = sockhandle; p->msgid = msgid; p->seqid = seqid; p->buf = nullptr; p->buflen = bodylen; if (bodylen > 0) { p->buf = (char*)malloc(bodylen); memmove(p->buf, msgbody, bodylen); } msg_mutex_->lock(); if (bot_node_) { bot_node_->next = p; bot_node_ = p; } else { top_node_ = p; bot_node_ = p; } ++msgnode_size_; msg_mutex_->unlock(); NotifyLoopCond(); } void App::AddIMMsg(unsigned short imcmd, a8::XParams params) { IMMsgNode *p = new IMMsgNode; p->msgid = imcmd; p->params = params; p->next = nullptr; im_msg_mutex_->lock(); if (im_bot_node_) { im_bot_node_->next = p; im_bot_node_ = p; } else { im_top_node_ = p; im_bot_node_ = p; } im_msg_mutex_->unlock(); NotifyLoopCond(); } void App::QuickExecute(int delta_time) { ProcessIMMsg(); DispatchMsg(); RoomMgr::Instance()->Update(delta_time); a8::Timer::Instance()->Update(); } void App::SlowerExecute(int delta_time) { } void App::NotifyLoopCond() { std::unique_lock lk(*loop_mutex_); loop_cond_->notify_all(); } void App::Schedule() { std::unique_lock lk(*loop_mutex_); loop_cond_->wait_for(lk, std::chrono::milliseconds(1)); } bool App::HasTask() { { if (!im_work_node_) { im_msg_mutex_->lock(); if (!im_work_node_ && im_top_node_) { im_work_node_ = im_top_node_; im_top_node_ = nullptr; im_bot_node_ = nullptr; } im_msg_mutex_->unlock(); } if (im_work_node_) { return true; } } { if (!work_node_) { msg_mutex_->lock(); if (!work_node_ && top_node_) { work_node_ = top_node_; top_node_ = nullptr; bot_node_ = nullptr; } msg_mutex_->unlock(); } if (work_node_) { return true; } } return false; } void App::DispatchMsg() { #ifdef PERFT long long begin_tick = a8::XGetTickCount(); #endif if (!work_node_ && top_node_) { msg_mutex_->lock(); work_node_ = top_node_; top_node_ = nullptr; bot_node_ = nullptr; working_msgnode_size_ = msgnode_size_; msg_mutex_->unlock(); } f8::MsgHdr hdr; while (work_node_) { MsgNode *pdelnode = work_node_; work_node_ = pdelnode->next; hdr.msgid = pdelnode->msgid; hdr.seqid = pdelnode->seqid; hdr.socket_handle = pdelnode->sockhandle; hdr.buf = pdelnode->buf; hdr.buflen = pdelnode->buflen; hdr.offset = 0; hdr.ip_saddr = pdelnode->ip_saddr; switch (pdelnode->sockfrom) { case SF_GameGate: { ProcessGameGateMsg(hdr); } break; } if (pdelnode->buf) { free(pdelnode->buf); } free(pdelnode); working_msgnode_size_--; if (a8::XGetTickCount() - begin_tick > 200) { break; } }//end while if (!work_node_) { working_msgnode_size_ = 0; } #ifdef PERFT a8::tick_t end_tick = a8::XGetTickCount(); if (end_tick - begin_tick > PerfMonitor::Instance()->max_dispatchmsg_time) { PerfMonitor::Instance()->max_dispatchmsg_time = end_tick - begin_tick; } #endif } void App::ProcessGameGateMsg(f8::MsgHdr& hdr) { if (hdr.msgid == ss::_SS_Ping) { ss::SS_Pong pongmsg; GGListener::Instance()->SendProxyMsg(hdr.socket_handle, pongmsg); return; } f8::NetMsgHandler* handler = f8::GetNetMsgHandler(&HandlerMgr::Instance()->ggmsghandler, hdr.msgid); if (handler) { switch (handler->handlerid) { case HID_RoomMgr: ProcessNetMsg(handler, RoomMgr::Instance(), hdr); break; case HID_PlayerMgr: ProcessNetMsg(handler, PlayerMgr::Instance(), hdr); break; case HID_Player: { Player* hum = PlayerMgr::Instance()->GetPlayerBySocket(hdr.socket_handle); if (hum) { hdr.hum = hum; ProcessNetMsg(handler, hum, hdr); } } break; } } } void App::ProcessIMMsg() { if (!im_work_node_ && im_top_node_) { im_msg_mutex_->lock(); im_work_node_ = im_top_node_; im_top_node_ = nullptr; im_bot_node_ = nullptr; im_msg_mutex_->unlock(); } while (im_work_node_) { IMMsgNode *pdelnode = im_work_node_; switch (im_work_node_->msgid) { case f8::IM_SysMsgQueue: { const a8::XParams* param = (const a8::XParams*)pdelnode->params.param1.GetUserData(); f8::MsgQueue::Instance()->ProcessMsg(pdelnode->params.sender.GetInt(), *param ); delete param; } break; case IM_ClientSocketDisconnect: { PlayerMgr::Instance()->OnClientDisconnect(pdelnode->params); } break; case IM_ExecGM: { HandlerMgr::Instance()->ProcGMMsg(pdelnode->params.param3, pdelnode->params.sender, pdelnode->params.param1.GetString(), pdelnode->params.param2.GetString() ); } break; } im_work_node_ = im_work_node_->next; delete pdelnode; } } void App::InitLog() { std::string filename_fmt = PROJ_LOG_FILENAME_FMT; a8::ReplaceString(filename_fmt, "$pid", a8::XValue(getpid())); std::string proj_root_dir = a8::Format(PROJ_ROOT_FMT, {a8::Format(PROJ_NAME_FMT,{GAME_ID})}); std::string proj_log_root_dir = a8::Format(PROJ_LOG_ROOT_FMT, {a8::Format(PROJ_NAME_FMT, {GAME_ID})}); std::string log_file_name = a8::Format(PROJ_LOG_ROOT_FMT, {a8::Format(PROJ_NAME_FMT, {GAME_ID})}) + "/" + filename_fmt; a8::MkDir(proj_root_dir); a8::MkDir(proj_log_root_dir); a8::UdpLog::Instance()->SetLogFileName(log_file_name); a8::UdpLog::Instance()->Init(); a8::UdpLog::Instance()->Info("proj_root_dir:%s", {proj_root_dir}); a8::UdpLog::Instance()->Info("proj_log_root_dir:%s", {proj_log_root_dir}); a8::UdpLog::Instance()->Info("log_file_name:%s", {log_file_name}); } void App::UnInitLog() { a8::UdpLog::Instance()->UnInit(); } bool App::ParseOpt() { int ch = 0; while ((ch = getopt(argc, argv, "i:t:r:f:n:")) != -1) { switch (ch) { case 'n': { node_id = a8::XValue(optarg); } break; case 'i': { instance_id = a8::XValue(optarg); } break; case 't': { is_test_mode = true; test_param = a8::XValue(optarg); } break; case 'f': { std::vector strings; a8::Split(optarg, strings, ','); for (auto& str : strings) { flags.insert(a8::XValue(str).GetInt()); } } break; } } return instance_id > 0 && node_id > 0; } long long App::NewUuid() { return uuid.Generate(); } a8::XParams* App::AddContext(long long context_id) { context_hash_[context_id] = a8::XParams(); return GetContext(context_id); } void App::DelContext(long long context_id) { context_hash_.erase(context_id); } a8::XParams* App::GetContext(long long context_id) { auto itr = context_hash_.find(context_id); return itr != context_hash_.end() ? &(itr->second) : nullptr; } bool App::HasFlag(int flag) { return flags.find(flag) != flags.end(); } void App::SetFlag(int flag) { flags.insert(flag); } void App::UnSetFlag(int flag) { flags.erase(flag); } void App::FreeSocketMsgQueue() { msg_mutex_->lock(); if (!work_node_) { work_node_ = top_node_; top_node_ = nullptr; bot_node_ = nullptr; } while (work_node_) { MsgNode* pdelnode = work_node_; work_node_ = work_node_->next; if (pdelnode->buf) { free(pdelnode->buf); } free(pdelnode); if (!work_node_) { work_node_ = top_node_; top_node_ = nullptr; bot_node_ = nullptr; } } msg_mutex_->unlock(); } void App::FreeIMMsgQueue() { im_msg_mutex_->lock(); if (!im_work_node_) { im_work_node_ = im_top_node_; im_top_node_ = nullptr; im_bot_node_ = nullptr; } while (im_work_node_) { IMMsgNode* pdelnode = im_work_node_; im_work_node_ = im_work_node_->next; if (pdelnode->msgid == f8::IM_SysMsgQueue) { a8::XParams* param = (a8::XParams*)pdelnode->params.param1.GetUserData(); delete param; } delete pdelnode; if (!im_work_node_) { im_work_node_ = im_top_node_; im_top_node_ = nullptr; im_bot_node_ = nullptr; } } im_msg_mutex_->unlock(); }