Starting the MR port, since the pods want it too. Four changes, and one correction of my own making. A release Fail now says what failed. It expanded to a bare abort() that threw the message away, and because the compiler merges identical cold paths, every Fail in a function became one anonymous stub - a crash named the function and nothing else. It now prints message, file and line. It also writes that line to rpl4-fail.log and closes the file. rpl4.log is std::cout with an ofstream's streambuf swapped in, and the text written there did NOT survive the exit however it was flushed; rather than guess where it stopped, the one line that matters goes to its own file, and fclose is a promise it reached the disk. Its own file because rpl4.log is already open for writing and Windows will not share it. -pb plays a spool back without recording a new one. Mode 2 has been in RPL4.CPP all along - one spool file instead of two, no spooling application - with no way to ask for it. -mr starts a recorder alongside the playback and that recorder is the half that cannot cope away from a pod bay. Which is the third fix: L4SpoolingNetworkManager::StartConnecting walks the hosts named in the egg, and called host->GetHostID() on whatever FindHost returned. FindHost answers NULL for a host that is in the egg but not connected - impossible in an arcade, ordinary everywhere else - and it crashed before the mission could start. The table is read back one pair per egg host in egg order, so a missing host cannot be skipped without shifting every entry after it; it writes the pair, says so, and carries on. And RPL4.CPP chose between the playback application and an idle one in silence. For the first few seconds those look identical from outside, so a spool that failed to load was indistinguishable from one that had not started yet. It now says which, and why not. The correction: I reported a failure in L4AudioRenderer::Initialize on audiomr.ini's clipping_radius. That was mine. I was running cdb from the source tree, so the game looked for audio\audiomr.ini beside the debugger rather than beside itself and found nothing. With the working directory right, audio initialises fine and always did. Where it stands: -pb loads last.spl - "2973012 bytes to play" - creates RPL4PlaybackApplication and runs without crashing. Whether it puts the race on the screen is the next thing to look at, and that wants eyes rather than a log. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
770 lines
20 KiB
C++
770 lines
20 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)
|
|
{
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
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);
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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()
|
|
{
|
|
}
|