aozhiwei 8c45440808 1
2019-11-25 14:27:54 +08:00

848 lines
27 KiB
C++

#include "precompile.h"
#include <float.h>
#include <a8/mutable_xobject.h>
#include <a8/collision.h>
#include "human.h"
#include "cs_proto.pb.h"
#include "metamgr.h"
#include "room.h"
#include "collider.h"
#include "loot.h"
#include "app.h"
#include "roommgr.h"
#include "android.h"
#include "gamelog.h"
#include "typeconvert.h"
#include "player.h"
#include "framework/cpp/utils.h"
#include "framework/cpp/httpclientpool.h"
const int kReviveTimeAdd = 3;
Human::Human():Entity()
{
}
Human::~Human()
{
}
void Human::Initialize()
{
Entity::Initialize();
CreateSnake();
RecalcSelfCollider();
observers_.insert(this);
}
void Human::FillMFObjectPart(cs::MFObjectPart* part_data)
{
part_data->set_object_type(ET_Player);
cs::MFPlayerPart* p = part_data->mutable_union_obj_1();
p->set_obj_uniid(entity_uniid);
FillMFSnake(p->mutable_snake());
}
void Human::FillMFObjectFull(cs::MFObjectFull* full_data)
{
full_data->set_object_type(ET_Player);
cs::MFPlayerFull* p = full_data->mutable_union_obj_1();
p->set_obj_uniid(entity_uniid);
FillMFSnake(p->mutable_snake());
p->set_dead(dead);
p->set_disconnected(disconnected);
p->set_kill_count(stats.kills);
if (dead) {
p->set_killer_name(stats.killer_name);
p->set_killer_id(stats.killer_id);
if (real_dead){
p->set_can_revive(false);
} else {
p->set_can_revive(true);
int countdown = std::ceil(room->xtimer.GetRemainTime(revive_timer) / SERVER_FRAME_RATE);
countdown = std::max(0, countdown - kReviveTimeAdd);
p->set_revive_countdown(countdown);
}
}
}
void Human::FillMFPlayerStats(cs::MFPlayerStats* stats_pb)
{
stats_pb->set_player_id(entity_uniid);
stats_pb->set_player_avatar_url(avatar_url);
if (!dead) {
stats_pb->set_time_alive(room->frame_no * 1000.0f / SERVER_FRAME_RATE);
} else {
stats_pb->set_time_alive(dead_frameno * 1000.0f / SERVER_FRAME_RATE);
}
stats_pb->set_kills(stats.kills);
stats_pb->set_damage_amount(stats.damage_amount_out);
stats_pb->set_heal_amount(stats.heal_amount);
stats_pb->set_history_time_alive(stats.history_time_alive);
stats_pb->set_history_kills(stats.history_kills);
stats_pb->set_history_damage_amount(stats.history_damage_amount);
stats_pb->set_history_heal_amount(stats.history_heal_amount);
stats_pb->set_gold(stats.gold);
stats_pb->set_score(stats.score);
stats_pb->set_pass_score(stats.pass_score);
stats_pb->set_rank_score(stats.rank_score);
stats_pb->set_has_pass(has_pass);
stats_pb->set_dead(dead);
stats_pb->set_killer_id(stats.killer_id);
stats_pb->set_killer_name(stats.killer_name);
{
Player* killer = room->GetPlayerByUniId(stats.killer_id);
if (killer) {
stats_pb->set_killer_avatar_url(killer->avatar_url);
stats_pb->set_killer_account_id(killer->account_id);
} else {
stats_pb->set_killer_avatar_url("");
stats_pb->set_killer_account_id("");
}
}
stats_pb->set_account_id(account_id);
for (auto& pair : stats.extra_drop) {
auto p = stats_pb->add_extra_drop();
p->set_key(pair.first);
p->set_value(pair.second);
}
}
void Human::GetAabbBox(AabbCollider& aabb_box)
{
abort();
#if 0
aabb_box.active = true;
aabb_box.owner = this;
aabb_box._min.x = -meta->p->radius();
aabb_box._min.y = -meta->p->radius();
aabb_box._max.x = meta->p->radius();
aabb_box._max.y = meta->p->radius();
#endif
}
void Human::FillMFTeamData(cs::MFTeamData* team_data)
{
#if 1
{
#else
if (room->gas_data.gas_mode == GasJump ||
room->frame_no - last_sync_teamdata_frameno_ > SERVER_FRAME_RATE * 2) {
#endif
last_sync_teamdata_frameno_ = room->frame_no;
team_data->set_player_id(entity_uniid);
team_data->set_name(name);
TypeConvert::ToPb(pos, team_data->mutable_pos());
team_data->set_disconnected(false);
team_data->set_dead(dead);
}
}
void Human::RecalcSelfCollider()
{
#if 0
if (!self_collider_) {
self_collider_ = new CircleCollider();
self_collider_->owner = this;
AddCollider(self_collider_);
}
self_collider_->pos = a8::Vec2();
self_collider_->rad = meta->p->radius();
#endif
}
void Human::SyncAroundPlayers(const char* file, int line, const char* func)
{
for (auto& cell : grid_list) {
for (Human* hum : cell->human_list) {
hum->AddToNewObjects(this);
assert(hum->part_objects.find(this) != hum->part_objects.end());
if (hum->part_objects.find(this) == hum->part_objects.end()) {
if (a8::XGetTickCount() - room->last_debugout_tick > 1000 * 10) {
room->last_debugout_tick = a8::XGetTickCount();
a8::UdpLog::Instance()->Warning("SyncAroundPlayers error file:%s line:%d func:%s",
{
file,
line,
func
});
}
}
}
}
}
void Human::FillSMGameOver(cs::SMGameOver& msg)
{
if (stats.rank <= 0) {
std::vector<Human*> human_list;
room->TouchHumanList(a8::XParams(),
[&human_list] (Human* hum, a8::XParams& param) -> bool
{
if (hum->leave_frameno_ == 0 ||
hum->leave_frameno_ > hum->room->battle_start_frameno_) {
human_list.push_back(hum);
}
return true;
});
std::sort(human_list.begin(), human_list.end(),
[] (Human* a, Human* b )
{
if (a->dead_frameno == b->dead_frameno) {
return a->entity_uniid < b->entity_uniid;
} else {
return a->dead_frameno == 0 ||
(b->dead_frameno != 0 && a->dead_frameno > b->dead_frameno);
}
});
int rank = human_list.size();
for (size_t i = 0; i < human_list.size(); ++i) {
if (human_list[i] == this) {
rank = i + 1;
break;
}
}
if (room->GetAliveTeamNum() == 1) {
std::set<Human*>* alive_team = room->GetAliveTeam();
if (alive_team == team_members) {
rank = 1;
}
}
stats.rank = rank;
}
msg.set_team_id(team_id);
msg.set_team_rank(stats.rank);
msg.set_team_allcnt(1);
msg.set_game_over(room->game_over);
msg.set_victory(!dead);
msg.set_room_uuid(a8::XValue(room->room_uuid));
cs::MFPlayerStats* p = msg.add_player_stats();
FillMFPlayerStats(p);
}
void Human::BeKill(int killer_id, const std::string& killer_name)
{
}
void Human::AddToNewObjects(Entity* entity)
{
new_objects.insert(entity);
}
void Human::AddToPartObjects(Entity* entity)
{
part_objects.insert(entity);
}
void Human::RemovePartObjects(Entity* entity)
{
part_objects.erase(entity);
}
void Human::RemoveObjects(Entity* entity)
{
del_objects.insert(entity->entity_uniid);
}
void Human::AddOutObjects(Entity* entity)
{
out_objects.insert(entity->entity_uniid);
}
void Human::RemoveOutObjects(Entity* entity)
{
out_objects.erase(entity->entity_uniid);
}
bool Human::HasLiveTeammate()
{
if (team_members) {
for (auto& hum : *team_members) {
if (hum != this && !hum->dead) {
return true;
}
}
}
return false;
}
void Human::RefreshView()
{
for (auto& cell : grid_list) {
for (Human* hum : cell->human_list) {
hum->AddToNewObjects(this);
hum->AddToPartObjects(this);
AddToNewObjects(hum);
AddToPartObjects(hum);
}
for (Entity* entity : cell->entity_list) {
switch (entity->entity_type) {
case ET_Loot:
{
AddToNewObjects(entity);
}
break;
default:
{
}
break;
}
}
}
}
void Human::OnGridListChange(std::set<GridCell*>& old_grid_list,
std::set<GridCell*>& inc_grid_list,
std::set<GridCell*>& dec_grid_list
)
{
for (GridCell* cell : inc_grid_list) {
for (Human* hum : cell->human_list) {
if (!room->grid_service.HumanInGridList(hum, old_grid_list)) {
hum->AddToNewObjects(this);
hum->AddToPartObjects(this);
hum->RemoveOutObjects(this);
AddToNewObjects(hum);
AddToPartObjects(hum);
RemoveOutObjects(hum);
}
}
for (Entity* entity : cell->entity_list) {
if (!room->grid_service.EntityInGridList(entity, old_grid_list)) {
switch (entity->entity_type) {
case ET_Loot:
{
AddToNewObjects(entity);
RemoveOutObjects(entity);
}
break;
default:
{
}
break;
}
}
}
}
for (GridCell* cell : dec_grid_list) {
for (Human* hum : cell->human_list) {
if (!room->grid_service.HumanInGridList(hum, grid_list)) {
AddOutObjects(hum);
hum->AddOutObjects(this);
}
}
for (Entity* entity : cell->entity_list) {
if (!room->grid_service.EntityInGridList(entity, grid_list)) {
switch (entity->entity_type) {
case ET_Loot:
{
AddOutObjects(entity);
}
break;
default:
{
}
break;
}
}
}
}
}
void Human::FillMFActivePlayerData(cs::MFActivePlayerData* player_data)
{
}
void Human::FillMFGasData(cs::MFGasData* gas_data)
{
gas_data->set_mode(room->gas_data.gas_mode);
if (room->gas_data.gas_mode == GasInactive) {
long long duration = MetaMgr::Instance()->gas_inactive_time * SERVER_FRAME_RATE -
(room->frame_no - room->gas_data.gas_start_frameno);
gas_data->set_duration(std::max(duration * 50, (long long)1000) / 1000);
}
}
bool Human::CanSee(const Human* hum) const
{
return room->grid_service.InView(grid_id, hum->grid_id);
}
void Human::RecalcAttr()
{
}
void Human::RecalcBuff()
{
buff = HumanAbility();
}
void Human::AddObserver(Human* observer)
{
observers_.insert(observer);
}
void Human::RemoveObserver(Human* observer)
{
observers_.erase(observer);
}
void Human::SendUpdateMsg()
{
if (!follow_target_) {
cs::MFActivePlayerData* active_player_data_pb = nullptr;
if (send_msg_times == 0 || need_sync_active_player) {
active_player_data_pb = new cs::MFActivePlayerData();
FillMFActivePlayerData(active_player_data_pb);
need_sync_active_player = false;
}
cs::SMUpdate* msg = room->frame_maker.MakeUpdateMsg(this);
if (send_msg_times == 0 || last_sync_gas_frameno < room->gas_data.gas_start_frameno) {
last_sync_gas_frameno = room->gas_data.gas_start_frameno;
}
bool refreshed_view = false;
std::set<Entity*> view_objects;
for (Human* observer : observers_) {
msg->clear_team_data();
if (observer->team_members) {
for (auto& itr : *observer->team_members) {
if (itr != observer) {
itr->FillMFTeamData(msg->add_team_data());
}
}
}
if (observer != this && !observer->follow_synced_active_player) {
msg->set_active_player_id(entity_uniid);
FillMFActivePlayerData(msg->mutable_active_player_data());
if (!refreshed_view) {
for (auto& cell : grid_list) {
for (Human* hum : cell->human_list) {
view_objects.insert(hum);
}
for (Entity* entity : cell->entity_list) {
switch (entity->entity_type) {
case ET_Loot:
{
view_objects.insert(entity);
}
break;
default:
{
}
break;
}
}
}
for (Entity* entity : view_objects) {
if (new_objects.find(entity) == new_objects.end()) {
entity->FillMFObjectFull(msg->add_full_objects());
}
}
refreshed_view = true;
}
observer->follow_synced_active_player = true;
} else {
if (active_player_data_pb) {
msg->set_active_player_id(entity_uniid);
*msg->mutable_active_player_data() = *active_player_data_pb;
} else {
msg->clear_active_player_id();
msg->clear_active_player_data();
}
}
observer->SendNotifyMsg(*msg);
}
delete msg;
if (active_player_data_pb) {
delete active_player_data_pb;
}
++send_msg_times;
}
ClearFrameData();
}
void Human::SendGameOver()
{
if (entity_subtype == EST_Player) {
//!!!必须要在SendNotifyMsg之前注意哦
if (!sent_battlereport_) {
SendBattleReport();
sent_battlereport_ = true;
GameLog::Instance()->GameEnd((Player*)this);
}
{
cs::SMGameOver msg;
FillSMGameOver(msg);
SendNotifyMsg(msg);
}
}
}
void Human::FollowTarget(Human* target)
{
if (target == this) {
return;
}
if (follow_target_) {
follow_target_->RemoveObserver(this);
}
target->AddObserver(this);
follow_target_ = target;
follow_synced_active_player = false;
}
void Human::SendDebugMsg(const std::string& debug_msg)
{
cs::SMDebugMsg notify_msg;
notify_msg.set_debug_msg(debug_msg);
SendNotifyMsg(notify_msg);
}
void Human::SendRollMsg(const std::string& roll_msg)
{
room->xtimer.AddDeadLineTimerAndAttach(
0,
a8::XParams()
.SetSender(this)
.SetParam1(roll_msg),
[] (const a8::XParams& param)
{
Human* target = (Human*)param.sender.GetUserData();
std::string roll_msg = param.param1;
target->room->TouchHumanList(a8::XParams(),
[target, roll_msg] (Human* hum, a8::XParams& param) -> bool
{
if (target != hum) {
cs::SMRollMsg msg;
msg.set_msg(roll_msg);
hum->SendNotifyMsg(msg);
}
return true;
});
},
&xtimer_attacher.timer_list_
);
}
void Human::SendUIUpdate()
{
cs::SMUiUpdate notifymsg;
notifymsg.set_alive_count(room->AliveCount());
notifymsg.set_kill_count(stats.kills);
room->FillSMUiUpdate(notifymsg);
SendNotifyMsg(notifymsg);
}
void Human::SendWxVoip()
{
cs::SMWxVoip notifymsg;
if (!team_uuid.empty()) {
notifymsg.set_group_id(a8::XValue(room->room_uuid).GetString() + "_" + a8::XValue(team_id).GetString());
}
SendNotifyMsg(notifymsg);
}
void Human::_UpdateMove(int speed)
{
a8::Vec2 pre_node_pos = head_->pos;
SnakeBodyNode* pre_node = head_;
float node_dist = 2 * head_->radius * (1 - meta->p->body_interval());
{
a8::Vec2 old_pos = head_->pos;
head_->pos = head_->pos + move_dir * head_->speed;
}
{
for (auto& node : body_list) {
a8::Vec2 new_pos = (pre_node_pos + node->pos) / 2;
a8::Vec2 dist_vec = pre_node->pos - new_pos;
float move_dist = dist_vec.Norm() - node_dist;
pre_node_pos = node->pos;
if (std::abs(move_dist) > 0.00001f) {
a8::Vec2 dist_dir= dist_vec;
dist_dir.Normalize();
node->pos = new_pos + dist_dir * (move_dist / dist_vec.Norm());
} else {
node->pos = new_pos;
}
pre_node = node;
}
}
}
void Human::ClearFrameData()
{
if (!new_objects.empty()) {
new_objects.clear();
}
if (!del_objects.empty()) {
for (auto& itr : del_objects) {
Entity* entity = room->GetEntityByUniId(itr);
if (entity) {
RemovePartObjects(entity);
}
}
del_objects.clear();
}
if (!out_objects.empty()) {
for (auto& itr : out_objects) {
Entity* entity = room->GetEntityByUniId(itr);
if (entity) {
RemovePartObjects(entity);
}
}
out_objects.clear();
}
if (!emotes_.empty()) {
emotes_.clear();
}
}
void Human::GenBattleReportData(a8::MutableXObject* params)
{
int rank = 0;
{
std::vector<Human*> human_list;
room->TouchHumanList(a8::XParams(),
[&human_list] (Human* hum, a8::XParams& param) -> bool
{
human_list.push_back(hum);
return true;
});
std::sort(human_list.begin(), human_list.end(),
[] (Human* a, Human* b )
{
if (a->dead_frameno == b->dead_frameno) {
return a->entity_uniid < b->entity_uniid;
} else {
return a->dead_frameno == 0 ||
(b->dead_frameno != 0 && a->dead_frameno > b->dead_frameno);
}
});
rank = human_list.size();
for (size_t i = 0; i < human_list.size(); ++i) {
if (human_list[i] == this) {
rank = i + 1;
break;
}
}
if (room->GetAliveTeamNum() == 1) {
std::set<Human*>* alive_team = room->GetAliveTeam();
if (alive_team == team_members) {
rank = 1;
}
}
}
stats.rank = rank;
params->SetVal("account_id", account_id);
params->SetVal("map_id", room->map_meta->p->map_id());
params->SetVal("map_name", room->map_meta->p->map_name());
params->SetVal("map_tpl_name", room->map_tpl_name);
params->SetVal("game_time", time(nullptr));
params->SetVal("hurt", stats.damage_amount_in);
params->SetVal("rank", rank);
params->SetVal("kills", stats.kills);
params->SetVal("harm", stats.damage_amount_out);
params->SetVal("add_HP", stats.heal_amount);
if (!dead) {
params->SetVal("alive_time", room->frame_no * 1000.0f / SERVER_FRAME_RATE);
} else {
params->SetVal("alive_time", dead_frameno * 1000.0f / SERVER_FRAME_RATE);
}
params->SetVal("team_status", team_members && team_members->size() > 1 ? 1 : 0);
params->SetVal("room_uuid", room->room_uuid);
int snipe_kill = 0;
int rifle_kill = 0;
int pistol_kill = 0;
int submachine_kill = 0;
params->SetVal("snipe_kill", snipe_kill);
params->SetVal("rifle_kill", rifle_kill);
params->SetVal("pistol_kill", pistol_kill);
params->SetVal("submachine_kill", submachine_kill);
params->SetVal("rescue_member", stats.rescue_member);
{
float rank_param = MetaMgr::Instance()->GetRankRewardParam(rank);
float kill_param = MetaMgr::Instance()->GetKillRewardParam(stats.kills);
int coin_num = (rank_param * MetaMgr::Instance()->rank_param) +
(kill_param * MetaMgr::Instance()->kill_param);
stats.gold = coin_num;
params->SetVal("coin_num", coin_num);
}
{
stats.pass_score = MetaMgr::Instance()->GetKillPointParam1(stats.kills);
stats.pass_score += MetaMgr::Instance()->GetRankPointParam1(rank);
stats.rank_score = MetaMgr::Instance()->GetKillPointParam2(stats.kills);
stats.rank_score += MetaMgr::Instance()->GetRankPointParam2(rank);
}
params->SetVal("score", 0);
params->SetVal("pass_score", has_pass ? stats.pass_score * 2 : stats.pass_score);
params->SetVal("rank_score", stats.rank_score);
}
void Human::SendBattleReport()
{
a8::MutableXObject* params = a8::MutableXObject::NewObject();
GenBattleReportData(params);
auto on_ok = [] (a8::XParams& param, a8::XObject& data)
{
};
auto on_error = [] (a8::XParams& param, const std::string& response)
{
a8::UdpLog::Instance()->Error("battleReport http error params: %s response: %s",
{
param.param2,
response
});
};
std::string url;
if (!f8::IsOnlineEnv()) {
if (App::Instance()->HasFlag(3)) {
url = "http://192.168.100.41/webapp/index.php?c=Role&a=battleReport";
} else {
url = "https://game2009api-test.kingsome.cn/webapp/index.php?c=Role&a=battleReport";
}
} else {
#if 1
url = "http://game2009api.kingsome.cn/webapp/index.php?c=Role&a=battleReport";
#else
url = "https://game2009api.kingsome.cn/webapp/index.php?c=Role&a=battleReport";
#endif
}
std::string data;
params->ToUrlEncodeStr(data);
f8::HttpClientPool::Instance()->HttpGet(
a8::XParams()
.SetSender(room->room_uuid)
.SetParam1(entity_uniid)
.SetParam2(data),
on_ok,
on_error,
url.c_str(),
*params,
MAX_SYS_HTTP_NUM + (entity_uniid % MAX_USER_HTTP_NUM)
);
delete params;
}
void Human::OnDie()
{
room->OnHumanDie(this);
SyncAroundPlayers(__FILE__, __LINE__, __func__);
{
std::set<Human*> over_humans;
if (!leave_) {
if (team_members) {
for (auto& member : *team_members) {
if (member->real_dead) {
over_humans.insert(member);
}
}
} else {
over_humans.insert(this);
}
}
if (room->GetAliveTeamNum() == 1) {
std::set<Human*>* alive_team = room->GetAliveTeam();
if (alive_team) {
for (Human* member : *alive_team) {
over_humans.insert(member);
}
}
}
for (Human* hum : over_humans) {
hum->SendGameOver();
}
}
}
void Human::Revive()
{
auto callback =
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
hum->dead = true;
hum->real_dead = true;
hum->OnDie();
};
int wait_revive_time = MetaMgr::Instance()->GetSysParamAsInt("revive_time", 25 + kReviveTimeAdd);
revive_timer = room->xtimer.AddDeadLineTimerAndAttach(SERVER_FRAME_RATE * wait_revive_time,
a8::XParams()
.SetSender(this),
callback,
&xtimer_attacher.timer_list_,
[] (const a8::XParams& param)
{
Human* hum = (Human*)param.sender.GetUserData();
hum->revive_timer = nullptr;
});
SyncAroundPlayers(__FILE__, __LINE__, __func__);
}
void Human::CreateSnake()
{
a8::Vec2 init_pos;
room->GenSnakeBornPos(init_pos);
head_ = new SnakeBodyNode();
head_->node_id = ++curr_node_id_;
head_->speed = meta->p->speed_normal();
head_->radius = meta->p->init_radius();
head_->pos = init_pos;
//head_->dir = meta->p->init_radius();
a8::Vec2 node_pos = init_pos;
SnakeBodyNode* pre_node = head_;
for (int i = 0; i < meta->p->init_body_size(); ++i) {
node_pos.y -= (1 - meta->p->body_interval()) * meta->p->init_radius();
SnakeBodyNode* node = new SnakeBodyNode();
node->node_id = ++curr_node_id_;
node->pre_node = pre_node;
node->speed = meta->p->speed_normal();
node->radius = meta->p->init_radius();
node->pos = node_pos;
body_list.push_back(node);
pre_node = node;
}
tail_ = pre_node;
}
void Human::FillMFSnake(cs::MFSnake* snake_pb)
{
{
cs::MFSnakeHead* head_pb = snake_pb->mutable_snake_head();
TypeConvert::ToPb(head_->pos, head_pb->mutable_pos());
TypeConvert::ToPb(head_->dir, head_pb->mutable_dir());
head_pb->set_radius(head_->radius);
head_pb->set_speed(head_->speed);
}
{
for (auto& body : body_list) {
TypeConvert::ToPb(
body->pos,
snake_pb->add_snake_body()->mutable_pos()
);
}
}
}