352 lines
9.7 KiB
C++
352 lines
9.7 KiB
C++
#include "precompile.h"
|
|
|
|
#include "playermgr.h"
|
|
#include "player.h"
|
|
#include "cs_proto.pb.h"
|
|
#include "room.h"
|
|
#include "android.h"
|
|
#include "metamgr.h"
|
|
#include "movement.h"
|
|
#include "bullet.h"
|
|
#include "collider.h"
|
|
#include "obstacle.h"
|
|
|
|
const int ROOM_MAX_PLAYER_NUM = 50;
|
|
const int ANDROID_NUM = 0;
|
|
|
|
void Room::Update(int delta_time)
|
|
{
|
|
elapsed_time_ += delta_time;
|
|
while (elapsed_time_ >= 50) {
|
|
ResetFrameData();
|
|
int i = 0;
|
|
for (auto& pair : moveable_hash_) {
|
|
pair.second->Update(50);
|
|
pair.second->updated_times++;
|
|
++i;
|
|
assert(i < 1000);
|
|
}
|
|
ClearDeletedObjects();
|
|
ProcAddedObjects();
|
|
elapsed_time_ -= 50;
|
|
}
|
|
}
|
|
|
|
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 = 1000 + rand() % 100;
|
|
hum->pos.y = 2000 + rand() % 200;
|
|
hum->attack_dir = hum->pos;
|
|
hum->attack_dir.Normalize();
|
|
hum->attack_dir.Rotate(a8::RandAngle());
|
|
}
|
|
hum->room = this;
|
|
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->new_objects.insert(hum);
|
|
hum->part_objects.insert(hum);
|
|
for (auto& pair : human_hash_) {
|
|
if (pair.second != hum) {
|
|
pair.second->new_objects.insert(hum);
|
|
pair.second->part_objects.insert(hum);
|
|
hum->new_objects.insert(pair.second);
|
|
hum->part_objects.insert(pair.second);
|
|
}
|
|
}
|
|
}
|
|
|
|
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 = 100 + rand() % 400;
|
|
hum->pos.y = 200 + rand() % 500;
|
|
hum->attack_dir = hum->pos;
|
|
hum->attack_dir.Normalize();
|
|
hum->attack_dir.Rotate(a8::RandAngle());
|
|
}
|
|
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->new_objects.insert(hum);
|
|
pair.second->part_objects.insert(hum);
|
|
hum->new_objects.insert(pair.second);
|
|
hum->part_objects.insert(pair.second);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::ShuaObstacle(Human* hum)
|
|
{
|
|
MetaData::MapThing* a_thing = MetaMgr::Instance()->GetMapThing(61001);
|
|
MetaData::MapThing* b_thing = MetaMgr::Instance()->GetMapThing(61007);
|
|
if (!a_thing || !b_thing) {
|
|
return;
|
|
}
|
|
#if 1
|
|
{
|
|
Obstacle* entity = new Obstacle();
|
|
entity->room = this;
|
|
entity->meta = a_thing;
|
|
entity->entity_uniid = AllocUniid();
|
|
#if 0
|
|
entity->dir = Vector2D::UP;
|
|
#endif
|
|
#if 0
|
|
entity->pos = Vector2D(100.0f, 164.0f);
|
|
#else
|
|
entity->pos = hum->pos - Vector2D::LEFT * hum->meta->i->radius() - 100;
|
|
#endif
|
|
entity->Initialize();
|
|
uniid_hash_[entity->entity_uniid] = entity;
|
|
for (auto& pair : human_hash_) {
|
|
pair.second->new_objects.insert(entity);
|
|
pair.second->part_objects.insert(entity);
|
|
}
|
|
}
|
|
#endif
|
|
#if 1
|
|
{
|
|
Obstacle* entity = new Obstacle();
|
|
entity->room = this;
|
|
entity->meta = b_thing;
|
|
entity->entity_uniid = AllocUniid();
|
|
#if 0
|
|
entity->dir = Vector2D::UP;
|
|
#endif
|
|
#if 0
|
|
entity->pos = Vector2D(100.0f, 100.0f);
|
|
#else
|
|
entity->pos = hum->pos + Vector2D::RIGHT * hum->meta->i->radius() + 100;
|
|
#endif
|
|
entity->Initialize();
|
|
uniid_hash_[entity->entity_uniid] = entity;
|
|
for (auto& pair : human_hash_) {
|
|
pair.second->new_objects.insert(entity);
|
|
pair.second->part_objects.insert(entity);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
bool Room::RandomPos(Human* hum, float distance, Vector2D& out_pos)
|
|
{
|
|
Vector2D dir = hum->pos;
|
|
dir.Rotate(a8::RandAngle());
|
|
dir.Normalize();
|
|
CircleCollider collider;
|
|
collider.owner = hum;
|
|
collider.pos = dir * distance;
|
|
collider.rad = hum->meta->i->radius();
|
|
|
|
for (auto& pair : uniid_hash_) {
|
|
if (pair.second->entity_type == ET_Player ||
|
|
pair.second->entity_type == ET_Bullet
|
|
) {
|
|
continue;
|
|
} else {
|
|
for (auto& itr : pair.second->colliders) {
|
|
if (collider.Intersect(itr)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
out_pos = hum->pos + collider.pos;
|
|
return true;
|
|
}
|
|
|
|
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::AddBullet(Bullet* bullet)
|
|
{
|
|
be_added_hash_[bullet->entity_uniid] = bullet;
|
|
}
|
|
|
|
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->TestCollision(pair.second)) {
|
|
objects.push_back(pair.second);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Room::AddDeletedObject(unsigned short obj_uniid)
|
|
{
|
|
frame_data.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()
|
|
{
|
|
frame_data.deleted_objects.clear();
|
|
frame_data.explosions.Clear();
|
|
frame_data.emotes.Clear();
|
|
frame_data.bullets.Clear();
|
|
frame_data.shots.Clear();
|
|
}
|
|
|
|
void Room::ClearDeletedObjects()
|
|
{
|
|
for (auto& obj_uniid : frame_data.deleted_objects) {
|
|
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);
|
|
}
|
|
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::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;
|
|
default:
|
|
abort();
|
|
break;
|
|
}
|
|
}
|
|
be_added_hash_.clear();
|
|
}
|
|
}
|
|
|
|
void Room::BeAddedObject(Entity* entity)
|
|
{
|
|
be_added_hash_[entity->entity_uniid] = entity;
|
|
}
|