#pragma once #include #include #include #include #include #include namespace frostbite2D { /** * @brief 脚本指令操作码枚举 */ enum class ScriptOpcode : uint8 { Integer = 2, ///< 整数值 Float = 4, ///< 浮点值 StringRef5 = 5, ///< 二进制字符串引用(类型5) StringRef6 = 6, ///< 二进制字符串引用(类型6) StringRef7 = 7, ///< 二进制字符串引用(类型7) StringRef8 = 8, ///< 二进制字符串引用(类型8) ExtendedString9 = 9, ///< 扩展字符串(带额外字节) ExtendedString10 = 10, ///< 扩展字符串 }; /** * @brief 脚本值类型 */ enum class ScriptValueType { Empty, ///< 空值 Integer, ///< 整数值 Float, ///< 浮点值 String, ///< 字符串值 }; /** * @brief 脚本解析结果值 */ struct ScriptValue { ScriptValueType type = ScriptValueType::Empty; ///< 值类型 int32 intValue = 0; ///< 整数值(type == Integer 时有效) double floatValue = 0.0; ///< 浮点值(type == Float 时有效) std::string stringValue; ///< 字符串值(type == String 时有效) /** * @brief 判断是否为空值 */ bool isEmpty() const { return type == ScriptValueType::Empty; } /** * @brief 转换为字符串表示 */ std::string toString() const; }; /** * @brief 脚本二进制数据解析器 * * 用于解析 PVF 存档中的脚本二进制数据。 * 每条指令为 5 字节:1 字节操作码 + 4 字节数据。 * 支持与 PvfArchive 交互获取字符串资源。 * * @example * auto& archive = PvfArchive::get(); * if (auto rawData = archive.getFileRawData("script/example.bin")) { * ScriptParser parser(*rawData, "script/example.bin"); * * // 迭代解析 * while (!parser.isEnd()) { * if (auto value = parser.next()) { * // 处理 value * } * } * * // 或者一次性解析所有 * auto allValues = parser.parseAll(); * } */ class ScriptParser { public: /** * @brief 从 RawData 构造 * @param data 原始数据 * @param filePath 文件路径(用于提取文件类型) */ ScriptParser(const RawData& data, const std::string& filePath); /** * @brief 从字节数组构造 * @param data 字节数组 * @param filePath 文件路径(用于提取文件类型) */ ScriptParser(const std::vector& data, const std::string& filePath); /** * @brief 从指针和大小构造 * @param data 数据指针 * @param size 数据大小 * @param filePath 文件路径(用于提取文件类型) */ ScriptParser(const char* data, size_t size, const std::string& filePath); // --------------------------------------------------------------------------- // 迭代器风格 API // --------------------------------------------------------------------------- /** * @brief 获取下一个值 * @return 解析的值,失败或结束返回 std::nullopt */ std::optional next(); /** * @brief 回退一个指令 */ void back(); /** * @brief 检查是否已到达数据末尾 * @return 到达末尾返回 true */ bool isEnd() const; /** * @brief 重置解析位置到开头 */ void reset(); // --------------------------------------------------------------------------- // 批量解析 // --------------------------------------------------------------------------- /** * @brief 解析所有值 * @return 所有解析值的列表 */ std::vector parseAll(); // --------------------------------------------------------------------------- // 状态查询 // --------------------------------------------------------------------------- /** * @brief 获取当前解析位置 * @return 当前位置(字节偏移) */ size_t position() const; /** * @brief 获取数据总大小 * @return 数据大小(字节) */ size_t size() const; /** * @brief 获取文件路径 * @return 文件路径 */ const std::string& filePath() const; /** * @brief 获取文件类型(从路径提取) * @return 文件类型 */ const std::string& fileType() const; /** * @brief 检查解析器是否有效(有数据) * @return 有效返回 true */ bool isValid() const; private: /** * @brief 从文件路径提取文件类型 * @param filePath 文件路径 * @return 文件类型 */ std::string extractFileType(const std::string& filePath) const; /** * @brief 读取 1 字节 * @param offset 偏移位置 * @return 字节值 */ uint8 readByte(size_t offset) const; /** * @brief 读取 4 字节整数 * @param offset 偏移位置 * @return 整数值 */ int32 readInt32(size_t offset) const; /** * @brief 解析单个值 * @param offset 偏移位置 * @return 解析的值 */ std::optional parseValueAt(size_t offset) const; std::vector data_; ///< 数据副本 size_t position_ = 2; ///< 当前解析位置(从第 2 字节开始) std::string filePath_; ///< 文件路径 std::string fileType_; ///< 文件类型 }; } // namespace frostbite2D