aozhiwei e9f0a994bd 1
2024-07-08 20:13:23 +08:00

729 lines
24 KiB
C++

#include "precompile.h"
#include <a8/mutable_xobject.h>
#include <a8/openssl.h>
#include <f8/app.h>
#include "roommgr.h"
#include "room.h"
#include "cs_proto.pb.h"
#include "GGListener.h"
#include "player.h"
#include "playermgr.h"
#include "app.h"
#include "jsondatamgr.h"
#include "playermgr.h"
#include "mapmgr.h"
#include "perfmonitor.h"
#include "httpproxy.h"
#include "mapmgr.h"
#include "debugcmd.h"
#include "custom_battle.h"
#include "custom_team.h"
#include "custom_member.h"
#include "tracemgr.h"
#include "mt/Param.h"
#include "mt/Text.h"
#include "mt/Hero.h"
#include "mt/Equip.h"
#include "mt/Map.h"
#include "mt/MapMode.h"
#include <f8/httpclientpool.h>
#include <f8/utils.h>
#include <f8/udplog.h>
#include <f8/timer.h>
static const int ROOM_NUM_UP_LIMIT = 1000;
static const int HUM_NUM_DOWN_LIMIT = 2500;
void RoomMgr::Init()
{
InstallReportStateTimer();
}
void RoomMgr::UnInit()
{
for (auto& pair : room_hash_) {
pair.second->ForceOver();
pair.second->UnInit();
}
for (auto& pair : over_room_hash_) {
pair.second->ForceOver();
pair.second->UnInit();
}
inactive_room_hash_.clear();
room_hash_.clear();
room_idx_hash_.clear();
over_room_hash_.clear();
}
void RoomMgr::Update(int delta_time)
{
long long real_alive_count = 0;
for (auto& pair : room_hash_) {
auto& room = pair.second;
room->Update(delta_time);
real_alive_count += room->RealAliveCount();
}
PerfMonitor::Instance()->real_alive_count = real_alive_count;
}
void RoomMgr::_CMJoin(f8::MsgHdr* hdr, const cs::CMJoin& msg)
{
#ifdef MYDEBUG
a8::XPrintf("CMJoin socket_handle:%d\n", {hdr->socket_handle});
#endif
if (IsLimitJoin()) {
JoinErrorHandle(msg, 2, hdr->socket_handle);
return;
}
{
auto member = GetCustomMemberBySocket(hdr->socket_handle);
if (member) {
#if 1
f8::UdpLog::Instance()->Warning("JoinError socket_not_exits socket_handle%d",
{
hdr->socket_handle,
});
#endif
JoinErrorHandle(msg, 100, hdr->socket_handle);
return;
}
}
{
cs::CMJoin* mutable_msg = (cs::CMJoin*)&msg;
AdjustCMJoin(mutable_msg);
#ifdef MYDEBUG
a8::XPrintf("AdjustCMJoinAfter %s\n",
{
f8::PbToJson(&msg)
});
#endif
}
if (!msg.payload_data().empty()) {
DispatchSpecRoom(hdr, msg);
return;
}
}
void RoomMgr::_CMReconnect(f8::MsgHdr* hdr, const cs::CMReconnect& msg)
{
auto send_reconnect_failed =
[] (int socket_handle, int errcode, const std::string& errmsg)
{
cs::SMReconnect respmsg;
respmsg.set_errcode(errcode);
respmsg.set_errmsg(errmsg);
GGListener::Instance()->SendToClient(socket_handle, 0, respmsg);
f8::Timer::Instance()->SetTimeout
(
1000 * 3,
[socket_handle] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
GGListener::Instance()->ForceCloseChildSocket(socket_handle);
}
}
);
};
auto room = GetRoomByUuid(a8::XValue(msg.room_uuid()));
if (!room) {
send_reconnect_failed(hdr->socket_handle, 1,
TEXT("battle_server_reconnect_failreason_room_destoryed", "房间已销毁"));
f8::UdpLog::Instance()->Debug
("房间已销毁 %s",
{
msg.room_uuid()
});
return;
}
Player* hum = room->GetPlayerByAccountId(msg.account_id());
if (!hum) {
send_reconnect_failed(hdr->socket_handle, 1,
TEXT("battle_server_reconnect_failreason_notfound_accountid", "accountid未在房间列表"));
return;
}
hum->_CMReconnect(hdr, msg);
}
void RoomMgr::_CMPing(f8::MsgHdr* hdr, const cs::CMPing& msg)
{
cs::SMPing respmsg;
GGListener::Instance()->SendToClient(hdr->socket_handle, 0, respmsg);
}
int RoomMgr::RoomNum()
{
return room_hash_.size();
}
int RoomMgr::OverRoomNum()
{
return over_room_hash_.size();
}
std::shared_ptr<Room> RoomMgr::GetJoinableRoom(std::shared_ptr<CustomBattle> p)
{
if (p->IsMoba()) {
return nullptr;
}
if (p->IsCustomMode()) {
return nullptr;
}
std::vector<std::vector<std::shared_ptr<Room>>> group_rooms;
for (int i = 0; i < RoomType_Max; ++i) {
group_rooms.push_back(std::vector<std::shared_ptr<Room>>());
}
for (auto& pair : inactive_room_hash_) {
auto& room = pair.second;
if (!room->GetCustomBattle() &&
room->CanJoin(p)) {
group_rooms.at(room->GetRoomType()).push_back(room);
}
}
if (!group_rooms.at(p->GetRoomType()).empty()) {
return group_rooms[p->GetRoomType()][rand() % group_rooms[p->GetRoomType()].size()];
}
if (p->GetRoomType() == kPvpRankMode) {
} else {
if (p->GetRoomType() == RoomType_OldBrid2) {
for (auto& room : group_rooms[RoomType_OldBrid3]) {
if (room->GetGasInactiveReaminTime() > 8 &&
room->GetPlayerNum() + 8 < room->GetRoomMaxPlayerNum()) {
return room;
}
}
} else if (p->GetRoomType() == RoomType_OldBrid3) {
for (auto& room : group_rooms[RoomType_OldBrid2]) {
if (room->GetGasInactiveReaminTime() > 8 &&
room->GetPlayerNum() + 8 < room->GetRoomMaxPlayerNum()) {
return room;
}
}
}
}
return nullptr;
}
std::shared_ptr<Room> RoomMgr::GetRoomByUuid(const std::string& room_uuid)
{
auto itr = room_hash_.find(room_uuid);
return itr != room_hash_.end() ? itr->second : nullptr;
}
std::shared_ptr<Room> RoomMgr::GetRoomByIdx(int room_idx)
{
auto itr = room_idx_hash_.find(room_idx);
return itr != room_idx_hash_.end() ? itr->second : nullptr;
}
void RoomMgr::AddOverRoom(const std::string& room_uuid)
{
auto callback =
[room_uuid] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
auto room = RoomMgr::Instance()->GetRoomByUuid(room_uuid);
if (room) {
RoomMgr::Instance()->room_hash_.erase(room->GetRoomUuid());
RoomMgr::Instance()->over_room_hash_[room->GetRoomUuid()] = room;
RoomMgr::Instance()->FreeOverRoom(room_uuid);
}
}
};
inactive_room_hash_.erase(room_uuid);
auto room = GetRoomByUuid(room_uuid);
if (room) {
room->added_to_over_room = true;
f8::Timer::Instance()->SetIntervalEx
(1000 * 5,
callback,
&room->timer_attacher);
}
}
void RoomMgr::ActiveRoom(const std::string& room_uuid)
{
inactive_room_hash_.erase(room_uuid);
}
void RoomMgr::ReportServerState(int instance_id, const std::string& host, int port)
{
auto cb =
[instance_id, host, port]
(bool ok, a8::XObject* rsp_obj, f8::HttpContext* ctx)
{
if (ok) {
f8::Timer::Instance()->SetTimeoutEx
(1000,
[instance_id, host, port] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
RoomMgr::Instance()->ReportServerState(
instance_id,
host,
port
);
}
},
&RoomMgr::Instance()->reportstate_timer_attacher_);
} else {
f8::Timer::Instance()->SetTimeoutEx
(1000,
[instance_id, host, port]
(int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
RoomMgr::Instance()->ReportServerState
(
instance_id,
host,
port
);
}
},
&RoomMgr::Instance()->reportstate_timer_attacher_);
}
};
std::string url = a8::Format("http://%s:%d/webapp/index.php?c=GS&a=report&",
{
host,
port
});
auto url_params = a8::MutableXObject::CreateObject();
url_params->SetVal("node_id", f8::App::Instance()->GetNodeId());
url_params->SetVal("instance_id", f8::App::Instance()->GetInstanceId());
url_params->SetVal("ip", JsonDataMgr::Instance()->ip);
url_params->SetVal("port", JsonDataMgr::Instance()->listen_port);
url_params->SetVal("online_num", PlayerMgr::Instance()->OnlineNum());
url_params->SetVal("room_num", RoomNum());
url_params->SetVal("channel", JsonDataMgr::Instance()->channel);
url_params->SetVal("alive_count", PerfMonitor::Instance()->real_alive_count);
url_params->SetVal("servicing", App::Instance()->IsServicing() ? 1 : 0);
url_params->SetVal("version", App::Instance()->GetVersion());
f8::HttpClientPool::Instance()->HttpGet
(
cb,
url.c_str(),
*url_params,
rand() % MAX_SYS_HTTP_NUM
);
}
void RoomMgr::FreeOverRoom(const std::string& room_uuid)
{
#ifdef MYDEBUG
a8::XPrintf("FreeOverRoom room_uuid:%s\n",
{
room_uuid
});
#endif
auto itr = over_room_hash_.find(room_uuid);
if (itr != over_room_hash_.end()) {
--PerfMonitor::Instance()->room_num[itr->second->GetRoomType()];
itr->second->UnInit();
room_idx_hash_.erase(itr->second->GetRoomIdx());
over_room_hash_.erase(itr);
}
}
void RoomMgr::InstallReportStateTimer()
{
reportstate_timer_attacher_.ClearTimerList();
auto master_svr_cluster_conf = JsonDataMgr::Instance()->GetMasterServerClusterConf();
for (int i = 0; i < master_svr_cluster_conf->Size(); ++i) {
auto master_svr_conf = master_svr_cluster_conf->At(i);
int instance_id = master_svr_conf->At("instance_id")->AsXValue();
std::string remote_ip = master_svr_conf->At("ip")->AsXValue();
int remote_port = master_svr_conf->At("listen_port")->AsXValue();
f8::Timer::Instance()->SetTimeoutEx
(1000 + (i + 1),
[instance_id, remote_ip, remote_port]
(int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
RoomMgr::Instance()->ReportServerState
(
instance_id,
remote_ip,
remote_port
);
}
},
&reportstate_timer_attacher_);
}
}
bool RoomMgr::IsLimitJoin()
{
return RoomNum() >= ROOM_NUM_UP_LIMIT ||
(
PerfMonitor::Instance()->real_alive_count >= HUM_NUM_DOWN_LIMIT
);
}
int RoomMgr::AllocRoomIdx()
{
do {
if (current_room_idx_ < 0) {
current_room_idx_ = 0;
}
if (current_room_idx_ >= (MAX_ROOM_IDX - 3)) {
current_room_idx_ = 0;
}
} while (GetRoomByIdx(++current_room_idx_));
return current_room_idx_;
}
std::shared_ptr<Room> RoomMgr::CreateRoom(RoomType_e room_type,
int mode_id,
int map_id,
RoomMode_e room_mode,
std::shared_ptr<CustomBattle> custom_battle)
{
int room_idx = AllocRoomIdx();
if (room_idx < 1) {
return nullptr;
}
RoomInitInfo init_info;
{
init_info.room_idx = room_idx;
init_info.room_uuid = f8::App::Instance()->NewGlobalUuid();
init_info.room_type = room_type;
init_info.room_mode = room_mode;
init_info.init_map_id = map_id;
#if 0
init_info.pve_instance_id = msg.pve_instance_id();
init_info.pve_human_num = std::max(1, msg.team_members_size());
#endif
init_info.custom_battle = custom_battle;
if (GetRoomByUuid(init_info.room_uuid)) {
A8_ABORT();
}
if (GetRoomByIdx(init_info.room_idx)) {
A8_ABORT();
}
init_info.map_mode_meta = mt::MapMode::GetById(mode_id);
if (!init_info.map_mode_meta) {
A8_ABORT();
}
}
auto room = std::make_shared<Room>();
MapMgr::Instance()->AttachRoom(room.get(), init_info);
room->InitData(init_info);
room->Init();
inactive_room_hash_[room->GetRoomUuid()] = room;
room_hash_[room->GetRoomUuid()] = room;
room_idx_hash_[room->GetRoomIdx()] = room;
++PerfMonitor::Instance()->room_num[room->GetRoomType()];
#ifdef MYDEBUG
f8::UdpLog::Instance()->Debug("createroom room_idx:%d room_uuid:%d room_type:%d map_mode:%d",
{
room->GetRoomIdx(),
room->GetRoomUuid(),
room->GetRoomType(),
room->GetMapModeMeta()->id()
});
#endif
#if 1
f8::Timer::Instance()->SetTimeout
(
1000 * 60 * 30,
[room_uuid = room->GetRoomUuid()] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
if (RoomMgr::Instance()->GetRoomByUuid(room_uuid)) {
f8::UdpLog::Instance()->Debug
("room timeout %s",
{
room_uuid
});
}
}
}
);
#endif
return room;
}
void RoomMgr::JoinErrorHandle(const cs::CMJoin& msg, int error_code, int socket_handle)
{
{
cs::SMJoinedNotify notifymsg;
notifymsg.set_error_code(error_code);
GGListener::Instance()->SendToClient(socket_handle, 0, notifymsg);
}
{
f8::Timer::Instance()->SetTimeout
(1000 * 2,
[socket_handle] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
GGListener::Instance()->ForceCloseChildSocket(socket_handle);
}
});
}
f8::UdpLog::Instance()->Warning
("join error errcode:%d accountid:%s max_mainloop_rundelay:%d "
"room_num:%d player_num:%d online_num:%d",
{
error_code,
msg.account_id(),
PerfMonitor::Instance()->max_run_delay_time,
RoomMgr::Instance()->RoomNum(),
PerfMonitor::Instance()->entity_num[ET_Player],
PlayerMgr::Instance()->OnlineNum(),
});
}
void RoomMgr::OnJoinRoomOk(const cs::CMJoin& msg, Player* hum)
{
}
void RoomMgr::AdjustCMJoin(cs::CMJoin* msg)
{
}
std::shared_ptr<CustomBattle> RoomMgr::GetCustomRoom(const std::string& room_uuid)
{
auto itr = custom_room_hash_.find(room_uuid);
return itr != custom_room_hash_.end() ? itr->second : nullptr;
}
std::shared_ptr<CustomBattle> RoomMgr::GetHisCustomRoom(const std::string& room_uuid)
{
auto itr = his_custom_room_hash_.find(room_uuid);
return itr != his_custom_room_hash_.end() ? itr->second : nullptr;
}
void RoomMgr::_CMJoinCustomBattle(f8::MsgHdr* hdr, const cs::CMJoin& msg, int custom_room_type)
{
if (msg.payload_data().empty()) {
return;
}
auto sd_handler = GGListener::Instance()->AddSocketDisconnectListener
(
hdr->socket_handle,
[] (const a8::Args& args)
{
int socket_handle = args.Get<int>(0);
RoomMgr::Instance()->socket_hash_.erase(socket_handle);
});
std::shared_ptr<cs::CMJoin> join_msg = std::make_shared<cs::CMJoin>();
*join_msg = msg;
auto ip_saddr = hdr->ip_saddr;
auto socket_handle = hdr->socket_handle;
auto cb =
[join_msg, ip_saddr, socket_handle, sd_handler]
(int errcode, const std::string errmsg, std::shared_ptr<CustomBattle> p)
{
auto& msg = *join_msg;
if (errcode) {
RoomMgr::Instance()->JoinErrorHandle(*join_msg, 2, socket_handle);
return;
}
auto member = p->GetMemberByAccountId(join_msg->account_id());
if (!member) {
member = p->GetObByAccountId(join_msg->account_id());
if (!member) {
return;
}
}
if (p->IsMoba()) {
if (p->GetTeamNum() < 0 ||
p->GetTeamNum() > 2) {
return;
}
}
{
const mt::Map* map_meta = mt::Map::GetById(p->GetMapId());
if (!map_meta || !map_meta->IsOpen()) {
RoomMgr::Instance()->JoinErrorHandle(msg, 3, socket_handle);
return;
}
}
p->OnEnter(join_msg, ip_saddr, socket_handle, sd_handler);
};
SendGetCustomBattleData(join_msg, cb, custom_room_type);
}
void RoomMgr::SendGetCustomBattleData(std::shared_ptr<cs::CMJoin> join_msg,
std::function<void(int, const std::string, std::shared_ptr<CustomBattle>)> cb,
int custom_room_type)
{
auto pos = join_msg->payload_data().find('|');
std::string head;
std::string body;
if (pos == std::string::npos) {
cb(1, "custom battle data error", nullptr);
return;
}
head = join_msg->payload_data().substr(0, pos);
body = join_msg->payload_data().substr(pos + 1);
auto data = std::make_shared<a8::XObject>();
if (!data->ReadFromJsonString(body) ||
!data->IsObject()) {
cb(1, "custom battle data error", nullptr);
return;
}
int start_time = data->Get("start_time", "").GetInt();
if (f8::App::Instance()->GetNowTime() - start_time > 40) {
cb(2, "custom battle is started", nullptr);
return;
}
std::string room_uuid = data->Get("room_uuid", "").GetString();
if (room_uuid.empty()) {
cb(1, "custom battle data error", nullptr);
return;
}
auto his_room = GetHisCustomRoom(room_uuid);
if (his_room) {
cb(2, "custom battle is dissolution", nullptr);
return;
}
auto cur_room = GetCustomRoom(room_uuid);
if (cur_room) {
cb(0, "", cur_room);
return;
}
{
std::string url;
JsonDataMgr::Instance()->GetApiUrl(url);
if (custom_room_type == CUSTOM_ROOM_CUSTOM) {
if (url.find('?') != std::string::npos) {
url += "&c=Battle&a=getCustomBattleDataNew";
} else {
url += "?&c=Battle&a=getCustomBattleDataNew";
}
} else if (custom_room_type == CUSTOM_ROOM_NORMAL) {
if (url.find('?') != std::string::npos) {
url += "&c=Battle&a=getNormalBattleData";
} else {
url += "?&c=Battle&a=getNormalBattleData";
}
} else {
A8_ABORT();
}
auto url_params = a8::MutableXObject::CreateObject();
url_params->SetVal("account_id", join_msg->account_id());
url_params->SetVal("session_id", join_msg->session_id());
url_params->SetVal("version", 1);
url_params->SetVal("__POST", join_msg->payload_data());
HttpProxy::Instance()->HttpGet
(
[cb, custom_room_type]
(bool ok, a8::XObject* rsp_obj, f8::HttpContext* ctx)
{
if (ok) {
f8::UdpLog::Instance()->Info
("GetBattleData ok %s",
{
rsp_obj->ToJsonStr()
});
if (rsp_obj->GetType() != a8::XOT_OBJECT ||
!rsp_obj->HasKey("errcode")) {
cb(1, "", nullptr);
return;
}
int errcode = rsp_obj->Get("errcode", "").GetInt();
std::string errmsg = rsp_obj->Get("errmsg", "").GetString();
if (errcode) {
cb(1, "", nullptr);
return;
}
std::string room_uuid = rsp_obj->Get("room_uuid", "").GetString();
if (room_uuid.empty()) {
cb(1, "custom battle data error", nullptr);
return;
}
auto cur_room = RoomMgr::Instance()->GetCustomRoom(room_uuid);
if (cur_room) {
cb(0, "", cur_room);
return;
}
auto custom_battle = std::make_shared<CustomBattle>();
custom_battle->Init();
custom_battle->SetCustomRoomType(custom_room_type);
custom_battle->ParseResult(*rsp_obj);
if (custom_battle->GetParseOk()) {
cb(0, "", custom_battle);
RoomMgr::Instance()->custom_room_hash_[custom_battle->GetMatchRoomUuid()] = custom_battle;
} else {
cb(1, "", custom_battle);
}
} else {
f8::UdpLog::Instance()->Warning
("GetCustomBattleData error %s",
{
""
});
cb(1, "custom battle data error", nullptr);
}
},
url.c_str(),
*url_params
);
}
}
void RoomMgr::DispatchSpecRoom(f8::MsgHdr* hdr, const cs::CMJoin& msg)
{
if (msg.payload_data().empty() ||
msg.payload_data().size() < 10) {
return;
}
auto pos = msg.payload_data().find('|');
std::string head;
std::string body;
if (pos == std::string::npos) {
return;
}
head = msg.payload_data().substr(0, pos);
std::vector<std::string> strings;
a8::Split(head, strings, ':');
if (strings.size() > 1) {
if (strings.at(1) == "custom_room") {
_CMJoinCustomBattle(hdr, msg, CUSTOM_ROOM_CUSTOM);
} else if (strings.at(1) == "normal_room") {
_CMJoinCustomBattle(hdr, msg, CUSTOM_ROOM_NORMAL);
} else {
#if 0
A8_ABORT();
#endif
}
} else {
#if 0
A8_ABORT();
#endif
}
}
bool RoomMgr::HasTask()
{
return !room_hash_.empty();
}
std::shared_ptr<CustomMember> RoomMgr::GetCustomMemberBySocket(int socket_handle)
{
auto itr = socket_hash_.find(socket_handle);
return itr != socket_hash_.end() ? itr->second : nullptr;
}
void RoomMgr::ReBindCustomMemberSocket(std::shared_ptr<CustomMember> p)
{
socket_hash_[p->GetSocketHandle()] = p;
}
void RoomMgr::UnBindCustomMemberSocket(int socket_handle)
{
socket_hash_.erase(socket_handle);
}