#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); *(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() { }