@@ -14,6 +14,7 @@ import (
1414 "runtime"
1515 "strconv"
1616 "strings"
17+ "time"
1718
1819 "github.com/majormjr/rcon"
1920)
@@ -225,16 +226,60 @@ func (f *FactorioServer) checkLogError(logline []string) error {
225226}
226227
227228func (f * FactorioServer ) Stop () error {
228- // TODO: Find an alternative to os.Kill on Windows. os.Interupt
229- // is not implemented. Maps will not be saved.
230229 if runtime .GOOS == "windows" {
230+
231+ // Disable our own handling of CTRL+C, so we don't close when we send it to the console.
232+ setCtrlHandlingIsDisabledForThisProcess (true )
233+
234+ // Send CTRL+C to all processes attached to the console (ourself, and the factorio server instance)
235+ sendCtrlCToPid (0 )
236+ log .Println ("Sent SIGINT to Factorio process. Factorio shutting down..." )
237+
238+ // Somehow, the Factorio devs managed to code the game to react appropriately to CTRL+C, including
239+ // saving the game, but not actually exit. So, we still have to manually kill the process, and
240+ // for extra fun, there's no way to know when the server save has actually completed (unless we want
241+ // to inject filesystem logic into what should be a process-level Stop() routine), so our best option
242+ // is to just wait an arbitrary amount of time and hope that the save is successful in that time.
243+ time .Sleep (2 * time .Second )
244+ f .Cmd .Process .Signal (os .Kill )
245+
246+ // Re-enable handling of CTRL+C after we're sure that the factrio server is shut down.
247+ setCtrlHandlingIsDisabledForThisProcess (false )
248+
249+ f .Running = false
250+ return nil
251+ }
252+
253+ err := f .Cmd .Process .Signal (os .Interrupt )
254+ if err != nil {
255+ if err .Error () == "os: process already finished" {
256+ f .Running = false
257+ return err
258+ }
259+ log .Printf ("Error sending SIGINT to Factorio process: %s" , err )
260+ return err
261+ }
262+ f .Running = false
263+ log .Printf ("Sent SIGINT to Factorio process. Factorio shutting down..." )
264+
265+ err = f .Rcon .Close ()
266+ if err != nil {
267+ log .Printf ("Error close rcon connection: %s" , err )
268+ }
269+
270+ return nil
271+ }
272+
273+ func (f * FactorioServer ) Kill () error {
274+ if runtime .GOOS == "windows" {
275+
231276 err := f .Cmd .Process .Signal (os .Kill )
232277 if err != nil {
233278 if err .Error () == "os: process already finished" {
234279 f .Running = false
235280 return err
236281 }
237- log .Printf ("Error sending SIGKILLL to Factorio process: %s" , err )
282+ log .Printf ("Error sending SIGKILL to Factorio process: %s" , err )
238283 return err
239284 }
240285 f .Running = false
@@ -243,17 +288,17 @@ func (f *FactorioServer) Stop() error {
243288 return nil
244289 }
245290
246- err := f .Cmd .Process .Signal (os .Interrupt )
291+ err := f .Cmd .Process .Signal (os .Kill )
247292 if err != nil {
248293 if err .Error () == "os: process already finished" {
249294 f .Running = false
250295 return err
251296 }
252- log .Printf ("Error sending SIGINT to Factorio process: %s" , err )
297+ log .Printf ("Error sending SIGKILL to Factorio process: %s" , err )
253298 return err
254299 }
255300 f .Running = false
256- log .Printf ("Sent SIGINT to Factorio process. Factorio shutting down.. ." )
301+ log .Printf ("Sent SIGKILL to Factorio process. Factorio forced to exit ." )
257302
258303 err = f .Rcon .Close ()
259304 if err != nil {
@@ -262,3 +307,5 @@ func (f *FactorioServer) Stop() error {
262307
263308 return nil
264309}
310+
311+
0 commit comments