1 /** 2 Copyright: Copyright (c) 2015-2016 Andrey Penechko. 3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 7 module voxelman.server.plugin; 8 9 import std.experimental.logger; 10 import std.datetime : MonoTime, Duration, msecs, usecs, dur; 11 12 import pluginlib; 13 import pluginlib.pluginmanager; 14 15 import voxelman.core.config; 16 import voxelman.core.events; 17 18 import voxelman.eventdispatcher.plugin : EventDispatcherPlugin; 19 import voxelman.command.plugin; 20 21 22 //version = manualGC; 23 version(manualGC) import core.memory; 24 25 shared static this() 26 { 27 auto s = new ServerPlugin; 28 pluginRegistry.regServerPlugin(s); 29 pluginRegistry.regServerMain(&s.run); 30 } 31 32 struct WorldSaveInternalEvent {} 33 34 enum ServerMode 35 { 36 dedicated, 37 internal 38 } 39 40 class ServerPlugin : IPlugin 41 { 42 private: 43 PluginManager pluginman; 44 EventDispatcherPlugin evDispatcher; 45 46 public: 47 ServerMode mode; 48 bool isRunning = false; 49 bool isAutosaveEnabled = true; 50 Duration autosavePeriod = dur!"seconds"(10); 51 MonoTime lastSaveTime; 52 53 mixin IdAndSemverFrom!(voxelman.server.plugininfo); 54 55 override void init(IPluginManager pluginman) 56 { 57 evDispatcher = pluginman.getPlugin!EventDispatcherPlugin; 58 59 auto commandPlugin = pluginman.getPlugin!CommandPluginServer; 60 commandPlugin.registerCommand("sv_stop|stop", &onStopCommand); 61 commandPlugin.registerCommand("save", &onSaveCommand); 62 } 63 64 void onStopCommand(CommandParams) { isRunning = false; } 65 void onSaveCommand(CommandParams) { save(); } 66 67 void load(string[] args) 68 { 69 pluginman = new PluginManager; 70 // register all plugins and managers 71 import voxelman.pluginlib.plugininforeader : filterEnabledPlugins; 72 foreach(p; pluginRegistry.serverPlugins.byValue.filterEnabledPlugins(args)) 73 { 74 pluginman.registerPlugin(p); 75 } 76 // Actual loading sequence 77 pluginman.initPlugins(); 78 } 79 80 void run(string[] args, bool dedicated) 81 { 82 import core.thread : Thread, thread_joinAll; 83 import core.memory; 84 85 if (dedicated) 86 mode = ServerMode.dedicated; 87 else 88 mode = ServerMode.internal; 89 90 load(args); 91 infof("Starting game..."); 92 evDispatcher.postEvent(GameStartEvent()); 93 infof("[Running]"); 94 95 MonoTime prevTime = MonoTime.currTime; 96 Duration frameTime = SERVER_FRAME_TIME_USECS.usecs; 97 lastSaveTime = MonoTime.currTime; 98 99 version(manualGC) GC.disable(); 100 101 // Main loop 102 isRunning = true; 103 import voxelman.client.servercontrol : isServerRunning; 104 while (isRunning && isServerRunning()) 105 { 106 MonoTime newTime = MonoTime.currTime; 107 double delta = (newTime - prevTime).total!"usecs" / 1_000_000.0; 108 prevTime = newTime; 109 110 evDispatcher.postEvent(PreUpdateEvent(delta)); 111 evDispatcher.postEvent(UpdateEvent(delta)); 112 evDispatcher.postEvent(PostUpdateEvent(delta)); 113 autosave(MonoTime.currTime); 114 115 version(manualGC) 116 { 117 auto collectStartTime = MonoTime.currTime; 118 GC.collect(); 119 GC.minimize(); 120 auto collectDur = MonoTime.currTime - collectStartTime; 121 //if (collectDur > 50.msecs) 122 // infof("GC.collect() time %s", collectDur); 123 } 124 125 Duration updateTime = MonoTime.currTime - newTime; 126 Duration sleepTime = frameTime - updateTime; 127 if (sleepTime > Duration.zero) 128 Thread.sleep(sleepTime); 129 } 130 infof("Saving..."); 131 save(); 132 infof("Stopping..."); 133 evDispatcher.postEvent(GameStopEvent()); 134 135 if (mode == ServerMode.dedicated) 136 { 137 thread_joinAll(); 138 } 139 infof("[Stopped]"); 140 } 141 142 void autosave(MonoTime now) 143 { 144 if (isAutosaveEnabled && now - lastSaveTime >= autosavePeriod) { 145 lastSaveTime = now; 146 save(); 147 } 148 } 149 150 void save() 151 { 152 evDispatcher.postEvent(WorldSaveInternalEvent()); 153 } 154 }