diff --git a/Ballance/BMapInspector/CMakeLists.txt b/Ballance/BMapInspector/CMakeLists.txt index 0c19734..d6ec689 100644 --- a/Ballance/BMapInspector/CMakeLists.txt +++ b/Ballance/BMapInspector/CMakeLists.txt @@ -19,6 +19,7 @@ PRIVATE Rule/BBugRules.cpp Rule/SOneRules.cpp Rule/SSBRules.cpp + Rule/LXRules.cpp ) # Setup headers target_sources(BMapInspector @@ -40,6 +41,7 @@ FILES Rule/BBugRules.hpp Rule/SOneRules.hpp Rule/SSBRules.hpp + Rule/LXRules.hpp ) # Setup header infomation target_include_directories(BMapInspector diff --git a/Ballance/BMapInspector/Rule.cpp b/Ballance/BMapInspector/Rule.cpp index 49a09ac..81afb4d 100644 --- a/Ballance/BMapInspector/Rule.cpp +++ b/Ballance/BMapInspector/Rule.cpp @@ -7,6 +7,7 @@ #include "Rule/ZZQRules.hpp" #include "Rule/SOneRules.hpp" #include "Rule/SSBRules.hpp" +#include "Rule/LXRules.hpp" namespace BMapInspector::Rule { @@ -30,6 +31,7 @@ namespace BMapInspector::Rule { rules.emplace_back(new YYCRule2()); rules.emplace_back(new SOneRule1()); rules.emplace_back(new SSBRule1()); + rules.emplace_back(new LXRule1()); // Add more rules... } diff --git a/Ballance/BMapInspector/Rule/LXRules.cpp b/Ballance/BMapInspector/Rule/LXRules.cpp new file mode 100644 index 0000000..bb6be5f --- /dev/null +++ b/Ballance/BMapInspector/Rule/LXRules.cpp @@ -0,0 +1,119 @@ +#include "YYCRules.hpp" +#include "Shared.hpp" +#include "LXRules.hpp" +#include + +namespace L = LibCmo; +namespace C = LibCmo::CK2; +namespace O = LibCmo::CK2::ObjImpls; + +namespace BMapInspector::Rule { +#pragma region LX Rule 1 + + constexpr char8_t LX1[] = u8"LX1"; + + LXRule1::LXRule1() : IRule() {} + + LXRule1::~LXRule1() {} + + std::u8string_view LXRule1::GetRuleName() const { + return LX1; + } + + void LXRule1::Check(Reporter::Reporter& reporter, Map::Level& level) const { + auto* ctx = level.GetCKContext(); + + // First we fetch all Ballance element and push them into set. + std::set elements; + for (auto* group_name : Shared::GroupNames::ALL_PH) { + auto* group = Shared::FetchGroup(ctx, group_name); + if (group == nullptr) continue; + auto group_objects = Shared::Iter3dObjects(group); + for (auto* group_object : group_objects) { + elements.emplace(group_object); + } + } + + // Then we analyse their mesh, material, texture and fill corresponding set. + std::set element_meshes; + std::set element_materials; + std::set element_textures; + for (auto* element_object : elements) { + auto* mesh = element_object->GetCurrentMesh(); + if (mesh == nullptr) continue; + + // Add into mesh set + auto mesh_insert_rv = element_meshes.emplace(mesh); + + // Only process it if we have inserted it + // because we do not want to duplicatedly process it. + if (mesh_insert_rv.second) { + // Iterate all meshes + auto mtls = Shared::IterMaterial(mesh); + for (auto* mtl : mtls) { + // Add into material set + auto mtl_insert_rv = element_materials.emplace(mtl); + + // Also only process it if we have inserted it + if (mtl_insert_rv.second) { + // Fetch texture + auto texture = mtl->GetTexture(); + if (texture == nullptr) continue; + // And insert it + element_textures.emplace(texture); + } + } + } + } + + // Now, check any other object whether use these data. + for (auto* other_object : level.Get3dObjects()) { + // If it is element, skip it. + if (elements.contains(other_object)) continue; + + // Get mesh + auto* mesh = other_object->GetCurrentMesh(); + if (mesh == nullptr) continue; + // And check mesh + if (element_meshes.contains(mesh)) { + reporter.FormatError( + LX1, + u8R"(Object "%s" used mesh "%s" is already used by a Ballance element. This will cause this object can not be rendered correctly in level.)", + Shared::RenderObjectName(other_object), + Shared::RenderObjectName(mesh)); + } else { + // If not, check material. + // Iterate all meshes + auto mtls = Shared::IterMaterial(mesh); + for (auto* mtl : mtls) { + if (element_materials.contains(mtl)) { + reporter.FormatError( + LX1, + u8R"(Object "%s" used material "%s" (referred by mesh "%s") is already used by a Ballance element. This will cause this object can not be rendered correctly in level.)", + Shared::RenderObjectName(other_object), + Shared::RenderObjectName(mtl), + Shared::RenderObjectName(mesh)); + } else { + // Still not, check texture. + // Fetch texture + auto texture = mtl->GetTexture(); + if (texture == nullptr) continue; + // And check it + if (element_textures.contains(texture)) { + reporter.FormatError( + LX1, + u8R"(Object "%s" used texture "%s" (referred by mesh "%s" and material "%s") is already used by a Ballance element. This will cause this object can not be rendered correctly in level.)", + Shared::RenderObjectName(other_object), + Shared::RenderObjectName(texture), + Shared::RenderObjectName(mesh), + Shared::RenderObjectName(mtl)); + } + } + } + } + } + } + +#pragma endregion + +} // namespace BMapInspector::Rule diff --git a/Ballance/BMapInspector/Rule/LXRules.hpp b/Ballance/BMapInspector/Rule/LXRules.hpp new file mode 100644 index 0000000..f605513 --- /dev/null +++ b/Ballance/BMapInspector/Rule/LXRules.hpp @@ -0,0 +1,22 @@ +#pragma once +#include "../Rule.hpp" + +namespace BMapInspector::Rule { + + /** + * @brief LengXi Rule 1 + * @details + * All meshes, materials and textures used by Ballance elements should not be used by any other objects. + */ + class LXRule1 : public IRule { + public: + LXRule1(); + virtual ~LXRule1(); + YYCC_DELETE_COPY_MOVE(LXRule1) + + public: + std::u8string_view GetRuleName() const override; + void Check(Reporter::Reporter& reporter, Map::Level& level) const override; + }; + +} diff --git a/Ballance/BMapInspector/Rule/SSBRules.cpp b/Ballance/BMapInspector/Rule/SSBRules.cpp index 2621ff5..f5dc3af 100644 --- a/Ballance/BMapInspector/Rule/SSBRules.cpp +++ b/Ballance/BMapInspector/Rule/SSBRules.cpp @@ -29,6 +29,13 @@ namespace BMapInspector::Rule { for (auto* physicalized_3dobject : physicalized_3dobjects) { // Get its world matrix const auto& matrix = physicalized_3dobject->GetWorldMatrix(); + + // YYC MARK: + // Following method is the bad way to check scale factor, + // because it rely on some premise. + // But it is simple, especially we do not have fully implement VxMatrix, + // or have any linear algebra library. + // Extract 3 columns V::VxVector3 col1(matrix[0][0], matrix[1][0], matrix[2][0]); V::VxVector3 col2(matrix[0][1], matrix[1][1], matrix[2][1]); diff --git a/Ballance/BMapInspector/Rule/Shared.hpp b/Ballance/BMapInspector/Rule/Shared.hpp index 5cbd1be..17c9a2c 100644 --- a/Ballance/BMapInspector/Rule/Shared.hpp +++ b/Ballance/BMapInspector/Rule/Shared.hpp @@ -16,6 +16,37 @@ namespace BMapInspector::Rule::Shared { constexpr char8_t PHYS_FLOORS[] = u8"Phys_Floors"; constexpr char8_t PHYS_FLOORRAILS[] = u8"Phys_FloorRails"; constexpr char8_t PHYS_FLOORSTOPPER[] = u8"Phys_FloorStopper"; + + constexpr std::array ALL_PH{ + u8"P_Extra_Life", + u8"P_Extra_Point", + u8"P_Trafo_Paper", + u8"P_Trafo_Stone", + u8"P_Trafo_Wood", + u8"P_Ball_Paper", + u8"P_Ball_Stone", + u8"P_Ball_Wood", + u8"P_Box", + u8"P_Dome", + u8"P_Modul_01", + u8"P_Modul_03", + u8"P_Modul_08", + u8"P_Modul_17", + u8"P_Modul_18", + u8"P_Modul_19", + u8"P_Modul_25", + u8"P_Modul_26", + u8"P_Modul_29", + u8"P_Modul_30", + u8"P_Modul_34", + u8"P_Modul_37", + u8"P_Modul_41", + u8"PS_Levelstart", + u8"PE_Levelende", + u8"PC_Checkpoints", + u8"PR_Resetpoints", + }; + // clang-format on } // namespace GroupNames diff --git a/Ballance/BMapInspector/Rule/YYCRules.cpp b/Ballance/BMapInspector/Rule/YYCRules.cpp index 8ad8248..44ed6df 100644 --- a/Ballance/BMapInspector/Rule/YYCRules.cpp +++ b/Ballance/BMapInspector/Rule/YYCRules.cpp @@ -48,7 +48,7 @@ namespace BMapInspector::Rule { // No, this is not rail texture, throw error. reporter.FormatError( YYC1, - u8R"(Object "%s" is grouped into Phys_FloorRails, but its texture "%s" (referred by mesh %s and material %s) seems not the rail texture. This will cause this object be smooth unexpectly.)", + u8R"(Object "%s" is grouped into Phys_FloorRails, but its texture "%s" (referred by mesh %s and material %s) seems not the rail texture. This will cause some parts of this object be smooth unexpectly.)", Shared::RenderObjectName(group_3dobject), Shared::RenderObjectName(texture), Shared::RenderObjectName(mesh),