DEADSOFTWARE

net: it is now possible to use more than one master (use "List=host:port,host:port...
[d2df-sdl.git] / src / game / g_game.pas
index df45196b1e0b168175efb8de36681b85041e1888..3356c80981de79eb3f32169ebeb6aaf5403590a7 100644 (file)
@@ -2,8 +2,7 @@
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
+ * the Free Software Foundation, version 3 of the License ONLY.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -102,7 +101,7 @@ procedure g_Game_StartClient(Addr: String; Port: Word; PW: String);
 procedure g_Game_Restart();
 procedure g_Game_RestartLevel();
 procedure g_Game_RestartRound(NoMapRestart: Boolean = False);
-procedure g_Game_ClientWAD(NewWAD: String; WHash: TMD5Digest);
+procedure g_Game_ClientWAD(NewWAD: String; const WHash: TMD5Digest);
 procedure g_Game_SaveOptions();
 function  g_Game_StartMap(Map: String; Force: Boolean = False; const oldMapPath: AnsiString=''): Boolean;
 procedure g_Game_ChangeMap(const MapPath: String);
@@ -384,7 +383,7 @@ uses
   g_triggers, g_monsters, e_sound, CONFIG,
   g_language, g_net,
   ENet, e_msg, g_netmsg, g_netmaster,
-  sfs, wadreader;
+  sfs, wadreader, g_system;
 
 
 var
@@ -895,7 +894,7 @@ begin
   gDelayedEvents[n].DENum := Num;
   gDelayedEvents[n].DEStr := Str;
   if DEType = DE_GLOBEVENT then
-    gDelayedEvents[n].Time := (GetTimer() {div 1000}) + Time
+    gDelayedEvents[n].Time := (sys_GetTicks() {div 1000}) + Time
   else
     gDelayedEvents[n].Time := gTime + Time;
   Result := n;
@@ -1678,6 +1677,9 @@ begin
     Exit;
   end;
 
+  // process master server communications
+  g_Net_Slist_Pulse();
+
   case gState of
     STATE_INTERSINGLE, // Ñòàòèñòêà ïîñëå ïðîõîæäåíèÿ óðîâíÿ â Îäèíî÷íîé èãðå
     STATE_INTERCUSTOM, // Ñòàòèñòêà ïîñëå ïðîõîæäåíèÿ óðîâíÿ â Ñâîåé èãðå
@@ -2125,19 +2127,18 @@ begin
       // send unexpected platform changes
       g_Map_NetSendInterestingPanels();
 
+      g_Net_Slist_ServerUpdate();
+      {
       if NetUseMaster then
       begin
-        if gTime >= NetTimeToMaster then
+        if (gTime >= NetTimeToMaster) or g_Net_Slist_IsConnectionInProgress then
         begin
-          if (NetMHost = nil) or (NetMPeer = nil) then
-          begin
-            if not g_Net_Slist_Connect then g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_SLIST_ERROR]);
-          end;
-
+          if (not g_Net_Slist_IsConnectionActive) then g_Net_Slist_Connect(false); // non-blocking connection to the master
           g_Net_Slist_Update;
           NetTimeToMaster := gTime + NetMasterRate;
         end;
       end;
+      }
     end
     else if (NetMode = NET_CLIENT) then
     begin
@@ -2192,7 +2193,7 @@ begin
     KeyPress(IK_F10);
   end;
 
-  Time := GetTimer() {div 1000};
+  Time := sys_GetTicks() {div 1000};
 
 // Îáðàáîòêà îòëîæåííûõ ñîáûòèé:
   if gDelayedEvents <> nil then
@@ -2548,7 +2549,7 @@ var
 begin
   e_TextureFontGetSize(gStdFont, ww2, hh2);
 
-  g_ProcessMessages();
+  sys_HandleInput;
 
   if g_Console_Action(ACTION_SCORES) then
   begin
@@ -3512,7 +3513,7 @@ end;
 
 procedure DrawPlayer(p: TPlayer);
 var
-  px, py, a, b, c, d: Integer;
+  px, py, a, b, c, d, i: Integer;
   //R: TRect;
 begin
   if (p = nil) or (p.FDummy) then
@@ -3667,8 +3668,21 @@ begin
 
   renderMapInternal(-c, -d, true);
 
