/
CVS/
boards/CVS/
clans/
gmc/CVS/
help/CVS/
include/CVS/
players/
progs/CVS/
races/CVS/
system/CVS/
text/
text/CVS/
todo/
todo/CVS/
units/CVS/
// $Id: clean.pas,v 1.9 2001/05/11 14:25:02 druid Exp $

unit clean;

interface

uses
    Windows,
    Classes;

{ This is the misc. thread function, also known as the 'simple task thread'.
  This thread takes care of autosaves and autocleans,
  and serves as a watchdog for both the timer thread and the individual
  user threads. }

type GCleanThread = class(TThread)
     private
       t_log : string;

     protected
       procedure AutoSave;
       procedure SyncWrite;
       procedure SyncWritelog(s:string);
       procedure Execute; override;

     public
       constructor Create;
     end;

implementation

uses
    SysUtils,
    chars,
    conns,
    constants,
    dtypes,
    area,
    util,
    timers,
    Winsock2,
    mudthread,
    mudsystem;

constructor GCleanThread.Create;
begin
  inherited Create(false);

  SyncWritelog('Started cleanup thread.');
  SetThreadPriority(Handle, THREAD_PRIORITY_IDLE);
  freeonterminate := true;
end;

procedure GCleanThread.SyncWrite;
begin
  write_console(t_log);
end;

procedure GCleanThread.SyncWritelog(s:string);
begin
  t_log := s;
  Synchronize(SyncWrite);
end;

procedure GCleanThread.AutoSave;
var
   ch : GCharacter;
   node : GListNode;
begin
  SyncWritelog('Autosaving characters...');

  node := char_list.head;

  while (node <> nil) do
    begin
    ch := node.element;

    if (not ch.IS_NPC) then
      GPlayer(ch).save(ch.name^);

    node := node.next;
    end;
end;

// kill a non-responsive thread after 30 seconds
const
     THREAD_TIMEOUT = 0.5 / 1440.0;

procedure GCleanThread.Execute;
var
   a : integer;
   node, node_next : GListNode;
   conn : GConnection;
begin
  a := 0;
  repeat
    sleep(10000);

    inc(a);

    if (a = 15) then
      begin
      AutoSave;
      a := 0;
      end;

{$IFNDEF NOCRASHDETECTION}
    node := connection_list.head;

    while (node <> nil) do
      begin
      node_next := node.next;
      conn := node.element;

      if (GGameThread(conn.thread).last_update + THREAD_TIMEOUT < Now()) then
        begin
        bugreport('update_main', 'timers.pas', 'Thread of ' + conn.ch.name^ + ' probably died',
                  'The server has detected a malfunctioning user thread and will terminate it.');

        conn.ch.emptyBuffer;

        conn.send('Your previous command possibly triggered an illegal action on this server.'#13#10);
        conn.send('The administration has been notified, and you have been disconnected'#13#10);
        conn.send('to prevent any data loss.'#13#10);
        conn.send('Your character is linkless, and it would be wise to reconnect as soon'#13#10);
        conn.send('as possible.'#13#10);

        closesocket(conn.socket);

        conn.ch.conn := nil;

        act(AT_REPORT,'$n has lost $s link.',false,conn.ch,nil,nil,TO_ROOM);
        SET_BIT(conn.ch.flags,PLR_LINKLESS);

        conn.Free;

        TerminateThread(conn.thread.handle, 1);

        node := node_next;
        continue;
        end;
        
      node := node_next;
      end;
{$ENDIF}

    if (GTimerThread(timer_thread).last_update + THREAD_TIMEOUT < Now()) then
      begin
      bugreport('update_main', 'timers.pas', 'Timer thread probably died',
                'The server has detected that the timer is malfunctioning and will try to restart it.');

      TerminateThread(timer_thread.handle, 1);

      timer_thread := GTimerThread.Create;
      end;

    cleanChars;
    cleanObjects;
  until (Terminated);

  SyncWritelog('Simple task thread terminated.');
end;

end.