1024 lines
37 KiB
C++
1024 lines
37 KiB
C++
#include "precompile.h"
|
|
|
|
#include <random>
|
|
|
|
#include <a8/mutable_xobject.h>
|
|
#include <a8/timer.h>
|
|
#include <a8/udplog.h>
|
|
|
|
#include "playermgr.h"
|
|
#include "player.h"
|
|
#include "cs_proto.pb.h"
|
|
#include "room.h"
|
|
#include "android.h"
|
|
#include "metamgr.h"
|
|
#include "bullet.h"
|
|
#include "collider.h"
|
|
#include "obstacle.h"
|
|
#include "building.h"
|
|
#include "loot.h"
|
|
#include "collision.h"
|
|
#include "roommgr.h"
|
|
#include "app.h"
|
|
|
|
const int ROOM_MAX_PLAYER_NUM = 50;
|
|
#if 0
|
|
const int ANDROID_NUM = 0;
|
|
#else
|
|
const int ANDROID_NUM = 10;
|
|
#endif
|
|
|
|
static long long RoomXGetTickCount(void* context)
|
|
{
|
|
Room* room = (Room*)context;
|
|
return room->frame_no;
|
|
}
|
|
|
|
Room::~Room()
|
|
{
|
|
|
|
}
|
|
|
|
void Room::Init()
|
|
{
|
|
xtimer.Init(RoomXGetTickCount, this, 100, 100);
|
|
xtimer_attacher.xtimer = &xtimer;
|
|
|
|
ShuaAndroid();
|
|
CreateThings();
|
|
stats_timer_ = a8::Timer::Instance()->AddRepeatTimer(
|
|
1000 * 5,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
if (!room->game_over) {
|
|
room->OutputDebugLog();
|
|
}
|
|
}
|
|
);
|
|
if (App::Instance()->flags.find(1) != App::Instance()->flags.end()) {
|
|
xtimer.AddDeadLineTimerAndAttach(SERVER_FRAME_RATE * 3,
|
|
a8::XParams()
|
|
.SetSender(this),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
room->AutoMatchTeam();
|
|
},
|
|
&xtimer_attacher.timer_list_);
|
|
}
|
|
InitAirDrop();
|
|
}
|
|
|
|
void Room::UnInit()
|
|
{
|
|
xtimer_attacher.ClearTimerList();
|
|
if (!stats_timer_) {
|
|
a8::Timer::Instance()->DeleteTimer(stats_timer_);
|
|
stats_timer_ = nullptr;
|
|
}
|
|
}
|
|
|
|
void Room::Update(int delta_time)
|
|
{
|
|
long long begin_tick = a8::XGetTickCount();
|
|
elapsed_time_ += delta_time;
|
|
while (elapsed_time_ >= 50) {
|
|
xtimer.Update();
|
|
if (frame_no % 2 == 0) {
|
|
ResetFrameData();
|
|
UpdateGas();
|
|
}
|
|
for (auto& pair : moveable_hash_) {
|
|
if (pair.second->entity_type == ET_Player &&
|
|
pair.second->updated_times <= 0) {
|
|
if (frame_no % 2 == 0) {
|
|
pair.second->Update(50);
|
|
pair.second->updated_times++;
|
|
}
|
|
} else {
|
|
pair.second->Update(50);
|
|
pair.second->updated_times++;
|
|
}
|
|
}
|
|
if (frame_no % 2 == 0) {
|
|
for (auto& pair : accountid_hash_) {
|
|
pair.second->SendUpdateMsg();
|
|
}
|
|
ClearDeletedObjects();
|
|
ProcAddedObjects();
|
|
{
|
|
{
|
|
std::vector<long long> del_ids;
|
|
for (auto& pair : frame_data.deleted_objects_hash) {
|
|
if (pair.first <= frame_no) {
|
|
del_ids.push_back(pair.first);
|
|
}
|
|
}
|
|
for (long long id : del_ids) {
|
|
frame_data.deleted_objects_hash.erase(id);
|
|
}
|
|
}
|
|
{
|
|
std::vector<long long> del_ids;
|
|
for (auto& pair : frame_data.softdeleted_objects_hash) {
|
|
if (pair.first <= frame_no) {
|
|
del_ids.push_back(pair.first);
|
|
}
|
|
}
|
|
for (long long id : del_ids) {
|
|
frame_data.softdeleted_objects_hash.erase(id);
|
|
}
|
|
}
|
|
{
|
|
std::vector<long long> del_ids;
|
|
for (auto& pair : frame_data.bullets_hash) {
|
|
if (pair.first <= frame_no) {
|
|
del_ids.push_back(pair.first);
|
|
}
|
|
}
|
|
for (long long id : del_ids) {
|
|
frame_data.bullets_hash.erase(id);
|
|
}
|
|
}
|
|
{
|
|
std::vector<long long> del_ids;
|
|
for (auto& pair : frame_data.shots_hash) {
|
|
if (pair.first <= frame_no) {
|
|
del_ids.push_back(pair.first);
|
|
}
|
|
}
|
|
for (long long id : del_ids) {
|
|
frame_data.shots_hash.erase(id);
|
|
}
|
|
}
|
|
{
|
|
std::vector<long long> del_ids;
|
|
for (auto& pair : frame_data.explosions_hash) {
|
|
if (pair.first <= frame_no) {
|
|
del_ids.push_back(pair.first);
|
|
}
|
|
}
|
|
for (long long id : del_ids) {
|
|
frame_data.explosions_hash.erase(id);
|
|
}
|
|
}
|
|
{
|
|
std::vector<long long> del_ids;
|
|
for (auto& pair : frame_data.smokes_hash) {
|
|
if (pair.first <= frame_no) {
|
|
del_ids.push_back(pair.first);
|
|
}
|
|
}
|
|
for (long long id : del_ids) {
|
|
frame_data.smokes_hash.erase(id);
|
|
}
|
|
}
|
|
{
|
|
std::vector<long long> del_ids;
|
|
for (auto& pair : frame_data.emotes_hash) {
|
|
if (pair.first <= frame_no) {
|
|
del_ids.push_back(pair.first);
|
|
}
|
|
}
|
|
for (long long id : del_ids) {
|
|
frame_data.emotes_hash.erase(id);
|
|
}
|
|
}
|
|
{
|
|
std::vector<long long> del_ids;
|
|
for (auto& pair : frame_data.airdrops_hash) {
|
|
if (pair.first <= frame_no) {
|
|
del_ids.push_back(pair.first);
|
|
}
|
|
}
|
|
for (long long id : del_ids) {
|
|
frame_data.airdrops_hash.erase(id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
++frame_no;
|
|
elapsed_time_ -= 50;
|
|
}
|
|
long long end_tick = a8::XGetTickCount();
|
|
if (end_tick - begin_tick > profile.max_rundelay) {
|
|
profile.max_rundelay = end_tick - begin_tick;
|
|
}
|
|
}
|
|
|
|
bool Room::IsFull()
|
|
{
|
|
return accountid_hash_.size() >= ROOM_MAX_PLAYER_NUM;
|
|
}
|
|
|
|
int Room::GetPlayerNum()
|
|
{
|
|
return accountid_hash_.size();
|
|
}
|
|
|
|
Player* Room::GetPlayerByAccountId(const std::string& accountid)
|
|
{
|
|
auto itr = accountid_hash_.find(accountid);
|
|
return itr != accountid_hash_.end() ? itr->second : nullptr;
|
|
}
|
|
|
|
Player* Room::GetPlayerByUniId(unsigned short uniid)
|
|
{
|
|
Entity* entity = GetEntityByUniId(uniid);
|
|
return entity->entity_type == ET_Player && entity->entity_subtype == EST_Player ? (Player*)entity : nullptr;
|
|
}
|
|
|
|
Entity* Room::GetEntityByUniId(unsigned short uniid)
|
|
{
|
|
auto itr = uniid_hash_.find(uniid);
|
|
return itr != uniid_hash_.end() ? itr->second : nullptr;
|
|
}
|
|
|
|
int Room::AliveCount()
|
|
{
|
|
return alive_count_;
|
|
}
|
|
|
|
void Room::AddPlayer(Player* hum)
|
|
{
|
|
{
|
|
hum->pos.x = 3000 + rand() % 100;
|
|
hum->pos.y = 3000 + rand() % 200;
|
|
hum->attack_dir = hum->pos;
|
|
hum->attack_dir.Normalize();
|
|
hum->attack_dir.Rotate(a8::RandAngle());
|
|
hum->move_dir = hum->attack_dir;
|
|
}
|
|
hum->entity_uniid = AllocUniid();
|
|
hum->room = this;
|
|
hum->join_frameno = frame_no;
|
|
hum->Initialize();
|
|
uniid_hash_[hum->entity_uniid] = hum;
|
|
moveable_hash_[hum->entity_uniid] = hum;
|
|
accountid_hash_[hum->account_id] = hum;
|
|
human_hash_[hum->entity_uniid] = hum;
|
|
++alive_count_;
|
|
hum->AddToNewObjects(hum);
|
|
hum->AddToPartObjects(hum);
|
|
for (auto& pair : human_hash_) {
|
|
if (pair.second != hum) {
|
|
pair.second->AddToNewObjects(hum);
|
|
pair.second->AddToPartObjects(hum);
|
|
hum->AddToNewObjects(pair.second);
|
|
hum->AddToPartObjects(pair.second);
|
|
}
|
|
}
|
|
for (auto& pair : uniid_hash_) {
|
|
switch (pair.second->entity_type) {
|
|
case ET_Building:
|
|
case ET_Obstacle:
|
|
{
|
|
hum->AddToNewObjects(pair.second);
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned short Room::AllocUniid()
|
|
{
|
|
while (GetEntityByUniId(++current_uniid) ||
|
|
be_added_hash_.find(current_uniid) != be_added_hash_.end() ||
|
|
current_uniid == 0) {}
|
|
return current_uniid;
|
|
}
|
|
|
|
void Room::ShuaAndroid()
|
|
{
|
|
MetaData::Player* hum_meta = MetaMgr::Instance()->GetPlayer(40002);
|
|
assert(hum_meta);
|
|
if (!hum_meta) {
|
|
abort();
|
|
}
|
|
for (int i = 0; i < ANDROID_NUM; ++i) {
|
|
Android* hum = new Android();
|
|
hum->name = a8::Format("机器人%d", {i+1});
|
|
hum->meta = hum_meta;
|
|
hum->entity_uniid = AllocUniid();
|
|
{
|
|
hum->pos.x = 3000 + rand() % 400;
|
|
hum->pos.y = 3000 + rand() % 500;
|
|
hum->attack_dir = hum->pos;
|
|
hum->attack_dir.Normalize();
|
|
hum->attack_dir.Rotate(a8::RandAngle());
|
|
hum->move_dir = hum->attack_dir;
|
|
}
|
|
hum->room = this;
|
|
hum->Initialize();
|
|
uniid_hash_[hum->entity_uniid] = hum;
|
|
moveable_hash_[hum->entity_uniid] = hum;
|
|
human_hash_[hum->entity_uniid] = hum;
|
|
++alive_count_;
|
|
|
|
for (auto& pair : human_hash_) {
|
|
if (pair.second != hum) {
|
|
pair.second->AddToNewObjects(hum);
|
|
pair.second->AddToPartObjects(hum);
|
|
hum->AddToNewObjects(pair.second);
|
|
hum->AddToPartObjects(pair.second);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Human* Room::FindEnemy(Human* hum)
|
|
{
|
|
std::vector<Human*> enemys;
|
|
enemys.reserve(50);
|
|
for (auto& pair : accountid_hash_) {
|
|
if (pair.second->team_id == 0 ||
|
|
pair.second->team_id != hum->team_id
|
|
) {
|
|
enemys.push_back(pair.second);
|
|
}
|
|
}
|
|
std::sort(enemys.begin(), enemys.end(),
|
|
[hum] (Human* a, Human *b) -> bool
|
|
{
|
|
return (hum->pos - a->pos).Norm() < (hum->pos - b->pos).Norm();
|
|
});
|
|
return !enemys.empty() ? enemys[0] : nullptr;
|
|
}
|
|
|
|
void Room::CollisionDetection(Entity* sender, int detection_flags, std::vector<Entity*>& objects)
|
|
{
|
|
assert(uniid_hash_.size() < 1000);
|
|
for (auto& pair : uniid_hash_) {
|
|
if (a8::HasBitFlag(detection_flags, ET_Player) && pair.second->entity_type == ET_Player) {
|
|
if (sender->entity_type == ET_Bullet) {
|
|
Bullet* bullet = (Bullet*)sender;
|
|
Human* hum = (Human*)pair.second;
|
|
if (hum != bullet->player &&
|
|
(hum->team_id == 0 || bullet->player->team_id != hum->team_id)) {
|
|
if (bullet->TestCollision(hum)) {
|
|
objects.push_back(hum);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (a8::HasBitFlag(detection_flags, ET_Obstacle) && pair.second->entity_type == ET_Obstacle) {
|
|
if (sender->entity_type == ET_Bullet || sender->entity_type == ET_Player) {
|
|
if (pair.second != sender &&
|
|
(sender->last_collision_door == nullptr || sender->last_collision_door != pair.second) &&
|
|
sender->TestCollision(pair.second)) {
|
|
objects.push_back(pair.second);
|
|
}
|
|
}
|
|
}
|
|
if (a8::HasBitFlag(detection_flags, ET_Building) && pair.second->entity_type == ET_Building) {
|
|
if (sender->entity_type == ET_Bullet || sender->entity_type == ET_Player) {
|
|
if (pair.second != sender && sender->TestCollision(pair.second)) {
|
|
objects.push_back(pair.second);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::AddDeletedObject(unsigned short obj_uniid, bool soft_delete)
|
|
{
|
|
std::set<unsigned short>* deleted_objects = nullptr;
|
|
if (soft_delete) {
|
|
auto itr = frame_data.softdeleted_objects_hash.find(frame_no);
|
|
if (itr == frame_data.softdeleted_objects_hash.end()) {
|
|
frame_data.softdeleted_objects_hash[frame_no] = std::set<unsigned short>();
|
|
itr = frame_data.softdeleted_objects_hash.find(frame_no);
|
|
}
|
|
deleted_objects = &itr->second;
|
|
} else {
|
|
auto itr = frame_data.deleted_objects_hash.find(frame_no);
|
|
if (itr == frame_data.deleted_objects_hash.end()) {
|
|
frame_data.deleted_objects_hash[frame_no] = std::set<unsigned short>();
|
|
itr = frame_data.deleted_objects_hash.find(frame_no);
|
|
}
|
|
deleted_objects = &itr->second;
|
|
}
|
|
deleted_objects->insert(obj_uniid);
|
|
}
|
|
|
|
void Room::FillSMJoinedNotify(Player* self_hum, cs::SMJoinedNotify& msg)
|
|
{
|
|
msg.set_team_mode(msg.team_mode());
|
|
msg.set_player_id(self_hum->entity_uniid);
|
|
msg.set_started(false);
|
|
for (auto& pair : uniid_hash_) {
|
|
if (pair.second->entity_type == ET_Player) {
|
|
Human* hum = (Human*)pair.second;
|
|
cs::MFPlayerInfo* info = msg.add_player_infos();
|
|
info->set_player_id(hum->entity_uniid);
|
|
info->set_team_id(hum->team_id);
|
|
info->set_name(hum->name);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::ResetFrameData()
|
|
{
|
|
}
|
|
|
|
void Room::ScatterDrop(Vector2D center, int drop_id)
|
|
{
|
|
MetaData::Drop* drop_meta = MetaMgr::Instance()->GetDrop(drop_id);
|
|
if (drop_meta) {
|
|
std::vector<std::tuple<int, int>> drop_items;
|
|
drop_meta->RandItems(drop_items);
|
|
for (auto& item : drop_items) {
|
|
Vector2D dir = Vector2D::UP;
|
|
dir.Rotate(a8::RandAngle());
|
|
DropItem(center + dir * (5 + rand() % 50), std::get<0>(item), std::get<1>(item));
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::CreateThings()
|
|
{
|
|
std::string tpl_name = map_meta->RandTemplate();
|
|
std::vector<MetaData::MapTplThing>* things = MetaMgr::Instance()->GetMapTplThing(tpl_name);
|
|
if (things) {
|
|
for (auto& thing_tpl : *things) {
|
|
if (thing_tpl.i->weight() >= rand() % 10000) {
|
|
int thing_id = thing_tpl.RandThing();
|
|
MetaData::MapThing* thing_meta = MetaMgr::Instance()->GetMapThing(thing_id);
|
|
if (thing_meta) {
|
|
if (thing_meta->i->is_house()) {
|
|
MetaData::Building* building_meta = MetaMgr::Instance()->GetBuilding(thing_meta->i->house_id());
|
|
if (building_meta) {
|
|
Building* entity = new Building();
|
|
entity->room = this;
|
|
entity->meta = building_meta;
|
|
entity->building_id = thing_id;
|
|
entity->entity_uniid = AllocUniid();
|
|
entity->pos = Vector2D(thing_tpl.i->x(), thing_tpl.i->y());
|
|
entity->Initialize();
|
|
uniid_hash_[entity->entity_uniid] = entity;
|
|
}
|
|
} else {
|
|
Obstacle* entity = new Obstacle();
|
|
entity->room = this;
|
|
entity->meta = thing_meta;
|
|
entity->entity_uniid = AllocUniid();
|
|
entity->pos = Vector2D(thing_tpl.i->x(), thing_tpl.i->y());
|
|
entity->Initialize();
|
|
uniid_hash_[entity->entity_uniid] = entity;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::FillSMMapInfo(cs::SMMapInfo& map_info)
|
|
{
|
|
for (auto& pair :uniid_hash_) {
|
|
switch (pair.second->entity_type) {
|
|
case ET_Obstacle:
|
|
{
|
|
Obstacle* entity = (Obstacle*)pair.second;
|
|
if (!entity->building) {
|
|
cs::MFMapObject* p = map_info.add_objects();
|
|
p->set_object_id(entity->meta->i->thing_id());
|
|
entity->pos.ToPB(p->mutable_pos());
|
|
}
|
|
}
|
|
break;
|
|
case ET_Building:
|
|
{
|
|
Building* entity = (Building*)pair.second;
|
|
cs::MFMapObject* p = map_info.add_objects();
|
|
p->set_object_id(entity->building_id);
|
|
entity->pos.ToPB(p->mutable_pos());
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::DropItem(Vector2D pos, int item_id, int item_count)
|
|
{
|
|
MetaData::Equip* equip_meta = MetaMgr::Instance()->GetEquip(item_id);
|
|
if (equip_meta) {
|
|
Loot* entity = new Loot();
|
|
entity->room = this;
|
|
entity->meta = equip_meta;
|
|
entity->entity_uniid = AllocUniid();
|
|
{
|
|
Vector2D dir = Vector2D::UP;
|
|
dir.Rotate(a8::RandAngle());
|
|
entity->pos = pos + dir * (25 + rand() % 50);
|
|
}
|
|
entity->item_id = equip_meta->i->id();
|
|
entity->count = item_count;
|
|
entity->Initialize();
|
|
uniid_hash_[entity->entity_uniid] = entity;
|
|
for (auto& pair : human_hash_) {
|
|
pair.second->AddToNewObjects(entity);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::CreateDoor(Building* building, int door_idx)
|
|
{
|
|
if (door_idx >= 0 && door_idx < building->meta->doors.size()) {
|
|
MetaData::Building::Door* door_meta = &building->meta->doors[door_idx];
|
|
MetaData::MapThing* thing = MetaMgr::Instance()->GetMapThing(61701);
|
|
if (thing) {
|
|
Obstacle* entity = new Obstacle();
|
|
entity->room = this;
|
|
entity->meta = thing;
|
|
entity->entity_uniid = AllocUniid();
|
|
entity->is_door = true;
|
|
entity->door_id = door_meta->door_id;
|
|
entity->door_state = DoorStateClose;
|
|
entity->building = building;
|
|
entity->door_house_uniid = building->entity_uniid;
|
|
entity->door_state0 = door_meta->state0;
|
|
entity->door_state1 = door_meta->state1;
|
|
entity->pos = Vector2D(building->pos.x + entity->door_state0->x() - building->meta->i->tilewidth() / 2.0,
|
|
building->pos.y + entity->door_state0->y() - building->meta->i->tileheight() / 2.0);
|
|
entity->Initialize();
|
|
uniid_hash_[entity->entity_uniid] = entity;
|
|
for (auto& pair : human_hash_) {
|
|
pair.second->AddToNewObjects(entity);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::CreateHouseObstacle(Building* building, int id, float x, float y)
|
|
{
|
|
MetaData::MapThing* thing = MetaMgr::Instance()->GetMapThing(id);
|
|
if (thing) {
|
|
Obstacle* entity = new Obstacle();
|
|
entity->room = this;
|
|
entity->meta = thing;
|
|
entity->building = building;
|
|
entity->entity_uniid = AllocUniid();
|
|
entity->pos = Vector2D(building->pos.x + x - building->meta->i->tilewidth() / 2.0,
|
|
building->pos.y + y - building->meta->i->tileheight() / 2.0);
|
|
entity->Initialize();
|
|
uniid_hash_[entity->entity_uniid] = entity;
|
|
for (auto& pair : human_hash_) {
|
|
pair.second->AddToNewObjects(entity);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::CreateObstacle(int id, float x, float y)
|
|
{
|
|
a8::XPrintf("createobstacle %d %f %f\n", {id, x, y});
|
|
MetaData::MapThing* thing = MetaMgr::Instance()->GetMapThing(id);
|
|
if (thing) {
|
|
Obstacle* entity = new Obstacle();
|
|
entity->room = this;
|
|
entity->meta = thing;
|
|
entity->building = nullptr;
|
|
entity->entity_uniid = AllocUniid();
|
|
entity->pos = Vector2D(x, y);
|
|
entity->Initialize();
|
|
uniid_hash_[entity->entity_uniid] = entity;
|
|
for (auto& pair : human_hash_) {
|
|
pair.second->AddToNewObjects(entity);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::CreateLoot(int equip_id, Vector2D pos, int count)
|
|
{
|
|
MetaData::Equip* equip_meta = MetaMgr::Instance()->GetEquip(equip_id);
|
|
if (equip_meta) {
|
|
Loot* entity = new Loot();
|
|
entity->room = this;
|
|
entity->meta = equip_meta;
|
|
entity->entity_uniid = AllocUniid();
|
|
entity->pos = pos;
|
|
entity->item_id = equip_id;
|
|
entity->count = count;
|
|
entity->Initialize();
|
|
uniid_hash_[entity->entity_uniid] = entity;
|
|
for (auto& pair : human_hash_) {
|
|
pair.second->AddToNewObjects(entity);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::CreateBullet(Human* hum, MetaData::Equip* gun_meta,
|
|
Vector2D pos, Vector2D dir, float fly_distance)
|
|
{
|
|
Bullet* bullet = new Bullet();
|
|
bullet->player = hum;
|
|
bullet->room = this;
|
|
bullet->gun_meta = gun_meta;
|
|
bullet->meta = MetaMgr::Instance()->GetEquip(gun_meta->i->use_bullet());
|
|
bullet->pos = pos;
|
|
bullet->dir = dir;
|
|
bullet->born_pos = pos;
|
|
bullet->born_dir = dir;
|
|
bullet->fly_distance = fly_distance;
|
|
bullet->entity_uniid = AllocUniid();
|
|
bullet->Initialize();
|
|
be_added_hash_[bullet->entity_uniid] = bullet;
|
|
}
|
|
|
|
void Room::FetchBuilding(Human* hum)
|
|
{
|
|
for (auto& pair : uniid_hash_) {
|
|
if (pair.second->entity_type == ET_Building) {
|
|
hum->AddToNewObjects(pair.second);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::OnHumanDie(Human* hum)
|
|
{
|
|
--alive_count_;
|
|
}
|
|
|
|
void Room::ClearDeletedObjects()
|
|
{
|
|
for (auto& pair : frame_data.deleted_objects_hash) {
|
|
for (auto& obj_uniid : pair.second) {
|
|
Entity* entity = GetEntityByUniId(obj_uniid);
|
|
if (entity) {
|
|
if (entity->entity_type != ET_Player) {
|
|
uniid_hash_.erase(entity->entity_uniid);
|
|
moveable_hash_.erase(entity->entity_uniid);
|
|
}
|
|
for (auto& pair : human_hash_) {
|
|
pair.second->RemoveNewObjects(entity);
|
|
pair.second->RemovePartObjects(entity);
|
|
}
|
|
delete entity;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (auto& pair : frame_data.softdeleted_objects_hash) {
|
|
for (auto& obj_uniid : pair.second) {
|
|
Entity* entity = GetEntityByUniId(obj_uniid);
|
|
if (entity) {
|
|
if (entity->entity_type != ET_Player) {
|
|
uniid_hash_.erase(entity->entity_uniid);
|
|
moveable_hash_.erase(entity->entity_uniid);
|
|
}
|
|
for (auto& pair : human_hash_) {
|
|
pair.second->RemoveNewObjects(entity);
|
|
pair.second->RemovePartObjects(entity);
|
|
}
|
|
delete entity;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::TouchPlayerList(a8::XParams param,
|
|
std::function<void (Player*, a8::XParams&)> func)
|
|
{
|
|
if (!func) {
|
|
return;
|
|
}
|
|
for (auto& pair : accountid_hash_) {
|
|
if (pair.second) {
|
|
func(pair.second, param);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::TouchHumanList(a8::XParams param,
|
|
std::function<void (Human*, a8::XParams&)> func)
|
|
{
|
|
if (!func) {
|
|
return;
|
|
}
|
|
for (auto& pair : human_hash_) {
|
|
if (pair.second) {
|
|
func(pair.second, param);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::ProcAddedObjects()
|
|
{
|
|
if (!be_added_hash_.empty()) {
|
|
for (auto& pair : be_added_hash_) {
|
|
uniid_hash_[pair.second->entity_uniid] = pair.second;
|
|
switch (pair.second->entity_type) {
|
|
case ET_Player:
|
|
case ET_Bullet:
|
|
{
|
|
moveable_hash_[pair.second->entity_uniid] = pair.second;
|
|
}
|
|
break;
|
|
case ET_Smoke:
|
|
{
|
|
for (auto& pair : human_hash_) {
|
|
pair.second->RemoveNewObjects(pair.second);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
abort();
|
|
break;
|
|
}
|
|
}
|
|
be_added_hash_.clear();
|
|
}
|
|
}
|
|
|
|
void Room::BeAddedObject(Entity* entity)
|
|
{
|
|
be_added_hash_[entity->entity_uniid] = entity;
|
|
}
|
|
|
|
void Room::UpdateGas()
|
|
{
|
|
switch (gas_data.gas_mode) {
|
|
case GasInactive:
|
|
{
|
|
if (frame_no - gas_data.gas_start_frameno >= GAS_INACTIVE_TIME * SERVER_FRAME_RATE) {
|
|
gas_data.gas_mode = GasWaiting;
|
|
gas_data.old_area_meta = MetaMgr::Instance()->GetSafeArea(30001);
|
|
gas_data.new_area_meta = MetaMgr::Instance()->GetSafeArea(30002);
|
|
gas_data.gas_progress = gas_data.old_area_meta->i->rad();
|
|
gas_data.gas_start_frameno = frame_no;
|
|
gas_data.pos_old = Vector2D(MAP_WIDTH / 2.0f,
|
|
MAP_HEIGHT / 2.0f);
|
|
gas_data.pos_old_bk = gas_data.pos_old;
|
|
{
|
|
bool gen_ok = GenSmallCircle(gas_data.pos_old,
|
|
gas_data.old_area_meta->i->rad(),
|
|
gas_data.new_area_meta->i->rad(),
|
|
gas_data.pos_new);
|
|
assert(gen_ok);
|
|
}
|
|
gas_data.rad_old = gas_data.old_area_meta->i->rad();
|
|
gas_data.rad_new = gas_data.new_area_meta->i->rad();
|
|
RoomMgr::Instance()->RemoveFromInactiveRoomHash(room_uuid);
|
|
}
|
|
}
|
|
break;
|
|
case GasWaiting:
|
|
{
|
|
if (frame_no - gas_data.gas_start_frameno >=
|
|
gas_data.old_area_meta->i->wait_time() * SERVER_FRAME_RATE) {
|
|
gas_data.gas_mode = GasMoving;
|
|
gas_data.gas_start_frameno = frame_no;;
|
|
}
|
|
}
|
|
break;
|
|
case GasMoving:
|
|
{
|
|
if (frame_no - gas_data.gas_start_frameno > 0 && !gas_data.is_last_gas) {
|
|
float distance = gas_data.old_area_meta->i->shrink_speed() *
|
|
((frame_no - 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 0
|
|
{
|
|
#else
|
|
if (!(gas_data.pos_new == gas_data.pos_old)) {
|
|
#endif
|
|
Vector2D p1 = gas_data.pos_new - gas_data.pos_old_bk;
|
|
gas_data.pre_pos_old = gas_data.pos_old;
|
|
if (p1.Norm() - distance <= 0.01f) {
|
|
gas_data.pos_old = gas_data.pos_new;
|
|
} else {
|
|
Vector2D dir = p1;
|
|
dir.Normalize();
|
|
gas_data.pos_old = gas_data.pos_old_bk + dir * distance;
|
|
}
|
|
if (gas_data.rad_old - distance <= gas_data.rad_new) {
|
|
#if 0
|
|
assert(gas_data.pos_new == gas_data.pos_old);
|
|
#endif
|
|
}
|
|
}
|
|
if (std::abs(gas_data.gas_progress - gas_data.rad_new) <= 0.001f) {
|
|
int pre_area_id = gas_data.new_area_meta->i->id();
|
|
Vector2D pre_pos = gas_data.pos_new;
|
|
if (!MetaMgr::Instance()->GetSafeArea(pre_area_id + 1)) {
|
|
gas_data.is_last_gas = true;
|
|
return;
|
|
}
|
|
gas_data.gas_mode = GasWaiting;
|
|
gas_data.old_area_meta = MetaMgr::Instance()->GetSafeArea(pre_area_id);
|
|
gas_data.new_area_meta = MetaMgr::Instance()->GetSafeArea(pre_area_id + 1);
|
|
gas_data.gas_progress = gas_data.old_area_meta->i->rad();
|
|
gas_data.gas_start_frameno = frame_no;
|
|
gas_data.pos_old = pre_pos;
|
|
gas_data.pos_old_bk = gas_data.pos_old;
|
|
{
|
|
bool gen_ok = GenSmallCircle(gas_data.pos_old,
|
|
gas_data.old_area_meta->i->rad(),
|
|
gas_data.new_area_meta->i->rad(),
|
|
gas_data.pos_new);
|
|
assert(gen_ok);
|
|
}
|
|
gas_data.rad_old = gas_data.old_area_meta->i->rad();
|
|
gas_data.rad_new = gas_data.new_area_meta->i->rad();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
if (gas_data.gas_mode != GasInactive) {
|
|
if (!game_over && alive_count_ <= 1) {
|
|
game_over = true;
|
|
game_over_frameno = frame_no;
|
|
}
|
|
for (auto& pair : human_hash_) {
|
|
if (pair.second->dead) {
|
|
continue;
|
|
}
|
|
if (game_over) {
|
|
pair.second->send_gameover = true;
|
|
}
|
|
bool b1 = CircleContainCircle(gas_data.pos_old,
|
|
gas_data.gas_progress,
|
|
pair.second->pos,
|
|
pair.second->GetRadius()
|
|
);
|
|
bool b2 = CircleContainCircle(gas_data.pos_new,
|
|
gas_data.rad_new,
|
|
pair.second->pos,
|
|
pair.second->GetRadius()
|
|
);
|
|
if (!b1 && !b2) {
|
|
pair.second->poisoning = true;
|
|
} else {
|
|
pair.second->poisoning = false;
|
|
pair.second->poisoning_time = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Room::GenSmallCircle(Vector2D big_circle_pos, float big_circle_rad, float small_circle_rad,
|
|
Vector2D& out_pos)
|
|
{
|
|
if (big_circle_rad <= small_circle_rad) {
|
|
abort();
|
|
}
|
|
Vector2D dir = Vector2D::UP;
|
|
dir.Rotate(a8::RandAngle());
|
|
float rad = rand() % (int)(big_circle_rad - small_circle_rad);
|
|
if (rad <= 0.001f){
|
|
rad = 0.001f;
|
|
}
|
|
out_pos = big_circle_pos + dir * rad;
|
|
return true;
|
|
}
|
|
|
|
void Room::OutputDebugLog()
|
|
{
|
|
a8::UdpLog::Instance()->Debug("roomid:%d max_rundelay:%d frame_no:%d game_over:%d game_over_frameno:%d "
|
|
"elapsed_time:%d alive_count:%d current_uniid:%d "
|
|
"state:%d accountid_hash.size:%d moveable_hash_.size:%d "
|
|
"uniid_hash.size:%d human_hash.size:%d be_added_hash:%d",
|
|
{
|
|
room_uuid,
|
|
profile.max_rundelay,
|
|
frame_no,
|
|
game_over ? 1 : 0,
|
|
game_over_frameno,
|
|
elapsed_time_,
|
|
alive_count_,
|
|
current_uniid,
|
|
state_,
|
|
accountid_hash_.size(),
|
|
moveable_hash_.size(),
|
|
uniid_hash_.size(),
|
|
human_hash_.size(),
|
|
be_added_hash_.size()
|
|
});
|
|
{
|
|
int entity_num_arr[ET_MAX] = {0};
|
|
a8::MutableXObject* logobj = a8::MutableXObject::NewObject();
|
|
for (auto& pair : uniid_hash_) {
|
|
if (pair.second->entity_type >= 0 && pair.second->entity_type < ET_MAX) {
|
|
++(entity_num_arr[pair.second->entity_type]);
|
|
}
|
|
}
|
|
for (int i = 0; i < ET_MAX; ++i) {
|
|
logobj->SetVal(a8::XValue(i).GetString(), entity_num_arr[i]);
|
|
}
|
|
a8::UdpLog::Instance()->Debug("roomid:%d %s", {room_uuid, logobj->ToJsonStr()});
|
|
delete logobj;
|
|
}
|
|
profile.max_rundelay = 0;
|
|
}
|
|
|
|
void Room::AutoMatchTeam()
|
|
{
|
|
std::vector<Human*> humans;
|
|
for (auto& pair : human_hash_) {
|
|
humans.push_back(pair.second);
|
|
}
|
|
std::random_shuffle(humans.begin(), humans.end());
|
|
std::set<Human*>* team_members = nullptr;
|
|
for (size_t i = 0; i < humans.size(); ++i) {
|
|
if (i % 4 == 0) {
|
|
++current_teamid;
|
|
team_hash_[current_teamid] = std::set<Human*>();
|
|
auto itr = team_hash_.find(current_teamid);
|
|
team_members = &itr->second;
|
|
}
|
|
humans[i]->team_id = current_teamid;
|
|
humans[i]->team_members = team_members;
|
|
humans[i]->need_sync_team_data = true;
|
|
humans[i]->need_sync_teammate_data = true;
|
|
humans[i]->need_sync_active_player = true;
|
|
team_members->insert(humans[i]);
|
|
}
|
|
}
|
|
|
|
void Room::InitAirDrop()
|
|
{
|
|
std::list<MetaData::AirDrop>& air_drops = MetaMgr::Instance()->GetAirDrops();
|
|
a8::XPrintf("InitAirdrop %d %d\n", {room_uuid, air_drops.size()});
|
|
for (auto& air_drop : air_drops) {
|
|
xtimer.AddDeadLineTimerAndAttach(SERVER_FRAME_RATE * air_drop.i->time(),
|
|
a8::XParams()
|
|
.SetSender(this)
|
|
.SetParam1(air_drop.i->appear_time())
|
|
.SetParam2(air_drop.i->drop_id())
|
|
.SetParam3(air_drop.i->id()),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
if (!room->game_over) {
|
|
a8::XPrintf("airdrop %d %d %d\n",
|
|
{
|
|
param.param3,
|
|
param.param1,
|
|
param.param2
|
|
});
|
|
room->AirDrop(param.param1, param.param2);
|
|
}
|
|
},
|
|
&xtimer_attacher.timer_list_);
|
|
}
|
|
}
|
|
|
|
void Room::AirDrop(int appear_time, int box_id)
|
|
{
|
|
MetaData::MapThing* thing_meta = MetaMgr::Instance()->GetMapThing(box_id);
|
|
if (thing_meta) {
|
|
Vector2D dir = Vector2D::UP;
|
|
dir.Rotate(a8::RandAngle());
|
|
a8::XPrintf("gas_data.pos_new %f %f\n",
|
|
{
|
|
gas_data.pos_new.x,
|
|
gas_data.pos_new.y
|
|
});
|
|
Vector2D box_pos = gas_data.pos_new + dir * (500 + rand() % 300);
|
|
::google::protobuf::RepeatedPtrField<::cs::MFAirDrop>* airdrops = nullptr;
|
|
{
|
|
{
|
|
auto itr = frame_data.airdrops_hash.find(frame_no);
|
|
if (itr == frame_data.airdrops_hash.end()) {
|
|
frame_data.airdrops_hash[frame_no] = ::google::protobuf::RepeatedPtrField<::cs::MFAirDrop>();
|
|
itr = frame_data.airdrops_hash.find(frame_no);
|
|
}
|
|
airdrops = &itr->second;
|
|
}
|
|
}
|
|
cs::MFAirDrop* airdrop = airdrops->Add();
|
|
airdrop->set_appear_time(appear_time);
|
|
airdrop->set_box_id(box_id);
|
|
box_pos.ToPB(airdrop->mutable_pos());
|
|
|
|
xtimer.AddDeadLineTimerAndAttach(SERVER_FRAME_RATE * appear_time / 1000.f,
|
|
a8::XParams()
|
|
.SetSender(this)
|
|
.SetParam1(box_id)
|
|
.SetParam2(box_pos.x)
|
|
.SetParam3(box_pos.y),
|
|
[] (const a8::XParams& param)
|
|
{
|
|
Room* room = (Room*)param.sender.GetUserData();
|
|
if (!room->game_over) {
|
|
room->CreateObstacle(param.param1.GetInt(),
|
|
param.param2.GetDouble(),
|
|
param.param3.GetDouble());
|
|
}
|
|
},
|
|
&xtimer_attacher.timer_list_);
|
|
}
|
|
}
|