Browse Source

Add serialization for HoldModeComponent, HealerComponent, and CatapultLoadingComponent with tests

Co-authored-by: djeada <[email protected]>
copilot-swe-agent[bot] 1 tuần trước cách đây
mục cha
commit
6a66602b5b
3 tập tin đã thay đổi với 252 bổ sung1 xóa
  1. 91 0
      game/core/serialization.cpp
  2. 1 1
      tests/CMakeLists.txt
  3. 160 0
      tests/core/serialization_test.cpp

+ 91 - 0
game/core/serialization.cpp

@@ -238,6 +238,48 @@ auto Serialization::serializeEntity(const Entity *entity) -> QJsonObject {
     entity_obj["capture"] = capture_obj;
   }
 
+  if (const auto *hold_mode = entity->get_component<HoldModeComponent>()) {
+    QJsonObject hold_mode_obj;
+    hold_mode_obj["active"] = hold_mode->active;
+    hold_mode_obj["exit_cooldown"] =
+        static_cast<double>(hold_mode->exit_cooldown);
+    hold_mode_obj["stand_up_duration"] =
+        static_cast<double>(hold_mode->stand_up_duration);
+    entity_obj["hold_mode"] = hold_mode_obj;
+  }
+
+  if (const auto *healer = entity->get_component<HealerComponent>()) {
+    QJsonObject healer_obj;
+    healer_obj["healing_range"] = static_cast<double>(healer->healing_range);
+    healer_obj["healing_amount"] = healer->healing_amount;
+    healer_obj["healing_cooldown"] =
+        static_cast<double>(healer->healing_cooldown);
+    healer_obj["time_since_last_heal"] =
+        static_cast<double>(healer->time_since_last_heal);
+    entity_obj["healer"] = healer_obj;
+  }
+
+  if (const auto *catapult =
+          entity->get_component<CatapultLoadingComponent>()) {
+    QJsonObject catapult_obj;
+    catapult_obj["state"] = static_cast<int>(catapult->state);
+    catapult_obj["loading_time"] = static_cast<double>(catapult->loading_time);
+    catapult_obj["loading_duration"] =
+        static_cast<double>(catapult->loading_duration);
+    catapult_obj["firing_time"] = static_cast<double>(catapult->firing_time);
+    catapult_obj["firing_duration"] =
+        static_cast<double>(catapult->firing_duration);
+    catapult_obj["target_id"] = static_cast<qint64>(catapult->target_id);
+    catapult_obj["target_locked_x"] =
+        static_cast<double>(catapult->target_locked_x);
+    catapult_obj["target_locked_y"] =
+        static_cast<double>(catapult->target_locked_y);
+    catapult_obj["target_locked_z"] =
+        static_cast<double>(catapult->target_locked_z);
+    catapult_obj["target_position_locked"] = catapult->target_position_locked;
+    entity_obj["catapult_loading"] = catapult_obj;
+  }
+
   return entity_obj;
 }
 
@@ -456,6 +498,55 @@ void Serialization::deserializeEntity(Entity *entity, const QJsonObject &json) {
             static_cast<double>(Defaults::kCaptureRequiredTime)));
     capture->is_being_captured = capture_obj["is_being_captured"].toBool(false);
   }
