diff --git a/server/gameserver/constant.h b/server/gameserver/constant.h index fa0c5bd..060179c 100755 --- a/server/gameserver/constant.h +++ b/server/gameserver/constant.h @@ -338,7 +338,12 @@ enum AIMode_e enum ColliderTag_e { - kHalfWallTag = 1 + kHalfWallTag = 1, + kColliderSpecTag_Begin = 2, + kColliderTag_Grass = 2, //草丛 + kColliderTag_Water = 3, //水 + kColliderTag_Ice = 4, //冰 + kColliderSpecTag_End = 4, }; enum GameChannel_e @@ -406,8 +411,11 @@ const int TURN_OVER_SKILL_ID = 41001; const int HUNLUAN_BUFFID = 6001; +const long long SPEC_MAP_OBJECT_FLAGS = A8_DEFINE_RANGE_BIT(long long, kColliderSpecTag_Begin, kColliderSpecTag_End); + const int kThroughWall_BUFFID = 6003; const int FLY_BUFFID = 7001; const int JUMP_BUFFID = 7002; const int DRIVER_BUFFID = 7003; const int PASSENGER_BUFFID = 7004; + diff --git a/server/gameserver/human.cc b/server/gameserver/human.cc index de02edd..0d2e4f8 100644 --- a/server/gameserver/human.cc +++ b/server/gameserver/human.cc @@ -3307,6 +3307,104 @@ void Human::DoGetOnWithCar(Car* car) car->GetOn(this); } +void Human::CheckSpecObject() +{ + std::set colliders; + room->map_service->GetSpecColliders(SPEC_MAP_OBJECT_FLAGS, room, GetPos().x, GetPos().y, colliders); + + long long flags = 0; + for (const ColliderComponent* collider : colliders) { + switch (collider->owner->GetEntityType()) { + case ET_Obstacle: + case ET_Building: + { + if (TestCollision(room, (ColliderComponent*)collider)) { + flags |= collider->tag; + } + } + break; + default: + break; + } + } + + for (int i = kColliderSpecTag_Begin; i <= kColliderSpecTag_End; ++i) { + SpecMapObject& map_obj = spec_map_objects_[i - kColliderSpecTag_Begin]; + int buff_effect = 0; + if (a8::HasBitFlag(flags, i)) { + if (!HasBuffEffect(buff_effect)) { + OnEnterSpecMapArea(i, map_obj); + } + } else { + if (HasBuffEffect(buff_effect)) { + OnLeaveSpecMapArea(i, map_obj); + } + } + } +} + +void Human::OnEnterSpecMapArea(int tag, SpecMapObject& map_obj) +{ + ClearSpecMapAreaTimer(map_obj); + map_obj.enter_timer = room->xtimer.AddDeadLineTimerAndAttach + (MetaMgr::Instance()->GetSpecMapAreaEnterTime(tag) * SERVER_FRAME_RATE, + a8::XParams() + .SetSender(this) + .SetParam1(&map_obj) + .SetParam2(tag), + [] (const a8::XParams& param) + { + Human* hum = (Human*)param.sender.GetUserData(); + MetaData::Buff* buff_meta = MetaMgr::Instance()->GetBuff + (MetaMgr::Instance()->GetSpecMapAreaBuffId(param.param2)); + if (buff_meta) { + hum->AddBuff(hum, buff_meta, 1); + } + }, + &xtimer_attacher.timer_list_, + [] (const a8::XParams& param) + { + SpecMapObject* map_obj = (SpecMapObject*)param.param1.GetUserData(); + map_obj->enter_timer = nullptr; + }); + +} + +void Human::OnLeaveSpecMapArea(int tag, SpecMapObject& map_obj) +{ + ClearSpecMapAreaTimer(map_obj); + map_obj.leave_timer = room->xtimer.AddDeadLineTimerAndAttach + (MetaMgr::Instance()->GetSpecMapAreaLeaveTime(tag) * SERVER_FRAME_RATE, + a8::XParams() + .SetSender(this) + .SetParam1(&map_obj) + .SetParam2(tag), + [] (const a8::XParams& param) + { + Human* hum = (Human*)param.sender.GetUserData(); + hum->RemoveBuffById((MetaMgr::Instance()->GetSpecMapAreaBuffId(param.param2))); + }, + &xtimer_attacher.timer_list_, + [] (const a8::XParams& param) + { + SpecMapObject* map_obj = (SpecMapObject*)param.param1.GetUserData(); + map_obj->leave_timer = nullptr; + }); + +} + +void Human::ClearSpecMapAreaTimer(SpecMapObject& map_obj) +{ + if (map_obj.leave_timer) { + room->xtimer.DeleteTimer(map_obj.leave_timer); + map_obj.leave_timer = nullptr; + } + if (map_obj.enter_timer) { + room->xtimer.DeleteTimer(map_obj.enter_timer); + map_obj.enter_timer = nullptr; + } +} + void Human::DoSkillPreProc(int skill_id, int target_id, const a8::Vec2& target_pos) { if (action_type == AT_Reload || diff --git a/server/gameserver/human.h b/server/gameserver/human.h index 6da8b38..e5d1a57 100644 --- a/server/gameserver/human.h +++ b/server/gameserver/human.h @@ -25,6 +25,12 @@ enum HumanStatus HS_End }; +struct SpecMapObject +{ + struct xtimer_list* leave_timer = nullptr; + struct xtimer_list* enter_timer = nullptr; +}; + struct xtimer_list; class CircleCollider; class AabbCollider; @@ -271,6 +277,10 @@ private: void NextReload(int prev_weapon_id, int prev_weapon_idx); void DoGetOnWithLoot(Loot* loot_entity); void DoGetOnWithCar(Car* car); + void CheckSpecObject(); + void OnEnterSpecMapArea(int tag, SpecMapObject& map_obj); + void OnLeaveSpecMapArea(int tag, SpecMapObject& map_obj); + void ClearSpecMapAreaTimer(SpecMapObject& map_obj); virtual void AddBuffPostProc(Creature* caster, Buff* buff) override; virtual void OnBuffRemove(const Buff& buff) override; virtual void DoSkillPreProc(int skill_id, int target_id, const a8::Vec2& target_pos) override; @@ -327,6 +337,7 @@ private: size_t box_drop_times_ = 0; std::array fixed_object_sync_flags_ = {}; + std::array spec_map_objects_ = {}; bool already_report_battle_ = false; bool sent_battlereport_ = false; diff --git a/server/gameserver/mapinstance.cc b/server/gameserver/mapinstance.cc index 01f784d..77294ba 100644 --- a/server/gameserver/mapinstance.cc +++ b/server/gameserver/mapinstance.cc @@ -34,6 +34,7 @@ void MapInstance::Init() map_meta_->i->map_height() / MAP_GRID_WIDTH, MAP_GRID_WIDTH); CreateThings(); + CreateTerrain(); a8::UdpLog::Instance()->Info ("map_id:%d current_uniid:%d loots:%d mini_room_spawn_points:%d normal_room_spawn_points:%d " "building_num:%d obstalce_num:%d obstacle0_num:%d " @@ -149,6 +150,95 @@ void MapInstance::CreateThings() } } +void MapInstance::CreateTerrain() +{ + metatable::TerrainJson* terrain = MetaMgr::Instance()->GetTerrainJson(map_id); + std::list* layers = MetaMgr::Instance()->GetMapLayer(map_meta_->i->map_pic()); + if (!terrain || !layers) { + return; + //abort(); + } + if (layers->empty()) { + return; + } + metatable::MapLayerJson* first_layer = nullptr; + for (auto layer : *layers) { + if (!first_layer) { + first_layer = &layer; + } + if (layer.width() != first_layer->width()) { + abort(); + } + if (layer.height() != first_layer->height()) { + abort(); + } + if (layer.grids().size() != first_layer->grids().size()) { + abort(); + } + } + if (first_layer->grids().size() != first_layer->width() * first_layer->height()) { + abort(); + } + if (first_layer->grids().size() <= 0) { + abort(); + } + + std::vector grids; + grids.reserve(first_layer->grids().size()); + for (int i = 0; i < first_layer->grids().size(); ++i) { + grids.push_back(0); + } + std::set dusts; + for (auto idx : terrain->dust()) { + dusts.insert(idx); + } + std::set waters; + for (auto idx : terrain->water()) { + waters.insert(idx); + } + std::set grasses; + for (auto idx : terrain->grass()) { + grasses.insert(idx); + } + + int mask = A8_DEFINE_RANGE_BIT(int, 0, 22); + for (auto layer : *layers) { + for (int i = 0; i < first_layer->grids().size(); ++i) { + int grid_val = layer.grids(i) & mask; + if (grid_val != 0) { + grids[i] = grid_val; + } + } + } + + MetaData::MapThing* thing_meta = MetaMgr::Instance()->GetMapThing(0); + if (thing_meta) { + for (int w = 0; w < first_layer->width(); ++w) { + for (int h = 0; h < first_layer->height(); ++h) { + int grid_val = grids[w * first_layer->width() + h]; + if (grid_val != 0) { + float x = w * thing_meta->i->width() + thing_meta->i->width() / 2.0f; + float y = h * thing_meta->i->height() + thing_meta->i->height() / 2.0f; + int collider_tag = 0; + if (dusts.find(grid_val) != dusts.end()) { + a8::SetBitFlag(collider_tag, kColliderTag_Ice); + } else if (waters.find(grid_val) != waters.end()) { + a8::SetBitFlag(collider_tag, kColliderTag_Water); + } else if (grasses.find(grid_val) != grasses.end()) { + a8::SetBitFlag(collider_tag, kColliderTag_Grass); + } + if (collider_tag != 0) { + InternalCreateObstacle(thing_meta->i->thing_id(), x, y, collider_tag, + [] (Obstacle* entity) + { + }); + } + } + } + } + } +} + void MapInstance::CreateMapObject(MetaData::MapTplThing& thing_tpl) { int thing_id = thing_tpl.RandThing(); @@ -157,7 +247,7 @@ void MapInstance::CreateMapObject(MetaData::MapTplThing& thing_tpl) if (thing_meta->i->is_house()) { CreateBuilding(thing_id, thing_tpl.i->x(), thing_tpl.i->y()); } else { - InternalCreateObstacle(thing_id, thing_tpl.i->x(), thing_tpl.i->y(), + InternalCreateObstacle(thing_id, thing_tpl.i->x(), thing_tpl.i->y(), 0, [] (Obstacle* entity) { }); @@ -192,7 +282,7 @@ void MapInstance::CreateBuilding(int thing_id, float building_x, float building_ MetaData::Building::Door* door_meta = &building->meta->doors[door_idx]; float x = building->GetX() + door_meta->state0->x() - building->meta->i->tilewidth() / 2.0; float y = building->GetY() + door_meta->state0->y() - building->meta->i->tileheight() / 2.0; - InternalCreateObstacle(DOOR_THING_ID, x, y, + InternalCreateObstacle(DOOR_THING_ID, x, y, 0, [building, door_idx] (Obstacle* entity) { entity->SetDoorInfo(building, door_idx); @@ -206,7 +296,7 @@ void MapInstance::CreateBuilding(int thing_id, float building_x, float building_ int rnd = rand () % obj._rand_space(); for (auto& pair : obj._things()) { if (rnd <= pair.value()) { - InternalCreateObstacle(pair.key(), x, y, + InternalCreateObstacle(pair.key(), x, y, 0, [building] (Obstacle* entity) { entity->SetBuilding(building); @@ -219,12 +309,13 @@ void MapInstance::CreateBuilding(int thing_id, float building_x, float building_ buildings_.push_back(building); } -Obstacle* MapInstance::InternalCreateObstacle(int id, float x, float y, +Obstacle* MapInstance::InternalCreateObstacle(int id, float x, float y, int collider_tag, std::function on_precreate) { MetaData::MapThing* thing = MetaMgr::Instance()->GetMapThing(id); if (thing) { Obstacle* entity = EntityFactory::Instance()->MakeObstacle(AllocUniid()); + entity->collider_tag = collider_tag; entity->meta = thing; entity->is_permanent = true; entity->permanent_map_service = map_service_; diff --git a/server/gameserver/mapinstance.h b/server/gameserver/mapinstance.h index 278dd63..76de008 100644 --- a/server/gameserver/mapinstance.h +++ b/server/gameserver/mapinstance.h @@ -26,9 +26,10 @@ class MapInstance private: void CreateThings(); + void CreateTerrain(); void CreateMapObject(MetaData::MapTplThing& thing_tpl); void CreateBuilding(int thing_id, float building_x, float building_y); - Obstacle* InternalCreateObstacle(int id, float x, float y, + Obstacle* InternalCreateObstacle(int id, float x, float y, int collider_tag, std::function on_precreate); Entity* GetEntityByUniId(int uniid); int AllocUniid(); diff --git a/server/gameserver/mapservice.cc b/server/gameserver/mapservice.cc index 7b7f5cf..4c47aac 100644 --- a/server/gameserver/mapservice.cc +++ b/server/gameserver/mapservice.cc @@ -184,6 +184,9 @@ void MapService::GetColliders(Room* room, } struct CellNode *node, *tmp; list_for_each_entry_safe(node, tmp, head, entry) { + if (node->collider->tag != 0) { + continue; + } switch (node->collider->owner->GetEntityType()) { case ET_Obstacle: { @@ -225,6 +228,33 @@ void MapService::GetColliders(Room* room, } } +void MapService::GetSpecColliders(long long flags, + Room* room, + float world_x, + float world_y, + std::set& colliders) +{ + int center_grid_id = GetGridId(world_x, world_y); + if (center_grid_id < 0 || center_grid_id >= max_grid_id_) { + return; + } + for (int i = 0; i < a8::ArraySize(grid_offset_arr_); ++i) { + int grid_id = center_grid_id + grid_offset_arr_[i]; + if (grid_id >= 0 && grid_id < max_grid_id_) { + list_head* head = &map_cells_[grid_id]; + if (list_empty(head)) { + continue; + } + struct CellNode *node, *tmp; + list_for_each_entry_safe(node, tmp, head, entry) { + if (a8::HasBitFlag(flags, node->collider->tag)) { + colliders.insert(node->collider); + } + } + } + } +} + int MapService::GetGridId(float world_x, float world_y) { int grid_id = (int)(world_x/cell_width_) + (int)(world_y/cell_width_) * map_width_; diff --git a/server/gameserver/mapservice.h b/server/gameserver/mapservice.h index c30ce69..f7d81bf 100644 --- a/server/gameserver/mapservice.h +++ b/server/gameserver/mapservice.h @@ -43,6 +43,11 @@ class MapService float world_x, float world_y, std::set& colliders); + void GetSpecColliders(long long flags, + Room* room, + float world_x, + float world_y, + std::set& colliders); int FindPathRequest(Human* hum, const a8::Vec2& start_pos, const a8::Vec2& end_pos, diff --git a/server/gameserver/metamgr.cc b/server/gameserver/metamgr.cc index cfdf743..9bfcb28 100755 --- a/server/gameserver/metamgr.cc +++ b/server/gameserver/metamgr.cc @@ -1,5 +1,8 @@ #include "precompile.h" +#include +#include + #include #include @@ -63,6 +66,7 @@ public: std::list ai_meta_list; std::list ai_list; std::list text_meta_list; + std::list terrain_meta_list; std::map parameter_hash; std::map gamemap_hash; @@ -76,6 +80,7 @@ public: std::map building_hash; std::map drop_hash; std::map> maptpl_meta_hash; + std::map> layer_meta_hash; std::map> maptpl_hash; std::map dress_hash; std::vector dress_vec; @@ -141,6 +146,7 @@ public: f8::ReadCsvMetaFile(res_path + "robot@robot.csv", robot_meta_list); f8::ReadCsvMetaFile(res_path + "ai@ai.csv", ai_meta_list); f8::ReadCsvMetaFile(res_path + "text@text.csv", text_meta_list); + f8::ReadJsonMetaFile(res_path + "terrain.json", terrain_meta_list); BindToMetaData(); #if 1 { @@ -443,14 +449,29 @@ private: #if 1 { for (auto& tuple : item.template_list) { - auto itr = maptpl_meta_hash.find(std::get<0>(tuple)); - if (itr == maptpl_meta_hash.end()) { - maptpl_meta_hash[std::get<0>(tuple)] = std::list(); - itr = maptpl_meta_hash.find(std::get<0>(tuple)); - } else { - itr->second.clear(); + { + auto itr = maptpl_meta_hash.find(std::get<0>(tuple)); + if (itr == maptpl_meta_hash.end()) { + maptpl_meta_hash[std::get<0>(tuple)] = std::list(); + itr = maptpl_meta_hash.find(std::get<0>(tuple)); + } else { + itr->second.clear(); + } + f8::ReadJsonMetaFile(res_path + std::get<0>(tuple) + ".json", itr->second); + } + { + auto itr = layer_meta_hash.find(meta.map_pic()); + if (itr == layer_meta_hash.end()) { + layer_meta_hash[meta.map_pic()] = std::list(); + itr = layer_meta_hash.find(meta.map_pic()); + } else { + itr->second.clear(); + } + std::string filename = res_path + "map" + meta.map_pic() + ".layers.json"; + if (access(filename.c_str(), F_OK) != -1) { + f8::ReadJsonMetaFile(filename, itr->second); + } } - f8::ReadJsonMetaFile(res_path + std::get<0>(tuple) + ".json", itr->second); } } #endif @@ -732,12 +753,28 @@ MetaData::SafeArea* MetaMgr::GetSafeArea(int area_id) return itr != loader_->safearea_hash.end() ? itr->second : nullptr; } -std::vector* MetaMgr::GetMapTplThing(std::string& map_name) +std::vector* MetaMgr::GetMapTplThing(const std::string& map_name) { auto itr = loader_->maptpl_hash.find(map_name); return itr != loader_->maptpl_hash.end() ? &itr->second : nullptr; } +metatable::TerrainJson* MetaMgr::GetTerrainJson(int map_id) +{ + for (auto& itr : loader_->terrain_meta_list) { + if (itr.map_id() == map_id) { + return &itr; + } + } + return nullptr; +} + +std::list* MetaMgr::GetMapLayer(const std::string& map_name) +{ + auto itr = loader_->layer_meta_hash.find(map_name); + return itr != loader_->layer_meta_hash.end() ? &itr->second : nullptr; +} + std::list& MetaMgr::GetAirDrops() { return loader_->airdrop_list; @@ -871,3 +908,45 @@ std::string MetaMgr::GetText(const std::string& textid, const std::string& def_t auto itr = loader_->text_hash.find(textid); return itr != loader_->text_hash.end() ? itr->second : def_text; } + +int MetaMgr::GetSpecMapAreaBuffId(int tag) +{ + switch (tag) { + case kColliderTag_Grass: + return 6005; + case kColliderTag_Water: + return 6006; + case kColliderTag_Ice: + return 6007; + default: + return 0; + } +} + +int MetaMgr::GetSpecMapAreaEnterTime(int tag) +{ + switch (tag) { + case kColliderTag_Grass: + return grass_invisible_time; + case kColliderTag_Water: + return water_invisible_time; + case kColliderTag_Ice: + return ice_invisible_time; + default: + return 0; + } +} + +int MetaMgr::GetSpecMapAreaLeaveTime(int tag) +{ + switch (tag) { + case kColliderTag_Grass: + return grass_show_time; + case kColliderTag_Water: + return water_show_time; + case kColliderTag_Ice: + return ice_show_time; + default: + return 0; + } +} diff --git a/server/gameserver/metamgr.h b/server/gameserver/metamgr.h index 05e307a..5ec8475 100755 --- a/server/gameserver/metamgr.h +++ b/server/gameserver/metamgr.h @@ -31,7 +31,9 @@ class MetaMgr : public a8::Singleton MetaData::Building* GetBuilding(int building_id); MetaData::Drop* GetDrop(int drop_id); MetaData::SafeArea* GetSafeArea(int area_id); - std::vector* GetMapTplThing(std::string& map_name); + std::vector* GetMapTplThing(const std::string& map_name); + metatable::TerrainJson* GetTerrainJson(int map_id); + std::list* GetMapLayer(const std::string& map_name); std::list& GetAirDrops(); MetaData::AirDrop* GetAirDrop(int airdrop_id); MetaData::AirLine* RandAirLine(int map_id); @@ -52,6 +54,9 @@ class MetaMgr : public a8::Singleton MetaData::Robot* RandRobot(std::set& refreshed_robot_set); MetaData::AI* GetAI(int ai_level, int ai_mode); std::string GetText(const std::string& textid, const std::string& def_text=""); + int GetSpecMapAreaBuffId(int tag); + int GetSpecMapAreaEnterTime(int tag); + int GetSpecMapAreaLeaveTime(int tag); int gas_inactive_time = 10; int newbie_gas_inactive_time = 5; @@ -123,6 +128,16 @@ class MetaMgr : public a8::Singleton int level1room_robot_autodie_distance = 0; std::string level1room_born_point; + float grass_invisible_time = 0.5; + float grass_show_time = 0.5f; + float grass_invisible_time2 = 2.0f; + float water_invisible_time = 0.5; + float water_show_time = 0.5f; + float water_invisible_time2 = 2.0f; + float ice_invisible_time = 0.5; + float ice_show_time = 0.5f; + float ice_invisible_time2 = 2.0f; + #if 0 int refresh_robot_min_num = 0; int refresh_robot_max_num = 0; diff --git a/server/gameserver/obstacle.cc b/server/gameserver/obstacle.cc index 4300de4..d331e17 100644 --- a/server/gameserver/obstacle.cc +++ b/server/gameserver/obstacle.cc @@ -97,6 +97,9 @@ void Obstacle::RecalcSelfCollider() self_collider_->pos = a8::Vec2(); self_collider_->rad = 0.0f; } + for (auto collider : colliders_) { + collider->tag = collider_tag; + } } void Obstacle::FillMFObjectPart(Room* room, Human* hum, cs::MFObjectPart* part_data) @@ -171,12 +174,14 @@ void Obstacle::GetAabbBox(AabbCollider& aabb_box) if (self_collider_) { aabb_box.active = true; aabb_box.owner = this; + aabb_box.tag = collider_tag; aabb_box._min.x = -self_collider_->rad; aabb_box._min.y = -self_collider_->rad; aabb_box._max.x = self_collider_->rad; aabb_box._max.y = self_collider_->rad; return; } + aabb_box.tag = collider_tag; aabb_box.active = true; aabb_box.owner = this; } diff --git a/server/gameserver/obstacle.h b/server/gameserver/obstacle.h index 8427265..a335df7 100644 --- a/server/gameserver/obstacle.h +++ b/server/gameserver/obstacle.h @@ -25,6 +25,7 @@ class Obstacle : public Entity MetaData::MapThing* meta = nullptr; MapService* permanent_map_service = nullptr; bool is_permanent = false; + int collider_tag = 0; virtual ~Obstacle() override; virtual void Initialize() override; diff --git a/server/tools/protobuild/metatable.proto b/server/tools/protobuild/metatable.proto index b6d91d6..b65722e 100755 --- a/server/tools/protobuild/metatable.proto +++ b/server/tools/protobuild/metatable.proto @@ -33,6 +33,7 @@ message Map optional int32 map_mode = 10; optional int32 safearea = 11; optional string game_start_buff_list = 12; + optional string map_pic = 13; } message MapThing @@ -357,4 +358,20 @@ message MapTplThingJson optional float param3 = 11; optional string object_type = 12; optional int32 _object_type = 13; -} \ No newline at end of file +} + +message TerrainJson +{ + optional int32 map_id = 1; + repeated int32 dust = 2; + repeated int32 water = 3; + repeated int32 grass = 4; +} + +message MapLayerJson +{ + optional string name = 1; + optional int32 width = 2; + optional int32 height = 3; + repeated int32 grids = 4; +}