Example #1
0
void CArchiveBuilder::Build(const OsPath& archive, bool compress)
{
	// By default we disable zip compression because it significantly hurts download
	// size for releases (which re-compress all files with better compression
	// algorithms) - it's probably most important currently to optimise for
	// download size rather than install size or startup performance.
	// (See http://trac.wildfiregames.com/ticket/671)
	const bool noDeflate = !compress;

	PIArchiveWriter writer = CreateArchiveWriter_Zip(archive, noDeflate);

	// Use CTextureManager instead of CTextureConverter directly,
	// so it can deal with all the loading of settings.xml files
	CTextureManager textureManager(m_VFS, true, true);

	CColladaManager colladaManager(m_VFS);

	CXeromyces xero;

	for (size_t i = 0; i < m_Files.size(); ++i)
	{
		Status ret;

		const VfsPath path = m_Files[i];
		OsPath realPath;
		ret = m_VFS->GetRealPath(path, realPath);
		ENSURE(ret == INFO::OK);

		// Compress textures and store the new cached version instead of the original
		if ((boost::algorithm::starts_with(path.string(), L"art/textures/") ||
			 boost::algorithm::starts_with(path.string(), L"fonts/")
			) &&
			tex_is_known_extension(path) &&
			// Skip some subdirectories where the engine doesn't use CTextureManager yet:
			!boost::algorithm::starts_with(path.string(), L"art/textures/cursors/") &&
			!boost::algorithm::starts_with(path.string(), L"art/textures/terrain/alphamaps/")
		)
		{
			VfsPath cachedPath;
			debug_printf(L"Converting texture %ls\n", realPath.string().c_str());
			bool ok = textureManager.GenerateCachedTexture(path, cachedPath);
			ENSURE(ok);

			OsPath cachedRealPath;
			ret = m_VFS->GetRealPath(VfsPath("cache")/cachedPath, cachedRealPath);
			ENSURE(ret == INFO::OK);

			writer->AddFile(cachedRealPath, cachedPath);

			// We don't want to store the original file too (since it's a
			// large waste of space), so skip to the next file
			continue;
		}

		// Convert DAE models and store the new cached version instead of the original
		if (path.Extension() == L".dae")
		{
			CColladaManager::FileType type;

			if (boost::algorithm::starts_with(path.string(), L"art/meshes/"))
				type = CColladaManager::PMD;
			else if (boost::algorithm::starts_with(path.string(), L"art/animation/"))
				type = CColladaManager::PSA;
			else
			{
				// Unknown type of DAE, just add to archive and continue
				writer->AddFile(realPath, path);
				continue;
			}
			
			VfsPath cachedPath;
			debug_printf(L"Converting model %ls\n", realPath.string().c_str());
			bool ok = colladaManager.GenerateCachedFile(path, type, cachedPath);
			
			// The DAE might fail to convert for whatever reason, and in that case
			//	it can't be used in the game, so we just exclude it
			//  (alternatively we could throw release blocking errors on useless files)
			if (ok)
			{
				OsPath cachedRealPath;
				ret = m_VFS->GetRealPath(VfsPath("cache")/cachedPath, cachedRealPath);
				ENSURE(ret == INFO::OK);

				writer->AddFile(cachedRealPath, cachedPath);
			}

			// We don't want to store the original file too (since it's a
			// large waste of space), so skip to the next file
			continue;
		}

		debug_printf(L"Adding %ls\n", realPath.string().c_str());
		writer->AddFile(realPath, path);

		// Also cache XMB versions of all XML files
		if (path.Extension() == L".xml")
		{
			VfsPath cachedPath;
			debug_printf(L"Converting XML file %ls\n", realPath.string().c_str());
			bool ok = xero.GenerateCachedXMB(m_VFS, path, cachedPath);
			ENSURE(ok);

			OsPath cachedRealPath;
			ret = m_VFS->GetRealPath(VfsPath("cache")/cachedPath, cachedRealPath);
			ENSURE(ret == INFO::OK);

			writer->AddFile(cachedRealPath, cachedPath);
		}
	}
}
Example #2
0
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;
}