Two more blockers down, found by watching it rather than reasoning about
it - Cyd reported a black screen with a full pod cockpit over it, and both
halves of that turned out to be real and separate.
The black screen: playback had no mission. L4NetworkManager reads the -egg
file and posts a ReceiveEggFileMessage in single user mode, which is what
ends in CreateMission and builds the world - but that is the POD's network
manager. L4PlaybackNetworkManager descends from NetworkManager and
inherited none of it, so the playback application came up with a cockpit,
nothing behind it, and not a word in the log. A spool records what MOVED,
never the track it moved through, so the egg is not optional.
The cockpit: Application::SetCameraStation is the front end's answer to a
question asked on the setup screen, and playback never sees the setup
screen, so a Live Cam recording replayed as a pod - five instrument panes
over the view, map back in the middle. The egg knows what the station was;
it is the same egg the race ran on. Read it from the host type instead.
Then playback got far enough to reject the spool outright:
Error - Not a spool file for this application!
Error - Spool file major data version should be 3, not 0!
Correct of it. A spool opens with the application ID, the resource major
version, and one (remote, hostID) pair per egg host, and SpoolRecorder was
writing packets and nothing else - so playback read a zero where the
application ID belonged. The header is written now, in
L4NetworkManager::StartConnecting, because every field in it is
network-layer knowledge and that is the first moment all of it exists.
NOTE the recordings made before this cannot be played back. They have no
header, and there is nothing in the file to reconstruct one from - the
host table describes machines that were on the wire at the time. A race
recorded from here on will have one.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
826 lines
22 KiB
C++
826 lines
22 KiB
C++
#include "mungal4.h"
|
|
#pragma hdrstop
|
|
|
|
#include "l4splr.h"
|
|
#include "..\munga\mission.h"
|
|
#include "..\munga\controls.h"
|
|
#include "..\munga\appmsg.h"
|
|
|
|
//#############################################################################
|
|
//####################### SpoolingInterestManager #########################
|
|
//#############################################################################
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
SpoolingInterestManager::SpoolingInterestManager()
|
|
{
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
SpoolingInterestManager::~SpoolingInterestManager()
|
|
{
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
SpoolingInterestManager::LoadInterestArenas(Mission *)
|
|
{
|
|
Check(this);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
SpoolingInterestManager::LoadMission(Mission *)
|
|
{
|
|
Check(this);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
SpoolingInterestManager::ReceiveNetworkPacket(
|
|
NetworkPacket *packet,
|
|
Receiver::Message *
|
|
)
|
|
{
|
|
//
|
|
//--------------------------------------------------------------------
|
|
// All network messages coming to the interest manager will be spooled
|
|
//--------------------------------------------------------------------
|
|
//
|
|
packet->timeStamp = Now(); // HACK - spoof the clock stuff
|
|
Check(l4_spooling_application);
|
|
SpoolFile *spool = l4_spooling_application->GetSpoolFile();
|
|
Check(spool);
|
|
spool->SpoolPacket(packet);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
SpoolingInterestManager::Shutdown()
|
|
{
|
|
Check(this);
|
|
}
|
|
|
|
//#############################################################################
|
|
//###################### L4SpoolingNetworkManager #########################
|
|
//#############################################################################
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
L4SpoolingNetworkManager::L4SpoolingNetworkManager()
|
|
{
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
L4SpoolingNetworkManager::StartConnecting(Mission *mission)
|
|
{
|
|
//
|
|
//--------------------------------------------------------
|
|
// Let the L4 network manager start the connection process
|
|
//--------------------------------------------------------
|
|
//
|
|
L4NetworkManager::StartConnecting(mission);
|
|
|
|
//
|
|
//---------------------------------
|
|
// Local the spool file to write to
|
|
//---------------------------------
|
|
//
|
|
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));
|
|
|
|
//
|
|
//-----------------------------------------------------------------
|
|
// Now, write out the host IDs. Follow each host ID with a logical
|
|
// indicating whether it is local or remote
|
|
//-----------------------------------------------------------------
|
|
//
|
|
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());
|
|
SOCKADDR_IN net_address;
|
|
|
|
ResolveAddress(host_name, &net_address);
|
|
Host *host = host_mgr->FindHost(net_address);
|
|
|
|
//
|
|
// FindHost answers NULL for a host named in the egg that is not
|
|
// actually connected, and this went straight on to call
|
|
// host->GetHostID(). In an arcade every station in the egg is on
|
|
// the wire, so the case could not arise; anywhere else it is the
|
|
// ordinary state of affairs, and it crashed the spooling
|
|
// application before the mission could even start.
|
|
//
|
|
// The table below is read back one pair per egg host, in egg
|
|
// order, so a missing host cannot simply be skipped - that would
|
|
// shift every entry after it. Write the pair, say what happened,
|
|
// and carry on.
|
|
//
|
|
if (host == NULL)
|
|
{
|
|
DEBUG_STREAM << "Spool: host '" << host_name
|
|
<< "' is in the egg but not connected - recording it as"
|
|
<< " remote with no ID. Packets from it will not map back.\n"
|
|
<< std::flush;
|
|
|
|
*(Logical*)spool->GetPointer() = True;
|
|
spool->AdvancePointer(sizeof(Logical));
|
|
|
|
*(HostID*)spool->GetPointer() = (HostID) 0;
|
|
spool->AdvancePointer(sizeof(HostID));
|
|
continue;
|
|
}
|
|
|
|
*(Logical*)spool->GetPointer() = (host != host_mgr->GetLocalHost());
|
|
spool->AdvancePointer(sizeof(Logical));
|
|
|
|
*(HostID*)spool->GetPointer() = host->GetHostID();
|
|
spool->AdvancePointer(sizeof(HostID));
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
L4SpoolingNetworkManager::~L4SpoolingNetworkManager()
|
|
{
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
L4SpoolingNetworkManager::ReceiveNetworkPacket(
|
|
NetworkPacket *packet,
|
|
Receiver::Message *message
|
|
)
|
|
{
|
|
//
|
|
//------------------------------------------------------
|
|
// Any egg messages will be spooled before being sent on
|
|
//------------------------------------------------------
|
|
//
|
|
if (message->messageID == ReceiveEggFileMessageID)
|
|
{
|
|
packet->timeStamp = Now(); // HACK - spoof the clock stuff
|
|
Check(l4_spooling_application);
|
|
SpoolFile *spool = l4_spooling_application->GetSpoolFile();
|
|
Check(spool);
|
|
spool->SpoolPacket(packet);
|
|
}
|
|
L4NetworkManager::ReceiveNetworkPacket(packet, message);
|
|
}
|
|
|
|
//#############################################################################
|
|
//###################### L4PlaybackNetworkManager #########################
|
|
//#############################################################################
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
L4PlaybackNetworkManager::L4PlaybackNetworkManager():
|
|
NetworkManager(L4PlaybackNetworkManager::DefaultData)
|
|
{
|
|
//
|
|
// Give this application its mission.
|
|
//
|
|
// Nothing else will. A spool is a record of what MOVED, not of the
|
|
// world it moved through - no track, no models, no drop zones - and
|
|
// playback has neither a wire to be sent an egg over nor a console to
|
|
// send one. L4NetworkManager does exactly this for single user mode,
|
|
// but that is the pod's network manager; this one descends from
|
|
// NetworkManager and inherited none of it, so a playback build came up
|
|
// with a cockpit, no world behind it, and nothing in the log to say
|
|
// why. A black screen is what that looks like.
|
|
//
|
|
const char *egg_name =
|
|
((L4Application *) application)->GetEggNotationFileName();
|
|
|
|
if (egg_name == NULL || strlen(egg_name) == 0)
|
|
{
|
|
DEBUG_STREAM << "Playback: no egg given. A spool records the race but"
|
|
<< " not the track it was run on, so -egg must name the one it"
|
|
<< " was recorded with.\n" << std::flush;
|
|
return;
|
|
}
|
|
|
|
DEBUG_STREAM << "Playback: loading world from egg '" << egg_name
|
|
<< "'\n" << std::flush;
|
|
|
|
networkEggNotationFile = new NotationFile(egg_name);
|
|
Register_Object(networkEggNotationFile);
|
|
|
|
//
|
|
// The handler is NetworkManager's, and it ends in CreateMission, which
|
|
// is what calls StartConnecting below to read the host table back out
|
|
// of the spool.
|
|
//
|
|
ReceiveEggFileMessage egg_message(-1, 10, "local egg", 10);
|
|
application->Post(DefaultEventPriority, this, &egg_message);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
L4PlaybackNetworkManager::StartConnecting(Mission *mission)
|
|
{
|
|
//
|
|
// Create the host iterator for the mission egg
|
|
//
|
|
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" << std::flush;
|
|
PostQuitMessage(AbortExitCodeID);
|
|
}
|
|
|
|
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" << std::flush;
|
|
PostQuitMessage(AbortExitCodeID);
|
|
}
|
|
|
|
HostManager *host_mgr = application->GetHostManager();
|
|
Check(host_mgr);
|
|
|
|
//
|
|
// Iterate through all the host addresses in the egg and create all the host
|
|
// structures, note that there MUST be an entry in the egg for us.
|
|
//
|
|
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(),
|
|
NULL,
|
|
INVALID_SOCKET,
|
|
host_name
|
|
);
|
|
Register_Object(my_host);
|
|
if (remote)
|
|
{
|
|
host_mgr->AdoptRemoteHost(my_host);
|
|
}
|
|
else
|
|
{
|
|
host_mgr->AdoptLocalHost(my_host);
|
|
|
|
//
|
|
// Lay the cockpit out as whatever this station WAS.
|
|
//
|
|
// Application::SetCameraStation is normally the front end's
|
|
// answer to a question asked on the setup screen, and playback
|
|
// never sees the setup screen - so a recording made from a Live
|
|
// Cam replayed with five instrument panes hung over the view
|
|
// and the map back in the middle, which is a pod's cockpit, not
|
|
// a camera's. The egg knows: it is the same egg the race ran
|
|
// on, and it says what this host was.
|
|
//
|
|
Application::SetCameraStation(
|
|
mission_host_data->GetHostType() == CameraShipHostType
|
|
);
|
|
if (mission_host_data->GetHostType() == CameraShipHostType)
|
|
{
|
|
DEBUG_STREAM << "Playback: this station recorded as a Live Cam"
|
|
<< " - no instrument panes, map landscape\n" << std::flush;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now, just send the load message
|
|
//
|
|
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;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Logical
|
|
L4PlaybackNetworkManager::CheckBuffers(NetworkPacket*)
|
|
{
|
|
//
|
|
// The buffers are always empty
|
|
//
|
|
return False;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
L4PlaybackNetworkManager::~L4PlaybackNetworkManager()
|
|
{
|
|
}
|
|
|
|
//#############################################################################
|
|
//###################### 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)
|
|
};
|
|
|
|
Receiver::MessageHandlerSet& L4SpoolingApplication::GetMessageHandlers()
|
|
{
|
|
static Receiver::MessageHandlerSet messageHandlers(ELEMENTS(L4SpoolingApplication::MessageHandlerEntries), L4SpoolingApplication::MessageHandlerEntries, L4Application::GetMessageHandlers());
|
|
return messageHandlers;
|
|
}
|
|
|
|
//#############################################################################
|
|
// Virtual Data support
|
|
//
|
|
Derivation* L4SpoolingApplication::GetClassDerivations()
|
|
{
|
|
static Derivation classDerivations(L4Application::GetClassDerivations(), "L4SpoolingApplication");
|
|
return &classDerivations;
|
|
}
|
|
|
|
L4SpoolingApplication::SharedData
|
|
L4SpoolingApplication::DefaultData(
|
|
L4SpoolingApplication::GetClassDerivations(),
|
|
L4SpoolingApplication::GetMessageHandlers()
|
|
);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
L4SpoolingApplication::LoadMissionMessageHandler(Message *)
|
|
{
|
|
applicationState.SetState(WaitingForLaunch);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
L4SpoolingApplication::RunMissionMessageHandler(RunMissionMessage *)
|
|
{
|
|
Check(this);
|
|
|
|
applicationState.SetState(RunningMission);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void L4SpoolingApplication::StopMissionMessageHandler(StopMissionMessage *message)
|
|
{
|
|
if (!missionSpooled)
|
|
{
|
|
missionSpooled = True;
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// Post this message again until the application is running
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
Time post_time = Now();
|
|
post_time += 3.0f;
|
|
|
|
Post(DefaultEventPriority, this, 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);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
L4SpoolingApplication::ReceiveNetworkPacket(
|
|
NetworkPacket *packet,
|
|
Receiver::Message *message
|
|
)
|
|
{
|
|
Check(this);
|
|
|
|
//
|
|
//------------------------------------------------------
|
|
// Any egg messages will be spooled before being sent on
|
|
//------------------------------------------------------
|
|
//
|
|
switch (message->messageID)
|
|
{
|
|
case StopMissionMessageID:
|
|
if (missionSpooled)
|
|
{
|
|
packet->timeStamp = Now(); // HACK - spoof the clock stuff
|
|
SpoolFile *spool = GetSpoolFile();
|
|
Check(spool);
|
|
spool->SpoolPacket(packet);
|
|
break;
|
|
}
|
|
|
|
case RunMissionMessageID:
|
|
packet->timeStamp = Now(); // HACK - spoof the clock stuff
|
|
SpoolFile *spool = GetSpoolFile();
|
|
Check(spool);
|
|
spool->SpoolPacket(packet);
|
|
break;
|
|
}
|
|
L4Application::ReceiveNetworkPacket(packet, message);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
L4SpoolingApplication::L4SpoolingApplication(
|
|
HINSTANCE hInstance,
|
|
HWND hWnd,
|
|
ResourceFile *resource_file,
|
|
ApplicationID application_ID
|
|
):
|
|
L4Application(
|
|
hInstance,
|
|
hWnd,
|
|
resource_file,
|
|
application_ID,
|
|
L4ApplicationClassID,
|
|
DefaultData
|
|
)
|
|
{
|
|
missionSpooled = False;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Registry*
|
|
L4SpoolingApplication::MakeRegistry()
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
InterestManager*
|
|
L4SpoolingApplication::MakeInterestManager()
|
|
{
|
|
return new SpoolingInterestManager;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
NetworkManager*
|
|
L4SpoolingApplication::MakeNetworkManager()
|
|
{
|
|
return new L4SpoolingNetworkManager;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
L4SpoolingApplication::Initialize()
|
|
{
|
|
Check(this);
|
|
Application::Initialize();
|
|
|
|
//
|
|
// Create the console host and socket
|
|
//
|
|
L4NetworkManager *net_mgr = GetNetworkManager();
|
|
Check(net_mgr);
|
|
net_mgr->CreateConsoleHost();
|
|
|
|
//
|
|
// Allocate the spool file
|
|
//
|
|
MissionReviewApplicationManager *app_mgr = GetApplicationManager();
|
|
Check(app_mgr);
|
|
spoolFile = app_mgr->GetEmptySpoolFile();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
L4SpoolingApplication::LoadBackgroundTasks()
|
|
{
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
VideoRenderer*
|
|
L4SpoolingApplication::MakeVideoRenderer()
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
AudioRenderer*
|
|
L4SpoolingApplication::MakeAudioRenderer()
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
GaugeRenderer*
|
|
L4SpoolingApplication::MakeGaugeRenderer(int *secondaryIndex, int *aux1Index, int *aux2Index)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Mission*
|
|
L4SpoolingApplication::MakeMission(
|
|
NotationFile *notation_file,
|
|
ResourceFile *resources
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(notation_file);
|
|
Check(resources);
|
|
|
|
//////////// return new L4Mission(notation_file, resources);
|
|
return new Mission(notation_file, resources);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Entity*
|
|
L4SpoolingApplication::MakeViewpointEntity(Entity__MakeMessage *)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Logical L4SpoolingApplication::ExecuteForeground(Time, Scalar)
|
|
{
|
|
SET_FOREGROUND_PROCESSING();
|
|
Check(this);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Controls Manager
|
|
//
|
|
// Poll all devices, update all control variables.
|
|
//
|
|
// This is executed before the update manager so that the
|
|
// models have valid control values. It is not necessary for
|
|
// the controls to operate at the frame rate of this loop. If
|
|
// the controls manager can run run at a lower rate it can
|
|
// throttle itself internally.
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
Check(controlsManager);
|
|
controlsManager->Execute();
|
|
|
|
CLEAR_FOREGROUND_PROCESSING();
|
|
return executeFrames && !Exit_Code;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void L4SpoolingApplication::ExecuteBackgroundTask()
|
|
{
|
|
Check(this);
|
|
|
|
Check(networkManager);
|
|
if (!networkManager->RoutePacket())
|
|
{
|
|
ProcessOneEvent(DefaultEventPriority);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Logical
|
|
L4SpoolingApplication::Shutdown(int remainingApps)
|
|
{
|
|
Check(this);
|
|
|
|
L4Application::Shutdown(remainingApps);
|
|
return !Exit_Code && !missionSpooled;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
L4SpoolingApplication::~L4SpoolingApplication()
|
|
{
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Logical
|
|
L4SpoolingApplication::TestInstance() const
|
|
{
|
|
return IsDerivedFrom(*GetClassDerivations());
|
|
}
|
|
|
|
//#############################################################################
|
|
//########################### 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;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
SpoolerTask::Execute()
|
|
{
|
|
Check(this);
|
|
Check(application);
|
|
|
|
SpoolFile* spool = application->GetSpoolFile();
|
|
if (!spool)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// We have a spool file, so interpret it based upon the application state
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
Check(spool);
|
|
NetworkPacket *packet;
|
|
switch (application->GetApplicationState())
|
|
{
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// If we are waiting for an egg, post the egg messages to the application
|
|
// from the spool
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
case Application::WaitingForEgg:
|
|
packet = (NetworkPacket*)spool->GetPointer();
|
|
while (packet->clientID == NetworkClient::NetworkManagerClientID)
|
|
{
|
|
spool->NextPacket();
|
|
DispatchPacket(packet);
|
|
packet = (NetworkPacket*)spool->GetPointer();
|
|
}
|
|
break;
|
|
|
|
//
|
|
//-------------------------------------------------------------------
|
|
// If the application is loading, then move off the block of interest
|
|
// messages into the interest manager
|
|
//-------------------------------------------------------------------
|
|
//
|
|
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;
|
|
|
|
//
|
|
//-------------------------------------------------------------------
|
|
// These messages need to be doled out based upon the system time, as
|
|
// modified by when the run message was received
|
|
//-------------------------------------------------------------------
|
|
//
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
SpoolerTask::~SpoolerTask()
|
|
{
|
|
}
|