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 class ServerPlugin : IPlugin 35 { 36 private: 37 PluginManager pluginman; 38 EventDispatcherPlugin evDispatcher; 39 40 public: 41 bool isRunning = false; 42 bool isAutosaveEnabled = true; 43 Duration autosavePeriod = dur!"seconds"(10); 44 MonoTime lastSaveTime; 45 46 mixin IdAndSemverFrom!(voxelman.server.plugininfo); 47 48 override void init(IPluginManager pluginman) 49 { 50 evDispatcher = pluginman.getPlugin!EventDispatcherPlugin; 51 52 auto commandPlugin = pluginman.getPlugin!CommandPluginServer; 53 commandPlugin.registerCommand("sv_stop|stop", &onStopCommand); 54 commandPlugin.registerCommand("save", &onSaveCommand); 55 } 56 57 void onStopCommand(CommandParams) { isRunning = false; } 58 void onSaveCommand(CommandParams) { save(); } 59 60 void load(string[] args) 61 { 62 pluginman = new PluginManager; 63 // register all plugins and managers 64 import voxelman.pluginlib.plugininforeader : filterEnabledPlugins; 65 foreach(p; pluginRegistry.serverPlugins.byValue.filterEnabledPlugins(args)) 66 { 67 pluginman.registerPlugin(p); 68 } 69 // Actual loading sequence 70 pluginman.initPlugins(); 71 } 72 73 void run(string[] args) 74 { 75 import core.thread : Thread, thread_joinAll; 76 import core.memory; 77 78 load(args); 79 infof("Starting game..."); 80 evDispatcher.postEvent(GameStartEvent()); 81 infof("[Running]"); 82 83 MonoTime prevTime = MonoTime.currTime; 84 Duration frameTime = SERVER_FRAME_TIME_USECS.usecs; 85 lastSaveTime = MonoTime.currTime; 86 87 version(manualGC) GC.disable(); 88 89 // Main loop 90 isRunning = true; 91 while (isRunning) 92 { 93 MonoTime newTime = MonoTime.currTime; 94 double delta = (newTime - prevTime).total!"usecs" / 1_000_000.0; 95 prevTime = newTime; 96 97 evDispatcher.postEvent(PreUpdateEvent(delta)); 98 evDispatcher.postEvent(UpdateEvent(delta)); 99 evDispatcher.postEvent(PostUpdateEvent(delta)); 100 autosave(MonoTime.currTime); 101 102 version(manualGC) 103 { 104 auto collectStartTime = MonoTime.currTime; 105 GC.collect(); 106 GC.minimize(); 107 auto collectDur = MonoTime.currTime - collectStartTime; 108 //if (collectDur > 50.msecs) 109 // infof("GC.collect() time %s", collectDur); 110 } 111 112 Duration updateTime = MonoTime.currTime - newTime; 113 Duration sleepTime = frameTime - updateTime; 114 if (sleepTime > Duration.zero) 115 Thread.sleep(sleepTime); 116 } 117 infof("Saving..."); 118 save(); 119 infof("Stopping..."); 120 evDispatcher.postEvent(GameStopEvent()); 121 thread_joinAll(); 122 infof("[Stopped]"); 123 } 124 125 void autosave(MonoTime now) 126 { 127 if (isAutosaveEnabled && now - lastSaveTime >= autosavePeriod) { 128 lastSaveTime = now; 129 save(); 130 } 131 } 132 133 void save() 134 { 135 evDispatcher.postEvent(WorldSaveInternalEvent()); 136 } 137 }