port 2D step 2: 40250 item_proto/mob_proto through CLZO and pack://locale/<lang>/
proto.cpp reads the 40250 MIPX/MMPT tables with the ported CLZO/TEA (156-byte TItemTable, 255-byte SMobTable), replacing the m2dev XChaCha20 236/335 reader. Names follow CItemData::GetName / GetMonsterName (szLocaleName, cp1252). GDScript callers load AssetRoot.locale_file() = pack://locale/en/<name>, which makes the EterPack chain runtime-reachable; port-map entries for the functions a coverage run hit move to PORTED/ADAPTED. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// Synthetic item_proto record test. It locks the offsets used by the
|
||||
// ClientVS22 TItemTable layout without requiring the 2.2G asset tree.
|
||||
// Synthetic item_proto / mob_proto records. Locks the 40250 CItemData::TItemTable (156 bytes) and
|
||||
// CPythonNonPlayer::TMobTable (255 bytes) offsets without the client assets.
|
||||
#include "../src/proto/proto.h"
|
||||
|
||||
#include <array>
|
||||
@@ -16,51 +16,59 @@ static int g_fail = 0;
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static void put_u32(std::array<uint8_t, 236> &record, size_t offset, uint32_t value) {
|
||||
template <size_t N>
|
||||
static void put_u32(std::array<uint8_t, N> &record, size_t offset, uint32_t value) {
|
||||
record[offset + 0] = static_cast<uint8_t>(value);
|
||||
record[offset + 1] = static_cast<uint8_t>(value >> 8);
|
||||
record[offset + 2] = static_cast<uint8_t>(value >> 16);
|
||||
record[offset + 3] = static_cast<uint8_t>(value >> 24);
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::array<uint8_t, 236> record{};
|
||||
template <size_t N>
|
||||
static void put_u16(std::array<uint8_t, N> &record, size_t offset, uint16_t value) {
|
||||
record[offset + 0] = static_cast<uint8_t>(value);
|
||||
record[offset + 1] = static_cast<uint8_t>(value >> 8);
|
||||
}
|
||||
|
||||
static void item_layout() {
|
||||
std::array<uint8_t, 156> record{};
|
||||
put_u32(record, 0, 12345);
|
||||
put_u32(record, 4, 7);
|
||||
std::memcpy(record.data() + 8, "TestItem", 9);
|
||||
std::memcpy(record.data() + 73, "LocaleItem", 11);
|
||||
record[138] = 3;
|
||||
record[139] = 4;
|
||||
record[140] = 2;
|
||||
record[141] = 1;
|
||||
put_u32(record, 142, 1u << 8);
|
||||
put_u32(record, 146, 1u << 3);
|
||||
put_u32(record, 150, 0x12345678);
|
||||
put_u32(record, 158, 9000);
|
||||
put_u32(record, 162, 6000);
|
||||
record[166] = 1;
|
||||
put_u32(record, 167, 42);
|
||||
record[176] = 2;
|
||||
put_u32(record, 177, -7);
|
||||
put_u32(record, 191 + 3 * 4, 3);
|
||||
put_u32(record, 215, 1001);
|
||||
put_u32(record, 219, -1);
|
||||
put_u32(record, 227, 12346);
|
||||
record[231] = 0x34;
|
||||
record[232] = 0x12;
|
||||
record[233] = 11;
|
||||
record[234] = 75;
|
||||
record[235] = 88;
|
||||
std::memcpy(record.data() + 33, "LocaleItem", 11);
|
||||
record[58] = 3;
|
||||
record[59] = 4;
|
||||
record[60] = 2;
|
||||
record[61] = 1;
|
||||
put_u32(record, 62, 1u << 8);
|
||||
put_u32(record, 66, 1u << 3);
|
||||
put_u32(record, 70, 0x12345678);
|
||||
put_u32(record, 74, 0x55);
|
||||
put_u32(record, 78, 9000);
|
||||
put_u32(record, 82, 6000);
|
||||
record[86] = 1;
|
||||
put_u32(record, 87, 42);
|
||||
record[96] = 2;
|
||||
put_u32(record, 97, static_cast<uint32_t>(-7));
|
||||
put_u32(record, 111 + 3 * 4, 3);
|
||||
put_u32(record, 135, 1001);
|
||||
put_u32(record, 139, static_cast<uint32_t>(-1));
|
||||
put_u32(record, 147, 12346);
|
||||
put_u16(record, 151, 0x1234);
|
||||
record[153] = 11;
|
||||
record[154] = 75;
|
||||
record[155] = 88;
|
||||
|
||||
const mtproto::ItemRecord item = mtproto::parse_item(record.data(), record.size());
|
||||
CHECK(item.vnum == 12345, "vnum offset");
|
||||
CHECK(item.vnum_range == 7, "vnum range offset");
|
||||
CHECK(item.name == "TestItem", "name offset");
|
||||
CHECK(item.locale_name == "LocaleItem", "locale name offset");
|
||||
CHECK(item.type == 3 && item.sub_type == 4, "type offsets");
|
||||
CHECK(item.type == 3 && item.sub_type == 4 && item.weight == 2 && item.size == 1, "type offsets");
|
||||
CHECK(item.anti_flags == (1u << 8), "anti_flags offset");
|
||||
CHECK(item.flags == (1u << 3), "flags offset");
|
||||
CHECK(item.wear_flags == 0x12345678, "wear_flags offset");
|
||||
CHECK(item.immune_flag == 0x55, "immune_flag offset");
|
||||
CHECK(item.buy_price == 9000 && item.sell_price == 6000, "price offsets");
|
||||
CHECK(item.limits[0].type == 1 && item.limits[0].value == 42, "limit offsets");
|
||||
CHECK(item.applies[0].type == 2 && item.applies[0].value == -7, "apply offsets");
|
||||
@@ -69,11 +77,50 @@ int main() {
|
||||
CHECK(item.refined_vnum == 12346 && item.refine_set == 0x1234, "refine offsets");
|
||||
CHECK(item.alter_to_magic_pct == 11 && item.specular == 75 && item.gain_socket_pct == 88,
|
||||
"tail offsets");
|
||||
CHECK(mtproto::parse_item(record.data(), 236).vnum == 0, "m2dev 236-byte stride rejected");
|
||||
}
|
||||
|
||||
static void mob_layout() {
|
||||
std::array<uint8_t, 255> record{};
|
||||
put_u32(record, 0, 101);
|
||||
std::memcpy(record.data() + 4, "Wild Dog", 9);
|
||||
std::memcpy(record.data() + 29, "LocaleDog", 10);
|
||||
record[54] = 0; // bType
|
||||
record[55] = 1; // bRank
|
||||
record[56] = 2; // bBattleType
|
||||
record[57] = 45; // bLevel
|
||||
record[58] = 1; // bSize
|
||||
// 59 gold/exp/hp (16), 75 regen (2), 77 wDef, 79 AI/race/immune (12), 91 str..int (4), 95 damage (8)
|
||||
put_u16(record, 103, static_cast<uint16_t>(-5)); // sAttackSpeed
|
||||
put_u16(record, 105, 120); // sMovingSpeed
|
||||
// 107 aggr pct, 108 sight, 110 range, 112 enchants[6], 118 resists[11], 129 resurrection, 133 drop
|
||||
record[137] = 3; // bMountCapacity
|
||||
record[138] = 1; // bOnClickType
|
||||
record[139] = 2; // bEmpire
|
||||
std::memcpy(record.data() + 140, "monster/dog", 12);
|
||||
// 205 fDamMultiply, 209 summon, 213 drain sp
|
||||
put_u32(record, 217, 0xAABBCCDD); // dwMonsterColor
|
||||
// 221 polymorph, 225 skills 5x5, 250 berserk..revive
|
||||
record[254] = 9;
|
||||
|
||||
const mtproto::MobRecord m = mtproto::parse_mob(record.data(), record.size());
|
||||
CHECK(m.vnum == 101, "mob vnum offset");
|
||||
CHECK(m.name == "Wild Dog" && m.locale_name == "LocaleDog", "mob name offsets");
|
||||
CHECK(m.rank == 1 && m.battle_type == 2 && m.level == 45 && m.size == 1, "mob byte offsets");
|
||||
CHECK(m.attack_speed == -5 && m.moving_speed == 120, "mob speed offsets");
|
||||
CHECK(m.on_click_type == 1 && m.empire == 2, "mob click/empire offsets");
|
||||
CHECK(m.folder == "monster/dog", "mob folder offset");
|
||||
CHECK(m.monster_color == 0xAABBCCDD, "mob color offset");
|
||||
CHECK(mtproto::parse_mob(record.data(), 335).vnum == 0, "m2dev 335-byte stride rejected");
|
||||
}
|
||||
|
||||
int main() {
|
||||
item_layout();
|
||||
mob_layout();
|
||||
if (g_fail) {
|
||||
std::fprintf(stderr, "%d check(s) failed\n", g_fail);
|
||||
return 1;
|
||||
}
|
||||
std::printf("all item layout checks passed\n");
|
||||
std::printf("all item/mob layout checks passed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user