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
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
// net_probe — connect to a Metin2 auth server, run the libsodium handshake and
|
||||
// the CG_LOGIN3 exchange, print what happened. Purely diagnostic.
|
||||
//
|
||||
// net_probe <host> <port> <id> <pw> (defaults: 192.168.21.203 11000 admin 123456789)
|
||||
#include "../src/net/auth_client.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
std::string host = argc > 1 ? argv[1] : "192.168.21.203";
|
||||
uint16_t port = argc > 2 ? static_cast<uint16_t>(std::stoi(argv[2])) : 11000;
|
||||
std::string id = argc > 3 ? argv[3] : "admin";
|
||||
std::string pw = argc > 4 ? argv[4] : "123456789";
|
||||
|
||||
std::printf("net_probe -> %s:%u id=%s\n", host.c_str(), port, id.c_str());
|
||||
|
||||
mtnet::AuthClient client(id, pw);
|
||||
if (!client.connect(host, port)) {
|
||||
std::printf("connect() failed: %s\n", client.last_error().c_str());
|
||||
return 2;
|
||||
}
|
||||
|
||||
using clock = std::chrono::steady_clock;
|
||||
auto start = clock::now();
|
||||
auto last_state = mtnet::NetStream::State::Offline;
|
||||
bool reported_online = false, reported_cipher = false, reported_login = false;
|
||||
|
||||
while (std::chrono::duration_cast<std::chrono::seconds>(clock::now() - start).count() < 15) {
|
||||
client.process();
|
||||
|
||||
if (client.state() != last_state) {
|
||||
const char *s = client.state() == mtnet::NetStream::State::Connecting ? "Connecting"
|
||||
: client.state() == mtnet::NetStream::State::Online ? "Online"
|
||||
: "Offline";
|
||||
std::printf("[state] %s\n", s);
|
||||
last_state = client.state();
|
||||
}
|
||||
if (!reported_online && client.state() == mtnet::NetStream::State::Online) {
|
||||
std::printf("[tcp] connected\n");
|
||||
reported_online = true;
|
||||
}
|
||||
if (!reported_cipher && client.handshaked()) {
|
||||
std::printf("[handshake] cipher activated (KX ok)\n");
|
||||
reported_cipher = true;
|
||||
}
|
||||
if (!reported_login && client.sent_login()) {
|
||||
std::printf("[auth] PHASE_AUTH reached, CG_LOGIN3 sent\n");
|
||||
reported_login = true;
|
||||
}
|
||||
if (client.done()) {
|
||||
break;
|
||||
}
|
||||
if (client.state() == mtnet::NetStream::State::Offline && reported_online) {
|
||||
std::printf("[net] disconnected: %s\n", client.last_error().c_str());
|
||||
break;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
}
|
||||
|
||||
if (client.done() && client.success()) {
|
||||
std::printf("RESULT: auth OK, login_key=0x%08X\n", client.login_key());
|
||||
return 0;
|
||||
}
|
||||
if (client.done()) {
|
||||
std::printf("RESULT: auth failed (%s)\n",
|
||||
client.fail_reason().empty() ? client.last_error().c_str()
|
||||
: client.fail_reason().c_str());
|
||||
return 1;
|
||||
}
|
||||
std::printf("RESULT: timed out. last_error=%s online=%d cipher=%d login_sent=%d\n",
|
||||
client.last_error().c_str(), (int)reported_online, (int)reported_cipher,
|
||||
(int)reported_login);
|
||||
return 3;
|
||||
}
|
||||
Reference in New Issue
Block a user