-  if (gGameSettings.GameMode <> GM_SINGLE) and gPlayerIndicator then
-    p.DrawIndicator();
+  if (gGameSettings.GameMode <> GM_SINGLE) and (gPlayerIndicator > 0) then
+    case gPlayerIndicator of
+      1:
+        p.DrawIndicator(_RGB(255, 255, 255));
+
+      2:
+        for i := 0 to High(gPlayers) do
+          if gPlayers[i] <> nil then
+            if gPlayers[i] = p then p.DrawIndicator(_RGB(255, 255, 255))
+            else if (gPlayers[i].Team = p.Team) and (gPlayers[i].Team <> TEAM_NONE) then
+              if gPlayerIndicatorStyle = 1 then
+                gPlayers[i].DrawIndicator(_RGB(192, 192, 192))
+              else gPlayers[i].DrawIndicator(gPlayers[i].GetColor);
+    end;
+
   if p.FSpectator then
     e_TextureFontPrintEx(p.GameX + PLAYER_RECT_CX - 4,
                          p.GameY + PLAYER_RECT_CY - 4,
@@ -3724,7 +3738,7 @@ var
 begin
   if gExit = EXIT_QUIT then Exit;
 
-  Time := GetTimer() {div 1000};
+  Time := sys_GetTicks() {div 1000};
   FPSCounter := FPSCounter+1;
   if Time - FPSTime >= 1000 then
   begin
@@ -4090,7 +4104,7 @@ begin
     g_Game_DeleteTestMap();
 
   gExit := EXIT_QUIT;
-  PushExitEvent();
+  sys_RequestQuit;
 end;
 
 procedure g_FatalError(Text: String);
@@ -4148,7 +4162,7 @@ end;
 
 procedure g_Game_ChangeResolution(newWidth, newHeight: Word; nowFull, nowMax: Boolean);
 begin
-  g_Window_SetSize(newWidth, newHeight, nowFull);
+  sys_SetDisplayMode(newWidth, newHeight, gBPP, nowFull);
 end;
 
 procedure g_Game_AddPlayer(Team: Byte = TEAM_NONE);
@@ -4184,9 +4198,7 @@ begin
       if g_Game_IsServer and g_Game_IsNet then
         MH_SEND_PlayerCreate(gPlayer1.UID);
       gPlayer1.Respawn(False, True);
-
-      if g_Game_IsNet and NetUseMaster then
-        g_Net_Slist_Update;
+      g_Net_Slist_ServerPlayerComes();
     end;
 
     Exit;
@@ -4216,9 +4228,7 @@ begin
       if g_Game_IsServer and g_Game_IsNet then
         MH_SEND_PlayerCreate(gPlayer2.UID);
       gPlayer2.Respawn(False, True);
-
-      if g_Game_IsNet and NetUseMaster then
-        g_Net_Slist_Update;
+      g_Net_Slist_ServerPlayerComes();
     end;
 
     Exit;
@@ -4241,9 +4251,7 @@ begin
       Pl.Kill(K_SIMPLEKILL, 0, HIT_DISCON);
       g_Console_Add(Format(_lc[I_PLAYER_LEAVE], [Pl.Name]), True);
       g_Player_Remove(Pl.UID);
-
-      if g_Game_IsNet and NetUseMaster then
-        g_Net_Slist_Update;
+      g_Net_Slist_ServerPlayerLeaves();
     end else
       gPlayer2 := nil;
     Exit;
@@ -4257,9 +4265,7 @@ begin
       Pl.Kill(K_SIMPLEKILL, 0, HIT_DISCON);
       g_Console_Add(Format(_lc[I_PLAYER_LEAVE], [Pl.Name]), True);
       g_Player_Remove(Pl.UID);
-
-      if g_Game_IsNet and NetUseMaster then
-        g_Net_Slist_Update;
+      g_Net_Slist_ServerPlayerLeaves();
     end else
     begin
       gPlayer1 := nil;
@@ -4267,6 +4273,7 @@ begin
     end;
     Exit;
   end;
+  g_Net_Slist_ServerPlayerLeaves();
 end;
 
 procedure g_Game_Spectate();
@@ -4460,6 +4467,7 @@ procedure g_Game_StartServer(Map: String; GameMode: Byte;
                              IPAddr: LongWord; Port: Word);
 begin
   g_Game_Free();
+  g_Net_Slist_ServerClosed();
 
   e_WriteLog('Starting net game (server)...', TMsgType.Notify);
 
@@ -4534,11 +4542,14 @@ begin
     Exit;
   end;
 
-  g_Net_Slist_Set(NetSlistIP, NetSlistPort);
+  g_Net_Slist_Set(NetSlistIP, NetSlistPort, NetSlistList);
+
+  g_Net_Slist_ServerStarted();
 
 // Çàãðóçêà è çàïóñê êàðòû:
   if not g_Game_StartMap(Map, True) then
   begin
+    g_Net_Slist_ServerClosed();
     g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Map]));
     Exit;
   end;
