1 /** 2 Copyright: Copyright (c) 2015-2018 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 voxelman.log; 10 import core.time : MonoTime, Duration, msecs, usecs, dur; 11 12 import pluginlib; 13 14 import voxelman.core.config; 15 import voxelman.core.events; 16 17 import voxelman.eventdispatcher.plugin : EventDispatcherPlugin; 18 import voxelman.command.plugin; 19 20 21 //version = manualGC; 22 version(manualGC) import core.memory; 23 24 25 class ServerPlugin : IPlugin 26 { 27 private: 28 EventDispatcherPlugin evDispatcher; 29 30 public: 31 ServerMode mode; 32 bool isRunning = false; 33 bool isAutosaveEnabled = true; 34 Duration autosavePeriod = dur!"seconds"(10); 35 MonoTime lastSaveTime; 36 37 mixin IdAndSemverFrom!"voxelman.server.plugininfo"; 38 39 override void init(IPluginManager pluginman) 40 { 41 evDispatcher = pluginman.getPlugin!EventDispatcherPlugin; 42 43 auto commandPlugin = pluginman.getPlugin!CommandPluginServer; 44 commandPlugin.registerCommand(CommandInfo("sv_stop|stop", &onStopCommand, null, "Stops the server")); 45 commandPlugin.registerCommand(CommandInfo("save", &onSaveCommand, null, "Saves the world")); 46 } 47 48 void onStopCommand(CommandParams) { isRunning = false; } 49 void onSaveCommand(CommandParams) { save(); } 50 51 void run(string[] args, ServerMode serverMode) 52 { 53 import core.thread : Thread; 54 import core.memory; 55 56 mode = serverMode; 57 58 infof("Starting game..."); 59 evDispatcher.postEvent(GameStartEvent()); 60 infof("[Running]"); 61 62 MonoTime prevTime = MonoTime.currTime; 63 enum size_t SERVER_FRAME_TIME_USECS = 1_000_000 / SERVER_UPDATES_PER_SECOND; 64 Duration frameTime = SERVER_FRAME_TIME_USECS.usecs; 65 lastSaveTime = MonoTime.currTime; 66 67 version(manualGC) GC.disable(); 68 69 // Main loop 70 isRunning = true; 71 import voxelman.thread.servercontrol : isServerRunning; 72 while (isRunning && isServerRunning()) 73 { 74 MonoTime newTime = MonoTime.currTime; 75 double delta = (newTime - prevTime).total!"usecs" / 1_000_000.0; 76 prevTime = newTime; 77 78 evDispatcher.postEvent(PreUpdateEvent(delta)); 79 evDispatcher.postEvent(UpdateEvent(delta)); 80 evDispatcher.postEvent(PostUpdateEvent(delta)); 81 autosave(MonoTime.currTime); 82 83 version(manualGC) 84 { 85 if (mode == ServerMode.standalone) 86 { 87 auto collectStartTime = MonoTime.currTime; 88 GC.collect(); 89 GC.minimize(); 90 auto collectDur = MonoTime.currTime - collectStartTime; 91 //if (collectDur > 50.msecs) 92 // infof("GC.collect() time %s", collectDur); 93 } 94 } 95 96 Duration updateTime = MonoTime.currTime - newTime; 97 Duration sleepTime = frameTime - updateTime; 98 if (sleepTime > Duration.zero) 99 Thread.sleep(sleepTime); 100 } 101 infof("Saving..."); 102 save(); 103 infof("Stopping..."); 104 evDispatcher.postEvent(GameStopEvent()); 105 } 106 107 void autosave(MonoTime now) 108 { 109 if (isAutosaveEnabled && now - lastSaveTime >= autosavePeriod) { 110 lastSaveTime = now; 111 save(); 112 } 113 } 114 115 void save() 116 { 117 evDispatcher.postEvent(WorldSaveInternalEvent()); 118 } 119 }