void CNetTurnManager::QuickLoad() { TIMER(L"QuickLoad"); if (m_QuickSaveState.empty()) { LOGERROR("Cannot quickload game - no game was quicksaved"); return; } std::stringstream stream(m_QuickSaveState); if (!m_Simulation2.DeserializeState(stream)) { LOGERROR("Failed to quickload game"); return; } if (g_GUI && !m_QuickSaveMetadata.empty()) g_GUI->RestoreSavedGameData(m_QuickSaveMetadata); LOGMESSAGERENDER("Quickloaded game"); // See RewindTimeWarp ResetState(0, 1); }
void CProfileViewer::SaveToFile() { // Open the file, if necessary. If this method is called several times, // the profile results will be appended to the previous ones from the same // run. if (! m->outputStream.is_open()) { // Open the file. (It will be closed when the CProfileViewer // destructor is called.) OsPath path = psLogDir()/"profile.txt"; m->outputStream.open(OsString(path).c_str(), std::ofstream::out | std::ofstream::trunc); if (m->outputStream.fail()) { LOGERROR(L"Failed to open profile log file"); return; } else { LOGMESSAGERENDER(L"Profiler snapshot saved to '%ls'", path.string().c_str()); } } time_t t; time(&t); m->outputStream << "================================================================\n\n"; m->outputStream << "PS profiler snapshot - " << asctime(localtime(&t)); std::vector<AbstractProfileTable*> tables = m->rootTables; sort(tables.begin(), tables.end(), SortByName); for_each(tables.begin(), tables.end(), WriteTable(m->outputStream)); m->outputStream << "\n\n================================================================\n"; m->outputStream.flush(); }
void CProfiler2::ShutDownHTTP() { LOGMESSAGERENDER("Shutting down profiler2 HTTP server"); if (m_MgContext) { mg_stop(m_MgContext); m_MgContext = NULL; } }
void CProfiler2::EnableGPU() { ENSURE(m_Initialised); if (!m_GPU) { LOGMESSAGERENDER("Starting profiler2 GPU mode"); InitialiseGPU(); } }
// <extension> identifies the file format that is to be written // (case-insensitive). examples: "bmp", "png", "jpg". // BMP is good for quick output at the expense of large files. void WriteScreenshot(const VfsPath& extension) { // get next available numbered filename // note: %04d -> always 4 digits, so sorting by filename works correctly. const VfsPath basenameFormat(L"screenshots/screenshot%04d"); const VfsPath filenameFormat = basenameFormat.ChangeExtension(extension); VfsPath filename; vfs::NextNumberedFilename(g_VFS, filenameFormat, s_nextScreenshotNumber, filename); const size_t w = (size_t)g_xres, h = (size_t)g_yres; const size_t bpp = 24; GLenum fmt = GL_RGB; int flags = TEX_BOTTOM_UP; // we want writing BMP to be as fast as possible, // so read data from OpenGL in BMP format to obviate conversion. if(extension == L".bmp") { #if !CONFIG2_GLES // GLES doesn't support BGR fmt = GL_BGR; flags |= TEX_BGR; #endif } // Hide log messages and re-render RenderLogger(false); Render(); RenderLogger(true); const size_t img_size = w * h * bpp/8; const size_t hdr_size = tex_hdr_size(filename); shared_ptr<u8> buf; AllocateAligned(buf, hdr_size+img_size, maxSectorSize); GLvoid* img = buf.get() + hdr_size; Tex t; if(t.wrap(w, h, bpp, flags, buf, hdr_size) < 0) return; glReadPixels(0, 0, (GLsizei)w, (GLsizei)h, fmt, GL_UNSIGNED_BYTE, img); if (tex_write(&t, filename) == INFO::OK) { OsPath realPath; g_VFS->GetRealPath(filename, realPath); LOGMESSAGERENDER(g_L10n.Translate("Screenshot written to '%s'"), realPath.string8()); debug_printf( CStr(g_L10n.Translate("Screenshot written to '%s'") + "\n").c_str(), realPath.string8().c_str()); } else LOGERROR("Error writing screenshot to '%s'", filename.string8()); }
void CProfiler2::EnableHTTP() { ENSURE(m_Initialised); LOGMESSAGERENDER("Starting profiler2 HTTP server"); // Ignore multiple enablings if (m_MgContext) return; const char *options[] = { "listening_ports", "127.0.0.1:8000", // bind to localhost for security "num_threads", "6", // enough for the browser's parallel connection limit NULL }; m_MgContext = mg_start(MgCallback, this, options); ENSURE(m_MgContext); }
bool CNetClient::HandleMessage(CNetMessage* message) { // Handle non-FSM messages first Status status = m_Session->GetFileTransferer().HandleMessageReceive(message); if (status == INFO::OK) return true; if (status != INFO::SKIPPED) return false; if (message->GetType() == NMT_FILE_TRANSFER_REQUEST) { CFileTransferRequestMessage* reqMessage = (CFileTransferRequestMessage*)message; // TODO: we should support different transfer request types, instead of assuming // it's always requesting the simulation state std::stringstream stream; LOGMESSAGERENDER("Serializing game at turn %u for rejoining player", m_ClientTurnManager->GetCurrentTurn()); u32 turn = to_le32(m_ClientTurnManager->GetCurrentTurn()); stream.write((char*)&turn, sizeof(turn)); bool ok = m_Game->GetSimulation2()->SerializeState(stream); ENSURE(ok); // Compress the content with zlib to save bandwidth // (TODO: if this is still too large, compressing with e.g. LZMA works much better) std::string compressed; CompressZLib(stream.str(), compressed, true); m_Session->GetFileTransferer().StartResponse(reqMessage->m_RequestID, compressed); return true; } // Update FSM bool ok = Update(message->GetType(), message); if (!ok) LOGERROR("Net client: Error running FSM update (type=%d state=%d)", (int)message->GetType(), (int)GetCurrState()); return ok; }
void CNetTurnManager::QuickSave() { TIMER(L"QuickSave"); std::stringstream stream; if (!m_Simulation2.SerializeState(stream)) { LOGERROR("Failed to quicksave game"); return; } m_QuickSaveState = stream.str(); if (g_GUI) m_QuickSaveMetadata = g_GUI->GetSavedGameData(); else m_QuickSaveMetadata = std::string(); LOGMESSAGERENDER("Quicksaved game"); }
// Similar to WriteScreenshot, but generates an image of size 640*tiles x 480*tiles. void WriteBigScreenshot(const VfsPath& extension, int tiles) { // If the game hasn't started yet then use WriteScreenshot to generate the image. if(g_Game == NULL) { WriteScreenshot(L".bmp"); return; } // get next available numbered filename // note: %04d -> always 4 digits, so sorting by filename works correctly. const VfsPath basenameFormat(L"screenshots/screenshot%04d"); const VfsPath filenameFormat = basenameFormat.ChangeExtension(extension); VfsPath filename; vfs::NextNumberedFilename(g_VFS, filenameFormat, s_nextScreenshotNumber, filename); // Slightly ugly and inflexible: Always draw 640*480 tiles onto the screen, and // hope the screen is actually large enough for that. const int tile_w = 640, tile_h = 480; ENSURE(g_xres >= tile_w && g_yres >= tile_h); const int img_w = tile_w*tiles, img_h = tile_h*tiles; const int bpp = 24; GLenum fmt = GL_RGB; int flags = TEX_BOTTOM_UP; // we want writing BMP to be as fast as possible, // so read data from OpenGL in BMP format to obviate conversion. if(extension == L".bmp") { #if !CONFIG2_GLES // GLES doesn't support BGR fmt = GL_BGR; flags |= TEX_BGR; #endif } const size_t img_size = img_w * img_h * bpp/8; const size_t tile_size = tile_w * tile_h * bpp/8; const size_t hdr_size = tex_hdr_size(filename); void* tile_data = malloc(tile_size); if(!tile_data) { WARN_IF_ERR(ERR::NO_MEM); return; } shared_ptr<u8> img_buf; AllocateAligned(img_buf, hdr_size+img_size, maxSectorSize); Tex t; GLvoid* img = img_buf.get() + hdr_size; if(t.wrap(img_w, img_h, bpp, flags, img_buf, hdr_size) < 0) { free(tile_data); return; } ogl_WarnIfError(); // Resize various things so that the sizes and aspect ratios are correct { g_Renderer.Resize(tile_w, tile_h); SViewPort vp = { 0, 0, tile_w, tile_h }; g_Game->GetView()->GetCamera()->SetViewPort(vp); g_Game->GetView()->SetCameraProjection(); } #if !CONFIG2_GLES // Temporarily move everything onto the front buffer, so the user can // see the exciting progress as it renders (and can tell when it's finished). // (It doesn't just use SwapBuffers, because it doesn't know whether to // call the SDL version or the Atlas version.) GLint oldReadBuffer, oldDrawBuffer; glGetIntegerv(GL_READ_BUFFER, &oldReadBuffer); glGetIntegerv(GL_DRAW_BUFFER, &oldDrawBuffer); glDrawBuffer(GL_FRONT); glReadBuffer(GL_FRONT); #endif // Hide the cursor CStrW oldCursor = g_CursorName; g_CursorName = L""; // Render each tile for (int tile_y = 0; tile_y < tiles; ++tile_y) { for (int tile_x = 0; tile_x < tiles; ++tile_x) { // Adjust the camera to render the appropriate region g_Game->GetView()->GetCamera()->SetProjectionTile(tiles, tile_x, tile_y); RenderLogger(false); RenderGui(false); Render(); RenderGui(true); RenderLogger(true); // Copy the tile pixels into the main image glReadPixels(0, 0, tile_w, tile_h, fmt, GL_UNSIGNED_BYTE, tile_data); for (int y = 0; y < tile_h; ++y) { void* dest = (char*)img + ((tile_y*tile_h + y) * img_w + (tile_x*tile_w)) * bpp/8; void* src = (char*)tile_data + y * tile_w * bpp/8; memcpy(dest, src, tile_w * bpp/8); } } } // Restore the old cursor g_CursorName = oldCursor; #if !CONFIG2_GLES // Restore the buffer settings glDrawBuffer(oldDrawBuffer); glReadBuffer(oldReadBuffer); #endif // Restore the viewport settings { g_Renderer.Resize(g_xres, g_yres); SViewPort vp = { 0, 0, g_xres, g_yres }; g_Game->GetView()->GetCamera()->SetViewPort(vp); g_Game->GetView()->SetCameraProjection(); g_Game->GetView()->GetCamera()->SetProjectionTile(1, 0, 0); } if (tex_write(&t, filename) == INFO::OK) { OsPath realPath; g_VFS->GetRealPath(filename, realPath); LOGMESSAGERENDER(g_L10n.Translate("Screenshot written to '%s'"), realPath.string8()); debug_printf( CStr(g_L10n.Translate("Screenshot written to '%s'") + "\n").c_str(), realPath.string8().c_str()); } else LOGERROR("Error writing screenshot to '%s'", filename.string8()); free(tile_data); }
void CProfiler2::ShutdownGPU() { LOGMESSAGERENDER("Shutting down profiler2 GPU mode"); SAFE_DELETE(m_GPU); }
Status SavedGames::Save(const std::wstring& prefix, CSimulation2& simulation, CGUIManager* gui, int playerID) { // Determine the filename to save under const VfsPath basenameFormat(L"saves/" + prefix + L"-%04d"); const VfsPath filenameFormat = basenameFormat.ChangeExtension(L".0adsave"); VfsPath filename; // Don't make this a static global like NextNumberedFilename expects, because // that wouldn't work when 'prefix' changes, and because it's not thread-safe size_t nextSaveNumber = 0; vfs::NextNumberedFilename(g_VFS, filenameFormat, nextSaveNumber, filename); // ArchiveWriter_Zip can only write to OsPaths, not VfsPaths, // but we'd like to handle saved games via VFS. // To avoid potential confusion from writing with non-VFS then // reading the same file with VFS, we'll just write to a temporary // non-VFS path and then load and save again via VFS, // which is kind of a hack. OsPath tempSaveFileRealPath; WARN_RETURN_STATUS_IF_ERR(g_VFS->GetDirectoryRealPath("cache/", tempSaveFileRealPath)); tempSaveFileRealPath = tempSaveFileRealPath / "temp.0adsave"; time_t now = time(NULL); // Construct the serialized state to be saved std::stringstream simStateStream; if (!simulation.SerializeState(simStateStream)) WARN_RETURN(ERR::FAIL); CScriptValRooted metadata; simulation.GetScriptInterface().Eval("({})", metadata); simulation.GetScriptInterface().SetProperty(metadata.get(), "version_major", SAVED_GAME_VERSION_MAJOR); simulation.GetScriptInterface().SetProperty(metadata.get(), "version_minor", SAVED_GAME_VERSION_MINOR); simulation.GetScriptInterface().SetProperty(metadata.get(), "time", (double)now); simulation.GetScriptInterface().SetProperty(metadata.get(), "player", playerID); simulation.GetScriptInterface().SetProperty(metadata.get(), "initAttributes", simulation.GetInitAttributes()); if (gui) { CScriptVal guiMetadata = simulation.GetScriptInterface().CloneValueFromOtherContext(gui->GetScriptInterface(), gui->GetSavedGameData().get()); simulation.GetScriptInterface().SetProperty(metadata.get(), "gui", guiMetadata); } std::string metadataString = simulation.GetScriptInterface().StringifyJSON(metadata.get(), true); // Write the saved game as zip file containing the various components PIArchiveWriter archiveWriter = CreateArchiveWriter_Zip(tempSaveFileRealPath, false); if (!archiveWriter) WARN_RETURN(ERR::FAIL); WARN_RETURN_STATUS_IF_ERR(archiveWriter->AddMemory((const u8*)metadataString.c_str(), metadataString.length(), now, "metadata.json")); WARN_RETURN_STATUS_IF_ERR(archiveWriter->AddMemory((const u8*)simStateStream.str().c_str(), simStateStream.str().length(), now, "simulation.dat")); archiveWriter.reset(); // close the file WriteBuffer buffer; FileInfo tempSaveFile; WARN_RETURN_STATUS_IF_ERR(GetFileInfo(tempSaveFileRealPath, &tempSaveFile)); buffer.Reserve(tempSaveFile.Size()); WARN_RETURN_STATUS_IF_ERR(io::Load(tempSaveFileRealPath, buffer.Data().get(), buffer.Size())); WARN_RETURN_STATUS_IF_ERR(g_VFS->CreateFile(filename, buffer.Data(), buffer.Size())); OsPath realPath; WARN_RETURN_STATUS_IF_ERR(g_VFS->GetRealPath(filename, realPath)); LOGMESSAGERENDER(L"Saved game to %ls\n", realPath.string().c_str()); return INFO::OK; }