@@ -4550,6 +4561,7 @@ begin
       g_Map_GetPointCount(RESPAWNPOINT_RED)+
       g_Map_GetPointCount(RESPAWNPOINT_BLUE)) < 1 then
   begin
+    g_Net_Slist_ServerClosed();
     g_FatalError(_lc[I_GAME_ERROR_GET_SPAWN]);
     Exit;
   end;
@@ -4557,6 +4569,7 @@ begin
 // Íàñòðîéêè èãðîêîâ è áîòîâ:
   g_Player_Init();
 
+  g_Net_Slist_ServerMapStarted();
   NetState := NET_STATE_GAME;
 end;
 
@@ -4598,6 +4611,10 @@ begin
   NetState := NET_STATE_AUTH;
 
   g_Game_SetLoadingText(_lc[I_LOAD_CONNECT], 0, False);
+
+  // create (or update) map/resource databases
+  g_Res_CreateDatabases(true);
+
 // Ñòàðòóåì êëèåíò
   if not g_Net_Connect(Addr, Port) then
   begin
@@ -4613,13 +4630,22 @@ begin
   OuterLoop := True;
   while OuterLoop do
   begin
-    while (enet_host_service(NetHost, @NetEvent, 0) > 0) do
+    while (enet_host_service(NetHost, @NetEvent, 50) > 0) do
     begin
       if (NetEvent.kind = ENET_EVENT_TYPE_RECEIVE) then
       begin
+        if (NetEvent.channelID = NET_CHAN_DOWNLOAD_EX) then
+        begin
+          // ignore all download packets, they're processed by separate code
+          enet_packet_destroy(NetEvent.packet);
+          continue;
+        end;
         Ptr := NetEvent.packet^.data;
         if not InMsg.Init(Ptr, NetEvent.packet^.dataLength, True) then
+        begin
+          enet_packet_destroy(NetEvent.packet);
           continue;
+        end;
 
         InMsg.ReadLongWord(); // skip size
         MID := InMsg.ReadByte();
@@ -4642,11 +4668,11 @@ begin
           gGameSettings.Options := InMsg.ReadLongWord();
           T := InMsg.ReadLongWord();
 
-          newResPath := g_Res_SearchSameWAD(MapsDir, WadName, gWADHash);
-          if newResPath = '' then
+          //newResPath := g_Res_SearchSameWAD(MapsDir, WadName, gWADHash);
+          //if newResPath = '' then
           begin
-            g_Game_SetLoadingText(_lc[I_LOAD_DL_RES], 0, False);
-            newResPath := g_Res_DownloadWAD(WadName);
+            //g_Game_SetLoadingText(_lc[I_LOAD_DL_RES], 0, False);
+            newResPath := g_Res_DownloadMapWAD(WadName, gWADHash);
             if newResPath = '' then
             begin
               g_FatalError(_lc[I_NET_ERR_HASH]);
@@ -4654,6 +4680,7 @@ begin
               NetState := NET_STATE_NONE;
               Exit;
             end;
+            e_LogWritefln('using downloaded map wad [%s] for [%s]`', [newResPath, WadName], TMsgType.Notify);
           end;
           newResPath := ExtractRelativePath(MapsDir, newResPath);
 
@@ -4709,8 +4736,7 @@ begin
 
     ProcessLoading(true);
 
-    if e_KeyPressed(IK_SPACE) or e_KeyPressed(IK_ESCAPE) or e_KeyPressed(VK_ESCAPE) or
-       e_KeyPressed(JOY0_JUMP) or e_KeyPressed(JOY1_JUMP) or e_KeyPressed(JOY2_JUMP) or e_KeyPressed(JOY3_JUMP) then
+    if g_Net_UserRequestExit() then
     begin
       State := 0;
       break;
