Clean, self-contained extraction of the BattleTech-specific work from the
reverse-engineering workspace -- engine + game + content + build, with nothing
from Red Planet or the raw archive dumps. Builds green (Win32) and runs the
single-player drive->animate->target->fire->damage->destroy loop out of the box.
Layout:
engine/ MUNGA + MUNGA_L4 shared 2007 engine, carrying our BT render/loader
work (bgfload/L4D3D/L4VIDEO: BSL bit-slice decode, LOD/ground/shadow
models) + image codec; the minimal rp/ headers the audio HAL needs
game/ reconstructed BT logic + surviving-original BT source + fwd shims
+ WinMain launcher
content/ full runtime tree (BTL4.RES, VIDEO/, GAUGE/, AUDIO/, eggs, BTDPL.INI)
docs/ format specs + reconstruction ledgers
reference/ raw Ghidra pseudocode (recon source-of-truth) + decomp exporter
tools/ MP console emulator + map/resource scanners
One top-level CMake builds munga_engine lib + bt410_l4 game lib + btl4.exe.
All paths relativized (186 fwd shims + ~437 CMake abs paths -> repo-relative);
DXSDK is the one external, overridable via -DDXSDK. Verified: builds to a
byte-identical 2.27MB exe and runs combat (TARGET DESTROYED, 0 crashes) against
the bundled content.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1778 lines
44 KiB
C++
1778 lines
44 KiB
C++
#include "registry.h"
|
|
#include "renderer.h"
|
|
#include "controls.h"
|
|
#include "update.h"
|
|
#include "mission.h"
|
|
#include "player.h"
|
|
#include "director.h"
|
|
#include "appmgr.h"
|
|
#include "audrend.h"
|
|
#include "vidrend.h"
|
|
#include "gaugrend.h"
|
|
#include "hostmgr.h"
|
|
#include "interest.h"
|
|
#include "nttmgr.h"
|
|
#include "apptask.h"
|
|
#include "console.h"
|
|
#include "appmsg.h"
|
|
#include "evtstat.h"
|
|
|
|
#if defined(TRACE_FOREGROUND_PROCESSING)
|
|
BitTrace Foreground_Processing("Foreground Processing");
|
|
#endif
|
|
|
|
#if defined(TRACE_UPDATE_MANAGER)
|
|
BitTrace Update_Manager("Update Manager");
|
|
#endif
|
|
|
|
#if defined(TRACE_RENDERER_MANAGER)
|
|
BitTrace Renderer_Manager("Renderer Manager");
|
|
#endif
|
|
|
|
Application *application = NULL;
|
|
int Exit_Code = 0;
|
|
Logical Application::suppressGauges = False;
|
|
|
|
//#############################################################################
|
|
//########################### Application ###############################
|
|
//#############################################################################
|
|
|
|
//#############################################################################
|
|
// Message Support
|
|
//
|
|
const Receiver::HandlerEntry
|
|
Application::MessageHandlerEntries[]=
|
|
{
|
|
MESSAGE_ENTRY(Application, StateQuery),
|
|
MESSAGE_ENTRY(Application, CheckLoad),
|
|
MESSAGE_ENTRY(Application, RunMission),
|
|
MESSAGE_ENTRY(Application, StopMission),
|
|
MESSAGE_ENTRY(Application, ResumeMission),
|
|
MESSAGE_ENTRY(Application, SuspendMission),
|
|
MESSAGE_ENTRY(Application, KeyCommand),
|
|
MESSAGE_ENTRY(Application, LoadMission),
|
|
MESSAGE_ENTRY(Application, AbortMission)
|
|
};
|
|
|
|
Application::MessageHandlerSet& Application::GetMessageHandlers()
|
|
{
|
|
static Application::MessageHandlerSet messageHandlers(ELEMENTS(Application::MessageHandlerEntries), Application::MessageHandlerEntries, NetworkClient::GetMessageHandlers());
|
|
return messageHandlers;
|
|
}
|
|
|
|
//#############################################################################
|
|
// Virtual Data support
|
|
//
|
|
Derivation* Application::GetClassDerivations()
|
|
{
|
|
static Derivation classDerivations(NetworkClient::GetClassDerivations(), "Application");
|
|
return &classDerivations;
|
|
}
|
|
|
|
Application::SharedData
|
|
Application::DefaultData(
|
|
Application::GetClassDerivations(),
|
|
Application::GetMessageHandlers()
|
|
);
|
|
|
|
//
|
|
//#############################################################################
|
|
// TestInstance
|
|
//#############################################################################
|
|
//
|
|
Logical
|
|
Application::TestInstance() const
|
|
{
|
|
if (!IsDerivedFrom(*GetClassDerivations()))
|
|
{
|
|
return False;
|
|
}
|
|
Check(&applicationState);
|
|
if (eventQueue)
|
|
{
|
|
Check(eventQueue);
|
|
}
|
|
if (networkManager)
|
|
{
|
|
Check(networkManager);
|
|
}
|
|
if (entityManager)
|
|
{
|
|
Check(entityManager);
|
|
}
|
|
if (registry)
|
|
{
|
|
Check(registry);
|
|
}
|
|
if (hostManager)
|
|
{
|
|
Check(hostManager);
|
|
}
|
|
if (interestManager)
|
|
{
|
|
Check(interestManager);
|
|
}
|
|
if (updateManager)
|
|
{
|
|
Check(updateManager);
|
|
}
|
|
if (rendererManager)
|
|
{
|
|
Check(rendererManager);
|
|
}
|
|
if (controlsManager)
|
|
{
|
|
Check(controlsManager);
|
|
}
|
|
if (intercomManager)
|
|
{
|
|
Check(intercomManager);
|
|
}
|
|
if (resourceFile)
|
|
{
|
|
Check(resourceFile);
|
|
}
|
|
if (viewpointEntity)
|
|
{
|
|
Check(viewpointEntity);
|
|
}
|
|
if (currentMission)
|
|
{
|
|
Check(currentMission);
|
|
}
|
|
if (backgroundTasks)
|
|
{
|
|
Check(backgroundTasks);
|
|
}
|
|
if (audioRenderer)
|
|
{
|
|
Check(audioRenderer);
|
|
}
|
|
if (videoRenderer)
|
|
{
|
|
Check(videoRenderer);
|
|
}
|
|
if (gaugeRenderer)
|
|
{
|
|
Check(gaugeRenderer);
|
|
}
|
|
return True;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// Application
|
|
//#############################################################################
|
|
//
|
|
Application::Application(
|
|
ResourceFile *resource_file,
|
|
ApplicationID application_ID,
|
|
ClassID class_ID,
|
|
SharedData &shared_data
|
|
):
|
|
NetworkClient(class_ID, shared_data, ApplicationClientID),
|
|
applicationState(ApplicationStateCount)
|
|
{
|
|
Check(&shared_data);
|
|
Check(resource_file);
|
|
|
|
applicationID = application_ID;
|
|
|
|
//
|
|
// Create the event queue
|
|
//
|
|
eventQueue = GeneralEventQueue::Make(
|
|
EVENT_PRIORITIES_COUNT,
|
|
"MUNGA Event Count"
|
|
);
|
|
Check(eventQueue);
|
|
|
|
//
|
|
// Remember the resource file
|
|
//
|
|
resourceFile = resource_file;
|
|
missionPlayer = NULL;
|
|
|
|
//
|
|
// NULL managers not yet created
|
|
//
|
|
networkManager = NULL;
|
|
registry = NULL;
|
|
controlsManager = NULL;
|
|
intercomManager = NULL;
|
|
backgroundTasks = NULL;
|
|
interestManager = NULL;
|
|
audioRenderer = NULL;
|
|
videoRenderer = NULL;
|
|
gaugeRenderer = NULL;
|
|
|
|
//
|
|
// NULL pointers to other objects not yet created
|
|
//
|
|
viewpointEntity = NULL;
|
|
currentMission = NULL;
|
|
|
|
//
|
|
// Create base level managers
|
|
//
|
|
entityManager = new EntityManager;
|
|
Register_Object(entityManager);
|
|
hostManager = new HostManager;
|
|
Register_Object(hostManager);
|
|
updateManager = new UpdateManager;
|
|
Register_Object(updateManager);
|
|
rendererManager = new RendererManager;
|
|
Register_Object(rendererManager);
|
|
backgroundTasks = new BackgroundTasks;
|
|
Register_Object(backgroundTasks);
|
|
|
|
//
|
|
// Set up game state
|
|
//
|
|
executeFrames = False;
|
|
applicationState.SetState(InitializingState);
|
|
currentMission = NULL;
|
|
secondsRemainingInGame = 0.0f;
|
|
spoolFile = NULL;
|
|
routePacketFinished = False;
|
|
lastCreationMessage = Now();
|
|
|
|
//
|
|
// HACK - Init analysis bits
|
|
//
|
|
#if defined(TRACE_ON)
|
|
trace_manager.ResetTraces();
|
|
#endif
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// GetApplicationManager
|
|
//#############################################################################
|
|
//
|
|
ApplicationManager*
|
|
Application::GetApplicationManager()
|
|
{
|
|
PlugIteratorOf<ApplicationManager*> manager_link(this);
|
|
ApplicationManager *mgr;
|
|
while ((mgr = manager_link.ReadAndNext()) != NULL)
|
|
{
|
|
if (mgr->GetClassID() == ApplicationManagerClassID)
|
|
{
|
|
return mgr;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
Scalar
|
|
Application::GetApplicationLoopFrameRate()
|
|
{
|
|
ApplicationManager *mgr = GetApplicationManager();
|
|
Check(mgr);
|
|
return mgr->GetFrameRate();
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// Initialize
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Application::Initialize()
|
|
{
|
|
Check(this);
|
|
|
|
//
|
|
//----------------------------
|
|
// Create the interest Manager
|
|
//----------------------------
|
|
//
|
|
interestManager = MakeInterestManager();
|
|
Register_Object(interestManager);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Create the network manager
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
networkManager = MakeNetworkManager();
|
|
Register_Object(networkManager);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Create the registry, load static object streams
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
registry = MakeRegistry();
|
|
if (registry)
|
|
{
|
|
Register_Object(registry);
|
|
registry->LoadStaticObjectStreamResource();
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Create the mode manager
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
modeManager = MakeModeManager();
|
|
Register_Object(modeManager);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Create the controls manager
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
controlsManager = MakeControlsManager();
|
|
Register_Object(controlsManager);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Create the intercom manager
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
intercomManager = MakeIntercomManager();
|
|
Register_Object(intercomManager);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Add background tasks
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
LoadBackgroundTasks();
|
|
executeFrames = True;
|
|
applicationState.SetState(WaitingForEgg);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Create the audio renderer
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
Verify(audioRenderer == NULL);
|
|
if ((audioRenderer = MakeAudioRenderer()) != NULL)
|
|
{
|
|
Register_Object(audioRenderer);
|
|
audioRenderer->Initialize();
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Create the video renderer
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
Verify(videoRenderer == NULL);
|
|
if ((videoRenderer = MakeVideoRenderer()) != NULL)
|
|
{
|
|
Register_Object(videoRenderer);
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Create the gauge renderer
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
Verify(gaugeRenderer == NULL);
|
|
|
|
if (Application::GetVideoRenderer() != NULL)
|
|
{
|
|
int *secondaryIndex = Application::GetVideoRenderer()->GetSecondaryIndex();
|
|
int *aux1Index = Application::GetVideoRenderer()->GetAux1Index();
|
|
int *aux2Index = Application::GetVideoRenderer()->GetAux2Index();
|
|
if ((gaugeRenderer = MakeGaugeRenderer(secondaryIndex, aux1Index, aux2Index)) != NULL)
|
|
{
|
|
Register_Object(gaugeRenderer);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// LoadBackgroundTasks
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Application::LoadBackgroundTasks()
|
|
{
|
|
Check(this);
|
|
|
|
ApplicationTask *application_task;
|
|
|
|
application_task = new RoutePacketTask;
|
|
Register_Object(application_task);
|
|
backgroundTasks->AddTask(application_task);
|
|
|
|
application_task = new ProcessEventTask;
|
|
Register_Object(application_task);
|
|
backgroundTasks->AddTask(application_task);
|
|
|
|
application_task = new AudioRendererTask;
|
|
Register_Object(application_task);
|
|
backgroundTasks->AddTask(application_task);
|
|
|
|
application_task = new GaugeRendererTask;
|
|
Register_Object(application_task);
|
|
backgroundTasks->AddTask(application_task);
|
|
|
|
application_task = new NetworkManagerTask;
|
|
Register_Object(application_task);
|
|
backgroundTasks->AddTask(application_task);
|
|
|
|
application_task = new CompleteCyclesTask;
|
|
Register_Object(application_task);
|
|
backgroundTasks->AddTask(application_task);
|
|
|
|
application_task = new FryDeathRowTask;
|
|
Register_Object(application_task);
|
|
backgroundTasks->AddTask(application_task);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// MakeInterestManager
|
|
//#############################################################################
|
|
//
|
|
InterestManager*
|
|
Application::MakeInterestManager()
|
|
{
|
|
return new InterestManager;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// MakeNetworkManager
|
|
//#############################################################################
|
|
//
|
|
NetworkManager*
|
|
Application::MakeNetworkManager()
|
|
{
|
|
return new NetworkManager(NetworkManager::DefaultData);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// MakeRegistry
|
|
//#############################################################################
|
|
//
|
|
Registry*
|
|
Application::MakeRegistry()
|
|
{
|
|
Fail("Application::MakeRegistry - Should never reach here");
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// MakeModeManager
|
|
//#############################################################################
|
|
//
|
|
ModeManager*
|
|
Application::MakeModeManager()
|
|
{
|
|
Fail("Application::MakeModeManager - Should never reach here");
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// MakeControlsManager
|
|
//#############################################################################
|
|
//
|
|
ControlsManager*
|
|
Application::MakeControlsManager()
|
|
{
|
|
Fail("Application::MakeControlsManager - Should never reach here");
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// MakeIntercomManager
|
|
//#############################################################################
|
|
//
|
|
IcomManager*
|
|
Application::MakeIntercomManager()
|
|
{
|
|
Fail("Application::MakeIntercomManager - Should never reach here");
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// ExecuteForeground
|
|
//#############################################################################
|
|
//
|
|
Logical
|
|
Application::ExecuteForeground(
|
|
Time start_of_frame,
|
|
Scalar frame_duration
|
|
)
|
|
{
|
|
SET_FOREGROUND_PROCESSING();
|
|
|
|
Check(this);
|
|
Verify(application == this);
|
|
|
|
if (!executeFrames)
|
|
{
|
|
CLEAR_FOREGROUND_PROCESSING();
|
|
return executeFrames;
|
|
}
|
|
|
|
Time
|
|
frame_ticks;
|
|
frame_ticks = frame_duration;
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// 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);
|
|
Time startControls = Now();
|
|
controlsManager->Execute();
|
|
Time endControls = Now();
|
|
|
|
if (GetApplicationState() == WaitingForEgg)
|
|
{
|
|
// since we're idling, let the renderers clear the screens
|
|
videoRenderer->ExecuteIdle();
|
|
CLEAR_FOREGROUND_PROCESSING();
|
|
return executeFrames;
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Update Manager
|
|
//
|
|
// Execute replicants.
|
|
// Execute master entities if they are interesting here or
|
|
// elsewhere.
|
|
// Inform interest manager of possible interest zone change.
|
|
// If the master entity has provided and update message then
|
|
// send it to replicants.
|
|
//
|
|
// This is executed before the interest manager so that the
|
|
// interest manager can merge all interest zone changes before
|
|
// broadcasting interest arena deltas and building interesting
|
|
// entity lists.
|
|
//
|
|
// This is executed before the renderers so that the watchers
|
|
// have executed on the model and are ready for use by the
|
|
// renderers.
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
SET_UPDATE_MANAGER();
|
|
|
|
Time startUpdate = Now();
|
|
Check(updateManager);
|
|
updateManager->Execute(start_of_frame);
|
|
Time endUpdate = Now();
|
|
|
|
CLEAR_UPDATE_MANAGER();
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Interest Manager
|
|
//
|
|
// Update the net interest arena.
|
|
// Calculate which interest zones should be released and which
|
|
// interest zones should be loaded
|
|
// Send a becoming uninteresting and becoming interesting
|
|
// message to the entity.
|
|
// Broadcast the interest arena change
|
|
//
|
|
// The renderer manager call, update interest origins will
|
|
// update only those interest origins required by the renderers
|
|
// executing this frame.
|
|
//
|
|
// This is executed before the renderer manager so that when
|
|
// the renderers execute they execute upon interest lists that
|
|
// are valid as of the end of a model/update frame.
|
|
//
|
|
// In theory the interest manager does not have to run every
|
|
// frame. If throttled less, this would cause fuzz at interest
|
|
// zone borders, which may or may not be acceptable depending
|
|
// on the size of the interest arena.
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
Time startInterest = Now();
|
|
Check(rendererManager);
|
|
rendererManager->UpdateInterestOrigins(start_of_frame);
|
|
Check(interestManager);
|
|
interestManager->Execute();
|
|
Time endInterest = Now();
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Renderer Manager
|
|
//
|
|
// Execute renderers.
|
|
// Get interest list from interest manager.
|
|
// Poll watchers.
|
|
//
|
|
// It is not necessary for all renderers to operate at the frame
|
|
// rate of this loop. If a renderer can run at a lower rate it
|
|
// does so via the renderer manager which will govern if a
|
|
// renderer executes this frame.
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
SET_RENDERER_MANAGER();
|
|
Time startRender = Now();
|
|
Check(rendererManager);
|
|
rendererManager->Execute(start_of_frame, frame_ticks, frame_ticks);
|
|
Time endRender = Now();
|
|
CLEAR_RENDERER_MANAGER();
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Intercom Manager
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
Time startIntercom = Now();
|
|
Check(intercomManager);
|
|
intercomManager->Execute();
|
|
Time endIntercom = Now();
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Execution statistics
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
if (GetApplicationState() == RunningMission)
|
|
{
|
|
secondsRemainingInGame =
|
|
currentMission->GetGameLength() - (Now() - gameStarted);
|
|
}
|
|
routePacketFinished = False;
|
|
|
|
CLEAR_FOREGROUND_PROCESSING();
|
|
|
|
return executeFrames && !Exit_Code;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// ExecuteBackgroundTask
|
|
//#############################################################################
|
|
//
|
|
#define QUIET_TIME_OUT 3.0f
|
|
void
|
|
Application::ExecuteBackgroundTask()
|
|
{
|
|
Check(this);
|
|
|
|
//
|
|
//------------------------------------------------------------------------
|
|
// If we are processing the map's creation messages, don't allow any other
|
|
// processing to happen until nothing appears for the timeout period
|
|
//------------------------------------------------------------------------
|
|
//
|
|
if (GetApplicationState() == CreatingMission)
|
|
{
|
|
Check(networkManager);
|
|
|
|
if (networkManager->RoutePacket())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (ProcessOneEvent(DefaultEventPriority))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (ProcessOneEvent(LowEventPriority))
|
|
{
|
|
lastCreationMessage = Now();
|
|
}
|
|
else
|
|
{
|
|
Scalar wait = Now() - lastCreationMessage;
|
|
if (wait > QUIET_TIME_OUT)
|
|
{
|
|
applicationState.SetState(LoadingMission);
|
|
networkManager->Marker("MUNGA MARKER - Starting renderer load...\n");
|
|
networkManager->Mode(NetworkManager::UnreliableMode);
|
|
#if defined(LAB_ONLY)
|
|
DEBUG_STREAM << "Starting renderer load...\n" << std::flush;
|
|
#endif
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
// If there exists a high priority event, execute it
|
|
//
|
|
if (ProcessOneEvent(HighEventPriority))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// if
|
|
// we are not finished routing packets this frames or
|
|
// we are not running the game
|
|
// then
|
|
// attempt to route a network packet
|
|
// we are finished routing packets for this frame
|
|
//
|
|
if (
|
|
!routePacketFinished ||
|
|
applicationState.GetState() != RunningMission
|
|
)
|
|
{
|
|
Check(networkManager);
|
|
if (networkManager->RoutePacket())
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
routePacketFinished = True;
|
|
|
|
//
|
|
// Execute lower priority tasks
|
|
//
|
|
Check(backgroundTasks);
|
|
backgroundTasks->Execute();
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// Stop
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Application::Stop()
|
|
{
|
|
Check(this);
|
|
|
|
//
|
|
// Dump analysis sample
|
|
//
|
|
#if defined(USE_TIME_ANALYSIS)
|
|
DEBUG_STREAM << "\nGame timing statistics:\n" << std::flush;
|
|
trace_manager.SnapshotTimingAnalysis(True);
|
|
#endif
|
|
#if defined(USE_TRACE_LOG)
|
|
trace_manager.SaveTraceLog("trace.log");
|
|
#endif
|
|
#if defined(USE_EVENT_STATISTICS)
|
|
event_statistics_manager.Report();
|
|
#endif
|
|
|
|
//
|
|
// Set state variables to end game status
|
|
//
|
|
executeFrames = False;
|
|
DEBUG_STREAM << std::flush << std::flush;
|
|
applicationState.SetState(StoppingMission);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// Shutdown
|
|
//#############################################################################
|
|
//
|
|
Logical
|
|
Application::Shutdown(int remainingApps)
|
|
{
|
|
Check(this);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Shutdown gauge renderer
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
if (gaugeRenderer != NULL)
|
|
{
|
|
Check(gaugeRenderer);
|
|
gaugeRenderer->Shutdown();
|
|
gaugeRenderer->UnlinkFromEntity();
|
|
}
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Shutdown video renderer
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
if (videoRenderer != NULL)
|
|
{
|
|
Check(videoRenderer);
|
|
videoRenderer->Shutdown();
|
|
videoRenderer->UnlinkFromEntity();
|
|
}
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Shutdown audio renderer
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
if (audioRenderer != NULL)
|
|
{
|
|
Check(audioRenderer);
|
|
audioRenderer->Shutdown();
|
|
audioRenderer->UnlinkFromEntity();
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Delete the viewpoint entity
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
if (viewpointEntity != NULL)
|
|
{
|
|
Unregister_Object(viewpointEntity);
|
|
delete viewpointEntity;
|
|
viewpointEntity = NULL;
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Shutdown the interest manager
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
Check(interestManager);
|
|
interestManager->Shutdown();
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Shutdown the host manager
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
Check(hostManager);
|
|
hostManager->Shutdown();
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Shutdown the network manager
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
Check(networkManager);
|
|
networkManager->Shutdown();
|
|
|
|
//
|
|
//--------------------------------------------------
|
|
// Delete the current mission if it has been created
|
|
//--------------------------------------------------
|
|
//
|
|
if (currentMission)
|
|
{
|
|
Unregister_Object(currentMission);
|
|
delete currentMission;
|
|
currentMission = NULL;
|
|
}
|
|
|
|
//
|
|
//---------------------------------
|
|
// Allow the process to start again
|
|
//---------------------------------
|
|
//
|
|
executeFrames = True;
|
|
applicationState.SetState(WaitingForEgg);
|
|
#if 0
|
|
return !Exit_Code;
|
|
#else
|
|
return False;
|
|
#endif
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// Terminate
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Application::Terminate()
|
|
{
|
|
Check(this);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Delete the gauge renderer
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
if (gaugeRenderer != NULL)
|
|
{
|
|
Unregister_Object(gaugeRenderer);
|
|
delete gaugeRenderer;
|
|
gaugeRenderer = NULL;
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Delete the video renderer
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
if (videoRenderer != NULL)
|
|
{
|
|
Unregister_Object(videoRenderer);
|
|
delete videoRenderer;
|
|
videoRenderer = NULL;
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Delete the audio renderer
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
if (audioRenderer != NULL)
|
|
{
|
|
Unregister_Object(audioRenderer);
|
|
delete audioRenderer;
|
|
audioRenderer = NULL;
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// Delete the intercom manager
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
if (intercomManager != NULL)
|
|
{
|
|
Unregister_Object(intercomManager);
|
|
delete intercomManager;
|
|
intercomManager = NULL;
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// Delete the controls manager
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
if (controlsManager != NULL)
|
|
{
|
|
Unregister_Object(controlsManager);
|
|
delete controlsManager;
|
|
controlsManager = NULL;
|
|
}
|
|
|
|
//
|
|
//------------------------
|
|
// Delete the mode manager
|
|
//------------------------
|
|
//
|
|
if (modeManager)
|
|
{
|
|
Unregister_Object(modeManager);
|
|
delete modeManager;
|
|
modeManager = NULL;
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// Delete the registry
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
if (registry != NULL)
|
|
{
|
|
Unregister_Object(registry);
|
|
delete registry;
|
|
registry = NULL;
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// Delete the network manager
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
if (networkManager != NULL)
|
|
{
|
|
Unregister_Object(networkManager);
|
|
delete networkManager;
|
|
networkManager = NULL;
|
|
}
|
|
|
|
//
|
|
//----------------------------
|
|
// Delete the interest manager
|
|
//----------------------------
|
|
//
|
|
if (interestManager != NULL)
|
|
{
|
|
Unregister_Object(interestManager);
|
|
delete interestManager;
|
|
interestManager = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// ~Application
|
|
//#############################################################################
|
|
//
|
|
Application::~Application()
|
|
{
|
|
//
|
|
// Verify that these managers have been deleted
|
|
//
|
|
Verify(interestManager == NULL);
|
|
Verify(networkManager == NULL);
|
|
Verify(registry == NULL);
|
|
Verify(controlsManager == NULL);
|
|
Verify(intercomManager == NULL);
|
|
Verify(audioRenderer == NULL);
|
|
Verify(videoRenderer == NULL);
|
|
Verify(gaugeRenderer == NULL);
|
|
|
|
//
|
|
// Verify that the mission has been deleted
|
|
//
|
|
Verify(currentMission == NULL);
|
|
|
|
//
|
|
// Verify that the viewpoint entity has been deleted
|
|
//
|
|
Verify(viewpointEntity == NULL);
|
|
|
|
//
|
|
// Destroy these managers
|
|
//
|
|
Unregister_Object(backgroundTasks);
|
|
delete backgroundTasks;
|
|
backgroundTasks = NULL;
|
|
|
|
Unregister_Object(rendererManager);
|
|
delete rendererManager;
|
|
rendererManager = NULL;
|
|
|
|
Unregister_Object(updateManager);
|
|
delete updateManager;
|
|
updateManager = NULL;
|
|
|
|
Unregister_Object(hostManager);
|
|
delete hostManager;
|
|
hostManager = NULL;
|
|
|
|
Unregister_Object(entityManager);
|
|
delete entityManager;
|
|
entityManager = NULL;
|
|
|
|
resourceFile = NULL;
|
|
|
|
//
|
|
// Destroy the event queue
|
|
// HACK - the event queue is transparently created as an array,
|
|
// therefore must be deleted as one
|
|
//
|
|
Unregister_Object(eventQueue);
|
|
delete[] eventQueue;
|
|
eventQueue = NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// StateQueryMessageHandler
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Application::StateQueryMessageHandler(
|
|
#if DEBUG_LEVEL>0
|
|
StateQueryMessage *message
|
|
#else
|
|
StateQueryMessage *
|
|
#endif
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(message);
|
|
Verify(message->messageID == StateQueryMessageID);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Send the console our application state
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
Host *console_host;
|
|
|
|
Check(GetHostManager());
|
|
if ((console_host = GetHostManager()->GetConsoleHost()) != NULL)
|
|
{
|
|
Check(console_host);
|
|
|
|
unsigned int appState = applicationState.GetState();
|
|
|
|
ConsoleApplicationStateResponseMessage
|
|
response_message(
|
|
0, // GetHostManager()->GetLocalHostID(),
|
|
applicationState.GetState(),
|
|
GetApplicationID()
|
|
);
|
|
|
|
SendMessage(
|
|
console_host->GetHostID(),
|
|
ConsoleClientID,
|
|
&response_message
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// CreateMission
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Application::CreateMission(NotationFile *egg_notation_file)
|
|
{
|
|
Check(this);
|
|
Check(egg_notation_file);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Create mission from egg notation file
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
currentMission = MakeMission(egg_notation_file, resourceFile);
|
|
Register_Object(currentMission);
|
|
secondsRemainingInGame = currentMission->GetGameLength();
|
|
|
|
//
|
|
//----------------------------------------------------------------------
|
|
// Now, start up the network connect process. The network must have at
|
|
// least established the local host before returning, so that the player
|
|
// data load can work
|
|
//----------------------------------------------------------------------
|
|
//
|
|
NetworkManager *net_mgr = GetNetworkManager();
|
|
Check(net_mgr);
|
|
net_mgr->StartConnecting(currentMission);
|
|
currentMission->SetPlayerData(egg_notation_file);
|
|
|
|
InterestManager *interest_mgr = GetInterestManager();
|
|
Check(interest_mgr);
|
|
interest_mgr->LoadInterestArenas(currentMission);
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// MakeMission
|
|
//#############################################################################
|
|
//
|
|
Mission*
|
|
Application::MakeMission(
|
|
NotationFile*,
|
|
ResourceFile*
|
|
)
|
|
{
|
|
Fail("Application::MakeMisson - Should never reach here");
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// LoadMissionMessageHandler
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Application::LoadMissionMessageHandler(Message *)
|
|
{
|
|
Check(this);
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Load the interest manager
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
#ifdef USE_TIME_ANALYSIS
|
|
trace_manager.StartTimingAnalysis();
|
|
#endif
|
|
Check(interestManager);
|
|
interestManager->LoadMission(currentMission);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Make the player
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
Registry* registry = GetRegistry();
|
|
Check(registry);
|
|
missionPlayer = registry->MakePlayer(currentMission);
|
|
Register_Object(missionPlayer);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Set application state to loading
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
applicationState.SetState(CreatingMission);
|
|
#if defined(LAB_ONLY)
|
|
DEBUG_STREAM << "Starting entity creation...\n" << std::flush;
|
|
#endif
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// MakeAndLinkViewpointEntity
|
|
//#############################################################################
|
|
//
|
|
Entity*
|
|
Application::MakeAndLinkViewpointEntity(Entity::MakeMessage* message)
|
|
{
|
|
Check(this);
|
|
Check(message);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Create the viewpoint entity
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
#if DEBUG_LEVEL>0
|
|
HostManager *host = GetHostManager();
|
|
Check(host);
|
|
Verify(message->entityID.GetHostID() == host->GetLocalHostID());
|
|
#endif
|
|
|
|
Verify(viewpointEntity == NULL);
|
|
viewpointEntity = MakeViewpointEntity(message);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Post a message to check the status of the load
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
CheckLoadMessage check_load_message;
|
|
Post(DefaultEventPriority, this, &check_load_message);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Load audio renderer
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
if (audioRenderer != NULL)
|
|
{
|
|
Check(audioRenderer);
|
|
audioRenderer->LinkToEntity(viewpointEntity);
|
|
audioRenderer->LoadMission(GetCurrentMission());
|
|
audioRenderer->SetRendererStatusToRunning();
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Load video renderer
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
if (videoRenderer != NULL)
|
|
{
|
|
Check(videoRenderer);
|
|
videoRenderer->LinkToEntity(viewpointEntity);
|
|
videoRenderer->LoadMission(GetCurrentMission());
|
|
videoRenderer->SetRendererStatusToRunning();
|
|
}
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// Load gauge renderer
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
if (gaugeRenderer != NULL)
|
|
{
|
|
Check(gaugeRenderer);
|
|
gaugeRenderer->LinkToEntity(viewpointEntity);
|
|
gaugeRenderer->LoadMission(GetCurrentMission());
|
|
gaugeRenderer->SetRendererStatusToRunning();
|
|
}
|
|
|
|
return viewpointEntity;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// MakeViewpointEntity
|
|
//#############################################################################
|
|
//
|
|
Entity*
|
|
Application::MakeViewpointEntity(Entity::MakeMessage*)
|
|
{
|
|
Fail("Application::MakeViewpointEntity - Should never reach here");
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// MakeAudioRenderer
|
|
//#############################################################################
|
|
//
|
|
AudioRenderer*
|
|
Application::MakeAudioRenderer()
|
|
{
|
|
Fail("Application::MakeAudioRenderer - Should never reach here");
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// MakeVideoRenderer
|
|
//#############################################################################
|
|
//
|
|
VideoRenderer*
|
|
Application::MakeVideoRenderer()
|
|
{
|
|
Fail("Application::MakeVideoRenderer - Should never reach here");
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// MakeGaugeRenderer
|
|
//#############################################################################
|
|
//
|
|
GaugeRenderer*
|
|
Application::MakeGaugeRenderer(int *secondaryIndex, int *aux1Index, int *aux2Index)
|
|
{
|
|
Fail("Application::MakeGaugeRenderer - Should never reach here");
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// CheckLoadMessageHandler
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Application::CheckLoadMessageHandler(
|
|
CheckLoadMessage *message
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(message);
|
|
Verify(message->messageID == CheckLoadMessageID);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// If the application is already running then ignore this message
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
switch (applicationState.GetState())
|
|
{
|
|
case CreatingMission:
|
|
case LoadingMission:
|
|
case WaitingForLaunch:
|
|
if (eventQueue->IsPriorityEmpty(MinEventPriority))
|
|
{
|
|
Host *console_host;
|
|
|
|
if (applicationState.GetState() == LoadingMission)
|
|
{
|
|
ResourceFile *res_file = GetResourceFile();
|
|
Check(res_file);
|
|
res_file->ReleaseUnlockedResources();
|
|
#if defined(LAB_ONLY)
|
|
DEBUG_STREAM << "Waiting for translocation!\n" << std::flush;
|
|
#endif
|
|
#if defined(USE_TIME_ANALYSIS)
|
|
DEBUG_STREAM << "Loading time usage:\n" << std::flush;
|
|
trace_manager.SnapshotTimingAnalysis(True);
|
|
#endif
|
|
}
|
|
applicationState.SetState(WaitingForLaunch);
|
|
Check(GetHostManager());
|
|
|
|
static bool hasConsolidated = false;
|
|
|
|
if (!hasConsolidated)
|
|
{
|
|
//Consolidate level geometry here
|
|
VideoRenderer *renderer = Application::GetVideoRenderer();
|
|
renderer->ConsolidateStaticObjects();
|
|
hasConsolidated = true;
|
|
}
|
|
|
|
console_host = GetHostManager()->GetConsoleHost();
|
|
if (
|
|
(console_host == NULL) ||
|
|
(
|
|
console_host != NULL &&
|
|
console_host->GetConnectStatus() != Host::OnLineConnectionStatus
|
|
)
|
|
)
|
|
{
|
|
//
|
|
// In the absence of the console just post the message to run
|
|
//
|
|
RunMissionMessage run_mission_message;
|
|
Post(DefaultEventPriority, this, &run_mission_message);
|
|
Tell("Sent ready message to ourselves\n");
|
|
}
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------------------------------------
|
|
// Post this message again until the application is running
|
|
//-----------------------------------------------------------------------
|
|
//
|
|
Time post_time;
|
|
|
|
post_time = Now();
|
|
#if DEBUG_LEVEL<3
|
|
post_time += 1.0f;
|
|
#else
|
|
post_time += 5.0;
|
|
#endif
|
|
|
|
Post(DefaultEventPriority, this, message, post_time);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// RunMissionMessageHandler
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Application::RunMissionMessageHandler(
|
|
#if DEBUG_LEVEL>0
|
|
RunMissionMessage *message
|
|
#else
|
|
RunMissionMessage *
|
|
#endif
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(message);
|
|
Verify(message->messageID == RunMissionMessageID);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// If the application is already running then ignore this message
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
switch (GetApplicationState())
|
|
{
|
|
case RunningMission:
|
|
return;
|
|
|
|
case LaunchingMission:
|
|
//
|
|
// Start analysis sample
|
|
//
|
|
#if defined(USE_TRACE_LOG)
|
|
{
|
|
char *log_size_str = getenv("LOGSIZE");
|
|
if (log_size_str)
|
|
{
|
|
size_t log_size = atoi(log_size_str);
|
|
if (log_size > 0)
|
|
{
|
|
trace_manager.CreateTraceLog(log_size,True);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef USE_TIME_ANALYSIS
|
|
trace_manager.StartTimingAnalysis();
|
|
#endif
|
|
|
|
Tell("Application::RunMissionMessageHandler - running mission\n");
|
|
applicationState.SetState(RunningMission);
|
|
gameStarted = Now();
|
|
break;
|
|
|
|
case WaitingForLaunch:
|
|
{
|
|
Tell("Application::RunMissionMessageHandler - Translocation\n");
|
|
applicationState.SetState(LaunchingMission);
|
|
Player *player = GetMissionPlayer();
|
|
Check(player);
|
|
Player::MissionStartingMessage
|
|
launch(
|
|
Player::MissionStartingMessageID,
|
|
sizeof(Player::MissionStartingMessage)
|
|
);
|
|
player->Dispatch(&launch);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
Fail("Application::RunMissionMessageHandler - Not ready to run!\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// SuspendMissionMessageHandler
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Application::SuspendMissionMessageHandler(
|
|
#if DEBUG_LEVEL>0
|
|
SuspendMissionMessage *message
|
|
#else
|
|
SuspendMissionMessage *
|
|
#endif
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(message);
|
|
Verify(message->messageID == SuspendMissionMessageID);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// The application should be either running or already suspended
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
switch (GetApplicationState())
|
|
{
|
|
case RunningMission:
|
|
{
|
|
Player::MissionEndingMessage
|
|
player_message(
|
|
Player::MissionEndingMessageID,
|
|
sizeof(Player::MissionEndingMessage)
|
|
);
|
|
Player *player;
|
|
|
|
Tell("Application::SuspendMissionMessageHandler - Suspending\n");
|
|
applicationState.SetState(SuspendingMission);
|
|
|
|
player = GetMissionPlayer();
|
|
Check(player);
|
|
player->Dispatch(&player_message);
|
|
}
|
|
break;
|
|
|
|
case SuspendingMission:
|
|
//
|
|
// Already suspended
|
|
//
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// Any other state is an error
|
|
//
|
|
Fail("Application::SuspendMissionMessageHandler - Illegal state");
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// ResumeMissionMessageHandler
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Application::ResumeMissionMessageHandler(
|
|
#if DEBUG_LEVEL>0
|
|
ResumeMissionMessage *message
|
|
#else
|
|
ResumeMissionMessage *
|
|
#endif
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(message);
|
|
Verify(message->messageID == ResumeMissionMessageID);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// The application should be in the suspended state or resuming
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
switch (GetApplicationState())
|
|
{
|
|
case SuspendingMission:
|
|
{
|
|
Player::MissionStartingMessage
|
|
launch(
|
|
Player::MissionStartingMessageID,
|
|
sizeof(Player::MissionStartingMessage)
|
|
);
|
|
Player *player;
|
|
|
|
Tell("Application::ResumeMissionMessageHandler - Resuming mission\n");
|
|
applicationState.SetState(ResumingMission);
|
|
player = GetMissionPlayer();
|
|
Check(player);
|
|
player->Dispatch(&launch);
|
|
}
|
|
break;
|
|
|
|
case ResumingMission:
|
|
Tell("Application::ResumeMissionMessageHandler - Running mission\n");
|
|
applicationState.SetState(RunningMission);
|
|
gameStarted = Now();
|
|
break;
|
|
|
|
default:
|
|
Fail("Application::ResumeMissionMessageHandler - Illegal state\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// StopMissionMessageHandler
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Application::StopMissionMessageHandler(
|
|
#if DEBUG_LEVEL>0
|
|
StopMissionMessage *message
|
|
#else
|
|
StopMissionMessage *
|
|
#endif
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(message);
|
|
Verify(message->messageID == StopMissionMessageID);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// If the application is already stopping then ignore the message
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
switch (GetApplicationState())
|
|
{
|
|
case StoppingMission:
|
|
return;
|
|
|
|
case EndingMission:
|
|
case AbortingMission:
|
|
Stop();
|
|
break;
|
|
|
|
default:
|
|
{
|
|
applicationState.SetState(EndingMission);
|
|
Player *player = GetMissionPlayer();
|
|
if (player)
|
|
{
|
|
networkManager->Mode(NetworkManager::ReliableMode);
|
|
Check(player);
|
|
Player::MissionEndingMessage
|
|
launch(
|
|
Player::MissionEndingMessageID,
|
|
sizeof(Player::MissionEndingMessage)
|
|
);
|
|
player->Dispatch(&launch);
|
|
}
|
|
else
|
|
{
|
|
Stop();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// StopMissionMessageHandler
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Application::AbortMissionMessageHandler(
|
|
#if DEBUG_LEVEL>0
|
|
AbortMissionMessage *message
|
|
#else
|
|
AbortMissionMessage *
|
|
#endif
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(message);
|
|
Verify(message->messageID == AbortMissionMessageID);
|
|
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
// If the application is already stopping then ignore the message
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
switch (GetApplicationState())
|
|
{
|
|
case StoppingMission:
|
|
return;
|
|
|
|
case EndingMission:
|
|
case AbortingMission:
|
|
Stop();
|
|
break;
|
|
|
|
default:
|
|
{
|
|
applicationState.SetState(AbortingMission);
|
|
Player *player = GetMissionPlayer();
|
|
if (player)
|
|
{
|
|
Check(player);
|
|
Player::MissionEndingMessage
|
|
launch(
|
|
Player::MissionEndingMessageID,
|
|
sizeof(Player::MissionEndingMessage)
|
|
);
|
|
player->Dispatch(&launch);
|
|
}
|
|
else
|
|
{
|
|
Stop();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//#############################################################################
|
|
// KeyCommandMessageHandler
|
|
//#############################################################################
|
|
//
|
|
void
|
|
Application::KeyCommandMessageHandler(
|
|
ReceiverDataMessageOf<ControlsKey> *message
|
|
)
|
|
{
|
|
Check(this);
|
|
Check(message);
|
|
switch (message->dataContents)
|
|
{
|
|
case '&':
|
|
if (GetApplicationState() != StoppingMission)
|
|
{
|
|
Exit_Code = 1;
|
|
Stop();
|
|
DEBUG_STREAM << "Mission stopped by keystroke!\n" << std::flush;
|
|
if (GetApplicationState() == WaitingForEgg)
|
|
{
|
|
applicationState.SetState(EndingMission);
|
|
}
|
|
}
|
|
break;
|
|
|
|
#if defined(USE_TRACE_LOG)
|
|
case ' ':
|
|
trace_manager.MarkTraceLog();
|
|
break;
|
|
case '/':
|
|
trace_manager.ResumeTraceLogging();
|
|
break;
|
|
case '\\':
|
|
trace_manager.SuspendTraceLogging();
|
|
break;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~ Application__CheckLoadMessage ~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Application__CheckLoadMessage::Application__CheckLoadMessage():
|
|
NetworkClient::Message(
|
|
Application::CheckLoadMessageID,
|
|
sizeof(Application__CheckLoadMessage)
|
|
)
|
|
{
|
|
}
|
|
|
|
#ifdef TEST_CLASS
|
|
# include "app.tcp"
|
|
#endif
|