Files
BT411/engine/MUNGA/APP.cpp
T
arcattackandClaude Opus 4.8 7b7d465e5e Initial commit: bt411 -- standalone Windows BattleTech (Tesla 4.10 port)
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>
2026-07-05 21:03:40 -05:00

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