@@ -4773,6 +4799,7 @@ function g_Game_StartMap(Map: String; Force: Boolean = False; const oldMapPath:
 var
   NewWAD, ResName: String;
   I: Integer;
+  nws: AnsiString;
 begin
   g_Map_Free((Map <> gCurrentMapFileName) and (oldMapPath <> gCurrentMapFileName));
   g_Player_RemoveAllCorpses();
@@ -4796,15 +4823,25 @@ begin
     ResName := g_ExtractFileName(Map);
     if g_Game_IsServer then
     begin
-      gWADHash := MD5File(MapsDir + NewWAD);
-      g_Game_LoadWAD(NewWAD);
+      nws := findDiskWad(MapsDir+NewWAD);
+      if (length(nws) = 0) then
+      begin
+        ResName := '';
+      end
+      else
+      begin
+        if (g_Game_IsNet) then gWADHash := MD5File(nws);
+        //writeln('********: nws=', nws, ' : Map=', Map, ' : nw=', NewWAD, ' : resname=', ResName);
+        g_Game_LoadWAD(NewWAD);
+      end;
     end else
       // hash received in MC_RECV_GameEvent -> NET_EV_MAPSTART
       g_Game_ClientWAD(NewWAD, gWADHash);
   end else
     ResName := Map;
 
-  Result := g_Map_Load(MapsDir + gGameSettings.WAD + ':\' + ResName);
+  //writeln('********: gsw=', gGameSettings.WAD, '; rn=', ResName);
+  Result := (ResName <> '') and g_Map_Load(MapsDir + gGameSettings.WAD + ':\' + ResName);
   if Result then
     begin
       g_Player_ResetAll(Force or gLastMap, gGameSettings.GameType = GT_SINGLE);
@@ -4873,14 +4910,7 @@ begin
     MH_SEND_GameEvent(NET_EV_MAPSTART, gGameSettings.GameMode, Map);
 
   // Ìàñòåðñåðâåð
-    if NetUseMaster then
-    begin
-      if (NetMHost = nil) or (NetMPeer = nil) then
-        if not g_Net_Slist_Connect then
-          g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_SLIST_ERROR]);
-
-      g_Net_Slist_Update;
-    end;
+    g_Net_Slist_ServerMapStarted();
 
     if NetClients <> nil then
       for I := 0 to High(NetClients) do
@@ -4976,19 +5006,33 @@ begin
   gNextMap := Map;
 end;
 
-procedure g_Game_ClientWAD(NewWAD: String; WHash: TMD5Digest);
+procedure g_Game_ClientWAD(NewWAD: String; const WHash: TMD5Digest);
 var
-  gWAD: String;
+  gWAD, xwad: String;
 begin
-  if LowerCase(NewWAD) = LowerCase(gGameSettings.WAD) then
-    Exit;
-  if not g_Game_IsClient then
+  if not g_Game_IsClient then Exit;
+  //e_LogWritefln('*** g_Game_ClientWAD: `%s`', [NewWAD]);
+
+  gWAD := g_Res_DownloadMapWAD(ExtractFileName(NewWAD), WHash);
+  if gWAD = '' then
+  begin
+    g_Game_Free();
+    g_FatalError(Format(_lc[I_GAME_ERROR_MAP_WAD], [ExtractFileName(NewWAD)]));
     Exit;
+  end;
+
+  xwad := ExtractRelativePath(MapsDir, gWAD);
+  e_LogWritefln('using downloaded client map wad [%s] for [%s]`', [xwad, NewWAD], TMsgType.Notify);
+  NewWAD := xwad;
+  g_Game_LoadWAD(NewWAD);
+
+  {
+  if LowerCase(NewWAD) = LowerCase(gGameSettings.WAD) then Exit;
   gWAD := g_Res_SearchSameWAD(MapsDir, ExtractFileName(NewWAD), WHash);
   if gWAD = '' then
   begin
     g_Game_SetLoadingText(_lc[I_LOAD_DL_RES], 0, False);
-    gWAD := g_Res_DownloadWAD(ExtractFileName(NewWAD));
+    gWAD := g_Res_DownloadMapWAD(ExtractFileName(NewWAD), WHash);
     if gWAD = '' then
     begin
       g_Game_Free();
@@ -4998,6 +5042,7 @@ begin
   end;
   NewWAD := ExtractRelativePath(MapsDir, gWAD);
   g_Game_LoadWAD(NewWAD);
+  }
 end;
 
 procedure g_Game_RestartRound(NoMapRestart: Boolean = False);
@@ -5435,8 +5480,7 @@ begin
       NetServerName := P[1];
       if Length(NetServerName) > 64 then
         SetLength(NetServerName, 64);
-      if g_Game_IsServer and g_Game_IsNet and NetUseMaster then
-        g_Net_Slist_Update;
+      g_Net_Slist_ServerRenamed();
     end;
 
     g_Console_Add(cmd + ' = "' + NetServerName + '"');
@@ -5448,8 +5492,7 @@ begin
       NetPassword := P[1];
       if Length(NetPassword) > 24 then
         SetLength(NetPassword, 24);
-      if g_Game_IsServer and g_Game_IsNet and NetUseMaster then
-        g_Net_Slist_Update;
+      g_Net_Slist_ServerRenamed();
     end;
 
     g_Console_Add(cmd + ' = "' + AnsiLowerCase(NetPassword) + '"');
@@ -5463,6 +5506,7 @@ begin
       begin
         b := 0;
         for a := 0 to High(NetClients) do
+        begin
           if NetClients[a].Used then
           begin
             Inc(b);
@@ -5474,8 +5518,8 @@ begin
               MH_SEND_GameEvent(NET_EV_PLAYER_KICK, 0, s);
             end;
           end;
-        if NetUseMaster then
-          g_Net_Slist_Update;
+        end;
+        g_Net_Slist_ServerRenamed();
       end;
     end;
 
@@ -5486,17 +5530,7 @@ begin
     if (Length(P) > 1) then
     begin
       NetUseMaster := StrToIntDef(P[1], Byte(NetUseMaster)) > 0;
-      if g_Game_IsServer and g_Game_IsNet then
-        if NetUseMaster then
-        begin
-          if NetMPeer = nil then
-            if not g_Net_Slist_Connect() then
-              g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_SLIST_ERROR]);
-          g_Net_Slist_Update();
-        end
-        else
-          if NetMPeer <> nil then
-            g_Net_Slist_Disconnect();
+      if NetUseMaster then g_Net_Slist_Public() else g_Net_Slist_Private();
     end;
 
     g_Console_Add(cmd + ' = ' + IntToStr(Byte(NetUseMaster)));
