1 /** 2 Copyright: Copyright (c) 2016-2018 Andrey Penechko. 3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 7 module enginestarter; 8 9 import std.file : mkdirRecurse, getcwd; 10 import std.path : buildPath; 11 import std.getopt; 12 import core.thread : Thread, thread_joinAll; 13 import voxelman.log; 14 import pluginlib; 15 import pluginlib.plugininforeader : filterEnabledPlugins; 16 import pluginlib.pluginmanager; 17 18 19 struct EngineStarter 20 { 21 enum AppType { client, server, combined } 22 23 void start(string[] args) 24 { 25 AppType appType = AppType.combined; 26 bool logToConsole; 27 std.getopt.getopt(args, 28 std.getopt.config.passThrough, 29 "app", &appType, 30 "console_log", &logToConsole); 31 32 setupLogs(appType, logToConsole); 33 scope(exit) closeBinLog(); 34 35 infof("Started from '%s'", getcwd); 36 37 final switch(appType) with(AppType) 38 { 39 case client: startClient(args); break; 40 case server: startServer(args, ServerMode.standalone); break; 41 case combined: startCombined(args); break; 42 } 43 44 waitForThreads(); 45 } 46 47 void setupLogs(AppType appType, bool logToConsole = true, string logsFolder = "../logs") 48 { 49 mkdirRecurse(logsFolder); 50 enum textFormat = ".log"; 51 enum binFormat = ".bin"; 52 53 string name; 54 final switch(appType) with(AppType) 55 { 56 case client: name = "client"; break; 57 case server: name = "server"; break; 58 case combined: name = "client"; break; 59 } 60 61 auto logger = setupMultiLogger(); 62 setupFileLogger(logger, buildPath(logsFolder, name ~ textFormat)); 63 if (logToConsole) 64 setupStdoutLogger(logger); 65 66 initBinLog(buildPath(logsFolder, name ~ binFormat)); 67 } 68 69 void startServer(string[] args, ServerMode serverMode) 70 { 71 infof("Server thread: %s", Thread.getThis.id); 72 try { 73 auto pluginman = new PluginManager; 74 foreach(p; pluginRegistry.serverPlugins.byValue.filterEnabledPlugins(args)) 75 pluginman.registerPlugin(p); 76 pluginman.initPlugins(); 77 pluginRegistry.serverMain(args, serverMode); 78 } catch(Throwable t) { 79 criticalf("Server failed with error"); 80 criticalf("%s", t); 81 } 82 } 83 84 void startClient(string[] args) 85 { 86 infof("Client thread: %s", Thread.getThis.id); 87 try { 88 auto pluginman = new PluginManager; 89 foreach(p; pluginRegistry.clientPlugins.byValue.filterEnabledPlugins(args)) 90 pluginman.registerPlugin(p); 91 pluginman.initPlugins(); 92 pluginRegistry.clientMain(args); 93 } catch(Throwable t) { 94 criticalf("Client failed with error"); 95 criticalf("%s", t); 96 } 97 } 98 99 void startCombined(string[] args) 100 { 101 import voxelman.thread.servercontrol : stopServer; 102 103 void exec() 104 { 105 startServer(args, ServerMode.internal); 106 } 107 108 Thread serverThread = new Thread(&exec); 109 serverThread.start(); 110 111 startClient(args); 112 stopServer(); 113 } 114 115 void waitForThreads() 116 { 117 thread_joinAll(); 118 infof("[Stopped]"); 119 } 120 }