port 2V2-b: GamePhase dispatch consumes the Entergame burst
PythonNetworkStreamPhaseGame/PhaseGameActor/PhaseGameItem/Command, NetworkActorManager and PythonChat/PythonChatModule are ported verbatim and dispatched at runtime; the 2V0 chat stub module is removed and initChat() runs before initnet() as in 40250. InstanceBase, PythonCharacterManager and GameLib ActorInstance/RaceData/RaceManager compile but stay TODO until 2V2-c/d wire them. Units not ported yet get their singletons from PythonBoot's GameSingletons (CPythonApplication member order) and platform/pending stand-ins generated by platform_stub.py pending; const char* stand-ins return "". port.login_flow's fake server now sends the CInputLogin::Entergame order (actor insert, NPC positions, PHASE_GAME, land list, time, channel, greet notice, ping) and a TraceError observer asserts no unknown packet header. port.login_live passes against the real server for 10 s of game phase. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
d16fabf61c
commit
62b6e23bfc
@@ -15,7 +15,9 @@
|
||||
// 5. PHASE_LOADING, GC_MAIN_CHARACTER, GC_CHARACTER_POINTS: the loading phase answers the main
|
||||
// character with CG_CLIENT_VERSION(2), the server's proof the client reached Loading;
|
||||
// 6. (批次 2V2) the loading steps end in net.StartGame(): networkModule.SetGamePhase opens
|
||||
// game.GameWindow, whose Open sends CG_ENTERGAME.
|
||||
// game.GameWindow, whose Open sends CG_ENTERGAME;
|
||||
// 7. the server's Entergame answer (the actor's insert packets, PHASE_GAME, the Entergame burst) is
|
||||
// read by the ported GamePhase without an unknown packet, and a final ping gets its pong.
|
||||
//
|
||||
// The server checks every sequence byte against the 40250 table, so a skipped or extra sequenced
|
||||
// packet fails the run.
|
||||
@@ -25,7 +27,8 @@
|
||||
// With `live` (批次 2V1-e, ctest port.login_live) the same path runs against a real 40250 server and
|
||||
// the client's own state is the proof: the character list arrived, the loading window got
|
||||
// LoadData from GC_MAIN_CHARACTER, which CPythonNetworkStream::RecvMainCharacter answers with
|
||||
// CG_CLIENT_VERSION, and game.GameWindow is open, which sent CG_ENTERGAME. Everything about the
|
||||
// CG_CLIENT_VERSION, game.GameWindow is open, which sent CG_ENTERGAME, and 10 s of the real game
|
||||
// phase later it is still open and connected with no unknown packet. Everything about the
|
||||
// server comes from the environment and nothing of it is printed:
|
||||
//
|
||||
// MT_LIVE_HOST, MT_LIVE_LOGIN, MT_LIVE_PASSWORD required; without them the test is skipped
|
||||
@@ -36,6 +39,7 @@
|
||||
#include "../src/platform/ScriptLib/PythonBoot.h"
|
||||
#include "../src/platform/ScriptLib/PythonHost.h"
|
||||
#include "../src/platform/UserInterface/UserInterface.h"
|
||||
#include "../src/platform/EterBase/TraceErrorObserver.h"
|
||||
#include "port_login_flow_server.h"
|
||||
|
||||
#include <memory>
|
||||
@@ -44,6 +48,7 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
@@ -59,6 +64,25 @@ static int g_failures = 0;
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// TraceError lines; the script thread writes them while the host thread waits for its baton.
|
||||
static std::mutex g_syserr_mutex;
|
||||
static std::vector<std::string> g_syserr;
|
||||
|
||||
static void on_trace_error(const char* line)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_syserr_mutex);
|
||||
g_syserr.emplace_back(line);
|
||||
}
|
||||
|
||||
static int count_syserr(const char* needle)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_syserr_mutex);
|
||||
int n = 0;
|
||||
for (const auto& line : g_syserr)
|
||||
n += line.find(needle) != std::string::npos;
|
||||
return n;
|
||||
}
|
||||
|
||||
static bool py(const std::string& source)
|
||||
{
|
||||
std::string error;
|
||||
@@ -162,6 +186,7 @@ int main(int argc, char** argv)
|
||||
}
|
||||
auto failed = [&] { return server && server->Failed(); };
|
||||
|
||||
SetTraceErrorObserver(on_trace_error);
|
||||
PackSingletons();
|
||||
CHECK(PackInitialize("pack"));
|
||||
|
||||
@@ -239,12 +264,29 @@ int main(int argc, char** argv)
|
||||
return failed() || (py_true(gaming) && (!server || server->Has("game2:entergame")));
|
||||
});
|
||||
CHECK(entered && !failed());
|
||||
|
||||
// 7. (批次 2V2-b) The server answers CG_ENTERGAME with the character's own insert packets and
|
||||
// PHASE_GAME, then the Entergame burst (PVP/land list, time, channel, greet chat, ...). GamePhase
|
||||
// has to read all of it: an unknown or mis-sized packet makes CheckPacket log "Unknown packet
|
||||
// header" and drop the receive buffer. Offline the fake server ends with a ping the client
|
||||
// must answer; live the stream has to stay in the game window and connected for 10 s.
|
||||
const bool burst = pump_until(live ? 10 : 30, [&] {
|
||||
return failed() || (server && server->Has("game2:burst_pong"));
|
||||
});
|
||||
CHECK(live || (burst && !failed()));
|
||||
CHECK(py_true(gaming));
|
||||
CHECK(py("import net\nassert net.IsConnect(), 'disconnected in the game phase'"));
|
||||
CHECK(count_syserr("Unknown packet header") == 0);
|
||||
// The fake greet notice went through RecvChatPacket into the ported CPythonChat, where
|
||||
// uichat's chat set (created by the game interface) counts it.
|
||||
CHECK(live || py("import chat\nassert any(chat.GetLineCount(i) > 0 for i in range(4)), 'greet notice not in chat'"));
|
||||
}
|
||||
if (server)
|
||||
{
|
||||
const std::vector<std::string> expected = {
|
||||
"auth:handshake", "auth:login3", "game1:handshake", "game1:login2", "auth:closed",
|
||||
"game1:closed", "game2:handshake", "game2:login2", "game2:select", "game2:client_version", "game2:entergame",
|
||||
"game2:burst_sent", "game2:burst_pong",
|
||||
};
|
||||
auto events = server->Events();
|
||||
// auth:closed races game1's handshake; compare the order within each connection.
|
||||
|
||||
Reference in New Issue
Block a user