The console speaks to the room it is standing in
Cyd's point: a real pod bay console is its own machine, and every station - pod, Live Cam, mission review - hears it over the wire. That is why the spooler expects LoadMission and RunMission to arrive as packets. Ours is colocated, and the network stack is quite right not to push bytes through a socket to reach a client in the same process. But the console had gone further than that. It called application->Dispatch, stepping past the client's receive entry altogether, so nothing watching packets ever saw the console speak. The first Live Cam recording is the evidence: 14,342 packets, every one of them from the racer via the interest manager, and not one LoadMission, RunMission or StopMission - because those came from inside the house. The tee was not in the wrong layer for the wire; it was in the right place and the console was walking around it. So build the packet SendWire would have built and hand it to the client's own front door. NetworkClient::ReceiveNetworkPacket is Dispatch plus whatever is watching, and Application IS the client for ApplicationClientID, so this is the same delivery arriving where deliveries arrive - no socket, no loopback, no second copy of the protocol. Correcting myself twice over. RunMission does NOT have to be the first packet in the spool: playback reads spool->GetPointer(), the current cursor, by which time the task has consumed what came before, so it checks that the cursor has REACHED RunMission rather than that the file starts with it. And the ordering is therefore not "the whole job" as I claimed - the recorded timings already show a normal shape, fifteen entity creations inside the first twenty milliseconds and updates running from 0.110s to 308.940s of a five minute race. Still open: the egg feed is local too (FeedLocalEgg), so a spool carries no egg. Whether that matters depends on how the playback application loads its mission, which is the next thing to find out rather than guess at. WATCH ON NEXT LAUNCH: this changes how the local station is told to start and stop a race. It should be identical - ReceiveNetworkPacket dispatches the same message to the same object - but it is the launch path, so a race that does not start is this commit. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+50
-2
@@ -164,6 +164,46 @@ namespace
|
|||||||
pod->connection, packet, (int) sizeof(NetworkPacketHeader) + size);
|
pod->connection, packet, (int) sizeof(NetworkPacketHeader) + size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------
|
||||||
|
// The same packet, delivered to the station on this machine.
|
||||||
|
//
|
||||||
|
// A real pod bay console sits on its own machine and every station
|
||||||
|
// hears it over the wire. Here it is colocated, and the network stack
|
||||||
|
// is quite right not to push bytes through a socket to reach a client
|
||||||
|
// in the same process - but the console had gone further than that and
|
||||||
|
// called application->Dispatch, stepping past the client's receive
|
||||||
|
// entry altogether. Anything watching packets therefore never saw the
|
||||||
|
// console speak: the first Live Cam recording held all 14,342 of the
|
||||||
|
// racer's packets and not one LoadMission, RunMission or StopMission,
|
||||||
|
// because those were the messages that came from inside the house.
|
||||||
|
//
|
||||||
|
// So build the packet SendWire would have built and hand it to the
|
||||||
|
// client's own front door. No socket, no wire, no copy of the protocol
|
||||||
|
// - just the delivery arriving where a delivery arrives.
|
||||||
|
//---------------------------------------------------------------
|
||||||
|
void DeliverLocal(int client_ID, const void *message, int size)
|
||||||
|
{
|
||||||
|
char packet[sizeof(NetworkPacketHeader) + 1400];
|
||||||
|
|
||||||
|
if (size > (int) sizeof(packet) - (int) sizeof(NetworkPacketHeader))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memset(packet, 0, sizeof(NetworkPacketHeader));
|
||||||
|
|
||||||
|
NetworkPacketHeader *header = (NetworkPacketHeader *) packet;
|
||||||
|
|
||||||
|
header->clientID = (NetworkClient::ClientID) client_ID;
|
||||||
|
header->gameID = 0;
|
||||||
|
header->fromHost = 1; // the console's reserved host ID
|
||||||
|
memcpy(packet + sizeof(NetworkPacketHeader), message, size);
|
||||||
|
|
||||||
|
NetworkPacket *received = (NetworkPacket *) packet;
|
||||||
|
|
||||||
|
Check(application);
|
||||||
|
application->ReceiveNetworkPacket(received, &received->messageData);
|
||||||
|
}
|
||||||
|
|
||||||
void SendEggTo(RemotePod *pod)
|
void SendEggTo(RemotePod *pod)
|
||||||
{
|
{
|
||||||
int chunk_count = (gEggWireSize + 999) / 1000;
|
int chunk_count = (gEggWireSize + 999) / 1000;
|
||||||
@@ -348,7 +388,11 @@ namespace
|
|||||||
DEBUG_STREAM << "LocalConsole: stopping local pod\n" << std::flush;
|
DEBUG_STREAM << "LocalConsole: stopping local pod\n" << std::flush;
|
||||||
InterlockedExchange(&gMissionRunning, 0);
|
InterlockedExchange(&gMissionRunning, 0);
|
||||||
Application::StopMissionMessage message(0);
|
Application::StopMissionMessage message(0);
|
||||||
application->Dispatch(&message);
|
DeliverLocal(
|
||||||
|
NetworkClient::ApplicationClientID,
|
||||||
|
&message,
|
||||||
|
(int) message.messageLength
|
||||||
|
);
|
||||||
gPhase = PhaseStopped;
|
gPhase = PhaseStopped;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -455,7 +499,11 @@ namespace
|
|||||||
&run, (int) run.messageLength);
|
&run, (int) run.messageLength);
|
||||||
}
|
}
|
||||||
Application::RunMissionMessage local_run;
|
Application::RunMissionMessage local_run;
|
||||||
application->Dispatch(&local_run);
|
DeliverLocal(
|
||||||
|
NetworkClient::ApplicationClientID,
|
||||||
|
&local_run,
|
||||||
|
(int) local_run.messageLength
|
||||||
|
);
|
||||||
gRunSent = True;
|
gRunSent = True;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user