BTL4PB.CPP reconstructed against its AUTHENTIC surviving header (BTL4PB.HPP) from the binary's 0x4d3b74-0x4d40d8 cluster, cross-checked against the surviving RP411 twin -- and the review/camera launch in BTL4.CPP's main() is real code now. btl4.lib 11 -> 12 members, link clean, zero unresolved: the linker pulled the entire playback chain for the first time. The launch decode closed on two identifications: The `if (spool_file)` guard in the decomp means the manager getter is GetStoredSpoolFile -- the empty-spool getter cannot fail, so a review pod with no recorded battle simply starts nothing, which is the right field behaviour. The camera app's ctor (FUN_0047c3fc) sits in the ENGINE range with the (ResourceFile*, ApplicationID) shape: the camera pod's recorder IS the engine's own L4SpoolingApplication -- restored one commit ago -- started with ApplicationID 1 == BTL4. BT shipped no camera app of its own. What the playback app does, all binary-anchored: BTSpoolerTask pumps recorded packets through DispatchPacket -> the client's own ReceiveNetworkPacket; RunMission synchronises the clock (timeBias = Now - the recorded run packet's stamp); the frame loop runs controls ONLY in interactive review (mode 2), then update/interest/renderer/intercom; and StopMission plays the WINNERS CIRCLE -- release the spool, park each player's mech on the dropzone named "win1".."winN" by finishing rank, freeze it (DoNothing performance), and tilt the camera up 45 degrees over the tableau. DOS-authentic ctor shape throughout: the binary's base call is (resource, 0x3eb, DefaultData) -- no windowing parameters ever existed in 4.10; the RP411 twin's HINSTANCE/HWND threading is port drift, dropped. Also fixed from 5.3.105's debt: L4PlaybackNetworkManager chains NetworkManager::DefaultData -- the 1995 header declares no statics of its own; the RP411 self-reference was drift too. One [T3] in source: the idle frame's renderer service (the descendant's ExecuteIdle) has no 1995 entry point; pre-egg the idle frame spins. RUNTIME TEST PENDING, stated plainly: exercising review needs a camera/review egg and a recorded spool on the rig (CAMERA-REVIEW-NOTES.md has the roles). The normal pod path regressed clean (mode gate untouched). The Fail() census moves: BTL4.CPP and SEQCTL.CPP are now stub-free; 22 stubs remain across 15 files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
746 lines
19 KiB
C++
746 lines
19 KiB
C++
//===========================================================================//
|
|
// File: l4splr.cpp //
|
|
// Project: MUNGA Brick: L4 Spooling / Playback //
|
|
// Contents: The mission-review spool layer -- the recorder-side network //
|
|
// managers, the spooling application, and the playback pump //
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1995, Virtual World Entertainment, Inc. //
|
|
// All Rights reserved worldwide //
|
|
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
|
|
//===========================================================================//
|
|
//
|
|
// RECONSTRUCTION: no 1995 L4SPLR.CPP survives, but its HEADER does
|
|
// (CODE/RP/MUNGA_L4/L4SPLR.HPP), and the direct descendant source survives
|
|
// in the RP411 tree (MUNGA_L4/L4SPLR.cpp) -- this file is that source
|
|
// BACK-DATED onto the 1995 engine APIs the header declares, the same method
|
|
// as the MUNGA backfills (BACKFILLS.NOTES.md). Deltas from the RP411 body:
|
|
//
|
|
// * the windowing-era ctor (HINSTANCE/HWND) reverts to the header's
|
|
// (ResourceFile *, ApplicationID);
|
|
// * SOCKADDR_IN + two-arg ResolveAddress revert to the 1995
|
|
// unsigned-long address (L4NET.HPP:265) and FindHost(NetworkAddress);
|
|
// * L4Host construction takes NullNetworkAddress / socket 0, the same
|
|
// idiom as L4NET.CPP's own console-host build;
|
|
// * PostQuitMessage(AbortExitCodeID) becomes Exit_Code = AbortExitCodeID
|
|
// (the 1995 loop gate ExecuteForeground already tests);
|
|
// * accessor-style statics revert to the header's static members;
|
|
// * MakeGaugeRenderer()/Shutdown() lose their later-era parameters.
|
|
//
|
|
|
|
#include <mungal4.hpp>
|
|
#pragma hdrstop
|
|
|
|
#if !defined(L4SPLR_HPP)
|
|
# include <l4splr.hpp>
|
|
#endif
|
|
|
|
#if !defined(L4NET_HPP)
|
|
# include <l4net.hpp>
|
|
#endif
|
|
|
|
#if !defined(MISSION_HPP)
|
|
# include <mission.hpp>
|
|
#endif
|
|
|
|
#if !defined(APP_HPP)
|
|
# include <app.hpp>
|
|
#endif
|
|
|
|
#if !defined(L4CTRL_HPP)
|
|
# include <l4ctrl.hpp>
|
|
#endif
|
|
|
|
//#############################################################################
|
|
//###################### SpoolingInterestManager ##########################
|
|
//#############################################################################
|
|
|
|
SpoolingInterestManager::SpoolingInterestManager()
|
|
{
|
|
}
|
|
|
|
SpoolingInterestManager::~SpoolingInterestManager()
|
|
{
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
SpoolingInterestManager::LoadInterestArenas(Mission *)
|
|
{
|
|
Check(this);
|
|
}
|
|
|
|
void
|
|
SpoolingInterestManager::LoadMission(Mission *)
|
|
{
|
|
Check(this);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// Every network message reaching the interest manager is spooled.
|
|
//#############################################################################
|
|
//
|
|
void
|
|
SpoolingInterestManager::ReceiveNetworkPacket(
|
|
NetworkPacket *packet,
|
|
Receiver::Message *
|
|
)
|
|
{
|
|
packet->timeStamp = Now();
|
|
|
|
Check(l4_spooling_application);
|
|
SpoolFile
|
|
*spool = l4_spooling_application->GetSpoolFile();
|
|
Check(spool);
|
|
spool->SpoolPacket(packet);
|
|
}
|
|
|
|
void
|
|
SpoolingInterestManager::Shutdown()
|
|
{
|
|
Check(this);
|
|
}
|
|
|
|
//#############################################################################
|
|
//###################### L4SpoolingNetworkManager #########################
|
|
//#############################################################################
|
|
|
|
L4SpoolingNetworkManager::L4SpoolingNetworkManager()
|
|
{
|
|
}
|
|
|
|
L4SpoolingNetworkManager::~L4SpoolingNetworkManager()
|
|
{
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// Start the connection normally, then write the spool PREAMBLE: the
|
|
// application ID, the resource major version, and per mission host a
|
|
// remote/local flag plus its host ID -- everything playback needs to
|
|
// reconstruct the host table without a live network.
|
|
//#############################################################################
|
|
//
|
|
void
|
|
L4SpoolingNetworkManager::StartConnecting(Mission *mission)
|
|
{
|
|
L4NetworkManager::StartConnecting(mission);
|
|
|
|
Check(l4_spooling_application);
|
|
SpoolFile
|
|
*spool = l4_spooling_application->GetSpoolFile();
|
|
Check(spool);
|
|
|
|
*(ApplicationID *)spool->GetPointer() = application->GetApplicationID();
|
|
spool->AdvancePointer(sizeof(ApplicationID));
|
|
|
|
ResourceFile
|
|
*res_file = application->GetResourceFile();
|
|
Check(res_file);
|
|
int
|
|
major_version = res_file->versionArray[1];
|
|
*(int *)spool->GetPointer() = major_version;
|
|
spool->AdvancePointer(sizeof(major_version));
|
|
|
|
HostManager
|
|
*host_mgr = application->GetHostManager();
|
|
Check(host_mgr);
|
|
|
|
Mission::HostIterator
|
|
mission_host_iterator(mission);
|
|
MissionHostData
|
|
*mission_host_data;
|
|
|
|
while ((mission_host_data = mission_host_iterator.ReadAndNext()) != NULL)
|
|
{
|
|
CString
|
|
host_name(mission_host_data->GetAddressString());
|
|
unsigned long
|
|
net_address = ResolveAddress(host_name);
|
|
Host
|
|
*host = host_mgr->FindHost(net_address);
|
|
|
|
*(Logical *)spool->GetPointer() = (host != host_mgr->GetLocalHost());
|
|
spool->AdvancePointer(sizeof(Logical));
|
|
|
|
*(HostID *)spool->GetPointer() = host->GetHostID();
|
|
spool->AdvancePointer(sizeof(HostID));
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// Egg traffic is spooled on its way through.
|
|
//#############################################################################
|
|
//
|
|
void
|
|
L4SpoolingNetworkManager::ReceiveNetworkPacket(
|
|
NetworkPacket *packet,
|
|
Receiver::Message *message
|
|
)
|
|
{
|
|
if (message->messageID == ReceiveEggFileMessageID)
|
|
{
|
|
packet->timeStamp = Now();
|
|
Check(l4_spooling_application);
|
|
SpoolFile
|
|
*spool = l4_spooling_application->GetSpoolFile();
|
|
Check(spool);
|
|
spool->SpoolPacket(packet);
|
|
}
|
|
L4NetworkManager::ReceiveNetworkPacket(packet, message);
|
|
}
|
|
|
|
//#############################################################################
|
|
//###################### L4PlaybackNetworkManager #########################
|
|
//#############################################################################
|
|
|
|
//
|
|
// The 1995 header declares no statics of its own (the DefaultData reference
|
|
// in the RP411 descendant was later-era drift); chain the base's.
|
|
//
|
|
L4PlaybackNetworkManager::L4PlaybackNetworkManager():
|
|
NetworkManager(NetworkManager::DefaultData)
|
|
{
|
|
}
|
|
|
|
L4PlaybackNetworkManager::~L4PlaybackNetworkManager()
|
|
{
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// "Connect" from the spool instead of the wire: read back the preamble the
|
|
// spooler wrote, verify it belongs to this application and data version,
|
|
// rebuild the host table from the recorded flags, and post LoadMission.
|
|
//#############################################################################
|
|
//
|
|
void
|
|
L4PlaybackNetworkManager::StartConnecting(Mission *mission)
|
|
{
|
|
Mission::HostIterator
|
|
mission_host_iterator(mission);
|
|
MissionHostData
|
|
*mission_host_data;
|
|
|
|
Check(application);
|
|
SpoolFile
|
|
*spool = application->GetSpoolFile();
|
|
Check(spool);
|
|
|
|
ApplicationID
|
|
id = *(ApplicationID *)spool->GetPointer();
|
|
spool->AdvancePointer(sizeof(id));
|
|
int
|
|
major_rev = *(int *)spool->GetPointer();
|
|
spool->AdvancePointer(sizeof(major_rev));
|
|
|
|
if (id != application->GetApplicationID())
|
|
{
|
|
DEBUG_STREAM
|
|
<< "\n\nError - Not a spool file for this application!\n" << flush;
|
|
Exit_Code = AbortExitCodeID;
|
|
return;
|
|
}
|
|
|
|
ResourceFile
|
|
*resource_file = application->GetResourceFile();
|
|
Check(resource_file);
|
|
|
|
if (major_rev != resource_file->versionArray[1])
|
|
{
|
|
DEBUG_STREAM
|
|
<< "\n\nError - Spool file major data version should be "
|
|
<< (int)resource_file->versionArray[1] << ", not " << major_rev
|
|
<< "!\n" << flush;
|
|
Exit_Code = AbortExitCodeID;
|
|
return;
|
|
}
|
|
|
|
HostManager
|
|
*host_mgr = application->GetHostManager();
|
|
Check(host_mgr);
|
|
|
|
while ((mission_host_data = mission_host_iterator.ReadAndNext()) != NULL)
|
|
{
|
|
Check(mission_host_data);
|
|
CString
|
|
host_name(mission_host_data->GetAddressString());
|
|
|
|
Logical
|
|
remote = *(Logical *)spool->GetPointer();
|
|
spool->AdvancePointer(sizeof(Logical));
|
|
HostID
|
|
host_id = *(HostID *)spool->GetPointer();
|
|
spool->AdvancePointer(sizeof(HostID));
|
|
|
|
Host
|
|
*my_host =
|
|
new L4Host(
|
|
host_id,
|
|
mission_host_data->GetHostType(),
|
|
NullNetworkAddress,
|
|
0,
|
|
host_name
|
|
);
|
|
Register_Object(my_host);
|
|
if (remote)
|
|
{
|
|
host_mgr->AdoptRemoteHost(my_host);
|
|
}
|
|
else
|
|
{
|
|
host_mgr->AdoptLocalHost(my_host);
|
|
}
|
|
}
|
|
|
|
Check(application);
|
|
Application::Message
|
|
load_message(
|
|
Application::LoadMissionMessageID,
|
|
sizeof(Application::Message)
|
|
);
|
|
application->Post(DefaultEventPriority, application, &load_message);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
Logical
|
|
L4PlaybackNetworkManager::Shutdown()
|
|
{
|
|
Check(this);
|
|
NetworkManager::Shutdown();
|
|
|
|
Check(application);
|
|
HostManager
|
|
*host_mgr = application->GetHostManager();
|
|
Check(host_mgr);
|
|
HostManager::RemoteHostIterator
|
|
remote_hosts(host_mgr);
|
|
Host
|
|
*my_host;
|
|
while ((my_host = remote_hosts.ReadAndNext()) != NULL)
|
|
{
|
|
Check(my_host);
|
|
host_mgr->OrphanRemoteHost(my_host);
|
|
Unregister_Object(my_host);
|
|
delete my_host;
|
|
}
|
|
return True;
|
|
}
|
|
|
|
//
|
|
// Playback has no live wire: the buffers are always empty.
|
|
//
|
|
Logical
|
|
L4PlaybackNetworkManager::CheckBuffers(NetworkPacket *)
|
|
{
|
|
return False;
|
|
}
|
|
|
|
//#############################################################################
|
|
//###################### L4SpoolingApplication ##########################
|
|
//#############################################################################
|
|
|
|
L4SpoolingApplication
|
|
*&l4_spooling_application = (L4SpoolingApplication *&)application;
|
|
|
|
const Receiver::HandlerEntry
|
|
L4SpoolingApplication::MessageHandlerEntries[] =
|
|
{
|
|
MESSAGE_ENTRY(L4SpoolingApplication, RunMission),
|
|
MESSAGE_ENTRY(L4SpoolingApplication, StopMission),
|
|
MESSAGE_ENTRY(L4SpoolingApplication, AbortMission),
|
|
MESSAGE_ENTRY(L4SpoolingApplication, LoadMission)
|
|
};
|
|
|
|
L4SpoolingApplication::MessageHandlerSet
|
|
L4SpoolingApplication::MessageHandlers(
|
|
ELEMENTS(L4SpoolingApplication::MessageHandlerEntries),
|
|
L4SpoolingApplication::MessageHandlerEntries,
|
|
L4Application::MessageHandlers
|
|
);
|
|
|
|
Derivation
|
|
L4SpoolingApplication::ClassDerivations(
|
|
L4Application::ClassDerivations,
|
|
"L4SpoolingApplication"
|
|
);
|
|
|
|
L4SpoolingApplication::SharedData
|
|
L4SpoolingApplication::DefaultData(
|
|
L4SpoolingApplication::ClassDerivations,
|
|
L4SpoolingApplication::MessageHandlers
|
|
);
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
L4SpoolingApplication::L4SpoolingApplication(
|
|
ResourceFile *resource_file,
|
|
ApplicationID application_ID
|
|
):
|
|
L4Application(
|
|
resource_file,
|
|
application_ID,
|
|
L4ApplicationClassID,
|
|
DefaultData
|
|
)
|
|
{
|
|
missionSpooled = False;
|
|
}
|
|
|
|
L4SpoolingApplication::~L4SpoolingApplication()
|
|
{
|
|
}
|
|
|
|
Logical
|
|
L4SpoolingApplication::TestInstance() const
|
|
{
|
|
return IsDerivedFrom(ClassDerivations);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// Message handlers.
|
|
//#############################################################################
|
|
//
|
|
void
|
|
L4SpoolingApplication::LoadMissionMessageHandler(Message *)
|
|
{
|
|
applicationState.SetState(WaitingForLaunch);
|
|
}
|
|
|
|
void
|
|
L4SpoolingApplication::RunMissionMessageHandler(RunMissionMessage *)
|
|
{
|
|
Check(this);
|
|
applicationState.SetState(RunningMission);
|
|
}
|
|
|
|
//
|
|
// The stop is deferred until the mission has fully spooled, then the spool
|
|
// is handed to the application manager for storage.
|
|
//
|
|
void
|
|
L4SpoolingApplication::StopMissionMessageHandler(StopMissionMessage *message)
|
|
{
|
|
if (!missionSpooled)
|
|
{
|
|
missionSpooled = True;
|
|
|
|
Time
|
|
post_time = Now();
|
|
post_time += 3.0f;
|
|
|
|
//
|
|
// The StopMissionMessage IS a Receiver::Message (NetworkClient
|
|
// derives Receiver, so NetworkClient::Message resolves there); the
|
|
// explicit cast is for BC4.52's nested-scope upcast quirk only.
|
|
//
|
|
Post(
|
|
DefaultEventPriority, this,
|
|
(Receiver::Message *)message, post_time);
|
|
}
|
|
else
|
|
{
|
|
MissionReviewApplicationManager
|
|
*app_mgr = GetApplicationManager();
|
|
Check(app_mgr);
|
|
SpoolFile
|
|
*spool = GetSpoolFile();
|
|
Check(spool);
|
|
app_mgr->StoreSpoolFile(spool);
|
|
spoolFile = NULL;
|
|
|
|
L4Application::StopMissionMessageHandler(message);
|
|
}
|
|
}
|
|
|
|
void
|
|
L4SpoolingApplication::AbortMissionMessageHandler(
|
|
AbortMissionMessage *message
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(spoolFile);
|
|
spoolFile->Rewind();
|
|
|
|
L4Application::AbortMissionMessageHandler(message);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// Run/stop traffic is spooled on its way through -- the stop only once the
|
|
// mission has been marked spooled, so the recorded file ends exactly once.
|
|
//#############################################################################
|
|
//
|
|
void
|
|
L4SpoolingApplication::ReceiveNetworkPacket(
|
|
NetworkPacket *packet,
|
|
Receiver::Message *message
|
|
)
|
|
{
|
|
Check(this);
|
|
|
|
SpoolFile
|
|
*spool;
|
|
switch (message->messageID)
|
|
{
|
|
case StopMissionMessageID:
|
|
if (missionSpooled)
|
|
{
|
|
packet->timeStamp = Now();
|
|
spool = GetSpoolFile();
|
|
Check(spool);
|
|
spool->SpoolPacket(packet);
|
|
break;
|
|
}
|
|
// fall through -- an un-spooled stop records like a run
|
|
|
|
case RunMissionMessageID:
|
|
packet->timeStamp = Now();
|
|
spool = GetSpoolFile();
|
|
Check(spool);
|
|
spool->SpoolPacket(packet);
|
|
break;
|
|
}
|
|
L4Application::ReceiveNetworkPacket(packet, message);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// The maker overrides: a spooler records; it does not render.
|
|
//#############################################################################
|
|
//
|
|
Registry *
|
|
L4SpoolingApplication::MakeRegistry()
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
InterestManager *
|
|
L4SpoolingApplication::MakeInterestManager()
|
|
{
|
|
return new SpoolingInterestManager;
|
|
}
|
|
|
|
NetworkManager *
|
|
L4SpoolingApplication::MakeNetworkManager()
|
|
{
|
|
return new L4SpoolingNetworkManager;
|
|
}
|
|
|
|
VideoRenderer *
|
|
L4SpoolingApplication::MakeVideoRenderer()
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
AudioRenderer *
|
|
L4SpoolingApplication::MakeAudioRenderer()
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
GaugeRenderer *
|
|
L4SpoolingApplication::MakeGaugeRenderer()
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
Mission *
|
|
L4SpoolingApplication::MakeMission(
|
|
NotationFile *notation_file,
|
|
ResourceFile *resources
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(notation_file);
|
|
Check(resources);
|
|
|
|
return new Mission(notation_file, resources);
|
|
}
|
|
|
|
Entity *
|
|
L4SpoolingApplication::MakeViewpointEntity(Entity__MakeMessage *)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
void
|
|
L4SpoolingApplication::Initialize()
|
|
{
|
|
Check(this);
|
|
Application::Initialize();
|
|
|
|
L4NetworkManager
|
|
*net_mgr = GetNetworkManager();
|
|
Check(net_mgr);
|
|
net_mgr->CreateConsoleHost();
|
|
|
|
MissionReviewApplicationManager
|
|
*app_mgr = GetApplicationManager();
|
|
Check(app_mgr);
|
|
spoolFile = app_mgr->GetEmptySpoolFile();
|
|
}
|
|
|
|
void
|
|
L4SpoolingApplication::LoadBackgroundTasks()
|
|
{
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
//#############################################################################
|
|
//
|
|
Logical
|
|
L4SpoolingApplication::ExecuteForeground(
|
|
Time /* start_of_frame */,
|
|
Scalar /* frame_duration */
|
|
)
|
|
{
|
|
SET_FOREGROUND_PROCESSING();
|
|
Check(this);
|
|
|
|
//
|
|
// The 1995 base ControlsManager has no Execute; the LBE4 subclass owns
|
|
// the per-frame poll (L4CTRL.HPP:225), same cast L4APP itself uses.
|
|
//
|
|
Check(controlsManager);
|
|
((LBE4ControlsManager *)controlsManager)->Execute();
|
|
|
|
CLEAR_FOREGROUND_PROCESSING();
|
|
return executeFrames && !Exit_Code;
|
|
}
|
|
|
|
void
|
|
L4SpoolingApplication::ExecuteBackgroundTask()
|
|
{
|
|
Check(this);
|
|
|
|
Check(networkManager);
|
|
if (!networkManager->RoutePacket())
|
|
{
|
|
ProcessOneEvent(DefaultEventPriority);
|
|
}
|
|
}
|
|
|
|
Logical
|
|
L4SpoolingApplication::Shutdown()
|
|
{
|
|
Check(this);
|
|
|
|
L4Application::Shutdown();
|
|
return !Exit_Code && !missionSpooled;
|
|
}
|
|
|
|
//#############################################################################
|
|
//########################### SpoolerTask ###############################
|
|
//#############################################################################
|
|
|
|
SpoolerTask::SpoolerTask()
|
|
{
|
|
}
|
|
|
|
SpoolerTask::~SpoolerTask()
|
|
{
|
|
}
|
|
|
|
void
|
|
SpoolerTask::DispatchPacket(NetworkPacket *)
|
|
{
|
|
Fail("SpoolerTask::DispatchPacket - shouldn't be here!");
|
|
}
|
|
|
|
long
|
|
SpoolerTask::GetTimeBias()
|
|
{
|
|
Fail("SpoolerTask::GetTimeBias - shouldn't be here!");
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// The playback pump: interpret the spool against the application state --
|
|
// egg packets while waiting for the egg, interest packets while loading,
|
|
// then everything else doled out on the recorded timestamps biased by when
|
|
// the run began.
|
|
//#############################################################################
|
|
//
|
|
void
|
|
SpoolerTask::Execute()
|
|
{
|
|
Check(this);
|
|
Check(application);
|
|
|
|
SpoolFile
|
|
*spool = application->GetSpoolFile();
|
|
if (!spool)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Check(spool);
|
|
NetworkPacket
|
|
*packet;
|
|
switch (application->GetApplicationState())
|
|
{
|
|
case Application::WaitingForEgg:
|
|
packet = (NetworkPacket *)spool->GetPointer();
|
|
while (packet->clientID == NetworkClient::NetworkManagerClientID)
|
|
{
|
|
spool->NextPacket();
|
|
DispatchPacket(packet);
|
|
packet = (NetworkPacket *)spool->GetPointer();
|
|
}
|
|
break;
|
|
|
|
case Application::CreatingMission:
|
|
case Application::LoadingMission:
|
|
packet = (NetworkPacket *)spool->GetPointer();
|
|
while (
|
|
packet->clientID != NetworkClient::ApplicationClientID &&
|
|
spool->GetBytesRemaining() > 0
|
|
)
|
|
{
|
|
spool->NextPacket();
|
|
DispatchPacket(packet);
|
|
packet = (NetworkPacket *)spool->GetPointer();
|
|
}
|
|
break;
|
|
|
|
case Application::LaunchingMission:
|
|
case Application::RunningMission:
|
|
while (spool && spool->GetBytesRemaining() > 0)
|
|
{
|
|
packet = (NetworkPacket *)spool->GetPointer();
|
|
Time
|
|
when = packet->timeStamp;
|
|
when.ticks += GetTimeBias();
|
|
if (when > Now())
|
|
{
|
|
break;
|
|
}
|
|
spool->NextPacket();
|
|
DispatchPacket(packet);
|
|
spool = application->GetSpoolFile();
|
|
}
|
|
break;
|
|
}
|
|
}
|