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
@@ -440,6 +440,72 @@ bool FakeLoginServer::ServeGame(Connection& c, int index)
|
||||
return Fail(name + ": CG_ENTERGAME: " + error);
|
||||
Event(name + ":entergame");
|
||||
|
||||
// CInputLogin::Entergame order: ch->Show inserts the main actor while the client is still in
|
||||
// the loading phase (CHARACTER::EncodeInsertPacket = ADD + ADDITIONAL_INFO, then UpdatePacket),
|
||||
// then SendNPCPosition, PHASE_GAME, SendLandList, TIME, CHANNEL and the greet notice.
|
||||
GCCharacterAdd actor = zeroed<GCCharacterAdd>();
|
||||
actor.header = HDR_GC_CHARACTER_ADD;
|
||||
actor.vid = kMainVID;
|
||||
actor.x = kX;
|
||||
actor.y = kY;
|
||||
actor.type = 0; // CHAR_TYPE_PC
|
||||
actor.race = 0; // warrior male
|
||||
actor.moving_speed = 100;
|
||||
actor.attack_speed = 100;
|
||||
GCCharAddInfo info = zeroed<GCCharAddInfo>();
|
||||
info.header = HDR_GC_CHAR_ADDITIONAL_INFO;
|
||||
info.vid = kMainVID;
|
||||
std::strncpy(info.name, kCharacterName, sizeof(info.name) - 1);
|
||||
info.empire = 1;
|
||||
info.level = 10;
|
||||
GCCharacterUpdate update = zeroed<GCCharacterUpdate>();
|
||||
update.header = HDR_GC_CHARACTER_UPDATE;
|
||||
update.vid = kMainVID;
|
||||
update.moving_speed = 100;
|
||||
update.attack_speed = 100;
|
||||
if (!c.Send(actor) || !c.Send(info) || !c.Send(update))
|
||||
return Fail(name + ": send main actor");
|
||||
|
||||
// packet_npc_position = DynHead + count, then TNPCPosition entries.
|
||||
NPCPosition34 npc = zeroed<NPCPosition34>();
|
||||
npc.type = 1; // CHAR_TYPE_NPC
|
||||
std::strncpy(npc.name, "Npc", sizeof(npc.name) - 1);
|
||||
npc.x = kX + 500;
|
||||
npc.y = kY + 500;
|
||||
DynHead npc_head = {HDR_GC_NPC_POSITION, static_cast<std::uint16_t>(sizeof(DynHead) + sizeof(GCNPCPositionHead) + sizeof(npc))};
|
||||
GCNPCPositionHead npc_count = {1};
|
||||
if (!c.Send(npc_head) || !c.Send(npc_count) || !c.Send(npc))
|
||||
return Fail(name + ": send NPC positions");
|
||||
|
||||
if (!c.Phase(PHASE_GAME))
|
||||
return Fail(name + ": send PHASE_GAME");
|
||||
|
||||
LandPacketElement24 land = zeroed<LandPacketElement24>();
|
||||
land.id = 1;
|
||||
land.x = kX + 1000;
|
||||
land.y = kY + 1000;
|
||||
land.width = 2000;
|
||||
land.height = 2000;
|
||||
DynHead land_head = {HDR_GC_LAND_LIST, static_cast<std::uint16_t>(sizeof(DynHead) + sizeof(land))};
|
||||
GCTime game_time = {HDR_GC_TIME, static_cast<std::int32_t>(now_ms())};
|
||||
GCChannel channel = {HDR_GC_CHANNEL, 1};
|
||||
if (!c.Send(land_head) || !c.Send(land) || !c.Send(game_time) || !c.Send(channel))
|
||||
return Fail(name + ": send land/time/channel");
|
||||
|
||||
// SendGreetMessage: a CHAT_TYPE_NOTICE line with no speaker.
|
||||
const char greet[] = "Welcome";
|
||||
GCChatHead chat = {HDR_GC_CHAT, static_cast<std::uint16_t>(sizeof(GCChatHead) + sizeof(greet)), 2 /* CHAT_TYPE_NOTICE */, 0, 1};
|
||||
if (!c.Send(chat) || !c.Send(greet, sizeof(greet)))
|
||||
return Fail(name + ": send greet notice");
|
||||
Event(name + ":burst_sent");
|
||||
|
||||
// A ping after the burst proves that GamePhase consumed every packet above and can reply.
|
||||
Blank ping = {HDR_GC_PING};
|
||||
Blank pong = {};
|
||||
if (!c.Send(ping) || read_packet(c, HDR_CG_PONG, &pong, sizeof(pong), &error) != 1)
|
||||
return Fail(name + ": CG_PONG after the entergame burst: " + error);
|
||||
Event(name + ":burst_pong");
|
||||
|
||||
// Hold the connection until the test stops us.
|
||||
std::uint8_t byte = 0;
|
||||
while (!m_stop && c.Read(&byte, 1) == 1)
|
||||
|
||||
Reference in New Issue
Block a user