@@ -6151,8 +6185,7 @@ begin
         enet_peer_disconnect(pl^.Peer, NET_DISC_KICK);
         g_Console_Add(Format(_lc[I_PLAYER_KICK], [s]));
         MH_SEND_GameEvent(NET_EV_PLAYER_KICK, 0, s);
-        if NetUseMaster then
-          g_Net_Slist_Update;
+        g_Net_Slist_ServerPlayerLeaves();
       end else if gPlayers <> nil then
         for a := Low(gPlayers) to High(gPlayers) do
           if gPlayers[a] <> nil then
@@ -6165,8 +6198,7 @@ begin
               gPlayers[a].Kill(K_SIMPLEKILL, 0, HIT_DISCON);
               g_Console_Add(Format(_lc[I_PLAYER_LEAVE], [gPlayers[a].Name]), True);
               g_Player_Remove(gPlayers[a].UID);
-              if NetUseMaster then
-                g_Net_Slist_Update;
+              g_Net_Slist_ServerPlayerLeaves();
               // Åñëè íå ïåðåìåøàòü, ïðè äîáàâëåíèè íîâûõ áîòîâ ïîÿâÿòñÿ ñòàðûå
               g_Bot_MixNames();
             end;
@@ -6197,8 +6229,7 @@ begin
           enet_peer_disconnect(NetClients[a].Peer, NET_DISC_KICK);
           g_Console_Add(Format(_lc[I_PLAYER_KICK], [s]));
           MH_SEND_GameEvent(NET_EV_PLAYER_KICK, 0, s);
-          if NetUseMaster then
-            g_Net_Slist_Update;
+          g_Net_Slist_ServerPlayerLeaves();
         end;
       end;
     end else
@@ -6227,8 +6258,7 @@ begin
         enet_peer_disconnect(pl^.Peer, NET_DISC_TEMPBAN);
         g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
         MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
-        if NetUseMaster then
-          g_Net_Slist_Update;
+        g_Net_Slist_ServerPlayerLeaves();
       end else
         g_Console_Add(Format(_lc[I_NET_ERR_NAME404], [P[1]]));
     end else
@@ -6258,8 +6288,7 @@ begin
           enet_peer_disconnect(NetClients[a].Peer, NET_DISC_TEMPBAN);
           g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
           MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
-          if NetUseMaster then
-            g_Net_Slist_Update;
+          g_Net_Slist_ServerPlayerLeaves();
         end;
     end else
       g_Console_Add(_lc[I_MSG_SERVERONLY]);
@@ -6288,8 +6317,7 @@ begin
         g_Net_SaveBanList();
         g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
         MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
-        if NetUseMaster then
-          g_Net_Slist_Update;
+        g_Net_Slist_ServerPlayerLeaves();
       end else
         g_Console_Add(Format(_lc[I_NET_ERR_NAME404], [P[1]]));
     end else
@@ -6320,8 +6348,7 @@ begin
           g_Net_SaveBanList();
           g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
           MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
-          if NetUseMaster then
-            g_Net_Slist_Update;
+          g_Net_Slist_ServerPlayerLeaves();
         end;
     end else
       g_Console_Add(_lc[I_MSG_SERVERONLY]);