feat: add new 2 rules for BMapInspector
This commit is contained in:
@@ -24,12 +24,13 @@ namespace BMapInspector::Rule {
|
|||||||
Ruleset::Ruleset() : rules() {
|
Ruleset::Ruleset() : rules() {
|
||||||
// Add rule into list.
|
// Add rule into list.
|
||||||
//rules.emplace_back(new GpRule1());
|
//rules.emplace_back(new GpRule1());
|
||||||
//rules.emplace_back(new GpRule2());
|
rules.emplace_back(new GpRule2());
|
||||||
//rules.emplace_back(new Gp3Rule());
|
//rules.emplace_back(new Gp3Rule());
|
||||||
//rules.emplace_back(new Chirs1Rule());
|
//rules.emplace_back(new Chirs1Rule());
|
||||||
rules.emplace_back(new YYCRule1());
|
rules.emplace_back(new YYCRule1());
|
||||||
rules.emplace_back(new YYCRule2());
|
rules.emplace_back(new YYCRule2());
|
||||||
rules.emplace_back(new BBugRule1());
|
rules.emplace_back(new BBugRule1());
|
||||||
|
rules.emplace_back(new ZZQRule1());
|
||||||
rules.emplace_back(new SOneRule1());
|
rules.emplace_back(new SOneRule1());
|
||||||
rules.emplace_back(new SSBRule1());
|
rules.emplace_back(new SSBRule1());
|
||||||
rules.emplace_back(new LXRule1());
|
rules.emplace_back(new LXRule1());
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
#include "GpRules.hpp"
|
#include "GpRules.hpp"
|
||||||
|
#include "Shared.hpp"
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
namespace L = LibCmo;
|
||||||
|
namespace C = LibCmo::CK2;
|
||||||
|
namespace O = LibCmo::CK2::ObjImpls;
|
||||||
|
|
||||||
namespace BMapInspector::Rule {
|
namespace BMapInspector::Rule {
|
||||||
|
|
||||||
@@ -29,7 +35,95 @@ namespace BMapInspector::Rule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GpRule2::Check(Reporter::Reporter& reporter, Map::Level& level) const {
|
void GpRule2::Check(Reporter::Reporter& reporter, Map::Level& level) const {
|
||||||
|
auto* ctx = level.GetCKContext();
|
||||||
|
Shared::SectorNameBuilder builder;
|
||||||
|
|
||||||
|
// We need collect all group names first,
|
||||||
|
// becuase in following code we need frequent visit them
|
||||||
|
std::set<std::u8string> group_names;
|
||||||
|
for (auto* group : level.GetGroups()) {
|
||||||
|
auto group_name = group->GetName();
|
||||||
|
if (group_name != nullptr) {
|
||||||
|
group_names.emplace(std::u8string(group_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the sector count of this game.
|
||||||
|
L::CKDWORD sector_count;
|
||||||
|
for (sector_count = Shared::MIN_SECTOR; sector_count <= Shared::MAX_SECTOR; ++sector_count) {
|
||||||
|
// Build name first with special treat for sector 9
|
||||||
|
if (sector_count != 9) {
|
||||||
|
auto sector_name = builder.get_name(sector_count);
|
||||||
|
if (!group_names.contains(sector_name)) {
|
||||||
|
if (sector_count == Shared::MIN_SECTOR) {
|
||||||
|
reporter.WriteError(GP2, u8R"(Can not find any reasonable sector group in your map.)");
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto sector_names = builder.get_sector9_names();
|
||||||
|
bool has_legacy_sector = group_names.contains(sector_names.legacy_name);
|
||||||
|
bool has_intuitive_sector = group_names.contains(sector_names.intuitive_name);
|
||||||
|
if (!has_legacy_sector && !has_intuitive_sector) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (has_legacy_sector && has_intuitive_sector) {
|
||||||
|
reporter.FormatError(GP2, u8R"(Found "Sector_9" and "Sector_09" at the same map. This is not allowed.)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Now sector_count is the first sector which can not find,
|
||||||
|
// so we need minus one on it.
|
||||||
|
--sector_count;
|
||||||
|
|
||||||
|
// Report sector count info.
|
||||||
|
reporter.FormatInfo(GP2, u8"Your map has %" PRIuCKDWORD " sector(s).", sector_count);
|
||||||
|
// Report special warning for map which only contain 1 sector.
|
||||||
|
if (sector_count == 1) {
|
||||||
|
reporter.WriteWarning(
|
||||||
|
GP2,
|
||||||
|
u8"Your map only have one sector. This is okey but not suggested because it will cause mosaic issue on the flames of checkpoint. Consider adding another sector to resolve this issue.");
|
||||||
|
}
|
||||||
|
// Report warning for sector greater than 8.
|
||||||
|
if (sector_count > 8) {
|
||||||
|
reporter.WriteWarning(
|
||||||
|
GP2,
|
||||||
|
u8"You are creating a map with more than 8 levels. This will cause vanilla Ballance freezed when loading it. Please make sure that all players of your map have properly set 999 sector loader up.");
|
||||||
|
}
|
||||||
|
// If there is sector 9, check its kind and report wanring if it is intuitive kind.
|
||||||
|
if (sector_count > 8) {
|
||||||
|
auto sector_names = builder.get_sector9_names();
|
||||||
|
if (group_names.contains(sector_names.intuitive_name)) {
|
||||||
|
reporter.WriteWarning(
|
||||||
|
GP2, u8R"(You are using intuitive sector name, "Sector_09", for sector 9. This is only accepted by new 999 sector loader.)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We continue check following sectors to make sure that all sector is successive.
|
||||||
|
for (L::CKDWORD i = sector_count + 1; i <= Shared::MAX_SECTOR; ++i) {
|
||||||
|
if (i != 9) {
|
||||||
|
auto sector_name = builder.get_name(i);
|
||||||
|
if (group_names.contains(sector_name)) {
|
||||||
|
reporter.FormatError(GP2,
|
||||||
|
u8R"(Found group "%s" unexpected. Please check whether sector groups are successive in your map.)",
|
||||||
|
sector_name.c_str());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto sector_names = builder.get_sector9_names();
|
||||||
|
bool has_legacy_sector = group_names.contains(sector_names.legacy_name);
|
||||||
|
bool has_intuitive_sector = group_names.contains(sector_names.intuitive_name);
|
||||||
|
if (has_legacy_sector || has_intuitive_sector) {
|
||||||
|
reporter.FormatError(
|
||||||
|
GP2,
|
||||||
|
u8R"(Found group "%s" or "%s" unexpected. Please check whether sector groups are successive in your map.)",
|
||||||
|
sector_names.legacy_name.c_str(),
|
||||||
|
sector_names.intuitive_name.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|||||||
@@ -24,7 +24,13 @@ namespace BMapInspector::Rule {
|
|||||||
/**
|
/**
|
||||||
* @brief Gamepiaynmo Rule 2
|
* @brief Gamepiaynmo Rule 2
|
||||||
* @details
|
* @details
|
||||||
* Every Ballance group should not have any groups with same name.
|
* This rule will:
|
||||||
|
* \li Show how many sector located in given map.
|
||||||
|
* \li Check whether there is sector group.
|
||||||
|
* \li Check whether use intuitive sector name for sector 9.
|
||||||
|
* \li Warn for sector count is equal to 1. It will cause mosaic issue on the flames of checkpoint.
|
||||||
|
* \li Warn for sector count greater than 8. It will cause vanilla game freezed without 999 sector loader.
|
||||||
|
* \li Check whether sector group is successive.
|
||||||
*/
|
*/
|
||||||
class GpRule2 : public IRule {
|
class GpRule2 : public IRule {
|
||||||
public:
|
public:
|
||||||
@@ -37,6 +43,22 @@ namespace BMapInspector::Rule {
|
|||||||
void Check(Reporter::Reporter& reporter, Map::Level& level) const override;
|
void Check(Reporter::Reporter& reporter, Map::Level& level) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
///**
|
||||||
|
// * @brief Gamepiaynmo Rule 2
|
||||||
|
// * @details
|
||||||
|
// * Every Ballance group should not have any groups with same name.
|
||||||
|
// */
|
||||||
|
//class GpRule2 : public IRule {
|
||||||
|
//public:
|
||||||
|
// 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 2
|
// * @brief Gamepiaynmo Rule 2
|
||||||
// * @details
|
// * @details
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace BMapInspector::Rule {
|
|||||||
/**
|
/**
|
||||||
* @brief speedystoneball Rule 1
|
* @brief speedystoneball Rule 1
|
||||||
* @details
|
* @details
|
||||||
* Pjysicalized object should not have scale factor, especially negative scale factor (mirror).
|
* Physicalized object should not have scale factor, especially negative scale factor (mirror).
|
||||||
*/
|
*/
|
||||||
class SSBRule1 : public IRule {
|
class SSBRule1 : public IRule {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -1,13 +1,44 @@
|
|||||||
#include "Shared.hpp"
|
#include "Shared.hpp"
|
||||||
#include <yycc.hpp>
|
#include <yycc.hpp>
|
||||||
|
#include <yycc/string/op.hpp>
|
||||||
#include <yycc/carton/termcolor.hpp>
|
#include <yycc/carton/termcolor.hpp>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <stdexcept>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace strop = yycc::string::op;
|
||||||
namespace termcolor = yycc::carton::termcolor;
|
namespace termcolor = yycc::carton::termcolor;
|
||||||
|
|
||||||
namespace BMapInspector::Rule::Shared {
|
namespace BMapInspector::Rule::Shared {
|
||||||
|
|
||||||
|
#pragma region Utility Classes
|
||||||
|
|
||||||
|
#pragma region Sector Name Builder
|
||||||
|
|
||||||
|
SectorNameBuilder::SectorNameBuilder() {}
|
||||||
|
|
||||||
|
SectorNameBuilder::~SectorNameBuilder() {}
|
||||||
|
|
||||||
|
SectorName SectorNameBuilder::get_name(L::CKDWORD sector) const {
|
||||||
|
if (sector < MIN_SECTOR || sector > MAX_SECTOR) {
|
||||||
|
throw std::logic_error("invalid sector number");
|
||||||
|
} else {
|
||||||
|
if (sector < 9) {
|
||||||
|
return strop::printf(u8"Sector_%02" PRIuCKDWORD, sector);
|
||||||
|
} else {
|
||||||
|
return strop::printf(u8"Sector_%" PRIuCKDWORD, sector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Sector9Names SectorNameBuilder::get_sector9_names() const {
|
||||||
|
return Sector9Names{.legacy_name = u8"Sector_9", .intuitive_name = u8"Sector_09"};
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region Check Functions
|
#pragma region Check Functions
|
||||||
|
|
||||||
bool FPEqual(L::CKFLOAT lhs, L::CKFLOAT rhs, L::CKFLOAT tolerance) {
|
bool FPEqual(L::CKFLOAT lhs, L::CKFLOAT rhs, L::CKFLOAT tolerance) {
|
||||||
|
|||||||
@@ -57,6 +57,43 @@ namespace BMapInspector::Rule::Shared {
|
|||||||
|
|
||||||
} // namespace TextureNames
|
} // namespace TextureNames
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
#pragma region Utility Classes
|
||||||
|
|
||||||
|
constexpr L::CKDWORD MIN_SECTOR = 1;
|
||||||
|
constexpr L::CKDWORD MAX_SECTOR = 999;
|
||||||
|
|
||||||
|
using SectorName = std::u8string;
|
||||||
|
|
||||||
|
struct Sector9Names {
|
||||||
|
/** The Sector 9 name with "Sector_9" pattern which is accepted by all 999 sector loader */
|
||||||
|
std::u8string legacy_name;
|
||||||
|
/** The Sector 9 name with "Sector_09" pattern which is only accepted by new 999 sector loader */
|
||||||
|
std::u8string intuitive_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The class for building Ballance sector group name.
|
||||||
|
*/
|
||||||
|
class SectorNameBuilder {
|
||||||
|
public:
|
||||||
|
SectorNameBuilder();
|
||||||
|
~SectorNameBuilder();
|
||||||
|
YYCC_DEFAULT_COPY_MOVE(SectorNameBuilder)
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* @param[in] sector
|
||||||
|
* @return
|
||||||
|
* @remarks
|
||||||
|
* If you deliver sector index with 9, its return name is "Sector_9" which is accepted by all 999 sector loader.
|
||||||
|
*/
|
||||||
|
SectorName get_name(L::CKDWORD sector) const;
|
||||||
|
Sector9Names get_sector9_names() const;
|
||||||
|
};
|
||||||
|
|
||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
#pragma region Check Functions
|
#pragma region Check Functions
|
||||||
@@ -69,6 +106,7 @@ namespace BMapInspector::Rule::Shared {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
bool FPEqual(L::CKFLOAT lhs, L::CKFLOAT rhs, L::CKFLOAT tolerance);
|
bool FPEqual(L::CKFLOAT lhs, L::CKFLOAT rhs, L::CKFLOAT tolerance);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
* @param[in] ctx Can not be nullptr.
|
* @param[in] ctx Can not be nullptr.
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#include "ZZQRules.hpp"
|
||||||
|
#include "Shared.hpp"
|
||||||
|
|
||||||
|
namespace L = LibCmo;
|
||||||
|
namespace C = LibCmo::CK2;
|
||||||
|
namespace O = LibCmo::CK2::ObjImpls;
|
||||||
|
|
||||||
|
namespace BMapInspector::Rule {
|
||||||
|
|
||||||
|
#pragma region ZZQ Rule 1
|
||||||
|
|
||||||
|
constexpr char8_t ZZQ1[] = u8"ZZQ1";
|
||||||
|
|
||||||
|
ZZQRule1::ZZQRule1() : IRule() {}
|
||||||
|
|
||||||
|
ZZQRule1::~ZZQRule1() {}
|
||||||
|
|
||||||
|
std::u8string_view ZZQRule1::GetRuleName() const {
|
||||||
|
return ZZQ1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZZQRule1::Check(Reporter::Reporter& reporter, Map::Level& level) const {
|
||||||
|
auto* ctx = level.GetCKContext();
|
||||||
|
|
||||||
|
// We get "Phys_FloorStopper" group first.
|
||||||
|
auto* phys_floorstopper = Shared::FetchGroup(ctx, Shared::GroupNames::PHYS_FLOORSTOPPER);
|
||||||
|
if (phys_floorstopper == nullptr) return;
|
||||||
|
// We iterate all object grouped into it.
|
||||||
|
auto group_3dobjects = Shared::Iter3dObjects(phys_floorstopper);
|
||||||
|
|
||||||
|
// Show the first object if it have.
|
||||||
|
if (!group_3dobjects.empty()) {
|
||||||
|
auto* first_3dobjects = group_3dobjects.front();
|
||||||
|
reporter.FormatInfo(
|
||||||
|
ZZQ1,
|
||||||
|
u8R"(Object "%s" is the first object grouped into "Phys_FloorStopper". It is the only stopper which can make sound in game.)",
|
||||||
|
Shared::RenderObjectName(first_3dobjects));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warning for other objects
|
||||||
|
for (size_t i = 1; i < group_3dobjects.size(); ++i) {
|
||||||
|
auto* other_3dobject = group_3dobjects[i];
|
||||||
|
reporter.FormatWarning(
|
||||||
|
ZZQ1,
|
||||||
|
u8R"(Object "%s" is grouped into "Phys_FloorStopper" but it is not the only object. This will cause it can not make sound in game. Please confirm this is by your intention.)",
|
||||||
|
Shared::RenderObjectName(other_3dobject));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
} // namespace BMapInspector::Rule
|
||||||
|
|||||||
@@ -3,4 +3,25 @@
|
|||||||
|
|
||||||
namespace BMapInspector::Rule {
|
namespace BMapInspector::Rule {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ZZQ Rule 1
|
||||||
|
* @details
|
||||||
|
* Only the first object grouped into "Phys_FloorStopper" can make sound in game.
|
||||||
|
* So it would be better to make "Phys_FloorStopper" only have one item.
|
||||||
|
*
|
||||||
|
* At the same time, show which object is the first object in "Phys_FloorStopper"
|
||||||
|
* to know which object can make sound in game,
|
||||||
|
* if mapper require the stopper which can not make sound them by design.
|
||||||
|
*/
|
||||||
|
class ZZQRule1 : public IRule {
|
||||||
|
public:
|
||||||
|
ZZQRule1();
|
||||||
|
virtual ~ZZQRule1();
|
||||||
|
YYCC_DELETE_COPY_MOVE(ZZQRule1)
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::u8string_view GetRuleName() const override;
|
||||||
|
void Check(Reporter::Reporter& reporter, Map::Level& level) const override;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user