#include "precompile.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "app.h" #include "jsondatamgr.h" #include "handlermgr.h" #include "roommgr.h" #include "player.h" #include "playermgr.h" #include "mapmgr.h" #include "entityfactory.h" #include "perfmonitor.h" #include "killmgr.h" #include "httpproxy.h" #include "lispenv.h" #include "ss_msgid.pb.h" #include "ss_proto.pb.h" #include "f8/msgqueue.h" #include "f8/tglog.h" #include "f8/httpclientpool.h" #include "f8/btmgr.h" #include #include "tracemgr.h" #include "matchmgr.h" #include "selfchecker.h" #include "skillhelper.h" #include "mt/MetaMgr.h" #include "mt/Skill.h" struct MsgNode { SocketFrom_e sockfrom; int sockhandle; unsigned short msgid; unsigned int seqid; long ip_saddr; char* buf; int buflen; MsgNode* next; }; 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() { f8::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 " "max_full_obj:%d max_part_obj:%d max_bullet:%d max_packet:%d " "his_max_full_obj:%d his_max_part_obj:%d his_max_bullet:%d his_max_packet:%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_full_objects_num, PerfMonitor::Instance()->max_part_objects_num, PerfMonitor::Instance()->max_bullet_num, GGListener::Instance()->max_packet_size, PerfMonitor::Instance()->his_max_full_objects_num, PerfMonitor::Instance()->his_max_part_objects_num, PerfMonitor::Instance()->his_max_bullet_num, GGListener::Instance()->his_max_packet_size }); { PerfMonitor::Instance()->his_max_full_objects_num = std::max (PerfMonitor::Instance()->his_max_full_objects_num, PerfMonitor::Instance()->max_full_objects_num); PerfMonitor::Instance()->his_max_part_objects_num = std::max (PerfMonitor::Instance()->his_max_part_objects_num, PerfMonitor::Instance()->max_part_objects_num); PerfMonitor::Instance()->his_max_bullet_num = std::max (PerfMonitor::Instance()->his_max_bullet_num, PerfMonitor::Instance()->max_bullet_num); GGListener::Instance()->his_max_packet_size = std::max (GGListener::Instance()->his_max_packet_size, GGListener::Instance()->max_packet_size); } 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; PerfMonitor::Instance()->max_full_objects_num = 0; PerfMonitor::Instance()->max_part_objects_num = 0; PerfMonitor::Instance()->max_bullet_num = 0; GGListener::Instance()->max_packet_size = 0; f8::HttpClientPool::Instance()->max_sys_request_delay = 0; f8::HttpClientPool::Instance()->max_user_request_delay = 0; } bool App::Init(int argc, char* argv[]) { 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(); srand(time(nullptr)); InitLog(); #ifdef DEBUG TraceMgr::Instance()->Init("gameserver2006"); #endif PerfMonitor::Instance()->Init(); f8::MsgQueue::Instance()->Init(); HandlerMgr::Instance()->Init(); f8::Timer::Instance()->Init(); f8::TGLog::Instance()->Init(a8::Format(PROJ_NAME_FMT, {GAME_ID}), false, 0); f8::HttpClientPool::Instance()->Init(MAX_ALL_HTTP_NUM, MAX_SYS_HTTP_NUM, MAX_USER_HTTP_NUM); f8::BtMgr::Instance()->Init("exported"); #ifdef DEBUG f8::BtMgr::Instance()->SetLogging(true); #endif SkillHelper::Init(); JsonDataMgr::Instance()->Init(); LispEnv::Instance()->Init(); mt::MetaMgr::Instance()->Init(); SelfChecker::Init(); EntityFactory::Instance()->Init(); uuid.SetMachineId((node_id - 1) * MAX_NODE_ID + instance_id); KillMgr::Instance()->Init(); RoomMgr::Instance()->Init(); MatchMgr::Instance()->Init(); MapMgr::Instance()->Init(); PlayerMgr::Instance()->Init(); GGListener::Instance()->Init(); HttpProxy::Instance()->Init(); f8::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; f8::Timer::Instance()->SetInterval (perf_log_time, [] (int event, const a8::Args* args) { if (a8::TIMER_EXEC_EVENT == event) { SavePerfLog(); } }); } if (HasFlag(7)) { f8::Timer::Instance()->SetTimeout ( 1000 * 60 * 1, [] (int event, const a8::Args* args) { if (a8::TIMER_EXEC_EVENT == event) { App::Instance()->terminated = true; } } ); } return true; } void App::UnInit() { //const char* s2 = GetEnumString(); //int i = static_cast(Test_e::kFlyBuffId); HttpProxy::Instance()->UnInit(); GGListener::Instance()->UnInit(); PlayerMgr::Instance()->UnInit(); MapMgr::Instance()->UnInit(); MatchMgr::Instance()->UnInit(); RoomMgr::Instance()->UnInit(); KillMgr::Instance()->UnInit(); EntityFactory::Instance()->UnInit(); SelfChecker::UnInit(); mt::MetaMgr::Instance()->UnInit(); LispEnv::Instance()->UnInit(); JsonDataMgr::Instance()->UnInit(); f8::BtMgr::Instance()->UnInit(); f8::HttpClientPool::Instance()->UnInit(); HandlerMgr::Instance()->UnInit(); f8::MsgQueue::Instance()->UnInit(); f8::Timer::Instance()->UnInit(); PerfMonitor::Instance()->UnInit(); f8::TGLog::Instance()->UnInit(); #ifdef DEBUG TraceMgr::Instance()->UnInit(); #endif UnInitLog(); FreeSocketMsgQueue(); A8_SAFE_DELETE(msg_mutex_); A8_SAFE_DELETE(loop_cond_); A8_SAFE_DELETE(loop_mutex_); } int App::Run() { int ret = 0; f8::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::QuickExecute(int delta_time) { f8::MsgQueue::Instance()->Update(); DispatchMsg(); RoomMgr::Instance()->Update(delta_time); f8::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 (!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() { long long begin_tick = a8::XGetTickCount(); 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; } 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; } } 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_MatchTeam: { auto match_info = MatchMgr::Instance()->GetMatchInfo(hdr.socket_handle); if (match_info) { ProcessNetMsg(handler, std::get<1>(*match_info), 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::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); f8::UdpLog::Instance()->SetLogFileName(log_file_name); f8::UdpLog::Instance()->Init(); f8::UdpLog::Instance()->Info("proj_root_dir:%s", {proj_root_dir}); f8::UdpLog::Instance()->Info("proj_log_root_dir:%s", {proj_log_root_dir}); f8::UdpLog::Instance()->Info("log_file_name:%s", {log_file_name}); } void App::UnInitLog() { f8::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(); } 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(); } long long App::AllocTempHeroUniId() { if (curr_uniid_ < 1000) { curr_uniid_ = 1000; } if (curr_uniid_ > 100000000) { curr_uniid_ = 1001; } ++curr_uniid_; return -curr_uniid_; } long long App::AllocTempWeaponUniId() { if (curr_uniid_ < 1000) { curr_uniid_ = 1000; } if (curr_uniid_ > 100000000) { curr_uniid_ = 1000; } ++curr_uniid_; return -curr_uniid_; }