game2005/server/gameserver/matchteam.cc
aozhiwei a3f965089a 1
2021-12-13 13:20:57 +08:00

714 lines
19 KiB
C++

#include "precompile.h"
#include <a8/timer.h>
#include "matchteam.h"
#include "matchmgr.h"
#include "GGListener.h"
#include "metamgr.h"
#include "roommgr.h"
void RawTeamMember::FillMFMatchTeamMember(cs::MFMatchTeamMember* p)
{
p->set_account_id(msg.account_id());
p->set_name(msg.name());
p->set_avatar_url(msg.avatar_url());
if (choose_hero_times <= 0) {
p->set_hero_id(0);
} else {
p->set_hero_id(msg.hero_id());
*p->mutable_weapons() = msg.weapons();
*p->mutable_skins() = msg.skins();
*p->mutable_skill_list() = msg.skill_list();
*p->mutable_baseskin() = msg.baseskin();
}
p->set_is_leader(is_leader);
p->set_state(state);
p->set_head_frame(msg.head_frame());
p->set_hero_skin(msg.hero_skin());
}
void RawTeamMember::InitRobot()
{
static long long robot_idx = 1000;
msg.set_account_id(a8::Format("6000_2005_%d", {++robot_idx}));
{
std::set<int> refreshed_robot_set;
robot_meta = MetaMgr::Instance()->RandRobot(refreshed_robot_set);
if (robot_meta) {
msg.set_avatar_url(a8::Format("%s", {50001 + (robot_meta->i->id() % 3)}));
#if 1
msg.set_hero_id(30100 + 100 * (robot_meta->i->id() % 3));
#else
msg.set_hero_id(robot_meta->i->hero_id());
#endif
msg.set_name(robot_meta->i->name());
auto skin = msg.add_skins();
if (!robot_meta->skin_id.empty()) {
skin->set_skin_id(robot_meta->skin_id[0]);
skin->set_skin_lv(1);
}
{
MetaData::Player* hero_meta = MetaMgr::Instance()->GetPlayer(msg.hero_id());
if (hero_meta) {
MetaData::Item* skin_meta = MetaMgr::Instance()->GetHeroSkin(msg.hero_id());
if (skin_meta) {
msg.set_hero_skin(skin_meta->i->id());
}
}
}
} else {
A8_ABORT();
}
}
}
MatchTeam::~MatchTeam()
{
timer_attacher.ClearTimerList();
#ifdef DEBUG
a8::XPrintf("~MatchTeam %s\n", {GetTeamUUid()});
#endif
}
void MatchTeam::Init(f8::MsgHdr& hdr, const cs::CMJoin& msg)
{
master_team_ = this;
create_tick_ = a8::XGetTickCount();
a8::Timer::Instance()->AddRepeatTimerAndAttach
(1000,
a8::XParams()
.SetSender(this),
[] (const a8::XParams& param)
{
MatchTeam* team = (MatchTeam*)param.sender.GetUserData();
team->Update();
},
&timer_attacher.timer_list_
);
phase_= kMatchCombining;
phase_start_tick_ = a8::XGetTickCount();
countdown_ = MetaMgr::Instance()->match_team_time;
AddRawMember(hdr, msg);
}
void MatchTeam::_CMMatchCancel(f8::MsgHdr& hdr, const cs::CMMatchCancel& msg)
{
}
void MatchTeam::_CMMatchChoose(f8::MsgHdr& hdr, const cs::CMMatchChoose& msg)
{
#ifdef DEBUG
a8::XPrintf("cmmatchchoose %s phase_:%d %s\n", {hdr.socket_handle, phase_, GetTeamUUid()});
{
for (auto& pair : raw_member_hash_) {
a8::XPrintf("cmmatchchoose member %d:%d:%s %s:%d\n",
{
hdr.socket_handle,
phase_,
GetTeamUUid(),
pair.second->msg.account_id(),
pair.second->socket_handle
});
}
}
#endif
auto member = GetMemberBySocket(hdr.socket_handle);
if (member && master_team_->phase_ == kMatchChoose) {
member->msg.set_hero_id(msg.hero_id());
*member->msg.mutable_weapons() = msg.weapons();
*member->msg.mutable_skins() = msg.skins();
*member->msg.mutable_skill_list() = msg.skill_list();
*member->msg.mutable_baseskin() = msg.baseskin();
member->msg.set_hero_skin(msg.hero_skin());
++member->choose_hero_times;
#ifdef DEBUG
a8::XPrintf("matchchoose %s\n", {member->msg.account_id()});
#endif
}
}
void MatchTeam::_CMMatchStartGame(f8::MsgHdr& hdr, const cs::CMMatchStartGame& msg)
{
if (master_team_->phase_ == kMatchChoose) {
auto member = GetMemberBySocket(hdr.socket_handle);
if (member) {
member->state = kMatchPrepare;
#ifdef DEBUG
a8::XPrintf("matchgamestart %s\n", {member->msg.account_id()});
#endif
}
}
}
void MatchTeam::_CMMatchCancelStartGame(f8::MsgHdr& hdr, const cs::CMMatchCancelStartGame& msg)
{
if (master_team_->phase_ == kMatchChoose) {
auto member = GetMemberBySocket(hdr.socket_handle);
if (member) {
member->state = kMatchReadying;
#ifdef DEBUG
a8::XPrintf("matchcancelgamestart %s\n", {member->msg.account_id()});
#endif
}
}
}
void MatchTeam::_CMMatchSendMsg(f8::MsgHdr& hdr, const cs::CMMatchSendMsg& msg)
{
auto sender = GetMemberBySocket(hdr.socket_handle);
if (sender) {
for (auto member : master_team_->curr_member_hash_) {
if (member->socket_handle != 0) {
bool found = false;
for (auto& target : msg.target_list()) {
if (target == member->msg.account_id()) {
found = true;
break;
}
}
if (found) {
cs::SMMatchMemberMsgNotify notifymsg;
notifymsg.set_sender(sender->msg.account_id());
notifymsg.set_content(msg.content());
GGListener::Instance()->SendToClient(member->socket_handle, 0, notifymsg);
}
}
}
}
}
void MatchTeam::_CMMatchBroadcastMsg(f8::MsgHdr& hdr, const cs::CMMatchBroadcastMsg& msg)
{
auto sender = GetMemberBySocket(hdr.socket_handle);
if (sender) {
for (auto member : master_team_->curr_member_hash_) {
if (member->socket_handle != 0) {
if (!msg.exclude_self() ||
(msg.exclude_self() && sender->msg.account_id() != member->msg.account_id())) {
cs::SMMatchMemberMsgNotify notifymsg;
notifymsg.set_sender(sender->msg.account_id());
notifymsg.set_content(msg.content());
GGListener::Instance()->SendToClient(member->socket_handle, 0, notifymsg);
}
}
}
}
}
void MatchTeam::AddRawMember(f8::MsgHdr& hdr, const cs::CMJoin& msg)
{
std::shared_ptr<RawTeamMember> member = std::make_shared<RawTeamMember>();
member->team = this;
member->add_tick = a8::XGetTickCount();
member->socket_handle = hdr.socket_handle;
member->msg = msg;
raw_member_hash_[msg.account_id()] = member;
curr_member_hash_.push_back(member);
if (!first_member_) {
first_member_ = member;
}
if (master_team_ != this) {
master_team_->curr_member_hash_.push_back(member);
}
#ifdef DEBUG
a8::XPrintf("AddRawMember %s %s %d %d %d\n",
{
GetTeamUUid(),
msg.account_id(),
curr_member_hash_.size(),
master_team_->curr_member_hash_.size(),
master_team_ == this ? 1 : 0
});
#endif
}
bool MatchTeam::IsRawMember(const std::string &account_id)
{
auto itr = raw_member_hash_.find(account_id);
return itr != raw_member_hash_.end();
}
bool MatchTeam::IsValidMember(const cs::CMJoin& msg)
{
if (msg.team_members().size() <= 0) {
return false;
}
if (first_member_->msg.team_uuid() != msg.team_uuid()) {
return false;
}
if (first_member_->msg.team_members().size() != msg.team_members().size()) {
return false;
}
for (int i = 0; i < msg.team_members().size(); ++i) {
auto& a = msg.team_members(i);
auto& b = first_member_->msg.team_members(i);
if (a.account_id() != b.account_id()) {
return false;
}
}
return true;
}
void MatchTeam::Update()
{
if (IsMasterTeam()) {
UpdateMaster();
} else {
UpdateSlave();
}
if (phase_ == kMatchStartGame && IsMasterTeam()) {
StartGame();
}
}
void MatchTeam::SyncMatchInfo()
{
cs::SMUpdateMatchInfo notifymsg;
for (auto member : curr_member_hash_) {
member->FillMFMatchTeamMember(notifymsg.mutable_info()->add_members());
}
notifymsg.mutable_info()->set_phase(phase_);
notifymsg.mutable_info()->set_countdown(phase_left_time_);
notifymsg.mutable_info()->set_predict_time(MetaMgr::Instance()->match_team_time);
for (auto& member : curr_member_hash_) {
if (member->socket_handle != 0) {
GGListener::Instance()->SendToClient(member->socket_handle, 0, notifymsg);
}
}
}
void MatchTeam::TryCombineTeam()
{
if (GetPredictMemberNum() < MAX_TEAM_NUM) {
MatchTeam* matched_team = nullptr;
MatchMgr::Instance()->TraverseTeam
(
[this, &matched_team] (MatchTeam* team, bool& stop)
{
if (team == this) {
return;
}
if (CanCombine(team)) {
matched_team = team;
stop = true;
}
});
if (matched_team) {
Combine(matched_team);
}
}
}
void MatchTeam::UpdateMaster()
{
phase_left_time_ = GetPhaseLeftTime();
switch (phase_) {
case kMatchCombining:
{
if (IsShuaRobotTime()) {
if (curr_member_hash_.size() < MAX_TEAM_NUM) {
ShuaRobot();
}
} else {
if (GetPredictMemberNum() < MAX_TEAM_NUM) {
TryCombineTeam();
}
}
if (phase_left_time_ <= 0 || GetPredictMemberNum() >= MAX_TEAM_NUM) {
ChooseLeader();
phase_ = kMatchChoose;
phase_start_tick_ = a8::XGetTickCount();
countdown_ = MetaMgr::Instance()->match_choose_time;
}
}
break;
case kMatchChoose:
{
UpdateTeamState();
CheckChoose();
CheckPrepare();
if ((phase_left_time_ <= MetaMgr::Instance()->match_lock_time) || IsAllPrepare()) {
for (int i = 0; i < MAX_TEAM_NUM; ++i) {
AutoChoose(true);
}
for (auto& member : curr_member_hash_) {
member->state = kMatchPrepare;
}
phase_ = kMatchLock;
phase_start_tick_ = a8::XGetTickCount();
countdown_ = MetaMgr::Instance()->match_lock_time;
}
}
break;
case kMatchLock:
{
if (phase_left_time_ <= 0) {
phase_ = kMatchStartGame;
phase_start_tick_ = a8::XGetTickCount();
}
}
break;
case kMatchStartGame:
{
}
break;
default:
{
}
break;
}
master_team_->SyncMatchInfo();
}
void MatchTeam::UpdateSlave()
{
switch (phase_) {
case kMatchCombining:
{
}
break;
case kMatchChoose:
{
}
break;
case kMatchLock:
{
}
break;
default:
{
}
break;
}
}
int MatchTeam::GetPredictMemberNum()
{
int num = GetRawMemberNum();
for (auto& pair : combined_team_hash_) {
num += pair.second->GetRawMemberNum();
}
return num;
}
bool MatchTeam::HasSameCurrMember(MatchTeam* b)
{
bool has = false;
for (auto& a_member : curr_member_hash_) {
for (auto& b_member : b->curr_member_hash_) {
if (a_member->msg.account_id() == b_member->msg.account_id()) {
has = true;
break;
}
}
}
return has;
}
bool MatchTeam::CanCombine(MatchTeam* b)
{
if (this == b) {
#ifdef DEBUG
a8::XPrintf("CanCombine 1\n", {});
#endif
return false;
}
//已合并
if (master_team_ != this){
#ifdef DEBUG
a8::XPrintf("CanCombine 2\n", {});
#endif
return false;
}
//已合并
if (b->master_team_ != b) {
#ifdef DEBUG
a8::XPrintf("CanCombine 3\n", {});
#endif
return false;
}
if (phase_ != kMatchCombining) {
#ifdef DEBUG
a8::XPrintf("CanCombine 4\n", {});
#endif
return false;
}
if (b->phase_ != kMatchCombining) {
#ifdef DEBUG
a8::XPrintf("CanCombine 5\n", {});
#endif
return false;
}
if (IsShuaRobotTime()) {
#ifdef DEBUG
a8::XPrintf("CanCombine 6\n", {});
#endif
return false;
}
if (b->IsShuaRobotTime()) {
#ifdef DEBUG
a8::XPrintf("CanCombine 7\n", {});
#endif
return false;
}
if (!b->combined_team_hash_.empty()) {
#ifdef DEBUG
a8::XPrintf("CanCombine 8\n", {});
#endif
return false;
}
if (GetPredictMemberNum() + b->GetPredictMemberNum() > MAX_TEAM_NUM) {
#ifdef DEBUG
a8::XPrintf("CanCombine 9\n", {});
#endif
return false;
}
if (combined_team_hash_.find(b->GetTeamUUid()) != combined_team_hash_.end()) {
#ifdef DEBUG
a8::XPrintf("CanCombine 10\n", {});
#endif
return false;
}
if (b->combined_team_hash_.find(GetTeamUUid()) != b->combined_team_hash_.end()) {
#ifdef DEBUG
a8::XPrintf("CanCombine 10\n", {});
#endif
return false;
}
if (GetValidSocketNum() <= 0) {
#ifdef DEBUG
a8::XPrintf("CanCombine 21\n", {});
#endif
return false;
}
if (b->GetValidSocketNum() <= 0) {
#ifdef DEBUG
a8::XPrintf("CanCombine 22\n", {});
#endif
return false;
}
if (HasSameCurrMember(b)) {
#ifdef DEBUG
a8::XPrintf("CanCombine 11\n", {});
#endif
return false;
}
return true;
}
void MatchTeam::Combine(MatchTeam* b)
{
#ifdef DEBUG
a8::XPrintf("Combine %s->%s %d:%d",
{
b->GetTeamUUid(),
GetTeamUUid(),
b->curr_member_hash_.size(),
curr_member_hash_.size()
});
#endif
combined_team_hash_[b->GetTeamUUid()] = b;
b->master_team_ = this;
for (auto& member : b->curr_member_hash_) {
curr_member_hash_.push_back(member);
}
}
std::string MatchTeam::GetTeamUUid()
{
return first_member_->msg.team_uuid();
}
int MatchTeam::GetMapId()
{
return first_member_->msg.mapid();
}
bool MatchTeam::IsShuaRobotTime()
{
return phase_ == kMatchCombining &&
phase_left_time_ <= MetaMgr::Instance()->match_robot_time;
}
int MatchTeam::GetPhaseLeftTime()
{
int passtime = (a8::XGetTickCount() - phase_start_tick_) / 1000;
return std::max(0, countdown_ - passtime);
}
std::shared_ptr<RawTeamMember> MatchTeam::GetMemberBySocket(int socket_handle)
{
for (auto& pair : raw_member_hash_) {
if (pair.second->socket_handle == socket_handle) {
return pair.second;
}
}
return std::shared_ptr<RawTeamMember>();
}
void MatchTeam::ShuaRobot()
{
for (int i = curr_member_hash_.size(); i < MAX_TEAM_NUM; ++i) {
std::shared_ptr<RawTeamMember> member = std::make_shared<RawTeamMember>();
member->team = this;
member->add_tick = a8::XGetTickCount();
member->is_robot = true;
member->InitRobot();
curr_member_hash_.push_back(member);
}
}
void MatchTeam::StartGame()
{
if (GetValidSocketNum() > 0) {
RoomMgr::Instance()->JoinTeam(this);
}
for (auto& member : curr_member_hash_) {
if (member->socket_handle != 0) {
MatchMgr::Instance()->RemoveSocket(member->socket_handle);
}
}
for (auto& pair : combined_team_hash_) {
MatchMgr::Instance()->RemoveTeam(pair.first);
}
MatchMgr::Instance()->RemoveTeam(GetTeamUUid());
}
void MatchTeam::ChooseLeader()
{
std::shared_ptr<RawTeamMember> leader;
for (auto& member : curr_member_hash_) {
if (!member->is_robot) {
if (member->socket_handle) {
if (!leader) {
leader = member;
leader->is_leader = true;
continue;
}
}
}
member->is_leader = false;
}
}
void MatchTeam::AutoChoose(bool force)
{
for (auto& member : curr_member_hash_) {
if (member->choose_hero_times <= 0) {
if (member->is_robot){
++member->choose_hero_times;
break;
} else if (force) {
++member->choose_hero_times;
break;
}
}
}
}
bool MatchTeam::IsAllPrepare()
{
int num = 0;
for (auto& member : curr_member_hash_) {
if (member->state == kMatchPrepare) {
++num;
}
}
return num >= MAX_TEAM_NUM;
}
void MatchTeam::UpdateTeamState()
{
{
bool all_choose = true;
for (auto& member : curr_member_hash_) {
if (!member->is_robot && member->choose_hero_times <= 0 && member->socket_handle != 0) {
all_choose = false;
break;
}
}
if (all_choose) {
++all_player_choose_times_;
}
}
{
bool all_prepare = true;
for (auto& member : curr_member_hash_) {
if (!member->is_robot && member->state != kMatchPrepare && member->socket_handle != 0) {
all_prepare = false;
break;
}
}
if (all_prepare) {
++all_player_prepare_times_;
}
}
}
void MatchTeam::CheckChoose()
{
if (phase_ != kMatchChoose) {
return;
}
if (phase_left_time_ <= 10 || all_player_choose_times_ > 0) {
if (last_auto_choose_tick_ <= 0) {
AutoChoose();
last_auto_choose_tick_ = a8::XGetTickCount();
} else {
if (a8::XGetTickCount() - last_auto_choose_tick_ > (last_auto_choose_tick_ % 2000)) {
AutoChoose();
last_auto_choose_tick_ = a8::XGetTickCount();
}
}
}
}
void MatchTeam::CheckPrepare()
{
if (phase_ != kMatchChoose) {
return;
}
if (phase_left_time_ <= 10 || all_player_prepare_times_ > 0) {
if (last_auto_prepare_tick_ <= 0) {
AutoPrepare();
last_auto_prepare_tick_ = a8::XGetTickCount();
} else {
if (a8::XGetTickCount() - last_auto_prepare_tick_ > (last_auto_prepare_tick_ % 2000)) {
AutoPrepare();
last_auto_prepare_tick_ = a8::XGetTickCount();
}
}
}
}
void MatchTeam::AutoPrepare()
{
for (auto& member : curr_member_hash_) {
if (member->choose_hero_times > 0 &&
member->state != kMatchPrepare &&
member->socket_handle == 0) {
member->state = kMatchPrepare;
break;
}
}
}
int MatchTeam::GetValidSocketNum()
{
int valid_socket_num = 0;
for (auto& member : curr_member_hash_) {
if (member->socket_handle != 0) {
if (MatchMgr::Instance()->GetMatchInfo(member->socket_handle)) {
++valid_socket_num;
}
}
}
return valid_socket_num;
}