Files
metin2-client/libgr2/src/internal.h
T
shenandClaude Sonnet 5 47baf6c0c6 Metin2 game client (P0–P11) + mobile asset pipeline
Networked client on the existing Godot 4.7 + libgr2 renderer:
- net: m2dev wire protocol (libsodium KX + XChaCha20), auth/select/game
  phases, EntityStore world model, ~all GC/CG headers. char create/delete,
  private shop / mall / cube, SHOP_GC_START_EX, guild, party (+ CG_PARTY_SET_STATE),
  quests, dragon soul, refine, safebox, exchange.
- UI: in-game windows migrated 1:1 from the reference uiscript/root .py —
  char status (/stat), inventory+equipment, select-item ([SELECT_ITEM] quest
  token), system-option + game-option + ESC system menu, private-shop 39-grid,
  party info board, shop tabs, atlas, minimap, quickbar, chat, …
- EterGrnLib polish: GR2 material blend/two-sided, LOD crossfade, motion-event
  dispatch, contact shadow, ray-AABB picking, weapon grip pre-transform.

Portable asset IO (A1) — all extension/libgr2/formats/mtproto reads routed
through godot::FileAccess (res:// PCK works on iOS/Android); standalone-lib
*_path() kept for the non-Godot CTests. AssetResolver + PropertyRegistry
switched to a baked index (bake_asset_index.gd) instead of std::filesystem.

Mobile builds: build-{android,ios}.sh, export-android.sh, pack-assets.sh,
gen-debug-keystore.sh. Assets ship as a zip mounted at runtime by
project/asset_pack.gd (adb push now; HTTP download is a drop-in later).

ctest 10/10, 34 GDScript suites, macOS/iOS/Android all build.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013EJxkHiNKS4kybHS3XKyAJ
2026-08-31 20:02:12 +09:00

136 lines
6.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// libgr2 内部。SDK struct 镜像从 granny_file_format.h / granny_data_type_definition.h 抄。
#pragma once
#include "gr2/gr2.h"
#include <cstdint>
#include <string>
#include <unordered_map>
#include <vector>
namespace gr2 {
namespace detail {
// ── granny_file_format.h 镜像 ──────────────────────────────────────────
#pragma pack(push, 1)
struct GrnFileMagic { // grn_file_magic_value
uint32_t magic[4];
uint32_t header_size;
uint32_t header_format;
uint32_t reserved[2];
};
struct GrnReference { uint32_t section; uint32_t offset; };
struct GrnPointerFixup { uint32_t from_offset; GrnReference to; }; // 12B
struct GrnSection { // grn_section —— 44B
uint32_t compression;
uint32_t data_offset, data_size;
uint32_t expanded_data_size;
uint32_t internal_alignment;
uint32_t first16bit, first8bit;
uint32_t pointer_fixup_off, pointer_fixup_count;
uint32_t mixed_fixup_off, mixed_fixup_count;
};
#pragma pack(pop)
struct Section {
std::vector<uint8_t> data; // 展开后
SectionInfo info;
};
// section 内的位置。不物化指针(文件是 32 位指针,本进程 64 位),
// 全程用 (section, offset) + fixup 表按需解引用。
struct Ref {
int32_t section = -1;
uint32_t offset = 0;
bool valid() const { return section >= 0; }
};
// ── granny_data_type_definition.h:member_type 枚举(序数不可变)────────
enum MemberType {
MT_End = 0, MT_Inline, MT_Reference, MT_RefToArray, MT_ArrayOfRefs,
MT_VariantRef, MT_Removed, MT_RefToVariantArray, MT_String, MT_Transform,
MT_Real32, MT_Int8, MT_UInt8, MT_BinormInt8, MT_NormUInt8,
MT_Int16, MT_UInt16, MT_BinormInt16, MT_NormUInt16,
MT_Int32, MT_UInt32, MT_Real16, MT_EmptyRef, MT_OnePastLast
};
// data_type_definition 在文件里的字节数(32 位指针):
// Type(4) Name(ptr4) ReferenceType(ptr4) ArrayWidth(4) Extra[3](12) Ignored(ptr4)
constexpr uint32_t kTypeDefEntrySize = 32;
struct TypeMember {
std::string name;
int32_t type = MT_End;
int32_t array_width = 0; // 0 => 1
Ref ref_type; // Inline/Reference/... 的元素类型
uint32_t offset = 0; // 在对象实例里的字节偏移(打包,无对齐 pad)
uint32_t size = 0; // 本 member 的总字节数
};
} // namespace detail
struct File::Impl {
std::vector<detail::Section> sections; // 展开后数据 + info
std::vector<detail::GrnSection> raw; // 原始 section 头(fixup 用)
using Ref = detail::Ref;
using TypeMember = detail::TypeMember;
using GrnSection = detail::GrnSection;
// (section<<32 | from_offset) -> 目标 Ref
std::unordered_map<uint64_t, Ref> fixups;
Ref root_obj; // grn_file_header.RootObject
Ref root_type; // grn_file_header.RootObjectTypeDefinition
bool typetree_ready = false;
// 类型解析缓存:typedef 的 Ref -> 成员列表
std::unordered_map<uint64_t, std::vector<TypeMember>> type_cache;
// ── T2 / T1 ──
bool decompress_section(const GrnSection&, const uint8_t* src, detail::Section& out, LoadError*);
void build_fixups(const uint8_t* file, size_t file_len); // T1
// ── T3 ──
const uint8_t* at(Ref r, size_t need = 0) const; // section 内指针 + 边界检查
Ref follow(Ref slot) const; // 解一个"指针槽"
const std::vector<TypeMember>& parse_type(Ref type_ref); // 走 data_type_definition 数组
uint32_t object_size(Ref type_ref);
uint32_t member_unit_size(const TypeMember&);
const TypeMember* find_member(const std::vector<TypeMember>& ms, const char* name) const;
// 便捷读取
uint32_t rd_u32(Ref r) const;
int32_t rd_i32(Ref r) const { return (int32_t)rd_u32(r); }
float rd_f32(Ref r) const;
std::string rd_str(Ref slot) const; // 解引用一个 String 槽
// 成员访问(obj = 对象实例的 Ref,m = 其类型的某个成员)
Ref member_slot(Ref obj, const TypeMember& m) const { return {obj.section, obj.offset + m.offset}; }
Ref read_reference(Ref obj, const TypeMember& m) const { return follow(member_slot(obj, m)); }
// ArrayOfReferences: {int32 count; ptr → [count] 个指针槽 → 各自的对象}
std::vector<Ref> read_array_of_refs(Ref obj, const TypeMember& m) const;
// ReferenceToArray: {int32 count; ptr → [count] 个连续对象(elem_type)}
bool read_ref_to_array(Ref obj, const TypeMember& m, Ref& base, uint32_t& count, uint32_t& stride);
// ── T4/T5/T6/T7a ──
bool build_fileinfo(FileInfo& out, LoadError*);
bool extract_skeleton(Ref skel_obj, Ref skel_type, Skeleton& out);
bool extract_mesh(Ref mesh_obj, Ref mesh_type, const std::vector<Skeleton>& skels, Mesh& out);
// granny_material 链:直接 .Texture.FromFileName,或递归 .Maps[].Material。返回 dds 文件名(原样)。
std::string material_texture_name(Ref mat_obj, Ref mat_type, int depth);
bool extract_animation(Ref anim_obj, Ref anim_type, const Skeleton* skel, Animation& out);
// 曲线子类型分类(T7a)。curve_obj 指向 inline 曲线对象本体,curve_type 是它的类型。
std::string classify_curve_obj(Ref curve_obj, Ref curve_type);
void read_old_curve(Ref curve_obj, Ref curve_type, Curve& out); // T7b
double skeleton_self_check(int skeleton) const;
// granny_transform (68B) → 行主序 4x4(BuildCompositeTransform4x4 语义)
void transform_to_composite(Ref tf, Mat4& out, uint32_t& flags) const;
std::vector<Skeleton> skels_cache; // self-check 复用
std::vector<Ref> skel_refs; // 与 skels_cache 平行:各 skeleton 对象的 Ref(model 关联用)
mutable FileInfo* info_cache = nullptr; // 指向 File::info_
};
} // namespace gr2