+
+  if (json.contains("hold_mode")) {
+    const auto hold_mode_obj = json["hold_mode"].toObject();
+    auto *hold_mode = entity->add_component<HoldModeComponent>();
+    hold_mode->active = hold_mode_obj["active"].toBool(true);
+    hold_mode->exit_cooldown =
+        static_cast<float>(hold_mode_obj["exit_cooldown"].toDouble(0.0));
+    hold_mode->stand_up_duration =
+        static_cast<float>(hold_mode_obj["stand_up_duration"].toDouble(
+            static_cast<double>(Defaults::kHoldStandUpDuration)));
+  }
+
+  if (json.contains("healer")) {
+    const auto healer_obj = json["healer"].toObject();
+    auto *healer = entity->add_component<HealerComponent>();
+    healer->healing_range =
+        static_cast<float>(healer_obj["healing_range"].toDouble(8.0));
+    healer->healing_amount = healer_obj["healing_amount"].toInt(5);
+    healer->healing_cooldown =
+        static_cast<float>(healer_obj["healing_cooldown"].toDouble(2.0));
+    healer->time_since_last_heal =
+        static_cast<float>(healer_obj["time_since_last_heal"].toDouble(0.0));
+  }
+
+  if (json.contains("catapult_loading")) {
+    const auto catapult_obj = json["catapult_loading"].toObject();
+    auto *catapult = entity->add_component<CatapultLoadingComponent>();
+    catapult->state = static_cast<CatapultLoadingComponent::LoadingState>(
+        catapult_obj["state"].toInt(
+            static_cast<int>(CatapultLoadingComponent::LoadingState::Idle)));
+    catapult->loading_time =
+        static_cast<float>(catapult_obj["loading_time"].toDouble(0.0));
+    catapult->loading_duration =
+        static_cast<float>(catapult_obj["loading_duration"].toDouble(2.0));
+    catapult->firing_time =
+        static_cast<float>(catapult_obj["firing_time"].toDouble(0.0));
+    catapult->firing_duration =
+        static_cast<float>(catapult_obj["firing_duration"].toDouble(0.5));
+    catapult->target_id = static_cast<EntityID>(
+        catapult_obj["target_id"].toVariant().toULongLong());
+    catapult->target_locked_x =
+        static_cast<float>(catapult_obj["target_locked_x"].toDouble(0.0));
+    catapult->target_locked_y =
+        static_cast<float>(catapult_obj["target_locked_y"].toDouble(0.0));
+    catapult->target_locked_z =
+        static_cast<float>(catapult_obj["target_locked_z"].toDouble(0.0));
+    catapult->target_position_locked =
+        catapult_obj["target_position_locked"].toBool(false);
+  }
 }
 
 auto Serialization::serializeTerrain(

+ 1 - 1
tests/CMakeLists.txt

@@ -29,8 +29,8 @@ target_link_libraries(standard_of_iron_tests
         Qt${QT_VERSION_MAJOR}::Gui
         Qt${QT_VERSION_MAJOR}::Sql
         engine_core
-        game_systems
         render_gl
+        game_systems
 )
 
 # Include directories

+ 160 - 0
tests/core/serialization_test.cpp

@@ -592,6 +592,15 @@ TEST_F(SerializationTest, CompleteEntityWithAllComponents) {
   auto *capture = entity->add_component<CaptureComponent>();
   capture->is_being_captured = true;
 
+  auto *hold_mode = entity->add_component<HoldModeComponent>();
+  hold_mode->active = true;
+
+  auto *healer = entity->add_component<HealerComponent>();
+  healer->healing_amount = 10;
+
+  auto *catapult = entity->add_component<CatapultLoadingComponent>();
+  catapult->state = CatapultLoadingComponent::LoadingState::Idle;
+
   QJsonObject json = Serialization::serializeEntity(entity);
 
   EXPECT_TRUE(json.contains("transform"));
@@ -604,6 +613,9 @@ TEST_F(SerializationTest, CompleteEntityWithAllComponents) {
   EXPECT_TRUE(json.contains("production"));
   EXPECT_TRUE(json.contains("aiControlled"));
   EXPECT_TRUE(json.contains("capture"));
+  EXPECT_TRUE(json.contains("hold_mode"));
+  EXPECT_TRUE(json.contains("healer"));
+  EXPECT_TRUE(json.contains("catapult_loading"));
 
   auto *new_entity = world->create_entity();
   Serialization::deserializeEntity(new_entity, json);
@@ -618,6 +630,9 @@ TEST_F(SerializationTest, CompleteEntityWithAllComponents) {
   EXPECT_NE(new_entity->get_component<ProductionComponent>(), nullptr);
   EXPECT_NE(new_entity->get_component<AIControlledComponent>(), nullptr);
   EXPECT_NE(new_entity->get_component<CaptureComponent>(), nullptr);
+  EXPECT_NE(new_entity->get_component<HoldModeComponent>(), nullptr);
+  EXPECT_NE(new_entity->get_component<HealerComponent>(), nullptr);
+  EXPECT_NE(new_entity->get_component<CatapultLoadingComponent>(), nullptr);
 }
 
 TEST_F(SerializationTest, EmptyWorldSerialization) {
@@ -630,3 +645,148 @@ TEST_F(SerializationTest, EmptyWorldSerialization) {
   QJsonArray entities = world_obj["entities"].toArray();
   EXPECT_EQ(entities.size(), 0);
 }
+
+TEST_F(SerializationTest, HoldModeComponentSerialization) {
+  auto *entity = world->create_entity();
+  auto *hold_mode = entity->add_component<HoldModeComponent>();
+
+  hold_mode->active = false;
+  hold_mode->exit_cooldown = 1.5F;
+  hold_mode->stand_up_duration = 3.0F;
+
+  QJsonObject json = Serialization::serializeEntity(entity);
+
+  ASSERT_TRUE(json.contains("hold_mode"));
+  QJsonObject hold_mode_obj = json["hold_mode"].toObject();
+
+  EXPECT_FALSE(hold_mode_obj["active"].toBool());
+  EXPECT_FLOAT_EQ(hold_mode_obj["exit_cooldown"].toDouble(), 1.5);
+  EXPECT_FLOAT_EQ(hold_mode_obj["stand_up_duration"].toDouble(), 3.0);
+}
+
+TEST_F(SerializationTest, HoldModeComponentRoundTrip) {
+  auto *original_entity = world->create_entity();
+  auto *hold_mode = original_entity->add_component<HoldModeComponent>();
+  hold_mode->active = true;
+  hold_mode->exit_cooldown = 2.5F;
+  hold_mode->stand_up_duration = 4.0F;
+
+  QJsonObject json = Serialization::serializeEntity(original_entity);
+
+  auto *new_entity = world->create_entity();
+  Serialization::deserializeEntity(new_entity, json);
+
+  auto *deserialized = new_entity->get_component<HoldModeComponent>();
+  ASSERT_NE(deserialized, nullptr);
+  EXPECT_TRUE(deserialized->active);
+  EXPECT_FLOAT_EQ(deserialized->exit_cooldown, 2.5F);
+  EXPECT_FLOAT_EQ(deserialized->stand_up_duration, 4.0F);
+}
+
+TEST_F(SerializationTest, HealerComponentSerialization) {
+  auto *entity = world->create_entity();
+  auto *healer = entity->add_component<HealerComponent>();
+
+  healer->healing_range = 12.0F;
+  healer->healing_amount = 10;
+  healer->healing_cooldown = 3.0F;
+  healer->time_since_last_heal = 1.0F;
+
+  QJsonObject json = Serialization::serializeEntity(entity);
+
+  ASSERT_TRUE(json.contains("healer"));
+  QJsonObject healer_obj = json["healer"].toObject();
+
+  EXPECT_FLOAT_EQ(healer_obj["healing_range"].toDouble(), 12.0);
+  EXPECT_EQ(healer_obj["healing_amount"].toInt(), 10);
+  EXPECT_FLOAT_EQ(healer_obj["healing_cooldown"].toDouble(), 3.0);
+  EXPECT_FLOAT_EQ(healer_obj["time_since_last_heal"].toDouble(), 1.0);
+}
+
+TEST_F(SerializationTest, HealerComponentRoundTrip) {
+  auto *original_entity = world->create_entity();
+  auto *healer = original_entity->add_component<HealerComponent>();
+  healer->healing_range = 15.0F;
+  healer->healing_amount = 8;
+  healer->healing_cooldown = 4.0F;
+  healer->time_since_last_heal = 2.0F;
+
+  QJsonObject json = Serialization::serializeEntity(original_entity);
+
+  auto *new_entity = world->create_entity();
+  Serialization::deserializeEntity(new_entity, json);
+
+  auto *deserialized = new_entity->get_component<HealerComponent>();
+  ASSERT_NE(deserialized, nullptr);
+  EXPECT_FLOAT_EQ(deserialized->healing_range, 15.0F);
+  EXPECT_EQ(deserialized->healing_amount, 8);
+  EXPECT_FLOAT_EQ(deserialized->healing_cooldown, 4.0F);
+  EXPECT_FLOAT_EQ(deserialized->time_since_last_heal, 2.0F);
+}
+
+TEST_F(SerializationTest, CatapultLoadingComponentSerialization) {
+  auto *entity = world->create_entity();
+  auto *catapult = entity->add_component<CatapultLoadingComponent>();
+
+  catapult->state = CatapultLoadingComponent::LoadingState::Loading;
+  catapult->loading_time = 1.0F;
+  catapult->loading_duration = 3.0F;
+  catapult->firing_time = 0.0F;
+  catapult->firing_duration = 1.0F;
+  catapult->target_id = 42;
+  catapult->target_locked_x = 100.0F;
+  catapult->target_locked_y = 50.0F;
+  catapult->target_locked_z = 200.0F;
+  catapult->target_position_locked = true;
+
+  QJsonObject json = Serialization::serializeEntity(entity);
+
+  ASSERT_TRUE(json.contains("catapult_loading"));
+  QJsonObject catapult_obj = json["catapult_loading"].toObject();
+
+  EXPECT_EQ(catapult_obj["state"].toInt(),
+            static_cast<int>(CatapultLoadingComponent::LoadingState::Loading));
+  EXPECT_FLOAT_EQ(catapult_obj["loading_time"].toDouble(), 1.0);
+  EXPECT_FLOAT_EQ(catapult_obj["loading_duration"].toDouble(), 3.0);
+  EXPECT_FLOAT_EQ(catapult_obj["firing_time"].toDouble(), 0.0);
+  EXPECT_FLOAT_EQ(catapult_obj["firing_duration"].toDouble(), 1.0);
+  EXPECT_EQ(catapult_obj["target_id"].toVariant().toULongLong(), 42ULL);
+  EXPECT_FLOAT_EQ(catapult_obj["target_locked_x"].toDouble(), 100.0);
+  EXPECT_FLOAT_EQ(catapult_obj["target_locked_y"].toDouble(), 50.0);
+  EXPECT_FLOAT_EQ(catapult_obj["target_locked_z"].toDouble(), 200.0);
+  EXPECT_TRUE(catapult_obj["target_position_locked"].toBool());
+}
+
+TEST_F(SerializationTest, CatapultLoadingComponentRoundTrip) {
+  auto *original_entity = world->create_entity();
+  auto *catapult = original_entity->add_component<CatapultLoadingComponent>();
+  catapult->state = CatapultLoadingComponent::LoadingState::ReadyToFire;
+  catapult->loading_time = 2.0F;
+  catapult->loading_duration = 4.0F;
+  catapult->firing_time = 0.25F;
+  catapult->firing_duration = 0.75F;
+  catapult->target_id = 99;
+  catapult->target_locked_x = 150.0F;
+  catapult->target_locked_y = 75.0F;
+  catapult->target_locked_z = 250.0F;
+  catapult->target_position_locked = false;
+
+  QJsonObject json = Serialization::serializeEntity(original_entity);
+
+  auto *new_entity = world->create_entity();
+  Serialization::deserializeEntity(new_entity, json);
+
+  auto *deserialized = new_entity->get_component<CatapultLoadingComponent>();
+  ASSERT_NE(deserialized, nullptr);
+  EXPECT_EQ(deserialized->state,
+            CatapultLoadingComponent::LoadingState::ReadyToFire);
+  EXPECT_FLOAT_EQ(deserialized->loading_time, 2.0F);
+  EXPECT_FLOAT_EQ(deserialized->loading_duration, 4.0F);
+  EXPECT_FLOAT_EQ(deserialized->firing_time, 0.25F);
+  EXPECT_FLOAT_EQ(deserialized->firing_duration, 0.75F);
+  EXPECT_EQ(deserialized->target_id, 99U);
+  EXPECT_FLOAT_EQ(deserialized->target_locked_x, 150.0F);
+  EXPECT_FLOAT_EQ(deserialized->target_locked_y, 75.0F);
+  EXPECT_FLOAT_EQ(deserialized->target_locked_z, 250.0F);
+  EXPECT_FALSE(deserialized->target_position_locked);
+}