aozhiwei 028c03ac5a 1
2024-08-29 17:05:58 +08:00

4336 lines
134 KiB
C++

#include "precompile.h"
#include <random>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <a8/mutable_xobject.h>
#include <a8/collision.h>
#include <f8/udplog.h>
#include <f8/utils.h>
#include <f8/timer.h>
#include <f8/btmgr.h>
#include "playermgr.h"
#include "player.h"
#include "room.h"
#include "android.h"
#include "bullet.h"
#include "obstacle.h"
#include "roomobstacle.h"
#include "loot.h"
#include "car.h"
#include "hero.h"
#include "roommgr.h"
#include "app.h"
#include "gamelog.h"
#include "typeconvert.h"
#include "entityfactory.h"
#include "perfmonitor.h"
#include "mapinstance.h"
#include "mapmgr.h"
#include "incubator.h"
#include "team.h"
#include "frameeventdata.h"
#include "pbutils.h"
#include "movement.h"
#include "bornpoint.h"
#include "airdrop.h"
#include "airraid.h"
#include "sandtable.h"
#include "batchsync.h"
#include "trigger.h"
#include "custom_battle.h"
#include "custom_team.h"
#include "custom_member.h"
#include "room_agent.h"
#include "roomob.h"
#include "ingamevoice.h"
#include "jsondatamgr.h"
#include "httpproxy.h"
#include "netdata.h"
#include "stats.h"
#include "boxdrop.h"
#include "mt/Param.h"
#include "mt/Hero.h"
#include "mt/Equip.h"
#include "mt/Buff.h"
#include "mt/Skill.h"
#include "mt/SkillNumber.h"
#include "mt/SafeArea.h"
#include "mt/MapThing.h"
#include "mt/Text.h"
#include "mt/Map.h"
#include "mt/MapMode.h"
#include "mt/PveGemini.h"
#include "mt/PveGeminiMode.h"
#include "mt/RankReward.h"
#include "mt/RankPoint.h"
#include "mt/KillReward.h"
#include "mt/KillPoint.h"
#include "mt/Drop.h"
#include "mt/AirLine.h"
#include "mt/Robot.h"
#include "mt/SafeAreaPos.h"
#include "mt/MapThingGroup.h"
#include "mt/MobaRoom.h"
const int SHUA_RANGE = 580;
static long long RoomXGetTickCount(void* context)
{
Room* room = (Room*)context;
return room->GetFrameNo();
}
Room::~Room()
{
}
void Room::InitData(RoomInitInfo& init_info)
{
room_idx_ = init_info.room_idx;
room_mode_ = init_info.room_mode;
room_uuid_ = init_info.room_uuid;
room_type_ = init_info.room_type;
pve_human_num = init_info.pve_human_num;
grid_service = init_info.grid_service;
map_service = init_info.map_service;
map_instance = init_info.map_instance;
map_mode_meta_ = init_info.map_mode_meta;
map_meta_ = init_info.map_meta;
poly_ext_datas_ = map_instance->GetPolyExtDatas();
custom_battle_ = init_info.custom_battle;
rank_match_conf_ = mt::Param::GetRankModeConfByRoomType(room_type_);
}
void Room::Init()
{
xtimer.Init(RoomXGetTickCount, this, 100, 100);
xtimer_attacher_.SetOwner(&xtimer);
frame_event.room = this;
frame_event_data = std::make_shared<FrameEventData>();
ingame_voice_ = std::make_shared<InGameVoice>(this);
ingame_voice_->Init();
air_drop_ = std::make_shared<AirDrop>(this);
air_raid_ = std::make_shared<AirRaid>(this);
batch_sync_ = std::make_shared<BatchSync>(this);
room_agent_ = behaviac::Agent::Create<RoomAgent>();
room_agent_->SetRoom(this);
f8::BtMgr::Instance()->BtLoad(room_agent_, "npc/room");
f8::BtMgr::Instance()->BtSetCurrent(room_agent_, "npc/room");
CreateWorldObjects();
ShuaAndroid();
incubator_ = std::make_shared<Incubator>();
incubator_->room = this;
incubator_->Init();
sand_table_ = std::make_shared<SandTable>(this);
box_drop_ = std::make_shared<BoxDrop>(this);
#ifdef MYDEBUG
InitDebugInfo();
#endif
if (IsMobaModeRoom()) {
moba_over_timer = xtimer.SetTimeoutWpEx
(SERVER_FRAME_RATE * GetMapMeta()->GetMobaRoomMeta()->game_time(),
[this] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
if (!IsGameOver() && !GetVictoryTeam()) {
if (GetMobaTeamA()->GetKillCount() == GetMobaTeamB()->GetKillCount()) {
moba_overtime_race_frameno_ = GetFrameNo();
xtimer.SetTimeoutWpEx
(SERVER_FRAME_RATE * GetMapMeta()->GetMobaRoomMeta()->game_time(),
[this] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
MobaOver();
}
},
&xtimer_attacher_);
return;
}
MobaOver();
}
}
},
&xtimer_attacher_);
xtimer.SetIntervalWpEx
(SERVER_FRAME_RATE * 1,
[this] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
if (!IsGameOver() && !GetVictoryTeam()) {
MobaBatterysUpdate();
}
}
},
&xtimer_attacher_);
if (GetMapMeta()->GetMobaRoomMeta()->moba_towers.size() == 2) {
xtimer.SetIntervalWpEx
(SERVER_FRAME_RATE * GetMapMeta()->GetMobaRoomMeta()->tower_interval(),
[this] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
if (!IsGameOver() && !GetVictoryTeam()) {
for (size_t i = 0; i < 2; ++i) {
const auto side = i + 1;
auto& tuple = GetMapMeta()->GetMobaRoomMeta()->moba_towers.at(i);
TraverseTeams
(
[&tuple, side] (Team* team) -> bool
{
team->TraverseMembers
(
[&tuple, side] (Human* hum) -> bool
{
if (hum->side != side) {
return false;
}
float distance = hum->GetPos().Distance2D2(std::get<0>(tuple));
if (distance < std::get<1>(tuple)) {
if (!hum->dead && !hum->poisoning && !hum->downed) {
if (hum->GetHP() + 1 < hum->GetMaxHP()) {
hum->AddHp(hum->GetMaxHP() *
hum->room->GetMapMeta()->GetMobaRoomMeta()->tower_recover_hp_rate() *
(1.0f + hum->GetNetData()->GetDrugEfficacyPct()));
hum->TryAddBuff(hum, kRecoverHpEffectBuffId);
}
}
}
return true;
});
return true;
});
}
}
}
},
&xtimer_attacher_);
}
}
ob_ = std::make_shared<RoomOb>(this);
ob_->Init();
}
void Room::UnInit()
{
destorying_ = true;
incubator_->UnInit();
#ifdef MYDEBUG
UnInitDebugInfo();
#endif
box_drop_->UnInit();
box_drop_ = nullptr;
incubator_ = nullptr;
timer_attacher.ClearTimerList();
xtimer_attacher_.ClearTimerList();
grid_service->ClearRoomData(this);
for (auto& pair : accountid_hash_) {
PlayerMgr::Instance()->RemovePlayerBySocket(pair.second->GetSocketHandle());
}
for (auto& pair : uniid_hash_) {
delete pair.second;
}
uniid_hash_.clear();
for (auto& pair : later_add_hash_) {
delete pair.second;
}
later_add_hash_.clear();
for (auto& pair : removed_robot_hash_) {
delete pair.second;
}
removed_robot_hash_.clear();
f8::BtMgr::Instance()->BtDestory(room_agent_);
room_agent_ = nullptr;
team_hash_.clear();
frame_event_data = nullptr;
PerfMonitor::Instance()->alive_count -= AliveCount();
ob_->UnInit();
ob_ = nullptr;
ingame_voice_->UnInit();
ingame_voice_ = nullptr;
}
void Room::Update(int delta_time)
{
xtimer.Update();
if (IsGameOver() && GetFrameNo() - game_over_frameno_ > SERVER_FRAME_RATE * 20) {
elapsed_time_ += delta_time;
while (elapsed_time_ >= 50) {
++frameno_;
elapsed_time_ -= 50;
}
return;
}
elapsed_time_ += delta_time;
while (elapsed_time_ >= 50) {
#ifdef MYDEBUG1
long long begin_tick = a8::XGetTickCount();
long long end_tick = a8::XGetTickCount();
#endif
room_agent_->Exec();
if (GetFrameNo() % 2 == 0) {
UpdateGas();
}
#ifdef MYDEBUG1
end_tick = a8::XGetTickCount();
if (a8::XGetTickCount() - begin_tick > 1000) {
A8_ABORT();
}
begin_tick = a8::XGetTickCount();
#endif
for (auto& pair : moveable_hash_) {
pair.second->Update(50);
pair.second->LateUpdate(50);
}
for (auto& pair : task_hash_) {
(*pair.second)(nullptr);
}
#ifdef MYDEBUG1
end_tick = a8::XGetTickCount();
if (a8::XGetTickCount() - begin_tick > 1000) {
A8_ABORT();
}
begin_tick = a8::XGetTickCount();
#endif
if (GetFrameNo() % 2 == 0) {
SyncFrameData();
}
#ifdef MYDEBUG1
end_tick = a8::XGetTickCount();
if (a8::XGetTickCount() - begin_tick > 1000) {
A8_ABORT();
}
#endif
++frameno_;
elapsed_time_ -= 50;
}
}
bool Room::IsPveRoom()
{
return GetMapMeta()->IsPveMap();
}
int Room::GetPlayerNum()
{
int num = 0;
if (BattleStarted()) {
num = battle_player_count_;
} else {
TraversePlayerList
(
[&num] (Player* hum) -> bool
{
if (!hum->IsOb()) {
++num;
}
return true;
});
}
return num;
}
int Room::GetHumanNum()
{
int num = 0;
if (BattleStarted()) {
num = battle_human_count_;
} else {
TraverseHumanList
(
[&num] (Human* hum) -> bool
{
if (!hum->IsOb()) {
++num;
}
return true;
});
}
return num;
}
Player* Room::GetPlayerByAccountId(const std::string& accountid)
{
auto itr = accountid_hash_.find(accountid);
return itr != accountid_hash_.end() ? itr->second : nullptr;
}
Player* Room::GetPlayerByUniId(int uniid)
{
Entity* entity = GetEntityByUniId(uniid);
if (!entity) {
return nullptr;
}
return entity->IsEntityType(ET_Player) && entity->IsEntitySubType(EST_Player) ?
(Player*)entity : nullptr;
}
Entity* Room::GetEntityByUniId(int uniid)
{
auto itr = uniid_hash_.find(uniid);
return itr != uniid_hash_.end() ? itr->second : nullptr;
}
Human* Room::GetHumanByUniId(int uniid)
{
Entity* entity = GetEntityByUniId(uniid);
return entity && entity->GetEntityType() == ET_Player ? (Human*)entity : nullptr;
}
int Room::AliveCount()
{
return alive_count_;
}
Player* Room::NewPlayer()
{
Player* hum = EntityFactory::Instance()->MakePlayer(AllocUniid());
return hum;
}
void Room::AddPlayer(Player* hum, std::shared_ptr<BornPoint> init_born_point, bool no_matchteam)
{
if (GetGasData().GetGasMode() != GasInactive) {
A8_ABORT();
}
if (!hum->IsOb()) {
while (GetHumanNum() >= GetRoomMaxPlayerNum()) {
RandRemoveAndroid();
}
}
if (init_born_point) {
hum->SetBornPoint(init_born_point);
} else {
hum->SetBornPoint(AllocBornPoint(hum));
}
App::Instance()->verify_set_pos = 1;
if (!hum->GetBornPoint()) {
abort();
} else {
if (!IsMobaModeRoom() && !IsSandTableRoom()) {
hum->SetPos(hum->GetBornPoint()->NewRandPoint(hum->room, 10, 100));
} else {
hum->SetPos(hum->GetBornPoint()->RandPoint(this));
}
}
App::Instance()->verify_set_pos = 0;
glm::vec3 attack_dir = hum->GetPos().ToGlmVec3();
GlmHelper::Normalize(attack_dir);
GlmHelper::RotateY(attack_dir, a8::RandAngle());
hum->SetAttackDir(attack_dir);
hum->SetMoveDir(attack_dir);
hum->room = this;
hum->join_frameno = GetFrameNo();
hum->Initialize();
AddToEntityHash(hum);
AddToMoveableHash(hum);
AddToAccountHash(hum);
AddToHumanHash(hum);
if (!hum->IsOb()) {
AddToAliveHumanHash(hum);
}
if (!no_matchteam) {
MatchTeam(hum);
}
hum->PushJoinRoomMsg();
if (!hum->IsOb()) {
IncAliveCount();
}
grid_service->AddCreature(hum);
hum->FindLocation();
hum->RefreshView();
AddPlayerPostProc(hum);
NotifyUiUpdate();
OnAddHuman(hum);
frame_event.AddEnterGame(hum->GetWeakPtrRef());
GameLog::Instance()->GameStart(hum);
if (custom_battle_ && custom_battle_->AllIsJoined()) {
if (GetGasInactiveReaminTime() > 3) {
acc_inactive_time_ += GetGasInactiveReaminTime() - 2;
}
}
}
int Room::AllocUniid()
{
while (GetEntityByUniId(++current_uniid_) ||
later_add_hash_.find(current_uniid_) != later_add_hash_.end() ||
current_uniid_ == 0) {}
return current_uniid_;
}
void Room::ShuaAndroid()
{
if (IsCustomBattle()) {
return;
}
if (GetGasData().GetGasMode() != GasInactive) {
return;
}
if (IsMobaModeRoom()) {
return;
}
int robot_num = a8::RandEx(map_meta_->refresh_robot_min_num,
map_meta_->refresh_robot_max_num);
int refresh_time = a8::RandEx(map_meta_->refresh_robot_min_time,
map_meta_->refresh_robot_max_time);
if (robot_num > 0 && refresh_time > 0) {
CreateAndroid(robot_num);
xtimer.SetTimeoutEx
(SERVER_FRAME_RATE * refresh_time,
[this] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
ShuaAndroid();
}
},
&xtimer_attacher_);
}
}
void Room::CreateAndroid(int robot_num, std::shared_ptr<Team> team)
{
for (int i = 0; i < robot_num; ++i) {
if (GetHumanNum() >= GetRoomMaxPlayerNum()) {
return;
}
const mt::Robot* robot_meta = mt::Robot::RandRobot(refreshed_robot_set_);
if (!robot_meta) {
A8_ABORT();
}
Android* hum = EntityFactory::Instance()->MakeAndroid(AllocUniid());
hum->name = robot_meta->name();
#if 0
hum->meta = mt::Hero::GetById(30100);
#else
hum->meta = mt::Hero::GetById(robot_meta->hero_id());
#endif
hum->robot_meta = robot_meta;
hum->SetBornPoint(AllocBornPoint(hum));
App::Instance()->verify_set_pos = 1;
if (!hum->GetBornPoint()) {
abort();
} else {
if (!IsMobaModeRoom() && !IsSandTableRoom()) {
hum->SetPos(hum->GetBornPoint()->NewRandPoint(hum->room, 10, 100));
} else {
hum->SetPos(hum->GetBornPoint()->RandPoint(this));
}
}
App::Instance()->verify_set_pos = 0;
glm::vec3 attack_dir = hum->GetPos().ToGlmVec3();
GlmHelper::Normalize(attack_dir);
GlmHelper::RotateY(attack_dir, a8::RandAngle());
hum->SetAttackDir(attack_dir);
hum->SetMoveDir(attack_dir);
hum->room = this;
hum->join_frameno = GetFrameNo();
hum->Initialize();
AddToEntityHash(hum);
AddToHumanHash(hum);
if (team) {
team->AddMember(hum);
} else {
MatchTeam(hum);
}
if (!hum->IsOb()) {
IncAliveCount();
}
refreshed_robot_set_.insert(robot_meta->id());
if (!CanAddToScene(hum)) {
a8::SetBitFlag(hum->status, CS_Disable);
} else {
AddToAliveHumanHash(hum);
AddToMoveableHash(hum);
grid_service->AddCreature(hum);
hum->FindLocation();
hum->RefreshView();
}
OnAddHuman(hum);
frame_event.AddEnterGame(hum->GetWeakPtrRef());
}
NotifyUiUpdate();
}
Human* Room::CreateAndroidWithCustomMember(std::shared_ptr<CustomMember> custom_member,
std::shared_ptr<Team> team)
{
if (GetHumanNum() >= GetRoomMaxPlayerNum()) {
return nullptr;
}
const mt::Robot* robot_meta = mt::Robot::GetById(custom_member->GetRobotId());
if (!robot_meta) {
A8_ABORT();
}
Android* hum = EntityFactory::Instance()->MakeAndroid(AllocUniid());
hum->name = robot_meta->name();
hum->meta = mt::Hero::GetById(custom_member->GetNetData()->GetHeroId());
hum->robot_meta = robot_meta;
hum->SetBornPoint(AllocBornPoint(hum));
App::Instance()->verify_set_pos = 1;
if (!hum->GetBornPoint()) {
abort();
} else {
hum->SetPos(hum->GetBornPoint()->RandPoint(this));
}
App::Instance()->verify_set_pos = 0;
glm::vec3 attack_dir = hum->GetPos().ToGlmVec3();
GlmHelper::Normalize(attack_dir);
GlmHelper::RotateY(attack_dir, a8::RandAngle());
hum->SetAttackDir(attack_dir);
hum->SetMoveDir(attack_dir);
hum->room = this;
hum->join_frameno = GetFrameNo();
hum->Initialize();
AddToEntityHash(hum);
AddToHumanHash(hum);
if (team) {
team->AddMember(hum);
} else {
MatchTeam(hum);
}
if (!hum->IsOb()) {
IncAliveCount();
}
refreshed_robot_set_.insert(robot_meta->id());
if (!CanAddToScene(hum)) {
a8::SetBitFlag(hum->status, CS_Disable);
} else {
AddToAliveHumanHash(hum);
AddToMoveableHash(hum);
grid_service->AddCreature(hum);
hum->FindLocation();
hum->RefreshView();
}
OnAddHuman(hum);
frame_event.AddEnterGame(hum->GetWeakPtrRef());
NotifyUiUpdate();
return hum;
}
void Room::FillSMJoinedNotify(Human* self_hum, cs::SMJoinedNotify& msg)
{
msg.set_team_mode(msg.team_mode());
msg.set_adjust_bullet(1);
msg.set_is_newbie_room(IsNewBieBattle());
}
void Room::ScatterDrop(const glm::vec3& center, int drop_id, bool no_adjust, std::vector<int>* items)
{
const mt::Drop* drop_meta = mt::Drop::GetById(drop_id);
if (drop_meta) {
std::vector<std::tuple<int, int, int>> drop_items;
drop_meta->RandItems(drop_items);
for (auto& item : drop_items) {
glm::vec3 dir = GlmHelper::UP;
GlmHelper::RotateY(dir, a8::RandAngle());
const glm::vec3 pos = center;
const mt::Equip* equip_meta = mt::Equip::GetById(std::get<0>(item));
if (equip_meta) {
DropItemEx(center,
pos,
std::get<0>(item),
std::get<1>(item),
std::get<2>(item),
true,
no_adjust,
items);
}
}
}
}
void Room::DropItem(const glm::vec3& pos, int item_id, int item_count, int item_lv, bool no_adjust,
std::vector<int>* items)
{
DropItemEx(pos, pos, item_id, item_count, item_lv, false, no_adjust, items);
}
void Room::DropItemEx(const glm::vec3& born_pos, const glm::vec3& pos,
int item_id, int item_count, int item_lv, bool show_anim, bool no_adjust,
std::vector<int>* items)
{
const mt::Equip* equip_meta = mt::Equip::GetById(item_id);
if (!equip_meta) {
return;
}
int group_num = equip_meta->group_num();
if (item_id == mt::Equip::YELLOW_STONE_ID && group_num <= 0) {
group_num = 1;
}
group_num = std::max(group_num, 1);
if (equip_meta && group_num > 0 && item_count > 0) {
#if 1
if (equip_meta->equip_type() == EQUIP_TYPE_BULLET) {
return;
}
#endif
int total_count = item_count;
while (total_count > 0) {
int drop_num = std::min(total_count, group_num);
if (drop_num < 1) {
drop_num = 1;
}
glm::vec3 dir = GlmHelper::UP;
GlmHelper::RotateY(dir, a8::RandAngle());
int obj_uniid = CreateLootEx(item_id,
born_pos,
pos + dir * (25.0f + rand() % 50),
drop_num,
item_lv,
show_anim,
no_adjust);
if (obj_uniid && items) {
items->push_back(obj_uniid);
}
total_count -= drop_num;
}
}
}
RoomObstacle* Room::CreateObstacle(int id, float x, float y, float z,
std::shared_ptr<a8::Args> init_args)
{
RoomObstacle* entity = InternalCreateObstacle(id, x, y, z,
[] (Obstacle*)
{
},
init_args);
assert(entity);
if (entity) {
entity->BroadcastFullState(this);
}
return entity;
}
int Room::CreateLoot(int equip_id, const glm::vec3& born_pos, const glm::vec3& pos, int count,
int equip_lv, bool no_adjust)
{
return CreateLootEx(equip_id, born_pos, pos, count, equip_lv, false, no_adjust);
}
int Room::CreateLootEx(int equip_id, const glm::vec3& born_pos, const glm::vec3& pos, int count,
int equip_lv, bool show_anim, bool no_adjust)
{
glm::vec3 real_pos = pos;
if (!no_adjust) {
real_pos = born_pos;
glm::vec3 dir = pos - born_pos;
dir.y = 0;
float distance = GlmHelper::Norm2D(dir);
if (distance > 10) {
GlmHelper::Normalize(dir);
glm::vec3 start = born_pos;
map_instance->Scale(start);
for (int i = 0; i < 4; ++i) {
glm::vec3 end = born_pos + dir * distance;
glm::vec3 hit_point;
bool hit_result = false;
map_instance->Scale(end);
bool need_adjust = true;
if (map_instance->Raycast(start,
end,
hit_point,
hit_result,
map_instance->GetMoveIncludeFlags(),
map_instance->GetMoveExcludeFlags())) {
map_instance->UnScale(hit_point);
if (GlmHelper::Norm2D(hit_point - born_pos) > 5) {
real_pos = hit_point;
need_adjust = false;
break;
}
}
GlmHelper::RotateY(dir, glm::radians(90.0f));
}
}
}
const mt::Equip* equip_meta = mt::Equip::GetById(equip_id);
if (equip_meta) {
Loot* entity = EntityFactory::Instance()->MakeLoot(AllocUniid());
entity->room = this;
entity->meta = equip_meta;
entity->GetMutablePos().FromGlmVec3(real_pos);
entity->born_pos.FromGlmVec3(born_pos);
entity->show_anim = show_anim;
entity->create_frame_no = GetFrameNo();
#if 1
{
if (entity->GetPos().GetX() >= map_meta_->map_width()) {
entity->GetMutablePos().SetX(map_meta_->map_width() - 1);
}
if (entity->GetPos().GetX() < 1.0f) {
entity->GetMutablePos().SetX(1.0f);
}
if (entity->GetPos().GetY() >= map_meta_->map_height()) {
entity->GetMutablePos().SetY(map_meta_->map_height() - 1);
}
if (entity->GetPos().GetY() < 1.0f) {
entity->GetMutablePos().SetY(1.0f);
}
}
#endif
entity->item_id = equip_id;
entity->count = count;
entity->item_level = equip_lv;
entity->Initialize();
AddToEntityHash(entity);
grid_service->AddRoomEntity(this, entity);
entity->BroadcastFullState(this);
return entity->GetUniId();
} else {
return 0;
}
}
int Room::CreateBullet(Creature* sender,
Creature* passenger,
const mt::Equip* weapon_meta,
const mt::Equip* bullet_meta,
const mt::Skill* skill_meta,
glm::vec3 pos,
glm::vec3 dir,
float fly_distance,
long long weapon_uniid,
int trace_target_id,
int hand,
a8::XTimerWp keep_shot_animi_timer_ptr,
float shot_animi_time,
int weapon_buff_id,
std::shared_ptr<std::set<int>> reporter_list,
int shot_uniid,
std::function<void(Bullet*)> on_bullet_exit,
int duration,
std::shared_ptr<float> scale)
{
int bullet_uniid = 0;
if (grid_service->CanAdd(pos.x, pos.z)) {
Bullet* bullet = EntityFactory::Instance()->MakeBullet(AllocUniid());
bullet->sender.Attach(sender);
if (passenger) {
bullet->passenger.Attach(passenger);
}
bullet->room = this;
bullet->weapon_uniid = weapon_uniid;
bullet->gun_meta = weapon_meta;
bullet->meta = bullet_meta;
bullet->skill_meta = skill_meta;
bullet->GetMutablePos().FromGlmVec3(pos);
bullet->dir = dir;
bullet->born_pos.FromGlmVec3(pos);
bullet->born_dir = dir;
bullet->fly_distance = fly_distance;
bullet->trace_target_id = trace_target_id;
bullet->hand = hand;
bullet->keep_shot_animi_timer_ptr = keep_shot_animi_timer_ptr;
bullet->shot_animi_time = shot_animi_time;
bullet->spec_gun_buff_id = weapon_buff_id;
bullet->reporter_list = reporter_list;
bullet->shot_uniid = shot_uniid;
bullet->on_bullet_exit = on_bullet_exit;
bullet->duration = duration;
bullet->Initialize();
#ifdef MYDEBUG1
a8::XPrintf("xxxxxxx born_pos:%f,%f,%f curr_pos:%f,%f,%f\n",
{
bullet->born_pos.x,
bullet->born_pos.y,
bullet->born_pos.z,
bullet->GetPos().x,
bullet->GetPos().y,
bullet->GetPos().z,
});
#endif
AddObjectLater(bullet);
bullet_uniid = bullet->GetUniId();
}
return bullet_uniid;
}
Car* Room::CreateCar(Human* driver,
int car_uniid,
const mt::Equip* item_meta,
const glm::vec3& pos,
int team_id,
std::set<int>* special_operators)
{
Car* car = EntityFactory::Instance()->MakeCar(AllocUniid());
car->car_uniid = car_uniid;
car->meta = item_meta;
car->room = this;
car->team_id = team_id;
car->GetMutablePos().FromGlmVec3(pos);
car->SetAttackDir(GlmHelper::DONW);
if (special_operators) {
car->SetSpecialOperators(*special_operators);
}
car->Initialize();
AddToEntityHash(car);
AddToMoveableHash(car);
grid_service->AddCreature(car);
car->RefreshView();
for (int buff_id : car->hero_meta_->_init_buffs) {
car->MustBeAddBuff(car, buff_id);
}
return car;
}
Hero* Room::CreateHero(Creature* master,
const mt::Hero* meta,
const glm::vec3& pos,
const glm::vec3& dir,
int team_id,
int obj_uniid)
{
if (obj_uniid > 0) {
if (GetEntityByUniId(obj_uniid)) {
abort();
}
} else {
obj_uniid = AllocUniid();
}
Hero* hero = EntityFactory::Instance()->MakeHero(obj_uniid);
hero->meta = meta;
if (master) {
hero->master.Attach(master);
}
hero->room = this;
hero->src_pos = pos;
hero->GetMutablePos().FromGlmVec3(pos);
hero->SetMoveDir(dir);
hero->SetAttackDir(dir);
hero->team_id = team_id;
hero->Initialize();
AddToEntityHash(hero);
AddToMoveableHash(hero);
grid_service->AddCreature(hero);
hero->RefreshView();
for (int buff_id : meta->_init_buffs) {
hero->MustBeAddBuff(hero, buff_id);
}
return hero;
}
void Room::RemoveObjectLater(RoomEntity* entity)
{
InternalRemoveObjectLater(entity, entity->xtimer_attacher);
}
void Room::RemoveObjectLater(RoomObstacle* entity)
{
InternalRemoveObjectLater(entity, entity->xtimer_attacher);
}
void Room::InternalRemoveObjectLater(Entity* entity, a8::Attacher& xtimer_attacher)
{
int entity_uniid = entity->GetUniId();
auto remove_func =
[this, entity_uniid] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT != event) {
return;
}
Entity* entity = GetEntityByUniId(entity_uniid);
if (!entity) {
return;
}
switch (entity->GetEntityType()) {
case ET_Bullet:
{
RemoveFromMoveableHash((Bullet*)entity);
}
break;
case ET_Loot:
{
entity->BroadcastDeleteState(this);
grid_service->DelRoomEntity(this, entity);
}
break;
case ET_Player:
{
RemoveFromMoveableHash((Human*)entity);
RemoveFromHuamnHash((Human*)entity);
}
break;
case ET_Car:
{
#if 0
RemoveFromAroundPlayers(entity->room);
BroadcastDeleteState(entity->room);
grid_service->RemoveCreature((Car*)entity);
#endif
RemoveFromMoveableHash((Car*)entity);
}
break;
case ET_Hero:
{
#if 0
BroadcastDeleteState(entity->room);
RemoveFromAroundPlayers(entity->room);
grid_service->RemoveCreature((Hero*)entity);
#endif
RemoveFromMoveableHash((Hero*)entity);
}
break;
case ET_Obstacle:
{
entity->BroadcastDeleteState(this);
grid_service->DelRoomEntity(this, entity);
}
break;
default:
{
A8_ABORT();
}
break;
}
RemoveFromEntityHash(entity);
#ifdef MYDEBUG
#if 0
f8::UdpLog::Instance()->Debug
(
"remove object pointer:%d uniid:%d",
{
(long long)entity,
entity->GetUniId()
}
);
#endif
#endif
delete entity;
};
if (!entity->removing) {
entity->removing = true;
xtimer.SetTimeoutEx
(NEXT_FRAME_TIMER,
remove_func,
&xtimer_attacher);
}
}
void Room::OnHumanDie(Human* hum)
{
if (!hum->IsOb()) {
DecAliveCount();
RemoveFromAliveHumanHash(hum);
NotifyUiUpdate();
}
}
void Room::OnHumanRevive(Human* hum)
{
NotifyUiUpdate();
}
bool Room::OverBorder(const glm::vec3& pos, float radius)
{
{
if (pos.x - radius < 0.0001f) {
return true;
}
if (pos.x + radius > map_meta_->map_width()) {
return true;
}
}
{
if (pos.z - radius < 0.0001f) {
return true;
}
if (pos.z + radius > map_meta_->map_height()) {
return true;
}
}
return false;
}
Human* Room::GetWatchWarTarget(Human* hum)
{
if (!mt::Param::s().watchable) {
return nullptr;
}
if (hum->GetTeam()) {
Human* member = hum->GetTeam()->RandomOneAliveMember(hum);
if (member) {
return member;
}
}
std::vector<Human*> players;
std::vector<Human*> humans;
TraverseHumanList
(
[hum, &players, &humans] (Human* ele_hum) -> bool
{
if (ele_hum->GetUniId() != hum->GetUniId() &&
!ele_hum->dead &&
!a8::HasBitFlag(ele_hum->status, CS_Disable)) {
if (ele_hum->IsPlayer()) {
players.push_back(ele_hum);
} else {
humans.push_back(ele_hum);
}
}
return true;
});
Human* target = nullptr;
if (!players.empty()) {
target = players[rand() % players.size()];
} else if (!humans.empty()) {
target = humans[rand() % humans.size()];
#ifdef MYDEBUG1
{
std::sort(humans.begin(), humans.end(),
[hum] (Human* a, Human *b) -> bool
{
return (hum->GetPos()-a->GetPos()).Norm() < (hum->GetPos()-b->GetPos()).Norm();
});
target = humans[rand() % std::min(humans.size(), (size_t)3)];
}
#endif
}
if (!target) {
target = incubator_->ActiveAndroid(hum);
}
return target;
}
bool Room::BattleStarted()
{
return battle_start_frameno_ != 0 || IsPveRoom();
}
int Room::GetAliveTeamNum()
{
int num = 0;
TraverseTeams
(
[&num] (Team* ele_team) -> bool
{
if (!ele_team->IsViewTeam() && ele_team->HasAliveMember()) {
++num;
}
return true;
});
return num;
}
void Room::TraverseTeams(std::function<bool (Team*)> cb)
{
for (auto& pair : team_hash_) {
if (!pair.second->IsViewTeam() && !cb(pair.second.get())) {
break;
}
}
}
void Room::TraverseRawTeams(std::function<bool (Team*)> cb)
{
for (auto& pair : team_hash_) {
if (!cb(pair.second.get())) {
break;
}
}
}
int Room::GetTeamNum()
{
int num = 0;
if (BattleStarted()) {
num = battle_team_count_;
} else {
TraverseTeams
(
[&num] (Team* team) -> bool
{
if (!team->IsViewTeam()) {
++num;
}
return true;
});
}
return num;
}
void Room::OnPlayerOffline(Player* hum)
{
if (GetOnlinePlayerNum() <= 0 && game_over_timer.expired()) {
game_over_timer = xtimer.SetTimeoutWpEx
(
SERVER_FRAME_RATE * 15,
[this] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
if (GetOnlinePlayerNum() <= 0 && !added_to_over_room) {
ForceOver();
}
}
},
&xtimer_attacher_);
}
}
void Room::FillSMUiUpdate(cs::SMUiUpdate& msg)
{
for (auto& pair : car_hash_) {
if (!pair.second.taken) {
auto car = msg.add_car_list();
car->set_car_id(pair.second.car_id);
TypeConvert::ToPb(pair.second.pos, car->mutable_pos());
}
}
}
Team* Room::GetAliveTeam()
{
Team* alive_team = nullptr;
TraverseTeams
(
[&alive_team] (Team* ele_team) -> bool
{
if (!ele_team->IsViewTeam() && ele_team->HasAliveMember()) {
alive_team = ele_team;
return false;
}
return true;
});
return alive_team;
}
std::shared_ptr<Team> Room::NewTeam()
{
auto team = std::make_shared<Team>();
team->room = this;
team->SetTeamId(++current_teamid_);
team_hash_[team->GetTeamId()] = team;
return team;
}
std::shared_ptr<Team> Room::NewViewTeam()
{
auto team = std::make_shared<Team>();
team->room = this;
team->SetTeamId(++current_teamid_);
team->SetViewTeam();
team_hash_[team->GetTeamId()] = team;
return team;
}
void Room::TraversePlayerList(std::function<bool (Player*)> cb)
{
for (auto& pair : accountid_hash_) {
if (pair.second && !pair.second->IsOb()) {
if (!cb(pair.second)){
break;
}
}
}
}
void Room::TraverseRawPlayerList(std::function<void (Player*)> cb)
{
for (auto& pair : accountid_hash_) {
if (pair.second) {
cb(pair.second);
}
}
}
void Room::TraverseHumanList(std::function<bool (Human*)> cb)
{
for (auto& pair : human_hash_) {
if (pair.second && !pair.second->IsOb()) {
if (!cb(pair.second)) {
break;
}
}
}
}
void Room::TraverseRawHumanList(std::function<bool (Human*)> cb)
{
for (auto& pair : human_hash_) {
if (pair.second) {
if (!cb(pair.second)) {
break;
}
}
}
}
void Room::TraverseAliveHumanList(std::function<bool (Human*)> func)
{
for (auto& pair : alive_human_hash_) {
#ifdef MYDEBUG
if (pair.second->IsOb()) {
abort();
}
#endif
if (pair.second) {
if (!func(pair.second)) {
break;
}
}
}
}
void Room::TraverseCreatureList(std::function<bool (Creature*)> func)
{
for (auto& pair : moveable_hash_) {
if (pair.second && pair.second->IsCreature(this)) {
Creature* c = (Creature*)pair.second;
if (!c->IsOb()) {
if (!func(c)) {
break;
}
}
}
}
}
void Room::TraverseEntityList(std::function<bool (Entity*)> func)
{
for (auto& pair : uniid_hash_) {
if (pair.second) {
if (!func(pair.second)) {
break;
}
}
}
}
void Room::TraverseAlivePlayers(std::function<bool (Human*)> func)
{
for (auto& pair : alive_player_hash_) {
#ifdef MYDEBUG
if (pair.second->IsOb()) {
abort();
}
#endif
if (!func(pair.second)) {
break;
}
}
}
void Room::BroadcastDebugMsg(const std::string& debug_msg)
{
#ifdef MYDEBUG
TraverseHumanList
(
[debug_msg] (Human* hum) -> bool
{
hum->SendDebugMsg(debug_msg);
return true;
});
#endif
}
void Room::UpdateGas()
{
switch (GetGasData().GetGasMode()) {
case GasInactive:
UpdateGasInactive();
break;
case GasJump:
UpdateGasJump();
break;
case GasWaiting:
UpdateGasWaiting();
break;
case GasMoving:
UpdateGasMoving();
break;
}
if (GetGasData().GetGasMode() != GasInactive && GetGasData().GetGasMode() != GasJump) {
if (GetGasData().GetGasMode() != GasInactive) {
if (false) {
} else if (IsPveRoom()) {
if (!IsGameOver() &&
(
pve_data.pve_kill_boss ||
IsAllRealDead() ||
incubator_->IsTimeOut()
)) {
game_over_ = true;
game_over_frameno_ = GetFrameNo();
OnGameOver();
}
} else {
if (!IsGameOver() &&
AliveCount() <= GetMaxTeamNum() &&
GetAliveTeamNum() <= 1) {
game_over_ = true;
game_over_frameno_ = GetFrameNo();
OnGameOver();
}
}
for (auto& pair : moveable_hash_) {
if (!pair.second->IsCreature(this)) {
continue;
}
Creature* c = (Creature*)pair.second;
if (c->real_dead ||
a8::HasBitFlag(c->status, CS_Disable)) {
continue;
}
if (c->IsOb()) {
continue;
}
bool b1 = a8::CircleContainCircle
(gas_data_.pos_old,
gas_data_.gas_progress,
glm::vec2(c->GetPos().GetX(), c->GetPos().GetZ()),
c->GetRadius()
);
bool b2 = a8::CircleContainCircle
(gas_data_.pos_new,
gas_data_.rad_new,
glm::vec2(c->GetPos().GetX(), c->GetPos().GetZ()),
c->GetRadius()
);
if (!b1 && !b2) {
c->poisoning = true;
if (!c->GetBuffByEffectId(kBET_Poisoning)) {
c->TryAddBuff(c, kPoisioningBuffId);
}
} else {
c->poisoning = false;
c->poisoning_time = false;
if (c->GetBuffByEffectId(kBET_Poisoning)) {
c->RemoveBuffByEffectId(kBET_Poisoning);
}
}
}
}
}
}
void Room::UpdateGasInactive()
{
if (IsPveRoom()) {
UpdateGasInactivePve();
} else if (IsMobaModeRoom()) {
UpdateGasInactiveMoba();
} else {
UpdateGasInactivePvp();
}
}
void Room::UpdateGasInactivePvp()
{
bool over = GetFrameNo() - gas_data_.gas_start_frameno >=
GetGasInactiveTime() * SERVER_FRAME_RATE;
if (over) {
long long begin_tick = a8::XGetTickCount();
if (GetHumanNum() < GetRoomMaxPlayerNum()) {
if (IsCustomBattle()) {
} else {
CreateAndroid(GetRoomMaxPlayerNum() - GetHumanNum());
}
NotifyUiUpdate();
}
gas_data_.SetGasMode(GasJump);
gas_data_.gas_start_frameno = GetFrameNo();
battle_start_frameno_ = GetFrameNo();
CombineTeam();
FillTeam();
ClearPostBattleAutoFreeList();
OnBattleStart();
InitAndroidAI();
RoomMgr::Instance()->ActiveRoom(GetRoomUuid());
if (IsSandTableRoom()) {
{
const mt::SafeArea* first_safearea = mt::SafeArea::GetByType
(map_meta_->RandSafeArea());
gas_data_.SetGasMode(GasWaiting);
gas_data_.old_area_meta = first_safearea;
gas_data_.new_area_meta = mt::SafeArea::GetById(first_safearea->id() + 1);
gas_data_.pos_list = mt::SafeAreaPos::RandSafeAreaPos(first_safearea->id());
gas_data_.gas_progress = gas_data_.old_area_meta->rad();
gas_data_.gas_start_frameno = GetFrameNo();
#if 1
gas_data_.pos_old = glm::vec2(first_safearea->x1(),
first_safearea->y1());
#else
gas_data_.pos_old = map_meta_->first_safearea_center;
#endif
gas_data_.pos_old_bk = gas_data_.pos_old;
{
if (gas_data_.pos_list && !gas_data_.pos_list->_poses.empty()) {
gas_data_.pos_old = glm::vec2(
gas_data_.pos_list->_poses[0].x,
gas_data_.pos_list->_poses[0].z
);
gas_data_.pos_old_bk = gas_data_.pos_old;
}
bool gen_ok = GenSmallCircle();
if (!gen_ok) {
A8_ABORT();
}
}
gas_data_.rad_old = gas_data_.old_area_meta->rad();
gas_data_.rad_new = gas_data_.new_area_meta->rad();
if (map_meta_->init_gas_ring() > 0) {
ForwardGasRing(map_meta_->init_gas_ring());
}
}
TraverseHumanList
(
[] (Human* hum) -> bool
{
hum->RemoveBuffByEffectId(kBET_ThroughWall);
hum->OnLand();
if (hum->GetEntitySubType() == EST_Player) {
GameLog::Instance()->GameStart((Player*)hum);
}
return true;
});
NotifyUiUpdate();
NotifyGameStart();
sand_table_->OnGameStart();
if (custom_battle_) {
}
} else {
if (IsNoPlane()) {
{
const mt::SafeArea* first_safearea = mt::SafeArea::GetByType
(map_meta_->RandSafeArea());
gas_data_.SetGasMode(GasWaiting);
gas_data_.old_area_meta = first_safearea;
gas_data_.new_area_meta = mt::SafeArea::GetById(first_safearea->id() + 1);
gas_data_.pos_list = mt::SafeAreaPos::RandSafeAreaPos(first_safearea->id());
gas_data_.gas_progress = gas_data_.old_area_meta->rad();
gas_data_.gas_start_frameno = GetFrameNo();
#if 1
gas_data_.pos_old = glm::vec2(first_safearea->x1(),
first_safearea->y1());
#else
gas_data_.pos_old = map_meta_->first_safearea_center;
#endif
gas_data_.pos_old_bk = gas_data_.pos_old;
{
if (gas_data_.pos_list && !gas_data_.pos_list->_poses.empty()) {
gas_data_.pos_old = glm::vec2(
gas_data_.pos_list->_poses[0].x,
gas_data_.pos_list->_poses[0].z
);
gas_data_.pos_old_bk = gas_data_.pos_old;
}
bool gen_ok = GenSmallCircle();
if (!gen_ok) {
A8_ABORT();
}
}
gas_data_.rad_old = gas_data_.old_area_meta->rad();
gas_data_.rad_new = gas_data_.new_area_meta->rad();
if (map_meta_->init_gas_ring() > 0) {
ForwardGasRing(map_meta_->init_gas_ring());
}
}
TraverseHumanList
(
[] (Human* hum) -> bool
{
hum->RemoveBuffByEffectId(kBET_ThroughWall);
hum->OnLand();
if (hum->GetEntitySubType() == EST_Player) {
GameLog::Instance()->GameStart((Player*)hum);
}
return true;
});
NotifyUiUpdate();
NotifyGameStart();
sand_table_->OnGameStart();
if (custom_battle_) {
}
} else {
ShuaPlane();
#if 1
int auto_jump_interval = mt::Param::GetIntParam("auto_jump_interval");
auto_jump_timer_ = xtimer.SetIntervalWpEx
(SERVER_FRAME_RATE * auto_jump_interval + SERVER_FRAME_RATE * 3,
[this] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
AutoJump();
}
},
&xtimer_attacher_);
#else
int auto_jump_interval_delay = mt::Param::GetIntParam("auto_jump_interval_delay");
xtimer.SetTimeoutEx
(
SERVER_FRAME_RATE * auto_jump_interval_delay,
[this] (int event, const a8::Args* args)
{
int auto_jump_interval = mt::Param::GetIntParam("auto_jump_interval");
auto_jump_timer_ = xtimer.SetIntervalWpEx
(SERVER_FRAME_RATE * auto_jump_interval,
[this] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
AutoJump();
}
},
&xtimer_attacher_);
},
&xtimer_attacher_);
#endif
}
}
#ifdef MYDEBUG
a8::XPrintf("max_run_delay:%d %d\n", {PerfMonitor::Instance()->max_run_delay_time,
a8::XGetTickCount() - begin_tick});
#endif
}
}
void Room::UpdateGasInactivePve()
{
if (GetFrameNo() - gas_data_.gas_start_frameno >=
GetGasInactiveTime() * SERVER_FRAME_RATE) {
{
auto first_safearea = pve_mode_meta->_area[0];
gas_data_.SetGasMode(GasWaiting);
gas_data_.gas_start_frameno = GetFrameNo();
battle_start_frameno_ = GetFrameNo();
gas_data_.old_area_meta = first_safearea;
gas_data_.new_area_meta = pve_mode_meta->_area[0];
gas_data_.gas_start_frameno = GetFrameNo();
gas_data_.pos_new = glm::vec2(gas_data_.new_area_meta->x1(),
gas_data_.new_area_meta->y1());
gas_data_.pos_old = gas_data_.pos_new;
gas_data_.pos_old_bk = gas_data_.pos_old;
gas_data_.rad_old = gas_data_.old_area_meta->rad();
gas_data_.rad_new = gas_data_.new_area_meta->rad();
gas_data_.gas_progress = 0;
}
NotifyUiUpdate();
ClearPostBattleAutoFreeList();
OnBattleStart();
NotifyGameStart();
InitAndroidAI();
incubator_->InitPve();
}
}
void Room::UpdateGasInactiveMoba()
{
if (GetFrameNo() - gas_data_.gas_start_frameno >=
GetGasInactiveTime() * SERVER_FRAME_RATE) {
{
const mt::SafeArea* first_safearea = mt::SafeArea::GetByType
(map_meta_->RandSafeArea());
gas_data_.SetGasMode(GasWaiting);
gas_data_.gas_start_frameno = GetFrameNo();
battle_start_frameno_ = GetFrameNo() + 1;
gas_data_.old_area_meta = first_safearea;
gas_data_.new_area_meta = first_safearea;
gas_data_.gas_start_frameno = GetFrameNo();
gas_data_.pos_new = glm::vec2(gas_data_.new_area_meta->x1(),
gas_data_.new_area_meta->y1());
gas_data_.pos_old = gas_data_.pos_new;
gas_data_.pos_old_bk = gas_data_.pos_old;
gas_data_.rad_old = gas_data_.old_area_meta->rad();
gas_data_.rad_new = gas_data_.new_area_meta->rad();
gas_data_.gas_progress = 0;
}
TraverseHumanList
(
[] (Human* hum) -> bool
{
hum->RemoveBuffByEffectId(kBET_ThroughWall);
hum->OnLand();
if (hum->GetEntitySubType() == EST_Player) {
GameLog::Instance()->GameStart((Player*)hum);
}
return true;
});
NotifyUiUpdate();
#if 1
App::Instance()->verify_set_pos = 1;
TraverseHumanList
(
[this] (Human* ele_hum) -> bool
{
Human* hum = ele_hum;
if (!hum->GetBornPoint()) {
abort();
} else {
hum->SetPos(hum->GetBornPoint()->RandPoint(this));
}
#ifdef MYDEBUG
a8::XPrintf("set_pos side:%d %d pos:%f %f %f\n", {
hum->side,
hum->GetUniId(),
hum->GetPos().GetX(),
hum->GetPos().GetY(),
hum->GetPos().GetZ(),
});
#endif
hum->GetMovement()->ClearPath();
grid_service->MoveCreature(hum);
return true;
});
App::Instance()->verify_set_pos = 0;
TraverseTeams
(
[this] (Team* ele_team) -> bool
{
if (ele_team->HasPlayer()) {
batch_sync_->AddTeam(ele_team);
}
return true;
});
#else
CombineTeam();
FillTeam();
#endif
ClearPostBattleAutoFreeList();
OnBattleStart();
NotifyGameStart();
InitAndroidAI();
sand_table_->OnGameStart();
}
}
void Room::UpdateGasWaiting()
{
if (IsPveRoom() || IsMobaModeRoom()) {
} else {
if (GetFrameNo() - gas_data_.gas_start_frameno >=
gas_data_.old_area_meta->wait_time() * SERVER_FRAME_RATE) {
gas_data_.SetGasMode(GasMoving);
gas_data_.gas_start_frameno = GetFrameNo();;
}
}
}
void Room::UpdateGasMoving()
{
if (GetFrameNo() - gas_data_.gas_start_frameno > 0 && !gas_data_.is_last_gas) {
float distance = gas_data_.old_area_meta->shrink_speed() *
((GetFrameNo() - gas_data_.gas_start_frameno) * (1.0 / SERVER_FRAME_RATE));
gas_data_.gas_progress = std::max(gas_data_.rad_old - distance, gas_data_.rad_new);
#if 1
if (std::abs(gas_data_.gas_progress - gas_data_.rad_new) > 0.001f) {
/*
移动大圆形的条件:
两圆形距离:center_distance
*/
glm::vec2 p1 = gas_data_.pos_new - gas_data_.pos_old;
float center_distance = glm::length(p1);
if (center_distance + gas_data_.rad_new > gas_data_.gas_progress) {
glm::vec2 dir = glm::normalize(p1);
gas_data_.pos_old = gas_data_.pos_old + dir *
(center_distance + gas_data_.rad_new - gas_data_.gas_progress);
}
}
#else
if (!(gas_data_.pos_new == gas_data_.pos_old)) {
glm::vec2 p1 = gas_data_.pos_new - gas_data_.pos_old_bk;
gas_data_.pre_pos_old = gas_data_.pos_old;
if (glm::length(p1) - distance <= 0.01f) {
gas_data_.pos_old = gas_data_.pos_new;
} else {
glm::vec2 dir = p1;
dir = glm::normalize(dir);
gas_data_.pos_old = gas_data_.pos_old_bk + dir * distance;
}
if (gas_data_.rad_old - distance <= gas_data_.rad_new) {
assert(gas_data_.rad_old - distance <= gas_data_.rad_new + 5);
}
}
#endif
if (std::abs(gas_data_.gas_progress - gas_data_.rad_new) <= 0.001f) {
if (gas_data_.new_area_meta->IsLastGas()) {
gas_data_.is_last_gas = true;
return;
}
ForwardGasRing(1);
}
}
}
void Room::UpdateGasJump()
{
glm::vec3 len_vec = plane.dir *
((GetFrameNo() - GetGasData().gas_start_frameno)*airline_->plane_speed() / SERVER_FRAME_RATE);
plane.curr_pos = plane.start_point + len_vec;
if (GlmHelper::Norm(plane.end_point - plane.start_point) <=
GlmHelper::Norm(len_vec) + mt::Param::s().early_parachute_jump) {
TraverseHumanList
(
[] (Human* hum) -> bool
{
if (hum->HasBuffEffect(kBET_Fly)) {
hum->DoJump();
}
if (hum->GetEntitySubType() == EST_Player) {
GameLog::Instance()->GameStart((Player*)hum);
}
return true;
});
const mt::SafeArea* first_safearea = mt::SafeArea::GetByType
(map_meta_->RandSafeArea());
gas_data_.SetGasMode(GasWaiting);
gas_data_.old_area_meta = first_safearea;
gas_data_.new_area_meta = mt::SafeArea::GetById(first_safearea->id() + 1);
gas_data_.pos_list = mt::SafeAreaPos::RandSafeAreaPos(first_safearea->id());
gas_data_.gas_progress = gas_data_.old_area_meta->rad();
gas_data_.gas_start_frameno = GetFrameNo();
#if 1
gas_data_.pos_old = glm::vec2(first_safearea->x1(),
first_safearea->y1());
#else
gas_data_.pos_old = map_meta_->first_safearea_center;
#endif
gas_data_.pos_old_bk = gas_data_.pos_old;
{
if (gas_data_.pos_list && !gas_data_.pos_list->_poses.empty()) {
gas_data_.pos_old = glm::vec2(
gas_data_.pos_list->_poses[0].x,
gas_data_.pos_list->_poses[0].z
);
gas_data_.pos_old_bk = gas_data_.pos_old;
}
bool gen_ok = GenSmallCircle();
if (!gen_ok) {
A8_ABORT();
}
}
gas_data_.rad_old = gas_data_.old_area_meta->rad();
gas_data_.rad_new = gas_data_.new_area_meta->rad();
if (map_meta_->init_gas_ring() > 0) {
ForwardGasRing(map_meta_->init_gas_ring());
}
if (!auto_jump_timer_.expired()) {
xtimer.Delete(auto_jump_timer_);
}
air_drop_->Init();
air_raid_->Init();
NotifyGameStart();
NotifyUiUpdate();
}
}
bool Room::GenSmallCircle()
{
if (gas_data_.new_area_meta->rad() >= gas_data_.old_area_meta->rad()) {
A8_ABORT();
}
if (gas_data_.pos_list && gas_data_.gas_count + 1 < gas_data_.pos_list->_poses.size()) {
gas_data_.pos_new =
glm::vec2(
gas_data_.pos_list->_poses[gas_data_.gas_count + 1].x,
gas_data_.pos_list->_poses[gas_data_.gas_count + 1].z
);
} else {
gas_data_.pos_new = glm::vec2(gas_data_.new_area_meta->x1(),
gas_data_.new_area_meta->y1());
}
return true;
}
void Room::MatchTeam(Human* hum)
{
if (!hum->team_uuid.empty()) {
{
bool match_ok = false;
TraverseHumanList
(
[&match_ok, hum] (Human* ele_hum) -> bool
{
if (ele_hum != hum) {
if (ele_hum->team_uuid == hum->team_uuid) {
if (ele_hum->GetTeam() && !ele_hum->GetTeam()->IsFull()) {
ele_hum->GetTeam()->AddMember(hum);
match_ok = true;
return false;
}
}
}
return true;
});
if (match_ok) {
return;
}
}
if (mt::Param::s().prebattle_combine_team) {
if (!hum->GetTeam() && hum->auto_fill && combineable_team_hash_.size() > 1) {
for (auto& pair : combineable_team_hash_) {
auto team = pair.second;
if (team->CanCombine(hum)) {
team->AddMember(hum);
team->AddCombineMemberNum(hum->init_team_member_num);
return;
}
}
}
}//end if
}
if (!hum->GetTeam()) {
auto new_team = NewTeam();
new_team->SetInitTeamMemberNum(hum->init_team_member_num);
new_team->SetAutoFill(hum->auto_fill);
new_team->AddMember(hum);
if (hum->IsPlayer() && hum->auto_fill) {
combineable_team_hash_[new_team->GetTeamId()] = new_team;
}
}
}
void Room::CombineTeam()
{
if (!mt::Param::s().prebattle_combine_team) {
return;
}
if (IsCustomBattle()) {
return;
}
std::map<int, size_t> need_combine_teams;
std::map<int, size_t> need_combine_teams_copy;
int first_team_id = 0;
int total_count = 0;
TraverseTeams
(
[&need_combine_teams, &need_combine_teams_copy, &first_team_id, &total_count]
(Team* ele_team) -> bool
{
if (!ele_team->AllIsRunAway()) {
ele_team->TraverseMembers
(
[ele_team, &first_team_id, &total_count, &need_combine_teams] (Human* member) -> bool
{
if (member->auto_fill && !member->team_uuid.empty()) {
if (first_team_id == 0) {
first_team_id = ele_team->GetTeamId();
}
need_combine_teams[ele_team->GetTeamId()] = ele_team->GetMemberNum();
total_count += ele_team->GetMemberNum();
return false;
}
return true;
});
}
return true;
});
if (total_count <= 1) {
return;
}
if (need_combine_teams.size() <= 2) {
return;
}
if (total_count == 3) {
int del_team_id = 0;
for (auto& pair : need_combine_teams) {
if (pair.first != first_team_id) {
del_team_id = pair.first;
break;
}
}
if (del_team_id != 0) {
auto itr = need_combine_teams.find(del_team_id);
if (itr != need_combine_teams.end()) {
total_count -= itr->second;
need_combine_teams.erase(itr);
}
}
if (total_count <= 1) {
abort();
}
}
size_t first_team_num = 4;
switch (total_count) {
case 3:
{
first_team_num = 2;
break;
}
case 4:
{
first_team_num = 2;
break;
}
case 5:
{
first_team_num = 3;
break;
}
default:
{
first_team_num = 4;
break;
}
}
need_combine_teams_copy = need_combine_teams;
int try_count = 0;
do {
for (auto& pair1 : need_combine_teams) {
bool combine_ok = false;
for (auto& pair2 : need_combine_teams_copy) {
int team_id1 = pair1.first;
int team_id2 = pair2.first;
if (team_id2 == first_team_id) {
continue;
}
if (team_id1 == first_team_id) {
if (pair1.second + pair2.second > first_team_num) {
continue;
}
}
if (team_id1 != team_id2) {
if (pair1.second + pair2.second <= GetMaxTeamNum()) {
int new_team_num = pair1.second + pair2.second;
{
std::shared_ptr<Team> team1 = team_hash_.at(team_id1);
std::shared_ptr<Team> team2 = team_hash_.at(team_id2);
if (team1->GetMemberNum() + team2->GetMemberNum() > GetMaxTeamNum()) {
f8::UdpLog::Instance()->Warning("team_member > 4 :%d",
{
team1->GetMemberNum() + team2->GetMemberNum()
});
}
if (pair1.first == first_team_id || pair1.second >= pair2.second) {
team1->CombineTeam(team2.get());
team_hash_.erase(pair2.first);
} else {
team2->CombineTeam(team1.get());
team_hash_.erase(pair1.first);
}
}
if (first_team_id == team_id1) {
if (pair1.second + pair2.second >= first_team_num) {
need_combine_teams.erase(team_id1);
need_combine_teams_copy.erase(team_id1);
} else {
pair1.second = new_team_num;
if (need_combine_teams_copy.find(pair1.first) !=
need_combine_teams_copy.end()) {
need_combine_teams_copy[pair1.first] = new_team_num;
}
}
need_combine_teams.erase(team_id2);
need_combine_teams_copy.erase(team_id2);
} else {
if (pair1.second >= pair2.second) {
if (pair1.second + pair2.second >= GetMaxTeamNum()) {
need_combine_teams.erase(team_id1);
need_combine_teams_copy.erase(team_id1);
} else {
pair1.second = new_team_num;
if (need_combine_teams_copy.find(pair1.first) !=
need_combine_teams_copy.end()) {
need_combine_teams_copy[pair1.first] = new_team_num;
}
}
need_combine_teams.erase(team_id2);
need_combine_teams_copy.erase(team_id2);
} else {
if (pair1.second + pair2.second >= GetMaxTeamNum()) {
need_combine_teams.erase(team_id2);
need_combine_teams_copy.erase(team_id2);
} else {
pair2.second = new_team_num;
if (need_combine_teams.find(pair2.first) !=
need_combine_teams.end()) {
need_combine_teams[pair2.first] = new_team_num;
}
}
need_combine_teams.erase(team_id1);
need_combine_teams_copy.erase(team_id1);
}
}
combine_ok = true;
break;
}
}
}//end for
if (combine_ok) {
break;
}
}
} while (++try_count < 20);
}
void Room::FillTeam()
{
std::vector<std::shared_ptr<Team>> free_team_list;
TraverseTeams
(
[&free_team_list] (Team* ele_team) -> bool
{
if (ele_team->IsFreeTeam()) {
free_team_list.push_back(ele_team->shared_from_this());
}
return true;
});
std::random_shuffle(free_team_list.begin(), free_team_list.end());
for (auto& pair : accountid_hash_) {
if (free_team_list.empty()) {
break;
}
if (!pair.second->GetTeam()->IsFull()) {
for (int i = pair.second->GetTeam()->GetMemberNum(); i < GetMaxTeamNum(); ++i) {
if (!free_team_list.empty()) {
std::shared_ptr<Team> b_team = free_team_list.at(free_team_list.size() - 1);
pair.second->GetTeam()->CombineTeam(b_team.get());
free_team_list.erase(free_team_list.begin() + free_team_list.size() - 1);
team_hash_.erase(b_team->GetTeamId());
}
}
}
}
while (free_team_list.size() > 1) {
std::shared_ptr<Team> a_team = free_team_list[0];
free_team_list.erase(free_team_list.begin());
for (int i = 1; i < 4; ++i) {
if (!free_team_list.empty()) {
std::shared_ptr<Team> b_team = free_team_list.at(0);
a_team->CombineTeam(b_team.get());
free_team_list.erase(free_team_list.begin());
team_hash_.erase(b_team->GetTeamId());
}
}
}
TraverseTeams
(
[this] (Team* ele_team) -> bool
{
if (ele_team->HasPlayer()) {
batch_sync_->AddTeam(ele_team);
}
return true;
});
}
void Room::ShuaPlane()
{
airline_ = mt::AirLine::RandAirLine(map_meta_->map_id());
if (!airline_) {
A8_ABORT();
}
plane.start_point = airline_->GetStartPoint();
plane.end_point = airline_->GetEndPoint();
plane.dir = plane.end_point - plane.start_point;
GlmHelper::Normalize(plane.dir);
plane.curr_pos = plane.start_point;
last_player_jump_pos = plane.curr_pos;
TraverseHumanList
(
[this] (Human* ele_hum) -> bool
{
ele_hum->MustBeAddBuff(ele_hum, FLY_BUFFID);
ele_hum->ResetAllSkillCd();
App::Instance()->verify_set_pos = 1;
ele_hum->GetMutablePos().FromGlmVec3(plane.curr_pos);
App::Instance()->verify_set_pos = 0;
ele_hum->GetMovement()->ClearPath();
ele_hum->SetAttackDir(plane.dir);
ele_hum->SetMoveDir(plane.dir);
grid_service->MoveCreature(ele_hum);
ele_hum->AddToNewObjects(ele_hum);
ele_hum->ActiveAllSkill();
return true;
});
}
RoomObstacle* Room::InternalCreateObstacle(int id, float x, float y, float z,
std::function<void (Obstacle*)> on_precreate,
std::shared_ptr<a8::Args> init_args)
{
const mt::MapThing* thing = mt::MapThing::GetById(id);
if (thing) {
RoomObstacle* entity = EntityFactory::Instance()->MakeRoomObstacle(AllocUniid());
entity->meta = thing;
entity->room = this;
entity->init_args = init_args;
{
Position pos;
pos.SetX(x);
pos.SetY(y);
pos.SetZ(z);
entity->SetPos(pos);
}
entity->Initialize();
if (on_precreate) {
on_precreate(entity);
}
AddToEntityHash(entity);
grid_service->AddRoomEntity(this, entity);
return entity;
}
return nullptr;
}
void Room::AddObjectLater(RoomEntity* entity)
{
auto add_func =
[entity] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
if (entity->IsEntityType(ET_Bullet)) {
MoveableEntity* moveableentity = (MoveableEntity*)entity;
entity->room->AddToMoveableHash(moveableentity);
}
entity->room->AddToEntityHash(entity);
entity->room->RemoveFromLaterAddHash(entity);
}
};
AddToLaterAddHash(entity);
xtimer.SetTimeoutEx
(0,
add_func,
&entity->xtimer_attacher);
}
void Room::TryMobaReport(int try_count)
{
if (!IsMobaModeRoom()) {
return;
}
if (sending_moba_report_battle_) {
return;
}
if (already_moba_report_battle_) {
return;;
}
sending_moba_report_battle_ = true;
Player* player = nullptr;
TraversePlayerList
(
[&player] (Player* hum) -> bool
{
player = hum;
return true;
});
if (!player) {
return;
}
std::string url;
JsonDataMgr::Instance()->GetApiUrl(url);
std::shared_ptr<a8::MutableXObject> params = a8::MutableXObject::CreateObject();
std::shared_ptr<a8::MutableXObject> post_data = a8::MutableXObject::CreateObject();
params->SetVal("c", "Battle");
params->SetVal("a", "mobaTeamReport");
params->SetVal("account_id", player->account_id);
params->SetVal("session_id", player->session_id);
GenBattleMobaReportData(post_data.get());
std::string content = post_data->ToJsonStr();
HttpProxy::Instance()->HttpPost
(
[room_uuid = GetRoomUuid()]
(bool ok, a8::XObject* rsp_obj, f8::HttpContext* ctx)
{
auto room = RoomMgr::Instance()->GetRoomByUuid(room_uuid);
if (room) {
room->already_moba_report_battle_ = true;
room->sending_moba_report_battle_ = false;
room->TraverseHumanList
(
[] (Human* ele_hum) -> bool
{
ele_hum->SendGameOver();
return true;
});
}
},
url,
params,
content
);
#ifdef MYDEBUG
a8::XPrintf("MobaReportReportLen:%d\n", {params->ToJsonStr().size()});
#endif
}
void Room::OnGameOver()
{
if (IsAlreadyRoomReportBattle() ||
GetCustomBattle()) {
TraverseHumanList
(
[] (Human* ele_hum) -> bool
{
ele_hum->SendGameOver();
return true;
});
return;
} else {
TraverseHumanList
(
[] (Human* ele_hum) -> bool
{
ele_hum->SendGameOver();
return true;
});
CalcMvp();
if (IsMobaModeRoom()) {
TryMobaReport(0);
}
xtimer.SetIntervalEx
(SERVER_FRAME_RATE / 0.5,
[this, frameno = GetFrameNo()] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
bool all_sent = true;
if (IsMobaModeRoom()) {
all_sent = already_moba_report_battle_;
} else {
TraverseTeams
(
[&all_sent] (Team* team) -> bool
{
if (team->HasPlayer() && !team->IsViewTeam() &&
!team->IsAlreadyReportBattle()) {
all_sent = false;
return false;
}
return true;
});
}
if (all_sent) {
TryRoomReport(0);
xtimer.DeleteCurrentTimer();
} else if (GetFrameNo() - frameno > SERVER_FRAME_RATE * 5) {
TryRoomReport(0);
xtimer.DeleteCurrentTimer();
}
}
},
&xtimer_attacher_);
}
}
void Room::RandRemoveAndroid()
{
Human* hum = nullptr;
if (!hum) {
TraverseHumanList
(
[&hum] (Human* ele_hum) -> bool
{
if (ele_hum->IsAndroid() && ele_hum->team_uuid.empty()) {
hum = ele_hum;
return false;
}
return true;
});
}
if (hum) {
hum->CheckSpecObject(0);
if (hum->team_id != 0) {
Team* team = GetTeam(hum->team_id);
if (team) {
team->RemoveMember(hum);
if (team->GetMemberNum() < 1) {
team_hash_.erase(hum->team_id);
}
}
}
if (hum->GetBornPoint()) {
DecBornPointHumanNum(hum->GetBornPoint(), hum);
}
if (!hum->IsOb()) {
DecAliveCount();
}
TraverseRawHumanList
(
[hum] (Human* ele_hum) -> bool
{
ele_hum->RemovePartObjects(hum);
return true;
});
TraverseRawHumanList
(
[hum] (Human* ele_hum) -> bool
{
ele_hum->RemoveObjects(hum);
return true;
});
frame_event.AddExitGame(hum->GetWeakPtrRef());
grid_service->DeatchHuman(hum);
RemoveFromMoveableHash(hum);
RemoveFromEntityHash(hum);
RemoveFromHuamnHash(hum);
RemoveFromAliveHumanHash(hum);
AddToRemovedRobotHash(hum);
}
}
void Room::NotifyUiUpdate()
{
xtimer.SetTimeoutEx
(0,
[this] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
TraverseHumanList(
[] (Human * hum) -> bool
{
hum->SendUIUpdate();
return true;
});
}
},
&xtimer_attacher_);
}
void Room::UpdateCarObject(int old_uniid, int new_uniid, const glm::vec3 pos)
{
auto itr = car_hash_.find(old_uniid);
if (itr != car_hash_.end()) {
CarObject new_obj = itr->second;
new_obj.pos = pos;
car_hash_[new_uniid] = new_obj;
car_hash_.erase(old_uniid);
} else {
assert(false);
}
}
void Room::TakeOnCarObject(int car_uniid)
{
auto itr = car_hash_.find(car_uniid);
if (itr != car_hash_.end()) {
itr->second.taken = true;
}
}
void Room::TakeOffCarObject(int car_uniid, glm::vec3 pos)
{
auto itr = car_hash_.find(car_uniid);
if (itr != car_hash_.end()) {
itr->second.pos = pos;
itr->second.taken = false;
}
}
int Room::CreateAndTakeonCar(int car_id, glm::vec3 pos)
{
const mt::Equip* item_meta = mt::Equip::GetById(car_id);
if (!item_meta) {
return -1;
}
int car_uniid = AllocUniid();
CarObject car;
car.car_id = car_id;
car.pos = pos;
car.taken = true;
car_hash_[car_uniid] = car;
return car_uniid;
}
bool Room::HaveMyTeam(const std::string& team_uuid)
{
if (team_uuid.empty()) {
return false;
}
for (auto& pair : accountid_hash_) {
if (pair.second->team_uuid == team_uuid) {
return true;
}
}
return false;
}
std::shared_ptr<BornPoint> Room::AllocBornPoint(Human* hum)
{
std::shared_ptr<BornPoint> born_point = nullptr;
if (hum->GetBornPoint()) {
std::vector<std::shared_ptr<BornPoint>> point_list;
std::vector<std::shared_ptr<BornPoint>> free_point_list;
std::shared_ptr<BornPoint> pre_point = nullptr;
std::shared_ptr<BornPoint> reserve_point = nullptr;
for (auto& pair : born_point_hash_) {
if (pair.second != hum->GetBornPoint()) {
if (pair.second->player_num + pair.second->android_num <
pair.second->GetNum()) {
point_list.push_back(pair.second);
free_point_list.push_back(pair.second);;
}
if (!reserve_point || rand() % 100 < 10) {
reserve_point = pair.second;
}
} else {
pre_point = pair.second;
}
}
if (!free_point_list.empty()) {
born_point = free_point_list[rand() % free_point_list.size()];
if (pre_point) {
DecBornPointHumanNum(pre_point, hum);
}
} else {
if (point_list.empty() && reserve_point) {
born_point = ForceTakeBornPoint(hum, reserve_point);
} else {
born_point = !point_list.empty() ? point_list[rand() % point_list.size()] : nullptr;
if (pre_point) {
DecBornPointHumanNum(pre_point, hum);
}
}
}
} else {
std::vector<std::shared_ptr<BornPoint>> free_point_list;
for (auto& pair : born_point_hash_) {
if (pair.second->player_num + pair.second->android_num <
pair.second->GetNum()) {
free_point_list.push_back(pair.second);
}
}
if (!free_point_list.empty()) {
born_point = free_point_list[rand() % free_point_list.size()];
}
}
if (born_point) {
IncBornPointHumanNum(born_point, hum);
}
#ifdef MYDEBUG
if (!born_point) {
A8_ABORT();
}
#endif
return born_point;
}
std::shared_ptr<BornPoint> Room::GetBornPoint(int point_uniid)
{
auto itr = born_point_hash_.find(point_uniid);
return itr != born_point_hash_.end() ? itr->second : nullptr;
}
void Room::IncBornPointHumanNum(std::shared_ptr<BornPoint> point, Human* hum)
{
switch (hum->GetEntitySubType()) {
case EST_Player:
{
++point->player_num;
}
break;
case EST_Android:
{
++point->android_num;
}
break;
default:
{
}
break;
}
}
void Room::DecBornPointHumanNum(std::shared_ptr<BornPoint> point, Human* hum)
{
switch (hum->GetEntitySubType()) {
case EST_Player:
{
--point->player_num;
}
break;
case EST_Android:
{
--point->android_num;
}
break;
default:
{
}
break;
}
}
void Room::NotifyGameStart()
{
cs::SMGameStart msg;
for (auto& pair : accountid_hash_) {
pair.second->SendNotifyMsg(msg);
}
TraverseHumanList
(
[] (Human* ele_hum) -> bool
{
a8::SetBitFlag(ele_hum->status, CS_DisableAttack);
return true;
});
xtimer.SetTimeoutEx
(mt::Param::GetIntParam("prepare_time", 3000) / FRAME_RATE_MS,
[this] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
TraverseHumanList
(
[this] (Human* ele_hum) -> bool
{
a8::UnSetBitFlag(ele_hum->status, CS_DisableAttack);
for (int buff_id : map_meta_->buff_list) {
const mt::Buff* buff_meta = mt::Buff::GetById(buff_id);
if (buff_meta) {
#if 0
ele_hum->AddBuff(ele_hum,
buff_meta,
nullptr);
#endif
}
}
return true;
});
}
},
&xtimer_attacher_);
}
long long Room::GetGasInactiveTime()
{
long long inactive_time = 0;
if (IsPveRoom()) {
inactive_time = 10;
} else if (GetCustomBattle()) {
inactive_time = 15;
} else {
if (IsPvpRankModeRoom()) {
if (IsPvpMasterRankModeRoom()) {
inactive_time = mt::Param::s().master_rank_gas_inactive_time;
} else {
inactive_time = mt::Param::s().rank_gas_inactive_time;
}
} else {
inactive_time = mt::Param::s().gas_inactive_time;
}
}
#ifdef MYDEBUG
if (!f8::IsTestEnv()) {
inactive_time = 12;
}
#endif
if (IsMobaModeRoom()) {
inactive_time = 0;
}
inactive_time = std::max((long long)0, inactive_time - acc_inactive_time_);
if (IsNewerMap()) {
inactive_time = 10;
}
if (IsNewBieBattle()) {
inactive_time = 10;
}
return inactive_time;
}
long long Room::GetGasInactiveReaminTime()
{
if (GetGasData().GetGasMode() != GasInactive) {
return -1;
}
long long remain_time = GetGasInactiveTime() -
(GetFrameNo() - GetGasData().gas_start_frameno) * FRAME_RATE_MS;
return std::max((int)remain_time, 0);
}
void Room::EnableHuman(Human* target)
{
if (!RuningInTimer()) {
A8_ABORT();
}
#ifdef MYDEBUG
CheckPartObjects();
#if 0
f8::UdpLog::Instance()->Debug("enablehuman %d %d",
{
(long long)target,
target->GetUniId()
});
#endif
#endif
#if 0
target->OnEnable();
AddToMoveableHash(target);
if (!target->real_dead) {
AddToAliveHumanHash(target);
}
#else
if (a8::HasBitFlag(target->status, CS_Disable)) {
target->OnEnable();
AddToMoveableHash(target);
if (!target->real_dead) {
AddToAliveHumanHash(target);
}
} else {
A8_ABORT();
}
#endif
#ifdef MYDEBUG
CheckPartObjects();
#endif
}
void Room::DisableHuman(Human* target)
{
#if 0
if (!RuningInTimer()) {
A8_ABORT();
}
#endif
#ifdef MYDEBUG
CheckPartObjects();
#if 0
f8::UdpLog::Instance()->Debug("disablehuman %d %d",
{
(long long)target,
target->GetUniId()
});
#endif
#endif
if (!a8::HasBitFlag(target->status, CS_Disable)) {
target->OnDisable();
RemoveFromMoveableHash(target);
RemoveFromAliveHumanHash(target);
}
#ifdef MYDEBUG
CheckPartObjects();
#endif
}
bool Room::HasPlayerInRound(const glm::vec3& pos, float rad)
{
for (auto& pair : accountid_hash_) {
if (std::fabs(pair.second->GetPos().GetX() - pos.x) < rad &&
std::fabs(pair.second->GetPos().GetZ() - pos.z) < rad) {
return true;
}
}
return false;
}
void Room::CheckPartObjects(Human* testa, Human* testb)
{
}
bool Room::RuningInTimer()
{
return xtimer.IsRunning();
}
#ifdef MYDEBUG
void Room::InitDebugInfo()
{
}
void Room::UnInitDebugInfo()
{
}
#endif
void Room::AddPlayerPostProc(Player* hum)
{
}
void Room::AddToEntityHash(Entity* entity)
{
uniid_hash_[entity->GetUniId()] = entity;
}
void Room::AddToHumanHash(Human* hum)
{
human_hash_[hum->GetUniId()] = hum;
}
void Room::AddToAliveHumanHash(Human* hum)
{
#ifdef MYDEBUG
if (hum->IsOb()) {
abort();
}
#endif
alive_human_hash_[hum->GetUniId()] = hum;
if (hum->IsPlayer()) {
alive_player_hash_[hum->GetUniId()] = hum;
}
}
void Room::AddToMoveableHash(MoveableEntity* entity)
{
moveable_hash_[entity->GetUniId()] = entity;
}
void Room::AddToAccountHash(Player* hum)
{
accountid_hash_[hum->account_id] = hum;
}
void Room::AddToLaterAddHash(RoomEntity* entity)
{
later_add_hash_[entity->GetUniId()] = entity;
}
void Room::AddToRemovedRobotHash(Human* hum)
{
removed_robot_hash_[hum->GetUniId()] = hum;
}
void Room::RemoveFromEntityHash(Entity* entity)
{
uniid_hash_.erase(entity->GetUniId());
}
void Room::RemoveFromMoveableHash(MoveableEntity* entity)
{
moveable_hash_.erase(entity->GetUniId());
}
void Room::RemoveFromHuamnHash(Human* hum)
{
human_hash_.erase(hum->GetUniId());
}
void Room::RemoveFromAliveHumanHash(Human* hum)
{
alive_human_hash_.erase(hum->GetUniId());
if (hum->IsPlayer()) {
alive_player_hash_.erase(hum->GetUniId());
}
}
void Room::RemoveFromLaterAddHash(RoomEntity* entity)
{
later_add_hash_.erase(entity->GetUniId());
}
void Room::ForceSetBornPoint(Human* hum, std::shared_ptr<BornPoint> born_point)
{
if (born_point && hum->GetBornPoint() != born_point) {
if (hum->GetBornPoint()) {
DecBornPointHumanNum(hum->GetBornPoint(), hum);
}
hum->SetBornPoint(born_point);
if (hum->GetBornPoint()) {
IncBornPointHumanNum(hum->GetBornPoint(), hum);
hum->SetPos(hum->GetBornPoint()->RandPoint(this));
}
hum->FindLocation();
hum->RefreshView();
grid_service->MoveCreature(hum);
}
}
std::shared_ptr<BornPoint> Room::ForceTakeBornPoint(Human* hum, std::shared_ptr<BornPoint> reserve_born_point)
{
if (!reserve_born_point) {
A8_ABORT();
}
if (hum->GetBornPoint() == reserve_born_point) {
A8_ABORT();
}
if (!hum->GetBornPoint()) {
A8_ABORT();
}
std::shared_ptr<BornPoint> pre_point = hum->GetBornPoint();
if (pre_point) {
DecBornPointHumanNum(pre_point, hum);
}
TraverseHumanList
(
[this, reserve_born_point, pre_point] (Human* ele_hum) -> bool
{
if (ele_hum->GetBornPoint() == reserve_born_point) {
ForceSetBornPoint(ele_hum, pre_point);
}
return true;
});
return reserve_born_point;
}
Human* Room::GetOneCanEnableAndroid()
{
std::vector<Human*> humans;
GetCanEnableAndroids(humans, 1);
return !humans.empty() ? humans[0] : nullptr;
}
void Room::GetCanEnableAndroids(std::vector<Human*>& humans, size_t num)
{
TraverseHumanList
(
[&humans, num] (Human* ele_hum) -> bool
{
if (ele_hum->IsAndroid() &&
!ele_hum->real_dead &&
a8::HasBitFlag(ele_hum->status, CS_Disable)
) {
if (humans.size() >= num) {
return false;
}
humans.push_back(ele_hum);
}
return true;
});
}
Player* Room::GetOneAlivePlayer()
{
std::vector<Player*> humans;
GetAlivePlayers(humans, 1);
return !humans.empty() ? humans[0] : nullptr;
}
void Room::GetAlivePlayers(std::vector<Player*>& humans, size_t num)
{
for (auto& pair : accountid_hash_) {
if (!pair.second->real_dead) {
if (humans.size() >= num) {
break;
}
humans.push_back(pair.second);
}
}
}
int Room::GetCanShuaNum(int shua_num)
{
int real_shua_num = shua_num;
return real_shua_num;
}
bool Room::CanAddToScene(Human* hum)
{
return true;
}
void Room::SyncFrameData()
{
#ifdef MYDEBUG
long long begin_tick = a8::XGetTickCount();
long long end_tick = a8::XGetTickCount();
#endif
TraverseHumanList
(
#ifdef MYDEBUG
[&begin_tick, &end_tick] (Human* ele_hum) -> bool
#else
[] (Human* ele_hum) -> bool
#endif
{
ele_hum->SendUpdateMsg();
#ifdef MYDEBUG
end_tick = a8::XGetTickCount();
#if 0
if (a8::XGetTickCount() - begin_tick > 100) {
A8_ABORT();
}
#endif
begin_tick = a8::XGetTickCount();
#endif
return true;
});
#ifdef MYDEBUG
end_tick = a8::XGetTickCount();
if (a8::XGetTickCount() - begin_tick > 1000) {
A8_ABORT();
}
begin_tick = a8::XGetTickCount();
#endif
frame_event.Clear();
}
void Room::RemoveRescue(Human* hum)
{
TraverseHumanList
(
[this, hum] (Human* ele_hum) -> bool
{
if (ele_hum != hum && ele_hum->GetActionType() == AT_Relive &&
ele_hum->GetActionTargetId() == hum->GetUniId()) {
ele_hum->CancelAction();
}
return true;
});
}
void Room::NotifyCountdown(const std::string& msg, int time)
{
for (auto& pair : accountid_hash_) {
pair.second->SendShowCountdown(msg, time);
}
}
void Room::NotifySysPiao(const std::string& msg, int color, int duration)
{
for (auto& pair : accountid_hash_) {
pair.second->SendSysPiaoMsg(msg, color, duration);
}
}
int Room::GetOnlinePlayerNum()
{
int num = 0;
for (auto& pair : accountid_hash_) {
if (pair.second->SocketIsValid()) {
++num;
}
}
return num;
}
size_t Room::GetRoomMaxPlayerNum()
{
if (pve_instance) {
return pve_human_num;
}
if (custom_battle_) {
return custom_battle_->GetMemberNum();
}
return map_meta_->player();
}
void Room::InitAndroidAI()
{
}
void Room::ForwardGasRing(int n)
{
while (n > 0) {
if (gas_data_.new_area_meta->IsLastGas()) {
gas_data_.is_last_gas = true;
return;
}
int pre_area_id = gas_data_.new_area_meta->id();
gas_data_.SetGasMode(GasWaiting);
glm::vec2 pre_pos = gas_data_.pos_new;
gas_data_.old_area_meta = mt::SafeArea::GetById(pre_area_id);
gas_data_.new_area_meta = mt::SafeArea::GetById(pre_area_id + 1);
gas_data_.gas_progress = gas_data_.old_area_meta->rad();
gas_data_.gas_start_frameno = GetFrameNo();
gas_data_.pos_old = pre_pos;
gas_data_.pos_old_bk = gas_data_.pos_old;
{
bool gen_ok = GenSmallCircle();
if (!gen_ok) {
A8_ABORT();
}
}
gas_data_.rad_old = gas_data_.old_area_meta->rad();
gas_data_.rad_new = gas_data_.new_area_meta->rad();
gas_data_.gas_count++;
--n;
}
if (gas_data_.old_area_meta) {
auto boss_tuple = gas_data_.old_area_meta->GetBoss();
if (boss_tuple && !IsGameOver()) {
const mt::Hero* hero_meta = mt::Hero::GetById(std::get<2>(*boss_tuple));
if (hero_meta) {
int boss_uniid = AllocUniid();
NotifyNewsTicker
(2,
{
a8::XValue(boss_uniid).GetString(),
a8::XValue(hero_meta->id()).GetString(),
a8::XValue(std::get<0>(*boss_tuple).x).GetString(),
a8::XValue(std::get<0>(*boss_tuple).y).GetString(),
a8::XValue(std::get<0>(*boss_tuple).z).GetString(),
a8::XValue(std::get<1>(*boss_tuple)).GetString(),
});
xtimer.SetTimeoutEx
(SERVER_FRAME_RATE * std::get<1>(*boss_tuple),
[this, boss_tuple, hero_meta, boss_uniid] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
Hero* hero = CreateHero
(nullptr,
hero_meta,
std::get<0>(*boss_tuple),
GlmHelper::UP,
666,
boss_uniid);
if (hero) {
batch_sync_->AddGlobalObject(hero);
hero->GetTrigger()->AddListener
(
kDieEvent,
[this, boss_uniid] (const a8::Args& args) mutable
{
if (!IsGameOver()) {
batch_sync_->RemoveGlobalObject(boss_uniid);
NotifyKillList({boss_uniid});
}
});
}
}
},
&xtimer_attacher_);
}
}
}
}
void Room::GetPartObjectWatchList(Entity* entity, std::vector<Human*>& watch_list)
{
TraverseHumanList
(
[&watch_list, entity] (Human* hum) -> bool
{
if (hum->InPartObjects(entity)) {
watch_list.push_back(hum);
}
return true;
});
}
void Room::SetInfiniteBulletMode()
{
infinite_bullet_mode_ = true;
for (auto& pair : accountid_hash_) {
pair.second->SetInfiniteBulletMode();
}
}
void Room::AddToPostBattleAutoFreeList(a8::XTimerWp timer)
{
if (BattleStarted()) {
A8_ABORT();
}
if (timer.expired()) {
A8_ABORT();
}
post_battle_auto_free_list_.push_back(timer);
}
void Room::ClearPostBattleAutoFreeList()
{
size_t i = 0;
while (i < post_battle_auto_free_list_.size()) {
auto timer = post_battle_auto_free_list_[i];
if (!timer.expired()) {
xtimer.Delete(timer);
}
++i;
}
post_battle_auto_free_list_.clear();
}
void Room::OnBattleStart()
{
battle_start_frameno_ = GetFrameNo();
if (IsMobaModeRoom()) {
++battle_start_frameno_;
}
battle_starting_ = true;
std::vector<EntityWeakPtr> entitys;
entitys.reserve(uniid_hash_.size());
for (auto& pair : uniid_hash_) {
entitys.push_back(pair.second->GetEntityWeakPtrRef());
}
for (auto& e : entitys) {
if (e.Get()) {
e.Get()->OnBattleStart(this);
}
}
TraverseHumanList
(
[this] (Human* ele_hum) -> bool
{
++battle_human_count_;
return true;
});
TraversePlayerList
(
[this] (Player* ele_hum) -> bool
{
++battle_player_count_;
return true;
});
TraverseTeams
(
[this] (Team* ele_team) -> bool
{
++battle_team_count_;
return true;
});
if (!IsMobaModeRoom() && !IsSandTableRoom()) {
std::vector<std::shared_ptr<BornPoint>> born_point_list;
born_point_list.reserve(born_point_hash_.size());
for (auto& pair : born_point_hash_) {
pair.second->player_num = 0;
pair.second->android_num = 0;
born_point_list.push_back(pair.second);
}
if (born_point_list.empty()) {
A8_ABORT();
}
std::shuffle(born_point_list.begin(),
born_point_list.end(),
std::default_random_engine(a8::XGetTickCount()));
size_t cur_point_idx = 0;
TraverseTeams
(
[this, &born_point_list, &cur_point_idx] (Team* ele_team) mutable -> bool
{
if (cur_point_idx >= born_point_list.size()) {
cur_point_idx = 0;
}
auto point = born_point_list.at(cur_point_idx++);
ele_team->TraverseMembers
(
[point] (Human* hum) -> bool
{
if (hum->IsPlayer()) {
point->player_num++;
} else {
point->android_num++;
}
App::Instance()->verify_set_pos = 1;
hum->SetBornPoint(point);
hum->SetPos(hum->GetBornPoint()->NewRandPoint(hum->room, 10, 100));
App::Instance()->verify_set_pos = 0;
return true;
});
return true;
});
}
battle_starting_ = false;
SendSMTeamFull(nullptr);
GetBoxDrop()->OnBattleStart();
}
bool Room::CanAddObstacle(const glm::vec3& pos, int obstacle_id)
{
const mt::MapThing* thing_meta = mt::MapThing::GetById(obstacle_id);
if (!thing_meta) {
return false;
}
int rad = std::max(thing_meta->width(), thing_meta->height());
return map_service->CanAdd(pos, rad);
}
bool Room::IsDestoryRoom()
{
return GetMapMeta()->map_id() == 1002;
}
bool Room::IsSurvivalRoom()
{
return GetMapMeta()->map_id() == 1003;
}
void Room::OnEnterNewWave(int wave)
{
if (IsDestoryRoom() && wave > 0 && wave < pve_mode_meta->_area.size()) {
gas_data_.SetGasMode(GasWaiting);
gas_data_.gas_start_frameno = GetFrameNo();
gas_data_.old_area_meta = pve_mode_meta->_area[wave];
gas_data_.new_area_meta = pve_mode_meta->_area[wave];
gas_data_.gas_start_frameno = GetFrameNo();
gas_data_.pos_new = glm::vec2(gas_data_.new_area_meta->x1(),
gas_data_.new_area_meta->y1());
gas_data_.pos_old = gas_data_.pos_new;
gas_data_.pos_old_bk = gas_data_.pos_old;
gas_data_.rad_old = gas_data_.old_area_meta->rad();
gas_data_.rad_new = gas_data_.new_area_meta->rad();
gas_data_.gas_progress = 0;
}
NotifyUiUpdate();
#ifdef MYDEBUG
a8::XPrintf("OnEnternerWave:%d\n", {wave});
#endif
}
bool Room::IsAllRealDead()
{
bool is_all_dead = true;
TraverseHumanList
(
[&is_all_dead] (Human* hum)
{
if (!hum->real_dead) {
is_all_dead = false;
return false;
}
return true;
}
);
return is_all_dead;
}
void Room::AddTask(int task_uniid, std::shared_ptr<a8::CommonCbProcEx> cb)
{
if (task_hash_.find(task_uniid) != task_hash_.end()) {
abort();
}
task_hash_[task_uniid] = cb;
}
void Room::RemoveTask(int task_uniid)
{
task_hash_.erase(task_uniid);
}
void Room::AutoJump()
{
int auto_jump_min_num = mt::Param::GetIntParam("auto_jump_min_num");
int auto_jump_max_num = mt::Param::GetIntParam("auto_jump_max_num");
int jump_num = a8::RandEx(auto_jump_min_num, auto_jump_max_num);
if (GlmHelper::Norm(last_player_jump_pos - plane.curr_pos)< 64 * 8) {
jump_num = 1 + rand() % 2;
}
for (int i = 0; i < jump_num; ++i) {
TraverseHumanList
(
[] (Human* hum) -> bool
{
if (hum->HasBuffEffect(kBET_Fly) &&
hum->GetEntitySubType() != EST_Player) {
hum->DoJump();
return false;
}
return true;
});
}
}
int Room::GetPolyExtFlag(int poly_idx)
{
if (poly_idx >=0 && poly_idx < poly_ext_datas_.size()) {
return poly_ext_datas_.at(poly_idx);
}
return 0;
}
void Room::CreateWorldObjects()
{
if (IsPveRoom()) {
int uniid = AllocUniid();
std::shared_ptr<BornPoint> born_point = std::make_shared<BornPoint>();
std::shared_ptr<mt::WorldObject> wo_meta = std::make_shared<mt::WorldObject>();
wo_meta->pos = pve_instance->_spawn_point;
born_point->wo_meta = wo_meta;
born_point_hash_[uniid] = born_point;
return;
}
for (auto& itr : GetMapMeta()->_world_objects) {
std::shared_ptr<mt::WorldObject> obj = itr;
switch ((WorldObjectType_e)obj->object_type) {
case WorldObjectType_e::kLootType:
{
CreateLoot
(
obj->object_id,
obj->pos,
obj->pos,
1,
1,
true);
}
break;
case WorldObjectType_e::kBoxType:
{
CreateObstacle
(
obj->object_id,
obj->pos.x,
obj->pos.y,
obj->pos.z,
std::make_shared<a8::Args>(std::vector<std::any>({obj}))
);
}
break;
case WorldObjectType_e::kCarType:
{
const mt::Equip* equip_meta = mt::Equip::GetById(obj->object_id);
if (equip_meta) {
int car_uniid = AllocUniid();
glm::vec3 pos = obj->pos - obj->size / 2.0f;
Car* c = CreateCar(nullptr,
car_uniid,
equip_meta,
pos,
0,
nullptr);
if (c) {
CarObject car;
car.car_id = equip_meta->id();
car.pos = c->GetPos().ToGlmVec3();
car_hash_[c->GetUniId()] = car;
}
}
}
break;
case WorldObjectType_e::kMonsterType:
{
const mt::Hero* hero_meta = mt::Hero::GetById(obj->object_id);
if (hero_meta) {
glm::vec3 pos = obj->pos - obj->size / 2.0f;
Hero* hero = CreateHero
(nullptr,
hero_meta,
pos,
GlmHelper::UP,
666,
0);
}
}
break;
case WorldObjectType_e::kBornPointType:
{
int uniid = AllocUniid();
std::shared_ptr<BornPoint> born_point = std::make_shared<BornPoint>();
born_point->wo_meta = obj;
born_point_hash_[uniid] = born_point;
}
break;
default:
{
abort();
}
break;
}
}
for (auto& itr : GetMapMeta()->_group_world_objects) {
int ikey = itr.first;
auto objects = itr.second;
std::shuffle(objects.begin(), objects.end(), std::default_random_engine(a8::XGetTickCount()));
const mt::MapThingGroup* group_meta = mt::MapThingGroup::GetById(ikey);
if (group_meta) {
int i = 0;
for (auto& tuple : *group_meta->GetItems()) {
if (i < objects.size()) {
switch (std::get<0>(tuple)) {
case 1:
{
const mt::Equip* equip_meta = mt::Equip::GetById(std::get<1>(tuple));
if (equip_meta) {
CreateLoot
(
std::get<1>(tuple),
objects[i]->pos,
objects[i]->pos,
1,
1
);
} else {
const mt::MapThing* thing_meta = mt::MapThing::GetById(std::get<1>(tuple));
if (thing_meta) {
if (thing_meta->thing_type() == 16) {
for (int drop_id : thing_meta->RandDrop()) {
ScatterDrop(objects[i]->pos, drop_id);
}
} else {
CreateObstacle
(
std::get<1>(tuple),
objects[i]->pos.x,
objects[i]->pos.y,
objects[i]->pos.z
);
}
}
}
}
break;
case 2:
{
#ifdef MYDEBUG1
#else
const mt::Hero* hero_meta = mt::Hero::GetById(std::get<1>(tuple));
if (hero_meta) {
Position hero_pos;
hero_pos.FromGlmVec3(objects[i]->pos);
int team_id = 666;
Creature* master = nullptr;
glm::vec3 dir = GlmHelper::UP;
Hero* hero = CreateHero(master,
hero_meta,
hero_pos.ToGlmVec3(),
dir,
team_id);
}
#endif
}
break;
default:
{
}
break;
} //end switch
}
++i;
}
}
}
if (born_point_hash_.size() < GetRoomMaxPlayerNum() / 4) {
while (born_point_hash_.size() < GetRoomMaxPlayerNum() / 4) {
int uniid = AllocUniid();
std::shared_ptr<BornPoint> born_point = std::make_shared<BornPoint>();
std::shared_ptr<mt::WorldObject> wo_meta = std::make_shared<mt::WorldObject>();
wo_meta->pos.x = (60 + rand() % ((int)GetMapMeta()->map_width() - 100));
wo_meta->pos.y = 6.250846862793;
wo_meta->pos.z = (60 + rand() % ((int)GetMapMeta()->map_height() - 100));
born_point->wo_meta = wo_meta;
born_point_hash_[uniid] = born_point;
}
}
}
Team* Room::GetTeam(int team_id)
{
auto itr = team_hash_.find(team_id);
return itr != team_hash_.end() ? itr->second.get() : nullptr;
}
Creature* Room::GetCreatureByUniId(int uniid)
{
Entity* e = GetEntityByUniId(uniid);
return e && e->IsCreature(this) ? (Creature*)e : nullptr;
}
bool Room::RandomSafeAreaPoint(glm::vec3& point)
{
glm::vec3 dir = GlmHelper::UP;
GlmHelper::RotateY(dir, a8::RandAngle());
float rnd_rad = rand() % std::max(GetGasData().new_area_meta->rad(), 100);
glm::vec2 center = GetGasData().pos_new + glm::vec2(dir.x, dir.z) * (100.f + rnd_rad);
point = glm::vec3(center.x, 0.0f, center.y);
return true;
}
bool Room::FindWalkablePointWithOutHouse(const glm::vec3& center, int try_count, int step, glm::vec3& out_point)
{
glm::vec3 ref_point = center;
map_instance->PtInHouse(center, ref_point);
map_instance->Scale(ref_point);
glm::vec3 point;
bool ok = false;
for (int i = 0; i < try_count; ++i) {
ok = map_instance->FindNearestPoint(ref_point, 1.0f + step * i, point);
if (ok) {
break;
}
}
if (!ok) {
return false;
}
map_instance->UnScale(point);
out_point = point;
return true;
}
void Room::AddReportBullet(int bullet_uniid)
{
report_bullet_hash[bullet_uniid] = GetFrameNo();
xtimer.SetTimeoutEx
(
SERVER_FRAME_RATE * 10,
[this, bullet_uniid] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
report_bullet_hash.erase(bullet_uniid);
Entity* entity = GetEntityByUniId(bullet_uniid);
if (entity && entity->GetEntityType() == ET_Bullet) {
Bullet* bullet = (Bullet*)entity;
bullet->ForceRemove();
}
}
},
&xtimer_attacher_);
}
int Room::GetReportRoomMode()
{
if (IsPveRoom()) {
return 1;
} else if (IsMobaModeRoom()){
return 2;
} else {
return 0;
}
}
int Room::GetPvpMatchMode()
{
return GetRoomMode() == kPvpRankMode ? 1 : 0;
}
void Room::ForceOver()
{
if (added_to_over_room) {
return;
}
std::vector<Team*> alive_teams;
TraverseTeams
(
[&alive_teams] (Team* team)
{
if (team->HasAliveMember()) {
alive_teams.push_back(team);
}
team->HasPlayer();
return true;
});
std::sort(alive_teams.begin(), alive_teams.end(),
[] (Team* a, Team *b) -> bool
{
if (a->HasPlayer() && b->HasPlayer()) {
return a->GetTeamId() < b->GetTeamId();
}
if (a->HasPlayer()) {
return true;
}
if (b->HasPlayer()) {
return false;
}
return a->GetTeamId() < b->GetTeamId();
});
for (Team* team : alive_teams) {
team->TraverseMembers
(
[] (Human* member)
{
if (!member->dead) {
member->BeKill(VP_Gas,
TEXT("battle_server_killer_gas", "毒圈"),
VW_Gas,
VP_Gas,
TEXT("battle_server_killer_gas", "毒圈"));
}
return true;
});
}
force_over_ = true;
GameLog::Instance()->ForceOver(this);
xtimer.SetTimeoutEx
(SERVER_FRAME_RATE * 5,
[this] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
if (!game_over_) {
game_over_ = true;
game_over_frameno_ = GetFrameNo();
OnGameOver();
}
}
},
&xtimer_attacher_);
}
bool Room::SupportSandTable()
{
return !IsMobaModeRoom() && map_meta_->support_sandtable();
}
void Room::OnAddHuman(Human* hum)
{
if (IsSandTableRoom()) {
hum->TryAddBuff(hum, kThroughWall_BUFFID);
}
}
bool Room::IsSandTableRoom()
{
return !IsPveRoom() &&
SupportSandTable();
}
bool Room::HasRoomSwitch(int tag)
{
return a8::HasBitFlag(room_switch_, tag);
}
void Room::OpenRoomSwitch(int tag)
{
a8::SetBitFlag(room_switch_, tag);
}
void Room::CloseRoomSwitch(int tag)
{
a8::UnSetBitFlag(room_switch_, tag);
}
void Room::GMFastForward()
{
while (GetGasData().new_area_meta->GetSmallRingCount() >= 3) {
ForwardGasRing(1);
}
TraversePlayerList
(
[this] (Player* hum) -> bool
{
glm::vec3 src_point = glm::vec3(GetGasData().new_area_meta->GetLastArea()->x1(),
6.0f,
GetGasData().new_area_meta->GetLastArea()->y1());
{
glm::vec3 center = src_point;
map_instance->Scale(center);
glm::vec3 point;
bool ok = false;
for (int i = 0; i < 10; ++i) {
ok = map_instance->FindConnectableNearestPoint(center, 1.0f + 10 * i, point);
if (ok) {
break;
}
}
if (ok) {
map_instance->UnScale(point);
hum->GetMutablePos().FromGlmVec3(point);
grid_service->MoveCreature(hum);
}
}
return true;
});
GetIncubator()->Clear(5);
TraverseHumanList
(
[] (Human* ele_hum) -> bool
{
if (ele_hum->IsAndroid() &&
!a8::HasBitFlag(ele_hum->status, CS_Disable)) {
Human* hum = ele_hum;
hum->BeKill(VP_Gas,
TEXT("battle_server_killer_gas", "毒圈"),
VW_Gas,
VP_Gas,
TEXT("battle_server_killer_gas", "毒圈"));
}
return true;
});
xtimer.SetTimeoutEx
(
1,
[this] (int event, const a8::Args* args)
{
if (a8::TIMER_EXEC_EVENT == event) {
GetIncubator()->ShowHand();
}
},
&xtimer_attacher_);
}
void Room::LockRoom()
{
lock_room_ = true;
lock_room_frameno_ = GetFrameNo();
}
bool Room::BulletCanReach(const glm::vec3& start, const glm::vec3& end)
{
glm::vec3 a_start = start;
glm::vec3 a_end = end;
glm::vec3 hit_point;
bool hit_result = false;
map_instance->Scale(a_start);
map_instance->Scale(a_end);
if (map_instance->Raycast(a_start,
a_end,
hit_point,
hit_result,
map_instance->GetBulletIncludeFlags(),
map_instance->GetBulletExcludeFlags())) {
if (!hit_result) {
return true;
}
}
return false;
}
bool Room::MoveCanReach(const glm::vec3& start, const glm::vec3& end)
{
glm::vec3 a_start = start;
glm::vec3 a_end = end;
glm::vec3 hit_point;
bool hit_result = false;
map_instance->Scale(a_start);
map_instance->Scale(a_end);
if (map_instance->Raycast(a_start,
a_end,
hit_point,
hit_result,
map_instance->GetMoveIncludeFlags(),
map_instance->GetMoveExcludeFlags())) {
if (!hit_result) {
return true;
}
}
return false;
}
bool Room::IsPvpMasterRankModeRoom()
{
return rank_match_conf_ && rank_match_conf_->room_type == RoomType_MasterRank;
}
int Room::GetMaxTeamNum()
{
return MAX_TEAM_NUM;
}
bool Room::IsMiniMap()
{
return map_instance->map_id == 2002;
}
bool Room::IsNewerMap()
{
return map_instance->map_id == 2003;
}
int Room::GetMobaLeftTime()
{
if (moba_over_timer.expired()) {
return 0;
}
long long remain_time = xtimer.GetRemainTime(moba_over_timer);
return (remain_time * FRAME_RATE_MS);
}
Team* Room::GetMobaEnemyTeam(Team* self_team)
{
if (self_team == GetMobaTeamA()) {
return GetMobaTeamB();
} else {
return GetMobaTeamA();
}
}
std::shared_ptr<RoomOb> Room::GetRoomOb()
{
return ob_;
}
void Room::IncAliveCount()
{
++alive_count_;
alive_count_chged_frameno_ = GetFrameNo();
++PerfMonitor::Instance()->alive_count;
}
void Room::DecAliveCount()
{
--alive_count_;
alive_count_chged_frameno_ = GetFrameNo();
--PerfMonitor::Instance()->alive_count;
}
bool Room::CanJoin(std::shared_ptr<CustomBattle> p)
{
if (p->IsMoba()) {
return false;
}
if (!p->IsNormalMode()) {
return false;
}
if (p->GetTeamNum() > 1) {
return false;
}
if (p->GetTeamNum() < 1) {
return false;
}
if (lock_room_) {
return false;
}
if (IsCustomBattle()) {
return false;
}
if (IsMobaModeRoom()) {
return false;
}
if (room_mode_ != p->GetRoomMode()) {
return false;
}
if (GetGasData().GetGasMode() != GasInactive) {
return false;
}
if (map_meta_->map_id() != p->GetMapId()) {
return false;
}
if (GetMapModeMeta() != p->GetMapModeMeta()) {
return false;
}
auto p_team = p->GetTeamByIdx(0);
if (GetPlayerNum() + p_team->GetMemberNum() > GetRoomMaxPlayerNum()) {
return false;
}
int try_count = 0;
while (GetHumanNum() + p_team->GetMemberNum() > GetRoomMaxPlayerNum() &&
try_count < 100) {
++try_count;
RandRemoveAndroid();
}
return GetHumanNum() + p_team->GetMemberNum() <= GetRoomMaxPlayerNum();
}
void Room::MobaBatterysUpdate()
{
for (int i = 0; i < GetMapMeta()->GetMobaRoomMeta()->moba_batterys.size(); ++i) {
auto& tuple = GetMapMeta()->GetMobaRoomMeta()->moba_batterys.at(i);
int side = i + 1;
glm::vec3 center = std::get<0>(tuple);
CreatureWeakPtr target;
float last_distance = 0;
TraverseHumanList
(
[side, &target, &center, &tuple, &last_distance] (Human* hum) -> bool
{
if (hum->side != side &&
!hum->dead &&
!a8::HasBitFlag(hum->status, CS_Disable) &&
!hum->HasBuffEffect(kBET_Hide) &&
!hum->HasBuffEffect(kBET_Dive) &&
!hum->HasBuffEffect(kBET_Invincible)
) {
float distance = hum->GetPos().Distance2D2(center);
if (distance < std::get<1>(tuple)) {
if (!target.Get() || distance < last_distance) {
target = hum->GetWeakPtrRef();
last_distance = distance;
}
}
}
return true;
});
if (!target.Get() ||
(target.Get() && last_distance <= 0.000001f)) {
continue;
}
glm::vec3 bullet_dir = target.Get()->GetPos().ToGlmVec3() - center;
GlmHelper::Normalize(bullet_dir);
const mt::Equip* weapon_meta = mt::Equip::GetById(std::get<2>(tuple));
if (!weapon_meta) {
#ifdef MYDEBUG
abort();
#endif
continue;
}
glm::vec3 bullet_born_pos = std::get<0>(tuple);
int bullet_uniid = AllocUniid();
int shot_uniid = 0;
frame_event.AddBullet
(bullet_uniid,
target,
weapon_meta,
1,
bullet_born_pos,
bullet_dir,
last_distance,
target.Get()->GetUniId(),
0,
nullptr,
shot_uniid,
-1);
float fly_time = last_distance / weapon_meta->bullet_speed();
fly_time = 0.1;
xtimer.SetTimeoutWpEx
(
fly_time * SERVER_FRAME_RATE,
[this, target_pos = target.Get()->GetPos().ToGlmVec3(), side, weapon_meta, target]
(int event, const a8::Args* args) mutable
{
if (a8::TIMER_EXEC_EVENT == event) {
#if 1
if (target.Get() &&
target.Get()->IsHuman() &&
!target.Get()->dead) {
target.Get()->AsHuman()->BeKill
(
VP_Tower,
"",
VW_Tower,
VP_Tower,
""
);
}
#else
TraverseHumanList
(
[this, side, target_pos, weapon_meta] (Human* hum) -> bool
{
if (hum->side != side &&
!hum->dead &&
!a8::HasBitFlag(hum->status, CS_Disable) &&
!hum->HasBuffEffect(kBET_Hide) &&
!hum->HasBuffEffect(kBET_Dive) &&
!hum->HasBuffEffect(kBET_Invincible)
) {
if (hum->GetPos().Distance2D2(target_pos) < weapon_meta->bullet_rad()) {
hum->BeKill(
VP_Explosion,
"",
weapon_meta->id(),
VP_Explosion,
""
);
}
}
return true;
});
#endif
}
},
&xtimer_attacher_);
#ifdef MYDEBUG
a8::XPrintf("MobaBatterysUpdate fly_distance:%f fly_time:%f speed:%f\n",
{last_distance,
fly_time,
weapon_meta->bullet_speed()});
#endif
}
}
int Room::GetReportMapMode()
{
return GetMapModeMeta()->mapMode();
}
void Room::GenBattleRoomReportData(a8::MutableXObject* params)
{
params->SetVal("version", 2023030201);
params->SetVal("room_uuid", a8::XValue(GetRoomUuid()));
params->SetVal("room_mode", GetReportRoomMode());
params->SetVal("map_mode", GetReportMapMode());
params->SetVal("map_id", GetMapMeta()->map_id());
auto teams_pb = a8::MutableXObject::CreateArray();
TraverseTeams
(
[&teams_pb] (Team* team) -> bool
{
auto team_pb = a8::MutableXObject::CreateObject();
team->GenRoomReportData(team_pb.get());
teams_pb->Push(*team_pb);
return true;
}
);
params->SetVal("team_list", *teams_pb);
}
void Room::GenBattleMobaReportData(a8::MutableXObject* params)
{
params->SetVal("version", 2023030201);
params->SetVal("room_uuid", a8::XValue(GetRoomUuid()));
params->SetVal("room_mode", GetReportRoomMode());
params->SetVal("map_mode", GetReportMapMode());
params->SetVal("map_id", GetMapMeta()->map_id());
auto teams_pb = a8::MutableXObject::CreateArray();
TraverseTeams
(
[&teams_pb] (Team* team) -> bool
{
auto team_pb = a8::MutableXObject::CreateObject();
team->GenBattleReportData(team_pb.get());
teams_pb->Push(*team_pb);
return true;
}
);
params->SetVal("team_list", *teams_pb);
}
void Room::StartOverTimer()
{
int param1 = 1;
xtimer.SetIntervalEx
(
SERVER_FRAME_RATE * 6,
[this, param1] (int event, const a8::Args* args) mutable
{
if (a8::TIMER_EXEC_EVENT == event) {
if (GetOnlinePlayerNum() <= 0 && !added_to_over_room) {
RoomMgr::Instance()->AddOverRoom(room_uuid_);
xtimer.DeleteCurrentTimer();
return;
}
#ifdef MYDEBUG
if (param1 > 10) {
#else
if (param1 > 5) {
#endif
RoomMgr::Instance()->AddOverRoom(room_uuid_);
}
TraverseHumanList
(
[] (Human* ele_hum) -> bool
{
ele_hum->SendGameOver();
return true;
});
++param1;
}
},
&xtimer_attacher_);
}
void Room::TryRoomReport(int try_count)
{
if (sending_room_report_battle_) {
return;
}
if (already_room_report_battle_) {
return;;
}
sending_room_report_battle_ = true;
Player* player = nullptr;
TraversePlayerList
(
[&player] (Player* hum) -> bool
{
player = hum;
return true;
});
if (!player) {
return;
}
std::string url;
JsonDataMgr::Instance()->GetApiUrl(url);
std::shared_ptr<a8::MutableXObject> params = a8::MutableXObject::CreateObject();
std::shared_ptr<a8::MutableXObject> post_data = a8::MutableXObject::CreateObject();
GenBattleRoomReportData(post_data.get());
params->SetVal("c", "Battle");
params->SetVal("a", "roomReport");
params->SetVal("account_id", player->account_id);
params->SetVal("session_id", player->session_id);
std::string content = post_data->ToJsonStr();
HttpProxy::Instance()->HttpPost
(
[room_uuid = GetRoomUuid()]
(bool ok, a8::XObject* rsp_obj, f8::HttpContext* ctx)
{
auto room = RoomMgr::Instance()->GetRoomByUuid(room_uuid);
if (room) {
room->already_room_report_battle_ = true;
room->sending_room_report_battle_ = false;
room->TraverseHumanList
(
[] (Human* ele_hum) -> bool
{
ele_hum->SendGameOver();
return true;
});
room->StartOverTimer();
}
},
url,
params,
content
);
GetBoxDrop()->RequestReturnBoxNum();
#ifdef MYDEBUG
a8::XPrintf("RoomReportLen:%d\n", {params->ToJsonStr().size()});
#endif
}
bool Room::IsNoPlane()
{
return true;
}
void Room::CalcMvp()
{
float param0 = mt::Param::s().battle_score_param0;
float param1 = mt::Param::s().battle_score_param1;
float max_kill = 0;
float max_assist = 0;
float max_damage = 0.0f;
float max_recover = 0.0f;
float max_level = 0;
float max_alive = 0;
TraverseHumanList
(
[this, &max_kill, &max_assist, &max_damage, &max_recover, &max_level, &max_alive]
(Human* hum) mutable -> bool
{
#if 1
max_kill = std::max(max_kill, (float)hum->stats->kills);
max_assist = std::max(max_assist, (float)hum->stats->assist);
max_damage = std::max(max_damage, (float)hum->stats->damage_amount_out);
max_recover = std::max(max_recover, (float)hum->stats->heal_amount);
max_level = std::max(max_level, (float)hum->GetHeroLevel());
max_alive = std::max(max_alive, (float)hum->stats->alive_time / 1000);
#else
max_kill += hum->stats->kills;
max_assist += hum->stats->assist;
max_damage += hum->stats->damage_amount_out;
max_recover += hum->stats->heal_amount;
max_level += hum->GetHeroLevel();
max_alive += hum->stats->alive_time / 1000;
#endif
return true;
});
TraverseHumanList
(
[this, max_kill, max_assist, max_damage, max_recover, max_level, max_alive, param0, param1]
(Human* hum) -> bool
{
float kill_sco = param0;
{
if (max_kill > 0) {
float kill = hum->stats->kills;
kill_sco = (param1 - param0) / (max_kill - 0) * (kill - 0) + param0;
}
}
float assist_sco = param0;
{
if (max_assist > 0) {
float assist = hum->stats->assist;
assist_sco = (param1 - param0) / (max_assist - 0) * (assist - 0) + param0;
}
}
float damage_sco = param0;
{
if (max_damage > 0) {
float damage = hum->stats->damage_amount_out;
damage_sco = (param1 - param0) / (max_damage - 0) * (damage - 0) + param0;
}
}
float recover_sco = param0;
{
if (max_recover > 0) {
float recover = hum->stats->heal_amount;
recover_sco = (param1 - param0) / (max_recover - 0) * (recover - 0) + param0;
}
}
float level_sco = param0;
{
if (max_level > 1.00000) {
float level = hum->GetHeroLevel();
level_sco = (param1 - param0) / (max_level - 0) * (level - 0) + param0;
}
}
float alive_sco = param0;
{
if (max_alive > 0) {
float alive = hum->stats->alive_time / 1000;
alive_sco = (param1 - param0) / (max_alive - 0) * (alive - 0) + param0;
}
}
#ifdef MYDEBUG
if (hum->IsPlayer()) {
a8::XPrintf("kill_sco:%f assist_sco:%f damage_sco:%f recover_sco:%f alive_sco:%f "
"assist:%f max_assist:%f damage:%f max_damage:%f recover:%f max_recover:%f "
"level:%d max_level:%d""\n",
{
kill_sco,
assist_sco,
damage_sco,
recover_sco,
alive_sco,
hum->stats->assist,
max_assist,
hum->stats->damage_amount_out,
max_damage,
hum->stats->heal_amount,
max_recover,
hum->GetHeroLevel(),
max_level
});
}
#endif
float battle_score = 0.0f;
if (IsMobaModeRoom()) {
if (mt::Param::s().performance_score_weight_4V4.size() >= 5) {
kill_sco *= mt::Param::s().performance_score_weight_4V4.at(0);
assist_sco *= mt::Param::s().performance_score_weight_4V4.at(1);
damage_sco *= mt::Param::s().performance_score_weight_4V4.at(2);
recover_sco *= mt::Param::s().performance_score_weight_4V4.at(3);
level_sco *= mt::Param::s().performance_score_weight_4V4.at(4);
}
battle_score = std::round((kill_sco + assist_sco + damage_sco + recover_sco + level_sco) * 100.0f) / 100.0f;
} else {
if (mt::Param::s().performance_score_weight_BR.size() >= 5) {
kill_sco *= mt::Param::s().performance_score_weight_BR.at(0);
assist_sco *= mt::Param::s().performance_score_weight_BR.at(1);
damage_sco *= mt::Param::s().performance_score_weight_BR.at(2);
recover_sco *= mt::Param::s().performance_score_weight_BR.at(3);
alive_sco *= mt::Param::s().performance_score_weight_BR.at(4);
}
battle_score = std::round((kill_sco + assist_sco + damage_sco + recover_sco + alive_sco) * 100.0f) / 100.0f;
}
#ifdef MYDEBUG
if (hum->IsPlayer()) {
a8::XPrintf("battle_score:%f\n",
{
battle_score
});
}
#endif
hum->stats->battle_score = battle_score;
return true;
});
}
void Room::MobaOver()
{
if (!IsGameOver() && !GetVictoryTeam()) {
game_over_ = true;
game_over_frameno_ = GetFrameNo();
if (GetMobaTeamA()->GetKillCount() == GetMobaTeamB()->GetKillCount()) {
if (GetMobaTeamA()->GetLastKillFrameNo() == GetMobaTeamB()->GetLastKillFrameNo()) {
if (GetMobaTeamA()->GetTeamId() < GetMobaTeamA()->GetTeamId()) {
SetVictoryTeam(GetMobaTeamA());
} else {
SetVictoryTeam(GetMobaTeamB());
}
} else if (GetMobaTeamA()->GetLastKillFrameNo() >
GetMobaTeamB()->GetLastKillFrameNo()) {
SetVictoryTeam(GetMobaTeamA());
} else {
SetVictoryTeam(GetMobaTeamB());
}
} if (GetMobaTeamA()->GetKillCount() > GetMobaTeamB()->GetKillCount()) {
SetVictoryTeam(GetMobaTeamA());
} else {
SetVictoryTeam(GetMobaTeamB());
}
if (GetVictoryTeam() == GetMobaTeamA()) {
GetInGameVoice()->Victory(GetMobaTeamA());
GetInGameVoice()->Fail(GetMobaTeamB());
} else {
GetInGameVoice()->Victory(GetMobaTeamB());
GetInGameVoice()->Fail(GetMobaTeamA());
}
OnGameOver();
}
}
void Room::SetNewBieBattle(int is_newbie_battle)
{
is_newbie_battle_ = is_newbie_battle;
}