2026-02-02 22:26:41 +08:00
|
|
|
#pragma once
|
2026-02-04 17:03:53 +08:00
|
|
|
#include <VTAll.hpp>
|
2026-02-24 13:49:20 +08:00
|
|
|
#include <yycc.hpp>
|
|
|
|
|
#include <yycc/string/op.hpp>
|
2026-02-04 17:03:53 +08:00
|
|
|
#include <vector>
|
2026-02-04 20:46:04 +08:00
|
|
|
#include <array>
|
2026-02-24 13:49:20 +08:00
|
|
|
#include <type_traits>
|
2026-02-02 22:26:41 +08:00
|
|
|
|
|
|
|
|
namespace BMapInspector::Rule::Shared {
|
|
|
|
|
|
2026-02-04 17:03:53 +08:00
|
|
|
namespace L = LibCmo;
|
|
|
|
|
namespace C = LibCmo::CK2;
|
|
|
|
|
namespace O = LibCmo::CK2::ObjImpls;
|
|
|
|
|
|
|
|
|
|
#pragma region Constant Values
|
|
|
|
|
|
|
|
|
|
namespace GroupNames {
|
2026-02-04 20:46:04 +08:00
|
|
|
// clang-format off
|
|
|
|
|
constexpr char8_t PHYS_FLOORS[] = u8"Phys_Floors";
|
2026-02-04 17:03:53 +08:00
|
|
|
constexpr char8_t PHYS_FLOORRAILS[] = u8"Phys_FloorRails";
|
2026-02-04 20:46:04 +08:00
|
|
|
constexpr char8_t PHYS_FLOORSTOPPER[] = u8"Phys_FloorStopper";
|
2026-02-04 22:51:13 +08:00
|
|
|
|
|
|
|
|
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",
|
|
|
|
|
};
|
|
|
|
|
|
2026-02-04 20:46:04 +08:00
|
|
|
// clang-format on
|
|
|
|
|
} // namespace GroupNames
|
2026-02-04 17:03:53 +08:00
|
|
|
|
|
|
|
|
namespace TextureNames {
|
2026-02-04 20:46:04 +08:00
|
|
|
// clang-format off
|
2026-02-04 17:03:53 +08:00
|
|
|
constexpr char8_t RAIL_ENVIRONMENT[] = u8"Rail_Environment.bmp";
|
2026-02-24 14:24:02 +08:00
|
|
|
constexpr char8_t LATERNE_VERLAUF[] = u8"Laterne_Verlauf.tga";
|
2026-02-04 20:46:04 +08:00
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
|
|
} // namespace TextureNames
|
2026-02-04 17:03:53 +08:00
|
|
|
|
2026-02-20 16:00:00 +08:00
|
|
|
#pragma endregion
|
|
|
|
|
|
2026-02-24 13:49:20 +08:00
|
|
|
#pragma region Utility Classes
|
2026-02-20 16:00:00 +08:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
};
|
|
|
|
|
|
2026-02-04 17:03:53 +08:00
|
|
|
#pragma endregion
|
|
|
|
|
|
|
|
|
|
#pragma region Check Functions
|
|
|
|
|
|
2026-02-04 21:32:34 +08:00
|
|
|
/**
|
|
|
|
|
* @brief Check whether given 2 float point values are equal with given tolerance.
|
|
|
|
|
* @param lhs
|
|
|
|
|
* @param rhs
|
|
|
|
|
* @param tolerance
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
bool FPEqual(L::CKFLOAT lhs, L::CKFLOAT rhs, L::CKFLOAT tolerance);
|
2026-02-20 16:00:00 +08:00
|
|
|
|
2026-02-04 17:03:53 +08:00
|
|
|
/**
|
|
|
|
|
* @brief
|
|
|
|
|
* @param[in] ctx Can not be nullptr.
|
|
|
|
|
* @param[in] name Can not be nullptr.
|
2026-02-04 21:32:34 +08:00
|
|
|
* @return Found pointer to CKGroup, otherwise nullptr.
|
2026-02-04 17:03:53 +08:00
|
|
|
*/
|
|
|
|
|
O::CKGroup* FetchGroup(C::CKContext* ctx, L::CKSTRING name);
|
2026-02-24 14:24:02 +08:00
|
|
|
/**
|
|
|
|
|
* @brief
|
|
|
|
|
* @param[in] ctx Can not be nullptr.
|
|
|
|
|
* @param[in] name Can not be nullptr.
|
|
|
|
|
* @return Found pointer to CKMaterial, otherwise nullptr.
|
|
|
|
|
*/
|
|
|
|
|
O::CKMaterial* FetchMaterial(C::CKContext* ctx, L::CKSTRING name);
|
2026-02-04 20:46:04 +08:00
|
|
|
std::vector<O::CK3dObject*> FetchPhysicalized3dObjects(C::CKContext* ctx);
|
2026-02-04 17:03:53 +08:00
|
|
|
/**
|
|
|
|
|
* @brief Check whether given CKTexture has the given file name (case-insensitive).
|
|
|
|
|
* @param[in] tex Can not be nullptr.
|
|
|
|
|
* @param[in] name Can not be nullptr.
|
|
|
|
|
* @return True if it is, otherwise false.
|
|
|
|
|
*/
|
|
|
|
|
bool CheckTextureFileName(O::CKTexture* tex, L::CKSTRING name);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief
|
|
|
|
|
* @param[in] group Can not be nullptr.
|
|
|
|
|
* @return All objects is the child class of CK3dEntity.
|
|
|
|
|
*/
|
2026-02-04 20:46:04 +08:00
|
|
|
std::vector<O::CK3dObject*> Iter3dObjects(O::CKGroup* group);
|
2026-02-04 17:03:53 +08:00
|
|
|
/**
|
|
|
|
|
* @brief
|
|
|
|
|
* @param[in] mesh Can not be nullptr.
|
|
|
|
|
* @return All nullptr reference are removed.
|
|
|
|
|
*/
|
|
|
|
|
std::vector<O::CKMaterial*> IterMaterial(O::CKMesh* mesh);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief
|
|
|
|
|
* @param[in] obj Can not be nullptr.
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
2026-02-24 13:49:20 +08:00
|
|
|
std::u8string QuoteObjectName(O::CKObject* obj);
|
|
|
|
|
/**
|
|
|
|
|
* @brief
|
|
|
|
|
* @tparam InputIt
|
|
|
|
|
* @param first
|
|
|
|
|
* @param last
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
template<std::input_iterator InputIt>
|
|
|
|
|
requires std::is_pointer_v<std::iter_value_t<InputIt>>
|
|
|
|
|
&& std::is_base_of_v<O::CKObject, std::remove_pointer_t<std::iter_value_t<InputIt>>>
|
|
|
|
|
std::u8string QuoteObjectNames(InputIt first, InputIt last) {
|
2026-03-02 12:30:02 +08:00
|
|
|
std::u8string cache;
|
2026-02-24 13:49:20 +08:00
|
|
|
return yycc::string::op::join(
|
2026-03-02 12:30:02 +08:00
|
|
|
[&cache, &first, &last]() -> std::optional<std::u8string_view> {
|
2026-02-24 13:49:20 +08:00
|
|
|
if (first == last) return std::nullopt;
|
2026-03-02 12:30:02 +08:00
|
|
|
// YYC MARK:
|
|
|
|
|
// We must use "cache", otherwise "use after free" will occur.
|
|
|
|
|
cache = QuoteObjectName(*(first++));
|
|
|
|
|
return cache;
|
2026-02-24 13:49:20 +08:00
|
|
|
},
|
|
|
|
|
u8", ");
|
|
|
|
|
}
|
2026-02-04 17:03:53 +08:00
|
|
|
|
|
|
|
|
#pragma endregion
|
|
|
|
|
|
|
|
|
|
} // namespace BMapInspector::Rule::Shared
|