#include "proto_node.h" #include "../asset_io.h" #include #include using namespace godot; namespace mtgodot { void Metin2Proto::_bind_methods() { ClassDB::bind_method(D_METHOD("load_item_proto", "path"), &Metin2Proto::load_item_proto); ClassDB::bind_method(D_METHOD("load_mob_proto", "path"), &Metin2Proto::load_mob_proto); ClassDB::bind_method(D_METHOD("item", "vnum"), &Metin2Proto::item); ClassDB::bind_method(D_METHOD("mob", "vnum"), &Metin2Proto::mob); ClassDB::bind_method(D_METHOD("item_count"), &Metin2Proto::item_count); ClassDB::bind_method(D_METHOD("mob_count"), &Metin2Proto::mob_count); ClassDB::bind_method(D_METHOD("get_last_error"), &Metin2Proto::get_last_error); } bool Metin2Proto::load_item_proto(const String &path) { std::string err; PackedByteArray bytes = mtgodot::read_file(path); std::vector buf(bytes.ptr(), bytes.ptr() + bytes.size()); if (!mtproto::load_proto_bytes(buf, mtproto::ITEM_PROTO_KEY, m_item, &err)) { last_error = String(err.c_str()); return false; } m_item_ix.clear(); m_item_ix.reserve(m_item.elements); for (uint32_t i = 0; i < m_item.elements; ++i) { mtproto::ItemRecord r = mtproto::parse_item(m_item.record(i), m_item.stride); m_item_ix[r.vnum] = i; } last_error = ""; return true; } bool Metin2Proto::load_mob_proto(const String &path) { std::string err; PackedByteArray bytes = mtgodot::read_file(path); std::vector buf(bytes.ptr(), bytes.ptr() + bytes.size()); if (!mtproto::load_proto_bytes(buf, mtproto::MOB_PROTO_KEY, m_mob, &err)) { last_error = String(err.c_str()); return false; } m_mob_ix.clear(); m_mob_ix.reserve(m_mob.elements); for (uint32_t i = 0; i < m_mob.elements; ++i) { mtproto::MobRecord r = mtproto::parse_mob(m_mob.record(i), m_mob.stride); m_mob_ix[r.vnum] = i; } last_error = ""; return true; } Dictionary Metin2Proto::item(int vnum) const { Dictionary d; auto it = m_item_ix.find((uint32_t)vnum); if (it == m_item_ix.end() || m_item.record(it->second) == nullptr) { return d; } mtproto::ItemRecord r = mtproto::parse_item(m_item.record(it->second), m_item.stride); d["vnum"] = (int)r.vnum; d["vnum_range"] = (int)r.vnum_range; d["name"] = String::utf8(r.name.c_str()); d["locale_name"] = String::utf8(r.locale_name.c_str()); d["type"] = (int)r.type; d["sub_type"] = (int)r.sub_type; d["weight"] = (int)r.weight; d["size"] = (int)r.size; d["anti_flags"] = (int)r.anti_flags; d["flags"] = (int)r.flags; d["wear_flags"] = (int)r.wear_flags; d["buy_price"] = (int)r.buy_price; d["sell_price"] = (int)r.sell_price; { Array limits; for (const mtproto::ItemLimit &limit : r.limits) { Dictionary entry; entry["type"] = (int)limit.type; entry["value"] = (int)limit.value; limits.push_back(entry); } d["limits"] = limits; } { Array applies; for (const mtproto::ItemApply &apply : r.applies) { Dictionary entry; entry["type"] = (int)apply.type; entry["value"] = (int)apply.value; applies.push_back(entry); } d["applies"] = applies; } { Array vals; for (int i = 0; i < 6; ++i) { vals.push_back((int)r.values[i]); } d["values"] = vals; // armor: values[3] = body shape index for the race .msm } { Array sockets; for (int socket : r.sockets) { sockets.push_back(socket); } d["sockets"] = sockets; } d["refined_vnum"] = (int)r.refined_vnum; d["refine_set"] = (int)r.refine_set; d["alter_to_magic_pct"] = (int)r.alter_to_magic_pct; d["specular"] = (int)r.specular; d["gain_socket_pct"] = (int)r.gain_socket_pct; return d; } Dictionary Metin2Proto::mob(int vnum) const { Dictionary d; auto it = m_mob_ix.find((uint32_t)vnum); if (it == m_mob_ix.end() || m_mob.record(it->second) == nullptr) { return d; } mtproto::MobRecord r = mtproto::parse_mob(m_mob.record(it->second), m_mob.stride); d["vnum"] = (int)r.vnum; d["name"] = String::utf8(r.name.c_str()); d["locale_name"] = String::utf8(r.locale_name.c_str()); d["type"] = (int)r.type; d["rank"] = (int)r.rank; d["battle_type"] = (int)r.battle_type; d["level"] = (int)r.level; d["size"] = (int)r.size; return d; } } // namespace mtgodot