1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-15 16:49:55 +00:00
openmw-tes3mp/apps/openmw/main.cpp
David Cernat f3b8a5b909 [General] Check integrity of credits only on Windows clients
This avoids the problems that were encountered in Linux and macOS builds regarding this check while also still addressing the scenario where official Windows builds had their credits modified by people unrelated to the project.
2019-02-14 00:29:55 +02:00

380 lines
14 KiB
C++

#include <iostream>
#include <components/version/version.hpp>
#include <components/crashcatcher/crashcatcher.hpp>
#include <components/files/configurationmanager.hpp>
#include <components/files/escape.hpp>
#include <components/fallback/validate.hpp>
#include <components/misc/debugging.hpp>
#include "engine.hpp"
/*
Start of tes3mp addition
Include the header of the multiplayer's Main class
*/
#include "mwmp/Main.hpp"
/*
End of tes3mp addition
*/
#if defined(_WIN32)
// For OutputDebugString
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
// makes __argc and __argv available on windows
#include <cstdlib>
#endif
#if (defined(__APPLE__) || defined(__linux) || defined(__unix) || defined(__posix))
#include <unistd.h>
#endif
/*
Start of tes3mp addition
Include additional headers for multiplayer purposes
*/
#include <components/openmw-mp/ErrorMessages.hpp>
#include <components/openmw-mp/Log.hpp>
#include <components/openmw-mp/Utils.hpp>
#include <components/openmw-mp/Version.hpp>
/*
End of tes3mp addition
*/
/**
* Workaround for problems with whitespaces in paths in older versions of Boost library
*/
#if (BOOST_VERSION <= 104600)
namespace boost
{
template<>
inline boost::filesystem::path lexical_cast<boost::filesystem::path, std::string>(const std::string& arg)
{
return boost::filesystem::path(arg);
}
} /* namespace boost */
#endif /* (BOOST_VERSION <= 104600) */
using namespace Fallback;
/**
* \brief Parses application command line and calls \ref Cfg::ConfigurationManager
* to parse configuration files.
*
* Results are directly written to \ref Engine class.
*
* \retval true - Everything goes OK
* \retval false - Error
*/
bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::ConfigurationManager& cfgMgr)
{
// Create a local alias for brevity
namespace bpo = boost::program_options;
typedef std::vector<std::string> StringsVector;
bpo::options_description desc("Syntax: openmw <options>\nAllowed options");
desc.add_options()
("help", "print help message")
("version", "print version information and quit")
("data", bpo::value<Files::EscapePathContainer>()->default_value(Files::EscapePathContainer(), "data")
->multitoken()->composing(), "set data directories (later directories have higher priority)")
("data-local", bpo::value<Files::EscapeHashString>()->default_value(""),
"set local data directory (highest priority)")
("fallback-archive", bpo::value<Files::EscapeStringVector>()->default_value(Files::EscapeStringVector(), "fallback-archive")
->multitoken(), "set fallback BSA archives (later archives have higher priority)")
("resources", bpo::value<Files::EscapeHashString>()->default_value("resources"),
"set resources directory")
("start", bpo::value<Files::EscapeHashString>()->default_value(""),
"set initial cell")
("content", bpo::value<Files::EscapeStringVector>()->default_value(Files::EscapeStringVector(), "")
->multitoken(), "content file(s): esm/esp, or omwgame/omwaddon")
("no-sound", bpo::value<bool>()->implicit_value(true)
->default_value(false), "disable all sounds")
("script-all", bpo::value<bool>()->implicit_value(true)
->default_value(false), "compile all scripts (excluding dialogue scripts) at startup")
("script-all-dialogue", bpo::value<bool>()->implicit_value(true)
->default_value(false), "compile all dialogue scripts at startup")
("script-console", bpo::value<bool>()->implicit_value(true)
->default_value(false), "enable console-only script functionality")
("script-run", bpo::value<Files::EscapeHashString>()->default_value(""),
"select a file containing a list of console commands that is executed on startup")
("script-warn", bpo::value<int>()->implicit_value (1)
->default_value (1),
"handling of warnings when compiling scripts\n"
"\t0 - ignore warning\n"
"\t1 - show warning but consider script as correctly compiled anyway\n"
"\t2 - treat warnings as errors")
("script-blacklist", bpo::value<Files::EscapeStringVector>()->default_value(Files::EscapeStringVector(), "")
->multitoken(), "ignore the specified script (if the use of the blacklist is enabled)")
("script-blacklist-use", bpo::value<bool>()->implicit_value(true)
->default_value(true), "enable script blacklisting")
("load-savegame", bpo::value<Files::EscapeHashString>()->default_value(""),
"load a save game file on game startup (specify an absolute filename or a filename relative to the current working directory)")
("skip-menu", bpo::value<bool>()->implicit_value(true)
->default_value(false), "skip main menu on game startup")
("new-game", bpo::value<bool>()->implicit_value(true)
->default_value(false), "run new game sequence (ignored if skip-menu=0)")
("fs-strict", bpo::value<bool>()->implicit_value(true)
->default_value(false), "strict file system handling (no case folding)")
("encoding", bpo::value<Files::EscapeHashString>()->
default_value("win1252"),
"Character encoding used in OpenMW game messages:\n"
"\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n"
"\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n"
"\n\twin1252 - Western European (Latin) alphabet, used by default")
("fallback", bpo::value<FallbackMap>()->default_value(FallbackMap(), "")
->multitoken()->composing(), "fallback values")
("no-grab", bpo::value<bool>()->implicit_value(true)->default_value(false), "Don't grab mouse cursor")
("export-fonts", bpo::value<bool>()->implicit_value(true)
->default_value(false), "Export Morrowind .fnt fonts to PNG image and XML file in current directory")
("activate-dist", bpo::value <int> ()->default_value (-1), "activation distance override");
/*
Start of tes3mp addition
Parse options added by multiplayer
*/
mwmp::Main::optionsDesc(&desc);
/*
End of tes3mp addition
*/
bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv)
.options(desc).allow_unregistered().run();
bpo::variables_map variables;
// Runtime options override settings from all configs
bpo::store(valid_opts, variables);
bpo::notify(variables);
if (variables.count ("help"))
{
std::cout << desc << std::endl;
return false;
}
if (variables.count ("version"))
{
cfgMgr.readConfiguration(variables, desc, true);
Version::Version v = Version::getOpenmwVersion(variables["resources"].as<Files::EscapeHashString>().toStdString());
std::cout << v.describe() << std::endl;
return false;
}
cfgMgr.readConfiguration(variables, desc);
Version::Version v = Version::getOpenmwVersion(variables["resources"].as<Files::EscapeHashString>().toStdString());
/*
Start of tes3mp addition
Print the multiplayer version first
*/
Utils::printVersion("TES3MP client", TES3MP_VERSION, v.mCommitHash, TES3MP_PROTO_VERSION);
/*
End of tes3mp addition
*/
/*
Start of tes3mp change (minor)
Because there is no need to print the commit hash again, only print OpenMW's version
*/
std::cout << "OpenMW version " << v.mVersion << std::endl;
/*
End of tes3mp change (minor)
*/
/*
Start of tes3mp addition
Check for unmodified tes3mp-credits file on Windows; this makes it so people can't repackage official
releases with their own made-up credits, though it obviously has no bearing on unofficial releases that
change the checksum below
*/
#ifdef _WIN32
boost::filesystem::path folderPath(boost::filesystem::initial_path<boost::filesystem::path>());
folderPath = boost::filesystem::system_complete(boost::filesystem::path(argv[0])).remove_filename();
std::string creditsPath = folderPath.string() + "/tes3mp-credits";
unsigned int expectedChecksumInt = Utils::hexStrToInt(TES3MP_CREDITS_CHECKSUM);
bool hasValidCredits = Utils::doesFileHaveChecksum(creditsPath + ".md", expectedChecksumInt);
if (!hasValidCredits)
hasValidCredits = Utils::doesFileHaveChecksum(creditsPath + ".txt", expectedChecksumInt);
if (!hasValidCredits)
{
LOG_MESSAGE_SIMPLE(Log::LOG_FATAL, "The client is shutting down");
LOG_APPEND(Log::LOG_FATAL, "- %s", TES3MP_CREDITS_ERROR);
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "tes3mp", TES3MP_CREDITS_ERROR, 0);
return false;
}
#endif
/*
End of tes3mp addition
*/
engine.setGrabMouse(!variables["no-grab"].as<bool>());
// Font encoding settings
std::string encoding(variables["encoding"].as<Files::EscapeHashString>().toStdString());
std::cout << ToUTF8::encodingUsingMessage(encoding) << std::endl;
engine.setEncoding(ToUTF8::calculateEncoding(encoding));
// directory settings
engine.enableFSStrict(variables["fs-strict"].as<bool>());
Files::PathContainer dataDirs(Files::EscapePath::toPathContainer(variables["data"].as<Files::EscapePathContainer>()));
std::string local(variables["data-local"].as<Files::EscapeHashString>().toStdString());
if (!local.empty())
{
if (local.front() == '\"')
local = local.substr(1, local.length() - 2);
dataDirs.push_back(Files::PathContainer::value_type(local));
}
cfgMgr.processPaths(dataDirs);
engine.setDataDirs(dataDirs);
// fallback archives
StringsVector archives = variables["fallback-archive"].as<Files::EscapeStringVector>().toStdStringVector();
for (StringsVector::const_iterator it = archives.begin(); it != archives.end(); ++it)
{
engine.addArchive(*it);
}
engine.setResourceDir(variables["resources"].as<Files::EscapeHashString>().toStdString());
StringsVector content = variables["content"].as<Files::EscapeStringVector>().toStdStringVector();
if (content.empty())
{
std::cout << "No content file given (esm/esp, nor omwgame/omwaddon). Aborting..." << std::endl;
return false;
}
StringsVector::const_iterator it(content.begin());
StringsVector::const_iterator end(content.end());
for (; it != end; ++it)
{
engine.addContentFile(*it);
}
// startup-settings
engine.setCell(variables["start"].as<Files::EscapeHashString>().toStdString());
engine.setSkipMenu (variables["skip-menu"].as<bool>(), variables["new-game"].as<bool>());
if (!variables["skip-menu"].as<bool>() && variables["new-game"].as<bool>())
std::cerr << "Warning: new-game used without skip-menu -> ignoring it" << std::endl;
// scripts
engine.setCompileAll(variables["script-all"].as<bool>());
engine.setCompileAllDialogue(variables["script-all-dialogue"].as<bool>());
engine.setScriptConsoleMode (variables["script-console"].as<bool>());
engine.setStartupScript (variables["script-run"].as<Files::EscapeHashString>().toStdString());
engine.setWarningsMode (variables["script-warn"].as<int>());
engine.setScriptBlacklist (variables["script-blacklist"].as<Files::EscapeStringVector>().toStdStringVector());
engine.setScriptBlacklistUse (variables["script-blacklist-use"].as<bool>());
engine.setSaveGameFile (variables["load-savegame"].as<Files::EscapeHashString>().toStdString());
// other settings
engine.setSoundUsage(!variables["no-sound"].as<bool>());
engine.setFallbackValues(variables["fallback"].as<FallbackMap>().mMap);
engine.setActivationDistanceOverride (variables["activate-dist"].as<int>());
engine.enableFontExport(variables["export-fonts"].as<bool>());
/*
Start of tes3mp addition
Configure multiplayer using parsed variables
*/
mwmp::Main::configure(&variables);
/*
End of tes3mp addition
*/
return true;
}
int runApplication(int argc, char *argv[])
{
#ifdef __APPLE__
boost::filesystem::path binary_path = boost::filesystem::system_complete(boost::filesystem::path(argv[0]));
boost::filesystem::current_path(binary_path.parent_path());
setenv("OSG_GL_TEXTURE_STORAGE", "OFF", 0);
#endif
Files::ConfigurationManager cfgMgr;
std::unique_ptr<OMW::Engine> engine;
engine.reset(new OMW::Engine(cfgMgr));
if (parseOptions(argc, argv, *engine, cfgMgr))
{
engine->go();
}
return 0;
}
#ifdef ANDROID
extern "C" int SDL_main(int argc, char**argv)
#else
int main(int argc, char**argv)
#endif
{
/*
Start of tes3mp change (major)
Instead of logging information in openmw.log, use a more descriptive filename
that includes a timestamp
*/
return wrapApplication(&runApplication, argc, argv, "/tes3mp-client-" + Log::getFilenameTimestamp() + ".log");
/*
End of tes3mp change (major)
*/
}
// Platform specific for Windows when there is no console built into the executable.
// Windows will call the WinMain function instead of main in this case, the normal
// main function is then called with the __argc and __argv parameters.
#if defined(_WIN32) && !defined(_CONSOLE)
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
return main(__argc, __argv);
}
#endif