Index: binaries/system/readme.txt =================================================================== --- binaries/system/readme.txt +++ binaries/system/readme.txt @@ -64,6 +64,8 @@ -rejointest=N simulates a rejoin and checks simulation state each turn for serialization errors; this is similar to a serialization test but much faster and less complete. It should be enough for debugging most rejoin OOSes. +-unique-logs adds unix timestamp and process id to the filename of mainlog.html, interestinglog.html + and oos_dump.txt to prevent the files from becoming overwritten by another process. Windows-specific: -wQpcTscSafe allow timing via QueryPerformanceCounter despite the fact Index: source/main.cpp =================================================================== --- source/main.cpp +++ source/main.cpp @@ -83,7 +83,13 @@ #include // geteuid #endif // OS_UNIX +#if MSC_VERSION +#include +#define getpid _getpid // Use the non-deprecated function name +#endif + extern bool g_GameRestarted; +extern CStrW g_UniqueLogPostfix; void kill_mainloop(); @@ -463,6 +469,13 @@ return; } + if (args.Has("unique-logs")) + { + std::wstringstream postfix; + postfix << L"_" << std::time(nullptr) << L"_" << getpid(); + g_UniqueLogPostfix = postfix.str(); + } + const bool isVisualReplay = args.Has("replay-visual"); const bool isNonVisualReplay = args.Has("replay"); const bool isNonVisual = args.Has("autostart-nonvisual"); Index: source/network/NetClientTurnManager.cpp =================================================================== --- source/network/NetClientTurnManager.cpp +++ source/network/NetClientTurnManager.cpp @@ -33,6 +33,8 @@ #define NETCLIENTTURN_LOG(...) #endif +extern CStrW g_UniqueLogPostfix; + CNetClientTurnManager::CNetClientTurnManager(CSimulation2& simulation, CNetClient& client, int clientId, IReplayLogger& replay) : CTurnManager(simulation, DEFAULT_TURN_LENGTH_MP, clientId, replay), m_NetClient(client) { @@ -116,8 +118,10 @@ std::string hash; ENSURE(m_Simulation2.ComputeStateHash(hash, !TurnNeedsFullHash(turn))); - OsPath path = psLogDir() / "oos_dump.txt"; - std::ofstream file (OsString(path).c_str(), std::ofstream::out | std::ofstream::trunc); + CStrW oosdumpName = L"oos_dump" + g_UniqueLogPostfix + L".txt"; + + OsPath oosdumpPath(psLogDir() / oosdumpName); + std::ofstream file (OsString(oosdumpPath).c_str(), std::ofstream::out | std::ofstream::trunc); m_Simulation2.DumpDebugState(file); file.close(); @@ -131,7 +135,7 @@ playerNamesStrings.push_back(name); } - LOGERROR("Out-Of-Sync on turn %d\nPlayers: %s\nDumping state to %s", turn, playerNamesString.str().c_str(), path.string8()); + LOGERROR("Out-Of-Sync on turn %d\nPlayers: %s\nDumping state to %s", turn, playerNamesString.str().c_str(), oosdumpPath.string8()); ScriptInterface& scriptInterface = m_NetClient.GetScriptInterface(); JSContext* cx = scriptInterface.GetContext(); @@ -143,7 +147,7 @@ scriptInterface.SetProperty(msg, "players", playerNamesStrings); scriptInterface.SetProperty(msg, "expectedHash", expectedHashHex); scriptInterface.SetProperty(msg, "hash", Hexify(hash)); - scriptInterface.SetProperty(msg, "path_oos_dump", path.string8()); + scriptInterface.SetProperty(msg, "path_oos_dump", oosdumpPath.string8()); scriptInterface.SetProperty(msg, "path_replay", m_Replay.GetDirectory().string8()); m_NetClient.PushGuiMessage(msg); } Index: source/ps/CLogger.cpp =================================================================== --- source/ps/CLogger.cpp +++ source/ps/CLogger.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2016 Wildfire Games. +/* Copyright (C) 2017 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -34,6 +34,7 @@ #include +CStrW g_UniqueLogPostfix = L""; static const double RENDER_TIMEOUT = 10.0; // seconds before messages are deleted static const double RENDER_TIMEOUT_RATE = 10.0; // number of timed-out messages deleted per second static const size_t RENDER_LIMIT = 20; // maximum messages on screen at once @@ -65,10 +66,15 @@ CLogger::CLogger() { - OsPath mainlogPath(psLogDir()/"mainlog.html"); + CStrW mainlogName = L"mainlog" + g_UniqueLogPostfix + L".html"; + + OsPath mainlogPath(psLogDir()/mainlogName); m_MainLog = new std::ofstream(OsString(mainlogPath).c_str(), std::ofstream::out | std::ofstream::trunc); + debug_printf("Writing the mainlog at %s\n", mainlogPath.string8().c_str()); + + CStrW interestinglogName = L"interestinglog" + g_UniqueLogPostfix + L".html"; - OsPath interestinglogPath(psLogDir()/"interestinglog.html"); + OsPath interestinglogPath(psLogDir() / interestinglogName); m_InterestingLog = new std::ofstream(OsString(interestinglogPath).c_str(), std::ofstream::out | std::ofstream::trunc); m_OwnsStreams = true;