{$MODE OBJFPC} { -*- delphi -*- } {$INCLUDE settings.inc} program isdserver; uses {$IFDEF DEBUG} debug, {$ENDIF} sysutils, baseunix, storable, exceptions, game, refgamebits; {BOGUS Hint: Unit "refgamebits" not used in isdserver} var TheGame: TGame; Abortable: Boolean = False; const kUniverseFilename = 'universe.dat'; kTechTreeFilename = 'development.tt'; procedure SigIntHandler(Signal: Longint; Info: PSigInfo; Context: PSigContext); cdecl; begin {$IFDEF DEBUG} Writeln('caught ^C; aborting at:'); Writeln(GetStackTrace()); Writeln(); {$ENDIF} if (Abortable) then begin Assert(Assigned(TheGame)); TheGame.Aborted := True; end else begin Writeln('Not cleanly abortable at this time - halting'); Halt(1); end; end; {$IFNDEF Linux} procedure SigPipeHandler(Signal: Longint; Info: PSigInfo; Context: PSigContext); cdecl; begin {$IFDEF DEBUG} Writeln(); Writeln('caught SIGPIPE'); Writeln(GetStackTrace()); Writeln(); {$ENDIF} end; {$ENDIF} procedure HookSignalHandlers(); var NewAction: PSigActionRec; begin // this is like the only place in the entire codebase where we check for OOO... :-/ New(NewAction); if (not Assigned(NewAction)) then OutOfMemoryError(); try {$IFDEF Linux} NewAction^.sa_restorer := nil; {$ENDIF} FillByte(NewAction^.sa_mask, SizeOf(NewAction^.sa_mask), 0); // SIGINT - one-off handler NewAction^.sa_handler := @SigIntHandler; NewAction^.sa_flags := SA_ONESHOT; if (fpSigAction(SIGINT, NewAction, nil) <> 0) then raise EKernelError.Create(fpGetErrNo); {$IFNDEF Linux} // SIGPIPE - persistent handler // On Linux we use MSG_NOSIGNAL on send() instead -- see lib/corenetwork.pas NewAction^.sa_handler := @SigPipeHandler; NewAction^.sa_flags := SA_RESTART; if (fpSigAction(SIGPIPE, NewAction, nil) <> 0) then raise EKernelError.Create(fpGetErrNo); {$ENDIF} finally Dispose(NewAction); end; end; begin {$IFDEF DEBUG} SetHeapInfo('isd-server main'); {$ENDIF} Writeln('Interstellar Dynasties server'); TheGame := nil; HookSignalHandlers(); Randomize(); if (FileExists(kUniverseFilename)) then begin Writeln('Reading universe from disk...'); // XXX we should make the tech tree hot-reloadable TheGame := ReadObjectFromFile(kUniverseFilename) as TGame; end else begin Writeln('Generating new universe...'); TheGame := TGame.Create(kUniverseFilename, kTechTreeFilename); TheGame.Save(); end; Abortable := True; {$IFDEF DEBUG} SetHeapInfo('game loop'); {$ENDIF} TheGame.Run(); {$IFDEF DEBUG} SetHeapInfo('game aborted'); {$ENDIF} Writeln('Game aborted.'); Abortable := False; // otherwise, the ^C handler (if it wasn't what set Aborted to true in the first place) // might try to set TheGame.Aborted between the time we call Free below, and the time the program exits TheGame.Free(); end.