EntryPoint.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*
  2. * EntryPoint.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "CVCMIServer.h"
  12. #include "../lib/CConsoleHandler.h"
  13. #include "../lib/logging/CBasicLogConfigurator.h"
  14. #include "../lib/VCMIDirs.h"
  15. #include "../lib/VCMI_Lib.h"
  16. #ifdef VCMI_ANDROID
  17. #include <jni.h>
  18. #include <android/log.h>
  19. #include "lib/CAndroidVMHelper.h"
  20. #endif
  21. #include <boost/program_options.hpp>
  22. std::string SERVER_NAME_AFFIX = "server";
  23. std::string SERVER_NAME = GameConstants::VCMI_VERSION + std::string(" (") + SERVER_NAME_AFFIX + ')';
  24. static void handleCommandOptions(int argc, const char * argv[], boost::program_options::variables_map & options)
  25. {
  26. namespace po = boost::program_options;
  27. po::options_description opts("Allowed options");
  28. opts.add_options()
  29. ("help,h", "display help and exit")
  30. ("version,v", "display version information and exit")
  31. ("run-by-client", "indicate that server launched by client on same machine")
  32. ("port", po::value<ui16>(), "port at which server will listen to connections from client")
  33. ("lobby", "start server in lobby mode in which server connects to a global lobby");
  34. if(argc > 1)
  35. {
  36. try
  37. {
  38. po::store(po::parse_command_line(argc, argv, opts), options);
  39. }
  40. catch(boost::program_options::error & e)
  41. {
  42. std::cerr << "Failure during parsing command-line options:\n" << e.what() << std::endl;
  43. }
  44. }
  45. #ifdef SINGLE_PROCESS_APP
  46. options.emplace("run-by-client", po::variable_value{true, true});
  47. #endif
  48. po::notify(options);
  49. #ifndef SINGLE_PROCESS_APP
  50. if(options.count("help"))
  51. {
  52. auto time = std::time(nullptr);
  53. printf("%s - A Heroes of Might and Magic 3 clone\n", GameConstants::VCMI_VERSION.c_str());
  54. printf("Copyright (C) 2007-%d VCMI dev team - see AUTHORS file\n", std::localtime(&time)->tm_year + 1900);
  55. printf("This is free software; see the source for copying conditions. There is NO\n");
  56. printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
  57. printf("\n");
  58. std::cout << opts;
  59. exit(0);
  60. }
  61. if(options.count("version"))
  62. {
  63. printf("%s\n", GameConstants::VCMI_VERSION.c_str());
  64. std::cout << VCMIDirs::get().genHelpString();
  65. exit(0);
  66. }
  67. #endif
  68. }
  69. #ifdef SINGLE_PROCESS_APP
  70. #define main server_main
  71. #endif
  72. #if VCMI_ANDROID_DUAL_PROCESS
  73. void CVCMIServer::create()
  74. {
  75. const int argc = 1;
  76. const char * argv[argc] = { "android-server" };
  77. #else
  78. int main(int argc, const char * argv[])
  79. {
  80. #endif
  81. #if !defined(VCMI_ANDROID) && !defined(SINGLE_PROCESS_APP)
  82. // Correct working dir executable folder (not bundle folder) so we can use executable relative paths
  83. boost::filesystem::current_path(boost::filesystem::system_complete(argv[0]).parent_path());
  84. #endif
  85. #ifndef VCMI_IOS
  86. console = new CConsoleHandler();
  87. #endif
  88. CBasicLogConfigurator logConfig(VCMIDirs::get().userLogsPath() / "VCMI_Server_log.txt", console);
  89. logConfig.configureDefault();
  90. logGlobal->info(SERVER_NAME);
  91. boost::program_options::variables_map opts;
  92. handleCommandOptions(argc, argv, opts);
  93. preinitDLL(console, false);
  94. logConfig.configure();
  95. loadDLLClasses();
  96. srand((ui32)time(nullptr));
  97. {
  98. CVCMIServer server(opts);
  99. #ifdef SINGLE_PROCESS_APP
  100. boost::condition_variable * cond = reinterpret_cast<boost::condition_variable *>(const_cast<char *>(argv[0]));
  101. cond->notify_one();
  102. #endif
  103. server.run();
  104. // CVCMIServer destructor must be called here - before VLC cleanup
  105. }
  106. #if VCMI_ANDROID_DUAL_PROCESS
  107. CAndroidVMHelper envHelper;
  108. envHelper.callStaticVoidMethod(CAndroidVMHelper::NATIVE_METHODS_DEFAULT_CLASS, "killServer");
  109. #endif
  110. logConfig.deconfigure();
  111. vstd::clear_pointer(VLC);
  112. #if !VCMI_ANDROID_DUAL_PROCESS
  113. return 0;
  114. #endif
  115. }
  116. #if VCMI_ANDROID_DUAL_PROCESS
  117. extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_createServer(JNIEnv * env, jclass cls)
  118. {
  119. __android_log_write(ANDROID_LOG_INFO, "VCMI", "Got jni call to init server");
  120. CAndroidVMHelper::cacheVM(env);
  121. CVCMIServer::create();
  122. }
  123. extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_initClassloader(JNIEnv * baseEnv, jclass cls)
  124. {
  125. CAndroidVMHelper::initClassloader(baseEnv);
  126. }
  127. #elif defined(SINGLE_PROCESS_APP)
  128. void CVCMIServer::create(boost::condition_variable * cond, const std::vector<std::string> & args)
  129. {
  130. std::vector<const void *> argv = {cond};
  131. for(auto & a : args)
  132. argv.push_back(a.c_str());
  133. main(argv.size(), reinterpret_cast<const char **>(&*argv.begin()));
  134. }
  135. #ifdef VCMI_ANDROID
  136. void CVCMIServer::reuseClientJNIEnv(void * jniEnv)
  137. {
  138. CAndroidVMHelper::initClassloader(jniEnv);
  139. CAndroidVMHelper::alwaysUseLoadedClass = true;
  140. }
  141. #endif // VCMI_ANDROID
  142. #endif // VCMI_ANDROID_DUAL_PROCESS