feat: add more rules in BMapInspector
This commit is contained in:
@@ -17,6 +17,7 @@ PRIVATE
|
||||
Rule/YYCRules.cpp
|
||||
Rule/ZZQRules.cpp
|
||||
Rule/BBugRules.cpp
|
||||
Rule/SOneRules.cpp
|
||||
)
|
||||
# Setup headers
|
||||
target_sources(BMapInspector
|
||||
@@ -36,6 +37,7 @@ FILES
|
||||
Rule/YYCRules.hpp
|
||||
Rule/ZZQRules.hpp
|
||||
Rule/BBugRules.hpp
|
||||
Rule/SOneRules.hpp
|
||||
)
|
||||
# Setup header infomation
|
||||
target_include_directories(BMapInspector
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Rule/YYCRules.hpp"
|
||||
#include "Rule/BBugRules.hpp"
|
||||
#include "Rule/ZZQRules.hpp"
|
||||
#include "Rule/SOneRules.hpp"
|
||||
|
||||
namespace BMapInspector::Rule {
|
||||
|
||||
@@ -20,11 +21,13 @@ namespace BMapInspector::Rule {
|
||||
|
||||
Ruleset::Ruleset() : rules() {
|
||||
// Add rule into list.
|
||||
//rules.emplace_back(new Gp1Rule());
|
||||
//rules.emplace_back(new Gp2Rule());
|
||||
//rules.emplace_back(new GpRule1());
|
||||
//rules.emplace_back(new GpRule2());
|
||||
//rules.emplace_back(new Gp3Rule());
|
||||
//rules.emplace_back(new Chirs1Rule());
|
||||
rules.emplace_back(new YYCRule1());
|
||||
rules.emplace_back(new YYCRule2());
|
||||
rules.emplace_back(new SOneRule1());
|
||||
// Add more rules...
|
||||
}
|
||||
|
||||
|
||||
@@ -4,46 +4,50 @@ namespace BMapInspector::Rule {
|
||||
|
||||
#pragma region GP1 Rule
|
||||
|
||||
Gp1Rule::Gp1Rule() : IRule() {}
|
||||
GpRule1::GpRule1() : IRule() {}
|
||||
|
||||
Gp1Rule::~Gp1Rule() {}
|
||||
GpRule1::~GpRule1() {}
|
||||
|
||||
std::u8string_view Gp1Rule::GetRuleName() const {
|
||||
std::u8string_view GpRule1::GetRuleName() const {
|
||||
return u8"GP1";
|
||||
}
|
||||
|
||||
void Gp1Rule::Check(Reporter::Reporter& reporter, Map::Level& level) const {}
|
||||
void GpRule1::Check(Reporter::Reporter& reporter, Map::Level& level) const {}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region GP2 Rule
|
||||
|
||||
Gp2Rule::Gp2Rule() : IRule() {}
|
||||
constexpr char8_t GP2[] = u8"GP2";
|
||||
|
||||
Gp2Rule::~Gp2Rule() {}
|
||||
GpRule2::GpRule2() : IRule() {}
|
||||
|
||||
std::u8string_view Gp2Rule::GetRuleName() const {
|
||||
return u8"GP2";
|
||||
GpRule2::~GpRule2() {}
|
||||
|
||||
std::u8string_view GpRule2::GetRuleName() const {
|
||||
return GP2;
|
||||
}
|
||||
|
||||
void Gp2Rule::Check(Reporter::Reporter& reporter, Map::Level& level) const {}
|
||||
void GpRule2::Check(Reporter::Reporter& reporter, Map::Level& level) const {
|
||||
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region GP3 Rule
|
||||
|
||||
Gp3Rule::Gp3Rule() : IRule() {}
|
||||
|
||||
Gp3Rule::~Gp3Rule() {}
|
||||
|
||||
std::u8string_view Gp3Rule::GetRuleName() const {
|
||||
return u8"GP3";
|
||||
}
|
||||
|
||||
void Gp3Rule::Check(Reporter::Reporter& reporter, Map::Level& level) const {
|
||||
// TODO: Mesh hash is not implemented.
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
//
|
||||
// Gp3Rule::Gp3Rule() : IRule() {}
|
||||
//
|
||||
// Gp3Rule::~Gp3Rule() {}
|
||||
//
|
||||
// std::u8string_view Gp3Rule::GetRuleName() const {
|
||||
// return u8"GP3";
|
||||
// }
|
||||
//
|
||||
// void Gp3Rule::Check(Reporter::Reporter& reporter, Map::Level& level) const {
|
||||
// // TODO: Mesh hash is not implemented.
|
||||
// }
|
||||
//
|
||||
//#pragma endregion
|
||||
|
||||
} // namespace BMapInspector::Rule
|
||||
|
||||
@@ -10,11 +10,11 @@ namespace BMapInspector::Rule {
|
||||
* @details
|
||||
* The most comprehensive group checker inspired from Ballance Blender Plugin.
|
||||
*/
|
||||
class Gp1Rule : public IRule {
|
||||
class GpRule1 : public IRule {
|
||||
public:
|
||||
Gp1Rule();
|
||||
virtual ~Gp1Rule();
|
||||
YYCC_DELETE_COPY_MOVE(Gp1Rule)
|
||||
GpRule1();
|
||||
virtual ~GpRule1();
|
||||
YYCC_DELETE_COPY_MOVE(GpRule1)
|
||||
|
||||
public:
|
||||
std::u8string_view GetRuleName() const override;
|
||||
@@ -24,35 +24,40 @@ namespace BMapInspector::Rule {
|
||||
/**
|
||||
* @brief Gamepiaynmo Rule 2
|
||||
* @details
|
||||
* This rule make sure that one Ballance element must be grouped into only one sector group.
|
||||
* Multiple grouping and none grouping will throw error.
|
||||
* Every Ballance group should not have any groups with same name.
|
||||
*/
|
||||
class Gp2Rule : public IRule {
|
||||
class GpRule2 : public IRule {
|
||||
public:
|
||||
Gp2Rule();
|
||||
virtual ~Gp2Rule();
|
||||
YYCC_DELETE_COPY_MOVE(Gp2Rule)
|
||||
GpRule2();
|
||||
virtual ~GpRule2();
|
||||
YYCC_DELETE_COPY_MOVE(GpRule2)
|
||||
|
||||
public:
|
||||
std::u8string_view GetRuleName() const override;
|
||||
void Check(Reporter::Reporter& reporter, Map::Level& level) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Gamepiaynmo Rule 3
|
||||
* @details
|
||||
* This rule make sure that all Ballance element is grouped into correct element group.
|
||||
* This rule will check the mesh of PH and guess which element it is.
|
||||
*/
|
||||
class Gp3Rule : public IRule {
|
||||
public:
|
||||
Gp3Rule();
|
||||
virtual ~Gp3Rule();
|
||||
YYCC_DELETE_COPY_MOVE(Gp3Rule)
|
||||
///**
|
||||
// * @brief Gamepiaynmo Rule 2
|
||||
// * @details
|
||||
// * This rule make sure that one Ballance element must be grouped into only one sector group.
|
||||
// * Multiple grouping and none grouping will throw error.
|
||||
// */
|
||||
///**
|
||||
// * @brief Gamepiaynmo Rule 3
|
||||
// * @details
|
||||
// * This rule make sure that all Ballance element is grouped into correct element group.
|
||||
// * This rule will check the mesh of PH and guess which element it is.
|
||||
// */
|
||||
//class Gp3Rule : public IRule {
|
||||
//public:
|
||||
// Gp3Rule();
|
||||
// virtual ~Gp3Rule();
|
||||
// YYCC_DELETE_COPY_MOVE(Gp3Rule)
|
||||
|
||||
public:
|
||||
std::u8string_view GetRuleName() const override;
|
||||
void Check(Reporter::Reporter& reporter, Map::Level& level) const override;
|
||||
};
|
||||
//public:
|
||||
// std::u8string_view GetRuleName() const override;
|
||||
// void Check(Reporter::Reporter& reporter, Map::Level& level) const override;
|
||||
//};
|
||||
|
||||
}
|
||||
|
||||
39
Ballance/BMapInspector/Rule/SOneRules.cpp
Normal file
39
Ballance/BMapInspector/Rule/SOneRules.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "SOneRules.hpp"
|
||||
#include "Shared.hpp"
|
||||
|
||||
namespace L = LibCmo;
|
||||
namespace C = LibCmo::CK2;
|
||||
namespace O = LibCmo::CK2::ObjImpls;
|
||||
|
||||
namespace BMapInspector::Rule {
|
||||
|
||||
#pragma region SOne Rule 1
|
||||
|
||||
constexpr char8_t SONE1[] = u8"SONE1";
|
||||
|
||||
SOneRule1::SOneRule1() : IRule() {}
|
||||
|
||||
SOneRule1::~SOneRule1() {}
|
||||
|
||||
std::u8string_view SOneRule1::GetRuleName() const {
|
||||
return SONE1;
|
||||
}
|
||||
|
||||
void SOneRule1::Check(Reporter::Reporter& reporter, Map::Level& level) const {
|
||||
auto* ctx = level.GetCKContext();
|
||||
auto physicalized_3dobjects = Shared::FetchPhysicalized3dObjects(ctx);
|
||||
|
||||
for (auto* physicalized_3dobject : physicalized_3dobjects) {
|
||||
auto* mesh = physicalized_3dobject->GetCurrentMesh();
|
||||
if (mesh == nullptr) {
|
||||
reporter.FormatError(
|
||||
SONE1,
|
||||
u8R"(Object "%s" is grouped into physicalization group, but it doesn't have any associated mesh. This will cause itself and following objects can not be physicalized.)",
|
||||
Shared::RenderObjectName(physicalized_3dobject));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
} // namespace BMapInspector::Rule
|
||||
23
Ballance/BMapInspector/Rule/SOneRules.hpp
Normal file
23
Ballance/BMapInspector/Rule/SOneRules.hpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#include "../Rule.hpp"
|
||||
|
||||
namespace BMapInspector::Rule {
|
||||
|
||||
/**
|
||||
* @brief SomeOne_001 Rule 1
|
||||
* @details
|
||||
* If there is a physicalized object without any mesh,
|
||||
* itself and following objects will not be physicalized.
|
||||
*/
|
||||
class SOneRule1 : public IRule {
|
||||
public:
|
||||
SOneRule1();
|
||||
virtual ~SOneRule1();
|
||||
YYCC_DELETE_COPY_MOVE(SOneRule1)
|
||||
|
||||
public:
|
||||
std::u8string_view GetRuleName() const override;
|
||||
void Check(Reporter::Reporter& reporter, Map::Level& level) const override;
|
||||
};
|
||||
|
||||
} // namespace BMapInspector::Rule
|
||||
@@ -19,6 +19,28 @@ namespace BMapInspector::Rule::Shared {
|
||||
return static_cast<O::CKGroup*>(ctx->GetObjectByNameAndClass(name, C::CK_CLASSID::CKCID_GROUP, nullptr));
|
||||
}
|
||||
|
||||
static void Iter3dObjectsEx(std::vector<O::CK3dObject*>& container, O::CKGroup* group) {
|
||||
for (L::CKDWORD obj_idx = 0; obj_idx < group->GetObjectCount(); ++obj_idx) {
|
||||
auto* group_beobject = group->GetObject(obj_idx);
|
||||
if (!C::CKIsChildClassOf(group_beobject->GetClassID(), C::CK_CLASSID::CKCID_3DOBJECT)) continue;
|
||||
auto* group_3dobject = static_cast<O::CK3dObject*>(group_beobject);
|
||||
container.emplace_back(group_3dobject);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<O::CK3dObject*> FetchPhysicalized3dObjects(C::CKContext* ctx) {
|
||||
std::vector<O::CK3dObject*> rv;
|
||||
|
||||
auto* phys_floors = FetchGroup(ctx, GroupNames::PHYS_FLOORS);
|
||||
if (phys_floors != nullptr) Iter3dObjectsEx(rv, phys_floors);
|
||||
auto* phys_floorrails = FetchGroup(ctx, GroupNames::PHYS_FLOORRAILS);
|
||||
if (phys_floorrails != nullptr) Iter3dObjectsEx(rv, phys_floorrails);
|
||||
auto* phys_floorstopper = FetchGroup(ctx, GroupNames::PHYS_FLOORSTOPPER);
|
||||
if (phys_floorstopper != nullptr) Iter3dObjectsEx(rv, phys_floorstopper);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool CheckTextureFileName(O::CKTexture* tex, L::CKSTRING name) {
|
||||
// Get file name
|
||||
auto filename = tex->GetUnderlyingData().GetSlotFileName(0);
|
||||
@@ -30,14 +52,9 @@ namespace BMapInspector::Rule::Shared {
|
||||
return C::CKStrEqualI(filename_part.c_str(), name);
|
||||
}
|
||||
|
||||
std::vector<O::CK3dEntity*> Iter3dEntities(O::CKGroup* group) {
|
||||
std::vector<O::CK3dEntity*> rv;
|
||||
for (L::CKDWORD obj_idx = 0; obj_idx < group->GetObjectCount(); ++obj_idx) {
|
||||
auto* group_object = group->GetObject(obj_idx);
|
||||
if (!C::CKIsChildClassOf(group_object->GetClassID(), C::CK_CLASSID::CKCID_3DENTITY)) continue;
|
||||
auto* group_3dentity = static_cast<O::CK3dEntity*>(group_object);
|
||||
rv.emplace_back(group_3dentity);
|
||||
}
|
||||
std::vector<O::CK3dObject*> Iter3dObjects(O::CKGroup* group) {
|
||||
std::vector<O::CK3dObject*> rv;
|
||||
Iter3dObjectsEx(rv, group);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include <VTAll.hpp>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
namespace BMapInspector::Rule::Shared {
|
||||
|
||||
@@ -11,12 +12,19 @@ namespace BMapInspector::Rule::Shared {
|
||||
#pragma region Constant Values
|
||||
|
||||
namespace GroupNames {
|
||||
// clang-format off
|
||||
constexpr char8_t PHYS_FLOORS[] = u8"Phys_Floors";
|
||||
constexpr char8_t PHYS_FLOORRAILS[] = u8"Phys_FloorRails";
|
||||
}
|
||||
constexpr char8_t PHYS_FLOORSTOPPER[] = u8"Phys_FloorStopper";
|
||||
// clang-format on
|
||||
} // namespace GroupNames
|
||||
|
||||
namespace TextureNames {
|
||||
// clang-format off
|
||||
constexpr char8_t RAIL_ENVIRONMENT[] = u8"Rail_Environment.bmp";
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
} // namespace TextureNames
|
||||
|
||||
#pragma endregion
|
||||
|
||||
@@ -29,6 +37,7 @@ namespace BMapInspector::Rule::Shared {
|
||||
* @return
|
||||
*/
|
||||
O::CKGroup* FetchGroup(C::CKContext* ctx, L::CKSTRING name);
|
||||
std::vector<O::CK3dObject*> FetchPhysicalized3dObjects(C::CKContext* ctx);
|
||||
/**
|
||||
* @brief Check whether given CKTexture has the given file name (case-insensitive).
|
||||
* @param[in] tex Can not be nullptr.
|
||||
@@ -42,7 +51,7 @@ namespace BMapInspector::Rule::Shared {
|
||||
* @param[in] group Can not be nullptr.
|
||||
* @return All objects is the child class of CK3dEntity.
|
||||
*/
|
||||
std::vector<O::CK3dEntity*> Iter3dEntities(O::CKGroup* group);
|
||||
std::vector<O::CK3dObject*> Iter3dObjects(O::CKGroup* group);
|
||||
/**
|
||||
* @brief
|
||||
* @param[in] mesh Can not be nullptr.
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "YYCRules.hpp"
|
||||
#include "Shared.hpp"
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
|
||||
namespace L = LibCmo;
|
||||
namespace C = LibCmo::CK2;
|
||||
@@ -12,7 +14,7 @@ namespace BMapInspector::Rule {
|
||||
|
||||
constexpr char8_t YYC1[] = u8"YYC1";
|
||||
|
||||
YYCRule1::YYCRule1() {}
|
||||
YYCRule1::YYCRule1() : IRule() {}
|
||||
|
||||
YYCRule1::~YYCRule1() {}
|
||||
|
||||
@@ -30,10 +32,10 @@ namespace BMapInspector::Rule {
|
||||
// Create container holding smooth meshes
|
||||
std::set<O::CKMesh*> smooth_meshes;
|
||||
// We iterate all object grouped into it.
|
||||
auto group_3dentities = Shared::Iter3dEntities(phys_floorrails);
|
||||
for (auto* group_3dentity : group_3dentities) {
|
||||
auto group_3dobjects = Shared::Iter3dObjects(phys_floorrails);
|
||||
for (auto* group_3dobject : group_3dobjects) {
|
||||
// Then we iterate their current meshes
|
||||
auto* mesh = group_3dentity->GetCurrentMesh();
|
||||
auto* mesh = group_3dobject->GetCurrentMesh();
|
||||
if (mesh == nullptr) continue;
|
||||
|
||||
// Iterate all meshes
|
||||
@@ -47,7 +49,7 @@ namespace BMapInspector::Rule {
|
||||
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.)",
|
||||
Shared::RenderObjectName(group_3dentity),
|
||||
Shared::RenderObjectName(group_3dobject),
|
||||
Shared::RenderObjectName(texture),
|
||||
Shared::RenderObjectName(mesh),
|
||||
Shared::RenderObjectName(mtl));
|
||||
@@ -81,4 +83,50 @@ namespace BMapInspector::Rule {
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region YYC Rule 2
|
||||
|
||||
constexpr char8_t YYC2[] = u8"YYC2";
|
||||
|
||||
YYCRule2::YYCRule2() : IRule() {}
|
||||
|
||||
YYCRule2::~YYCRule2() {}
|
||||
|
||||
std::u8string_view YYCRule2::GetRuleName() const {
|
||||
return YYC2;
|
||||
}
|
||||
|
||||
void YYCRule2::Check(Reporter::Reporter& reporter, Map::Level& level) const {
|
||||
auto* ctx = level.GetCKContext();
|
||||
auto physicalized_3dobjects = Shared::FetchPhysicalized3dObjects(ctx);
|
||||
|
||||
// Iterate all physicalized 3dobject
|
||||
for (auto* physicalized_3dobject : physicalized_3dobjects) {
|
||||
// Get its mesh
|
||||
auto* mesh = physicalized_3dobject->GetCurrentMesh();
|
||||
if (mesh == nullptr) continue;
|
||||
|
||||
// Create a bool vector with vertex count and false init value.
|
||||
std::vector<bool> used_vertex(mesh->GetVertexCount(), false);
|
||||
// Iterate all face and set their vertex as used.
|
||||
auto* face_indices = mesh->GetFaceIndices();
|
||||
for (L::CKDWORD face_idx = 0; face_idx < mesh->GetFaceCount(); ++face_idx) {
|
||||
used_vertex[face_indices[face_idx * 3]] = true;
|
||||
used_vertex[face_indices[face_idx * 3 + 1]] = true;
|
||||
used_vertex[face_indices[face_idx * 3 + 2]] = true;
|
||||
}
|
||||
// Check whether there is unused vertex
|
||||
auto has_unused_vertex = std::any_of(used_vertex.begin(), used_vertex.end(), [](bool v) { return v == false; });
|
||||
// If there is unused vertex, report error
|
||||
if (has_unused_vertex) {
|
||||
reporter.FormatError(
|
||||
YYC2,
|
||||
u8R"(Object "%s" is grouped into physicalization groups, and its referred mesh "%s" has isolated vertex. This will cause it can not be physicalized.)",
|
||||
Shared::RenderObjectName(physicalized_3dobject),
|
||||
Shared::RenderObjectName(mesh));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
} // namespace BMapInspector::Rule
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace BMapInspector::Rule {
|
||||
class YYCRule1 : public IRule {
|
||||
public:
|
||||
YYCRule1();
|
||||
~YYCRule1();
|
||||
virtual ~YYCRule1();
|
||||
YYCC_DELETE_COPY_MOVE(YYCRule1)
|
||||
|
||||
public:
|
||||
@@ -20,4 +20,21 @@ namespace BMapInspector::Rule {
|
||||
void Check(Reporter::Reporter& reporter, Map::Level& level) const override;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief YYC12345 Rule 2
|
||||
* @details
|
||||
* The object grouped into physicalization group should not have isolated vertex,
|
||||
* otherwise it will fail to be physicalized.
|
||||
*/
|
||||
class YYCRule2 : public IRule {
|
||||
public:
|
||||
YYCRule2();
|
||||
virtual ~YYCRule2();
|
||||
YYCC_DELETE_COPY_MOVE(YYCRule2)
|
||||
|
||||
public:
|
||||
std::u8string_view GetRuleName() const override;
|
||||
void Check(Reporter::Reporter& reporter, Map::Level& level) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user