feat(client): 完成40250客户端核心功能1:1对齐与桥梁高度采样修复
- 桥梁与静态物体高度采样修复: - 严格对齐 40250 CMapOutdoor::GetHeight 与 CAttributeInstance::GetHeight - 解析 .mdatr 中的 AttributeHeight 网格,使用 is_in_triangle_2d 准确计算桥面多边形平面方程 - sample_height 查询邻近区块并返回 fMAX(fObjectHeight, fTerrainHeight),彻底解决走上桥面穿透掉入水底/河床的问题 - 新增 test_bridge_height_parity.gd 自动化对拍测试 - 40250 怪物击杀经验动效: - 1:1 实现 FLY_EXP(0) / FLY_HP / FLY_SP 粒子轨迹与爆炸吸附 - 40250 客户端全系统功能对齐(Batches 1-31): - 包含公会、交易、骑乘、变身、钓鱼、采矿、商城、信件、结婚、地牢等 134 套对拍系统与自动化回归测试 - 文档沉淀: - 新增 docs/CLIENT-PARITY-AUDIT-AND-FIX-GUIDE.md 客户端对拍缺陷发现与修复工程指南
This commit is contained in:
+82
-2
@@ -27,16 +27,17 @@ static int dump_strings(const gr2::File& f, size_t minlen) {
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
std::fprintf(stderr, "usage: gr2dump <file.gr2> [--sections] [--strings] [--gltf out.glb]\n");
|
||||
std::fprintf(stderr, "usage: gr2dump <file.gr2> [--sections] [--strings] [--members] [--transforms] [--gltf out.glb]\n");
|
||||
return 2;
|
||||
}
|
||||
const std::string path = argv[1];
|
||||
bool want_sections = false, want_strings = false, want_members = false;
|
||||
bool want_sections = false, want_strings = false, want_members = false, want_transforms = false;
|
||||
std::string gltf_out;
|
||||
for (int i = 2; i < argc; ++i) {
|
||||
if (!std::strcmp(argv[i], "--sections")) want_sections = true;
|
||||
else if (!std::strcmp(argv[i], "--strings")) want_strings = true;
|
||||
else if (!std::strcmp(argv[i], "--members")) want_members = true;
|
||||
else if (!std::strcmp(argv[i], "--transforms")) want_transforms = true;
|
||||
else if (!std::strcmp(argv[i], "--gltf") && i + 1 < argc) gltf_out = argv[++i];
|
||||
}
|
||||
|
||||
@@ -114,7 +115,15 @@ int main(int argc, char** argv) {
|
||||
int depth = 0;
|
||||
for (int p = b.parent; p >= 0 && depth < 64; ) { ++depth; p = sk.bones[p].parent; }
|
||||
std::printf(" %*s[%zu] %s (parent=%d)\n", depth * 2, "", i, b.name.c_str(), b.parent);
|
||||
if (want_transforms) {
|
||||
std::printf(" local.t=(%.3f,%.3f,%.3f) inverse_world.t=(%.3f,%.3f,%.3f)\n",
|
||||
b.local_transform[12], b.local_transform[13], b.local_transform[14],
|
||||
b.inverse_world[12], b.inverse_world[13], b.inverse_world[14]);
|
||||
}
|
||||
}
|
||||
if (want_transforms)
|
||||
std::printf(" initial_placement.t=(%.3f,%.3f,%.3f)\n",
|
||||
sk.initial_placement[12], sk.initial_placement[13], sk.initial_placement[14]);
|
||||
}
|
||||
|
||||
for (size_t mi = 0; mi < fi.meshes.size(); ++mi) {
|
||||
@@ -131,6 +140,21 @@ int main(int argc, char** argv) {
|
||||
std::printf(" group %zu: material=%d tri_first=%d tri_count=%d tex=%s\n",
|
||||
g, mix, me.tri_groups[g].tri_first,
|
||||
me.tri_groups[g].tri_count, tn);
|
||||
int g_up = 0, g_down = 0, g_side = 0;
|
||||
for (int t = 0; t < me.tri_groups[g].tri_count; ++t) {
|
||||
uint32_t idx = (me.tri_groups[g].tri_first + t) * 3;
|
||||
if (idx + 2 < me.indices.size()) {
|
||||
uint32_t i0 = me.indices[idx], i1 = me.indices[idx+1], i2 = me.indices[idx+2];
|
||||
const auto& v0 = me.vertices[i0]; const auto& v1 = me.vertices[i1]; const auto& v2 = me.vertices[i2];
|
||||
float e1[3] = {v1.pos[0]-v0.pos[0], v1.pos[1]-v0.pos[1], v1.pos[2]-v0.pos[2]};
|
||||
float e2[3] = {v2.pos[0]-v0.pos[0], v2.pos[1]-v0.pos[1], v2.pos[2]-v0.pos[2]};
|
||||
float nz = e1[0]*e2[1] - e1[1]*e2[0];
|
||||
if (nz > 1e-3f) ++g_up;
|
||||
else if (nz < -1e-3f) ++g_down;
|
||||
else ++g_side;
|
||||
}
|
||||
}
|
||||
std::printf(" tri face normal: +Z(up)=%d -Z(down)=%d sideways=%d\n", g_up, g_down, g_side);
|
||||
}
|
||||
for (size_t b = 0; b < me.material_textures.size(); ++b)
|
||||
std::printf(" binding %zu -> %s\n", b, me.material_textures[b].c_str());
|
||||
@@ -138,6 +162,62 @@ int main(int argc, char** argv) {
|
||||
for (int32_t b : me.bone_bindings) if (b < 0) ++dangling;
|
||||
if (!me.bone_bindings.empty())
|
||||
std::printf(" dangling bone bindings: %d\n", dangling);
|
||||
if (want_transforms && !me.vertices.empty()) {
|
||||
float lo[3] = {me.vertices[0].pos[0], me.vertices[0].pos[1], me.vertices[0].pos[2]};
|
||||
float hi[3] = {lo[0], lo[1], lo[2]};
|
||||
for (const auto& v : me.vertices) for (int a = 0; a < 3; ++a) {
|
||||
lo[a] = std::min(lo[a], v.pos[a]); hi[a] = std::max(hi[a], v.pos[a]);
|
||||
}
|
||||
std::printf(" aabb min=(%.3f,%.3f,%.3f) max=(%.3f,%.3f,%.3f)\n",
|
||||
lo[0], lo[1], lo[2], hi[0], hi[1], hi[2]);
|
||||
int normal_agree = 0, normal_disagree = 0;
|
||||
for (size_t t = 0; t + 2 < me.indices.size(); t += 3) {
|
||||
uint32_t i0 = me.indices[t + 0];
|
||||
uint32_t i1 = me.indices[t + 1];
|
||||
uint32_t i2 = me.indices[t + 2];
|
||||
if (i0 < me.vertices.size() && i1 < me.vertices.size() && i2 < me.vertices.size()) {
|
||||
const auto& v0 = me.vertices[i0];
|
||||
const auto& v1 = me.vertices[i1];
|
||||
const auto& v2 = me.vertices[i2];
|
||||
float e1[3] = {v1.pos[0] - v0.pos[0], v1.pos[1] - v0.pos[1], v1.pos[2] - v0.pos[2]};
|
||||
float e2[3] = {v2.pos[0] - v0.pos[0], v2.pos[1] - v0.pos[1], v2.pos[2] - v0.pos[2]};
|
||||
float nx = e1[1]*e2[2] - e1[2]*e2[1];
|
||||
float ny = e1[2]*e2[0] - e1[0]*e2[2];
|
||||
float nz = e1[0]*e2[1] - e1[1]*e2[0];
|
||||
float dot = nx * v0.normal[0] + ny * v0.normal[1] + nz * v0.normal[2];
|
||||
if (dot > 0.0f) ++normal_agree;
|
||||
else if (dot < 0.0f) ++normal_disagree;
|
||||
}
|
||||
}
|
||||
std::printf(" winding vs normal: agree=%d disagree=%d\n", normal_agree, normal_disagree);
|
||||
float avg_n[3] = {0,0,0};
|
||||
for (const auto& v : me.vertices) {
|
||||
avg_n[0] += v.normal[0]; avg_n[1] += v.normal[1]; avg_n[2] += v.normal[2];
|
||||
}
|
||||
if (!me.vertices.empty()) {
|
||||
float inv = 1.0f / me.vertices.size();
|
||||
std::printf(" avg normal: (%.3f, %.3f, %.3f)\n", avg_n[0]*inv, avg_n[1]*inv, avg_n[2]*inv);
|
||||
}
|
||||
int z_up = 0, z_down = 0, xy_side = 0;
|
||||
for (const auto& v : me.vertices) {
|
||||
if (v.normal[2] > 0.5f) ++z_up;
|
||||
else if (v.normal[2] < -0.5f) ++z_down;
|
||||
else ++xy_side;
|
||||
}
|
||||
std::printf(" vertex normal dir: +Z(up)=%d -Z(down)=%d sideways=%d\n", z_up, z_down, xy_side);
|
||||
if (me.indices.size() >= 6) {
|
||||
for (int tr = 0; tr < 2; ++tr) {
|
||||
uint32_t i0 = me.indices[tr*3+0], i1 = me.indices[tr*3+1], i2 = me.indices[tr*3+2];
|
||||
const auto &v0 = me.vertices[i0], &v1 = me.vertices[i1], &v2 = me.vertices[i2];
|
||||
std::printf(" tri%d: v0=(%.1f,%.1f,%.1f) n=(%.2f,%.2f,%.2f)\n"
|
||||
" v1=(%.1f,%.1f,%.1f) n=(%.2f,%.2f,%.2f)\n"
|
||||
" v2=(%.1f,%.1f,%.1f) n=(%.2f,%.2f,%.2f)\n",
|
||||
tr, v0.pos[0], v0.pos[1], v0.pos[2], v0.normal[0], v0.normal[1], v0.normal[2],
|
||||
v1.pos[0], v1.pos[1], v1.pos[2], v1.normal[0], v1.normal[1], v1.normal[2],
|
||||
v2.pos[0], v2.pos[1], v2.pos[2], v2.normal[0], v2.normal[1], v2.normal[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t ai = 0; ai < fi.animations.size(); ++ai) {
|
||||
|
||||
Reference in New Issue
Block a user