diff --git a/MUNGA/APP.cpp b/MUNGA/APP.cpp index e6eb8f1..24f0344 100644 --- a/MUNGA/APP.cpp +++ b/MUNGA/APP.cpp @@ -1386,15 +1386,22 @@ void console_host = GetHostManager()->GetConsoleHost(); if ( - (console_host == NULL) || + !gConsoleMarshalsLaunch && ( - console_host != NULL && - console_host->GetConnectStatus() != Host::OnLineConnectionStatus + (console_host == NULL) || + ( + console_host != NULL && + console_host->GetConnectStatus() != Host::OnLineConnectionStatus + ) ) ) { // - // In the absence of the console just post the message to run + // In the absence of the console just post the message to + // run. An IN-PROCESS console (hosted network race) has no + // connection to this pod but still owns the launch - the + // gConsoleMarshalsLaunch flag holds us at WaitingForLaunch + // until every pod in the mesh is staged. // RunMissionMessage run_mission_message; Post(DefaultEventPriority, this, &run_mission_message); diff --git a/MUNGA/APPMGR.cpp b/MUNGA/APPMGR.cpp index 0ba1bd5..390aae2 100644 --- a/MUNGA/APPMGR.cpp +++ b/MUNGA/APPMGR.cpp @@ -9,6 +9,9 @@ HWND ghWnd = 0; // the single-player local-console marshal here void (*gPerFrameHook)() = NULL; +// an in-process console owns the launch (hosted network races) +Logical gConsoleMarshalsLaunch = False; + ApplicationManager* ApplicationManager::CurrentAppManager = NULL; ApplicationManager::ApplicationManager(HINSTANCE hInstance, HWND hWnd, Scalar frame_rate) : Node(ApplicationManagerClassID), runningApplications(this) diff --git a/MUNGA/APPMGR.h b/MUNGA/APPMGR.h index dc7f64b..eac4952 100644 --- a/MUNGA/APPMGR.h +++ b/MUNGA/APPMGR.h @@ -8,6 +8,12 @@ extern HWND ghWnd; // foreground pass (the single-player local-console marshal uses this) extern void (*gPerFrameHook)(); +// True when an in-process console marshals the launch: suppresses the +// no-console self-run in CheckLoadMessageHandler so a hosted network +// race stages at WaitingForLaunch until every pod is ready. Plain +// single player leaves it False and auto-runs exactly as always. +extern Logical gConsoleMarshalsLaunch; + class ApplicationManager : public Node { public: diff --git a/RP_L4/RPL4.CPP b/RP_L4/RPL4.CPP index fe37a4f..1048cdd 100644 --- a/RP_L4/RPL4.CPP +++ b/RP_L4/RPL4.CPP @@ -68,6 +68,42 @@ const char* const ProgName = "rpl4"; Application *rpl4App; HWND hWnd; +// +// Unhandled-exception minidump: rpl4crash.dmp lands beside the exe so +// a crash on a test machine hands back a stack. dbghelp loads lazily - +// no link-time dependency. +// +static LONG WINAPI RPL4CrashDumpFilter(EXCEPTION_POINTERS *exception) +{ + HMODULE dbghelp = LoadLibraryA("dbghelp.dll"); + if (dbghelp != NULL) + { + typedef BOOL (WINAPI *MiniDumpWriteDumpFn)( + HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, + PMINIDUMP_EXCEPTION_INFORMATION, + PMINIDUMP_USER_STREAM_INFORMATION, + PMINIDUMP_CALLBACK_INFORMATION); + MiniDumpWriteDumpFn write_dump = + (MiniDumpWriteDumpFn) GetProcAddress(dbghelp, "MiniDumpWriteDump"); + if (write_dump != NULL) + { + HANDLE file = CreateFileA("rpl4crash.dmp", GENERIC_WRITE, 0, + NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (file != INVALID_HANDLE_VALUE) + { + MINIDUMP_EXCEPTION_INFORMATION dump_info; + dump_info.ThreadId = GetCurrentThreadId(); + dump_info.ExceptionPointers = exception; + dump_info.ClientPointers = FALSE; + write_dump(GetCurrentProcess(), GetCurrentProcessId(), file, + MiniDumpNormal, &dump_info, NULL, NULL); + CloseHandle(file); + } + } + } + return EXCEPTION_CONTINUE_SEARCH; +} + LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) @@ -91,6 +127,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine logfile.open(filename); std::cout.rdbuf(logfile.rdbuf()); + SetUnhandledExceptionFilter(RPL4CrashDumpFilter); + // load up our environment variables //controls if(getenv("L4CONTROLS") == NULL) diff --git a/RP_L4/RPL4CONSOLE.cpp b/RP_L4/RPL4CONSOLE.cpp index 3d302f4..a4514a6 100644 --- a/RP_L4/RPL4CONSOLE.cpp +++ b/RP_L4/RPL4CONSOLE.cpp @@ -531,6 +531,8 @@ void gNetworkRace = False; gRemotePodCount = 0; gPilotNameCount = 0; + // single player launches itself (the engine's no-console self-run) + gConsoleMarshalsLaunch = False; InstallCommon(mission_seconds); } @@ -546,6 +548,10 @@ Logical gRemotePodCount = 0; gPilotNameCount = 0; + // the owner pod must stage at WaitingForLaunch with everyone else - + // this console launches the whole mesh at once + gConsoleMarshalsLaunch = True; + strncpy(gEggPath, egg_path, sizeof(gEggPath) - 1); gEggPath[sizeof(gEggPath) - 1] = '\0';