506 lines
20 KiB
C++
506 lines
20 KiB
C++
#include "precompile.h"
|
|
|
|
#include <a8/timer.h>
|
|
#include <a8/mutable_xobject.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 "metamgr.h"
|
|
#include "jsondatamgr.h"
|
|
#include "playermgr.h"
|
|
#include "mapservice.h"
|
|
#include "gridservice.h"
|
|
#include "building.h"
|
|
#include "obstacle.h"
|
|
#include "loot.h"
|
|
|
|
#include "framework/cpp/httpclientpool.h"
|
|
#include "framework/cpp/utils.h"
|
|
|
|
const int MAP_GRID_WIDTH = 64;
|
|
|
|
const int ROOM_NUM_DOWN_LIMIT = 15;
|
|
const int ROOM_NUM_UP_LIMIT = 40;
|
|
const int HUM_NUM_DOWN_LIMIT = 1000;
|
|
|
|
static RoomType_e GetHumanRoomType(const cs::CMJoin& msg)
|
|
{
|
|
std::vector<std::string> tmp_strings;
|
|
a8::Split(msg.pre_settlement_info(), tmp_strings, ',');
|
|
if (tmp_strings.size() < 3) {
|
|
return RT_NewBrid;
|
|
}
|
|
//游戏次数,吃鸡数,击杀数
|
|
int game_times = a8::XValue(tmp_strings[0]);
|
|
#if 0
|
|
int win_times = a8::XValue(tmp_strings[1]);
|
|
int kill_times = a8::XValue(tmp_strings[2]);
|
|
#endif
|
|
if (game_times <= MetaMgr::Instance()->newbie_game_times) {
|
|
return RT_NewBrid;
|
|
}
|
|
return RT_OldBrid;
|
|
}
|
|
|
|
void RoomMgr::Init()
|
|
{
|
|
map_meta_ = MetaMgr::Instance()->GetMap(2001);
|
|
if (!map_meta_) {
|
|
abort();
|
|
}
|
|
map_service_ = new MapService();
|
|
grid_service_ = new GridService();
|
|
grid_service_->Init(map_meta_->i->map_width(),
|
|
map_meta_->i->map_height(),
|
|
MetaMgr::Instance()->map_cell_width);
|
|
map_service_->Init(map_meta_->i->map_width() / MAP_GRID_WIDTH,
|
|
map_meta_->i->map_height() / MAP_GRID_WIDTH,
|
|
MAP_GRID_WIDTH);
|
|
CreateThings();
|
|
a8::XPrintf("current_uniid:%d loots:%d spawn_points:%d\n",
|
|
{
|
|
current_uniid_,
|
|
loots_.size(),
|
|
spawn_points_.size()
|
|
});
|
|
if (current_uniid_ >= FIXED_OBJECT_MAXID) {
|
|
abort();
|
|
}
|
|
InstallReportStateTimer();
|
|
}
|
|
|
|
void RoomMgr::UnInit()
|
|
{
|
|
for (auto& pair : room_hash_) {
|
|
pair.second->UnInit();
|
|
delete pair.second;
|
|
}
|
|
for (auto& pair : over_room_hash_) {
|
|
pair.second->UnInit();
|
|
delete pair.second;
|
|
}
|
|
map_service_->UnInit();
|
|
grid_service_->UnInit();
|
|
A8_SAFE_DELETE(map_service_);
|
|
A8_SAFE_DELETE(grid_service_);
|
|
}
|
|
|
|
void RoomMgr::Update(int delta_time)
|
|
{
|
|
for (auto& pair : room_hash_) {
|
|
pair.second->Update(delta_time);
|
|
}
|
|
}
|
|
|
|
void RoomMgr::_CMJoin(f8::MsgHdr& hdr, const cs::CMJoin& msg)
|
|
{
|
|
MetaData::Player* hum_meta = MetaMgr::Instance()->GetPlayer(40001);
|
|
if (!hum_meta) {
|
|
abort();
|
|
}
|
|
if (IsLimitJoin()) {
|
|
{
|
|
cs::SMJoinedNotify notifymsg;
|
|
notifymsg.set_error_code(2);
|
|
GGListener::Instance()->SendToClient(hdr.socket_handle, hdr.seqid, notifymsg);
|
|
}
|
|
{
|
|
a8::Timer::Instance()->AddDeadLineTimer(1000 * 2,
|
|
a8::XParams()
|
|
.SetSender(hdr.socket_handle),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
GGListener::Instance()->ForceCloseChildSocket(param.sender);
|
|
});
|
|
}
|
|
a8::UdpLog::Instance()->Warning("room is full! accountid:%s max_mainloop_rundelay:%d "
|
|
"room_num:%d player_num:%d online_num:%d",
|
|
{
|
|
msg.account_id(),
|
|
App::Instance()->perf.max_run_delay_time,
|
|
RoomMgr::Instance()->RoomNum(),
|
|
App::Instance()->perf.entity_num[ET_Player],
|
|
PlayerMgr::Instance()->OnlineNum(),
|
|
});
|
|
return;
|
|
}
|
|
RoomType_e self_room_type = GetHumanRoomType(msg);
|
|
Room* room = GetJoinableRoom(msg, self_room_type);
|
|
if (!room) {
|
|
room = new Room();
|
|
room->room_type = self_room_type;
|
|
room->map_service = map_service_;
|
|
room->room_uuid = App::Instance()->NewUuid();
|
|
room->spawn_points = &spawn_points_;
|
|
room->loots = &loots_;
|
|
room->buildings = &buildings_;
|
|
if (GetRoomByUuid(room->room_uuid)) {
|
|
abort();
|
|
}
|
|
room->map_meta = map_meta_;
|
|
room->Init();
|
|
inactive_room_hash_[room->room_uuid] = room;
|
|
room_hash_[room->room_uuid] = room;
|
|
}
|
|
Player* hum = PlayerMgr::Instance()->CreatePlayerByCMJoin(hdr.ip_saddr, hdr.socket_handle, msg);
|
|
hum->meta = hum_meta;
|
|
room->AddPlayer(hum);
|
|
hum->ProcPrepareItems(msg.prepare_items());
|
|
{
|
|
for (auto& pair : msg.prepare_items2()) {
|
|
hum->AddItem(pair.key(), pair.value());
|
|
}
|
|
}
|
|
|
|
{
|
|
cs::SMJoinedNotify notifymsg;
|
|
notifymsg.set_error_code(0);
|
|
room->FillSMJoinedNotify(hum, notifymsg);
|
|
GGListener::Instance()->SendToClient(hdr.socket_handle, hdr.seqid, notifymsg);
|
|
}
|
|
{
|
|
cs::SMMapInfo notifymsg;
|
|
notifymsg.set_map_id(map_meta_->i->map_id());
|
|
notifymsg.set_map_width(map_meta_->i->map_width());
|
|
notifymsg.set_map_height(map_meta_->i->map_height());
|
|
GGListener::Instance()->SendToClient(hdr.socket_handle, hdr.seqid, notifymsg);
|
|
}
|
|
}
|
|
|
|
int RoomMgr::RoomNum()
|
|
{
|
|
return room_hash_.size();
|
|
}
|
|
|
|
int RoomMgr::OverRoomNum()
|
|
{
|
|
return over_room_hash_.size();
|
|
}
|
|
|
|
Room* RoomMgr::GetJoinableRoom(const cs::CMJoin& msg, const RoomType_e self_room_type)
|
|
{
|
|
std::vector<std::vector<Room*>> group_rooms;
|
|
for (int i = 0; i < RT_Max; ++i) {
|
|
group_rooms.push_back(std::vector<Room*>());
|
|
}
|
|
for (auto& pair : inactive_room_hash_) {
|
|
Room* room = pair.second;
|
|
if (room->CanJoin(msg.account_id(), self_room_type)) {
|
|
if (!msg.team_uuid().empty() && room->HaveMyTeam(msg.team_uuid())) {
|
|
return room;
|
|
}
|
|
group_rooms[room->room_type].push_back(room);
|
|
}
|
|
}
|
|
|
|
if (!group_rooms[self_room_type].empty()) {
|
|
return group_rooms[self_room_type][rand() % group_rooms[self_room_type].size()];
|
|
}
|
|
if (self_room_type == RT_NewBrid) {
|
|
if (RoomNum() < ROOM_NUM_DOWN_LIMIT - 5) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
for (int i = 0; i < RT_Max; ++i) {
|
|
if (RoomNum() > ROOM_NUM_DOWN_LIMIT - 5) {
|
|
for (Room* room : group_rooms[i]) {
|
|
return room;
|
|
}
|
|
} else {
|
|
if (i != self_room_type) {
|
|
for (Room* room : group_rooms[i]) {
|
|
return room;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Room* RoomMgr::GetRoomByUuid(long long room_uuid)
|
|
{
|
|
auto itr = room_hash_.find(room_uuid);
|
|
return itr != room_hash_.end() ? itr->second : nullptr;
|
|
}
|
|
|
|
void RoomMgr::AddOverRoom(long long room_uuid)
|
|
{
|
|
auto callback = [] (const a8::XParams& param)
|
|
{
|
|
Room* room = RoomMgr::Instance()->GetRoomByUuid(param.sender);
|
|
if (room) {
|
|
if ((room->pending_request <= 0) ||
|
|
(a8::XGetTickCount() - room->game_over_tick > 1000 * 8)) {
|
|
RoomMgr::Instance()->room_hash_.erase(room->room_uuid);
|
|
RoomMgr::Instance()->over_room_hash_[room->room_uuid] = room;
|
|
RoomMgr::Instance()->FreeOverRoom(param.sender);
|
|
}
|
|
}
|
|
};
|
|
|
|
inactive_room_hash_.erase(room_uuid);
|
|
Room* room = GetRoomByUuid(room_uuid);
|
|
if (room) {
|
|
room->game_over_tick = a8::XGetTickCount();
|
|
room->game_over_timer = a8::Timer::Instance()->AddRepeatTimer(500,
|
|
a8::XParams()
|
|
.SetSender(room_uuid),
|
|
callback);
|
|
}
|
|
}
|
|
|
|
void RoomMgr::ActiveRoom(long long room_uuid)
|
|
{
|
|
inactive_room_hash_.erase(room_uuid);
|
|
}
|
|
|
|
void RoomMgr::ReportServerState(int instance_id, const std::string& host, int port)
|
|
{
|
|
auto on_ok = [] (a8::XParams& param, a8::XObject& data)
|
|
{
|
|
a8::Timer::Instance()->AddDeadLineTimerAndAttach(1000,
|
|
a8::XParams()
|
|
.SetSender(param.sender)
|
|
.SetParam1(param.param1)
|
|
.SetParam2(param.param2),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
RoomMgr::Instance()->ReportServerState(
|
|
param.sender,
|
|
param.param1,
|
|
param.param2
|
|
);
|
|
},
|
|
&RoomMgr::Instance()->reportstate_timer_attacher_.timer_list_);
|
|
};
|
|
auto on_error = [] (a8::XParams& param, const std::string& response)
|
|
{
|
|
a8::Timer::Instance()->AddDeadLineTimerAndAttach(1000,
|
|
a8::XParams()
|
|
.SetSender(param.sender)
|
|
.SetParam1(param.param1)
|
|
.SetParam2(param.param2),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
RoomMgr::Instance()->ReportServerState(
|
|
param.sender,
|
|
param.param1,
|
|
param.param2
|
|
);
|
|
},
|
|
&RoomMgr::Instance()->reportstate_timer_attacher_.timer_list_);
|
|
};
|
|
std::string url = a8::Format("http://%s:%d/webapp/index.php?c=GS&a=report&",
|
|
{
|
|
host,
|
|
port
|
|
});
|
|
a8::MutableXObject* url_params = a8::MutableXObject::NewObject();
|
|
url_params->SetVal("node_id", App::Instance()->node_id);
|
|
url_params->SetVal("instance_id", App::Instance()->instance_id);
|
|
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("alive_count", App::Instance()->perf.alive_count);
|
|
url_params->SetVal("servicing", App::Instance()->servicing ? 1 : 0);
|
|
f8::HttpClientPool::Instance()->HttpGet(a8::XParams()
|
|
.SetSender(instance_id)
|
|
.SetParam1(host)
|
|
.SetParam2(port),
|
|
on_ok,
|
|
on_error,
|
|
url.c_str(),
|
|
*url_params,
|
|
rand() % MAX_SYS_HTTP_NUM
|
|
);
|
|
delete url_params;
|
|
}
|
|
|
|
void RoomMgr::FreeOverRoom(long long room_uuid)
|
|
{
|
|
auto itr = over_room_hash_.find(room_uuid);
|
|
if (itr != over_room_hash_.end()) {
|
|
itr->second->UnInit();
|
|
delete itr->second;
|
|
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();
|
|
|
|
a8::Timer::Instance()->AddDeadLineTimerAndAttach(1000 + (i + 1),
|
|
a8::XParams()
|
|
.SetSender(instance_id)
|
|
.SetParam1(remote_ip)
|
|
.SetParam2(remote_port),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
RoomMgr::Instance()->ReportServerState(
|
|
param.sender,
|
|
param.param1,
|
|
param.param2
|
|
);
|
|
},
|
|
&reportstate_timer_attacher_.timer_list_);
|
|
}
|
|
}
|
|
|
|
bool RoomMgr::IsLimitJoin()
|
|
{
|
|
return RoomNum() >= ROOM_NUM_UP_LIMIT ||
|
|
(
|
|
RoomNum() >= ROOM_NUM_DOWN_LIMIT &&
|
|
App::Instance()->perf.alive_count >= HUM_NUM_DOWN_LIMIT
|
|
);
|
|
}
|
|
|
|
void RoomMgr::CreateThings()
|
|
{
|
|
std::string map_tpl_name = map_meta_->RandTemplate();
|
|
std::vector<MetaData::MapTplThing>* things = MetaMgr::Instance()->GetMapTplThing(map_tpl_name);
|
|
if (things) {
|
|
for (auto& thing_tpl : *things) {
|
|
switch (thing_tpl.i->_object_type()) {
|
|
case kMOT_Object:
|
|
{
|
|
if (thing_tpl.i->weight() >= rand() % 10000) {
|
|
CreateMapObject(thing_tpl);
|
|
}
|
|
}
|
|
break;
|
|
case kMOT_SpawnPoint:
|
|
{
|
|
spawn_points_.push_back(&thing_tpl);
|
|
}
|
|
break;
|
|
default:
|
|
abort();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void RoomMgr::CreateMapObject(MetaData::MapTplThing& thing_tpl)
|
|
{
|
|
int thing_id = thing_tpl.RandThing();
|
|
MetaData::MapThing* thing_meta = MetaMgr::Instance()->GetMapThing(thing_id);
|
|
if (thing_meta) {
|
|
if (thing_meta->i->is_house()) {
|
|
CreateBuilding(thing_id, thing_tpl.i->x(), thing_tpl.i->y());
|
|
} else {
|
|
InternalCreateObstacle(thing_id, thing_tpl.i->x(), thing_tpl.i->y(),
|
|
[] (Obstacle* entity)
|
|
{
|
|
});
|
|
|
|
}
|
|
} else {
|
|
loots_.push_back(&thing_tpl);
|
|
}
|
|
}
|
|
|
|
void RoomMgr::CreateBuilding(int thing_id, float building_x, float building_y)
|
|
{
|
|
MetaData::MapThing* thing_meta = MetaMgr::Instance()->GetMapThing(thing_id);
|
|
if (!thing_meta) {
|
|
return;
|
|
}
|
|
MetaData::Building* building_meta = MetaMgr::Instance()->GetBuilding(thing_meta->i->house_id());
|
|
if (!building_meta) {
|
|
return;
|
|
}
|
|
Building* building = new Building();
|
|
#if 0
|
|
building->room = this;
|
|
#endif
|
|
building->meta = building_meta;
|
|
building->is_permanent = true;
|
|
building->permanent_map_service = map_service_;
|
|
building->building_id = thing_id;
|
|
building->entity_uniid = AllocUniid();
|
|
building->SetPos(a8::Vec2(building_x, building_y));
|
|
building->Initialize();
|
|
uniid_hash_[building->entity_uniid] = building;
|
|
grid_service_->AddEntity(building);
|
|
for (size_t door_idx = 0; door_idx < building_meta->doors.size(); ++door_idx) {
|
|
if (door_idx >= 0 && door_idx < building->meta->doors.size()) {
|
|
MetaData::Building::Door* door_meta = &building->meta->doors[door_idx];
|
|
float x = building->GetX() + door_meta->state0->x() - building->meta->i->tilewidth() / 2.0;
|
|
float y = building->GetY() + door_meta->state0->y() - building->meta->i->tileheight() / 2.0;
|
|
InternalCreateObstacle(DOOR_THING_ID, x, y,
|
|
[building, door_idx] (Obstacle* entity)
|
|
{
|
|
entity->SetDoorInfo(building, door_idx);
|
|
});
|
|
}
|
|
}
|
|
for (auto& obj : building_meta->i->lootobj()) {
|
|
float x = building->GetX() + obj.x() - building->meta->i->tilewidth() / 2.0;
|
|
float y = building->GetY() + obj.y() - building->meta->i->tileheight() / 2.0;
|
|
if (obj._rand_space() > 0) {
|
|
int rnd = rand () % obj._rand_space();
|
|
for (auto& pair : obj._things()) {
|
|
if (rnd <= pair.value()) {
|
|
InternalCreateObstacle(pair.key(), x, y,
|
|
[building] (Obstacle* entity)
|
|
{
|
|
entity->SetBuilding(building);
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
buildings_.push_back(building);
|
|
}
|
|
|
|
Obstacle* RoomMgr::InternalCreateObstacle(int id, float x, float y,
|
|
std::function<void (Obstacle*)> on_precreate)
|
|
{
|
|
MetaData::MapThing* thing = MetaMgr::Instance()->GetMapThing(id);
|
|
if (thing) {
|
|
Obstacle* entity = new Obstacle();
|
|
entity->meta = thing;
|
|
entity->is_permanent = true;
|
|
entity->permanent_map_service = map_service_;
|
|
entity->entity_uniid = AllocUniid();
|
|
entity->SetPos(a8::Vec2(x, y));
|
|
entity->Initialize();
|
|
if (on_precreate) {
|
|
on_precreate(entity);
|
|
}
|
|
uniid_hash_[entity->entity_uniid] = entity;
|
|
grid_service_->AddEntity(entity);
|
|
return entity;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Entity* RoomMgr::GetEntityByUniId(int uniid)
|
|
{
|
|
auto itr = uniid_hash_.find(uniid);
|
|
return itr != uniid_hash_.end() ? itr->second : nullptr;
|
|
}
|
|
|
|
int RoomMgr::AllocUniid()
|
|
{
|
|
while (GetEntityByUniId(++current_uniid_) || current_uniid_ == 0) {
|
|
}
|
|
return current_uniid_;
|
|
}
|