DEADSOFTWARE

net: do not hiccup when the game is in progress, and master server is not available
authorKetmar Dark <ketmar@ketmar.no-ip.org>
Thu, 10 Oct 2019 09:01:53 +0000 (12:01 +0300)
committerKetmar Dark <ketmar@ketmar.no-ip.org>
Thu, 10 Oct 2019 09:04:49 +0000 (12:04 +0300)
  the game repeatedly tries to connect to master server while the match is going on, and
  the master is not available. connection routine is blocking, so the whole game freezes
  for 3 seconds once a minute. definitely not a very pleasant expirience.

  i made connection to master optionally non-blocking. the game will still hang for 3 secs
  when loading a new map (this can be changed too, but i don't think that it really matters),
  but in-game hangups should be gone.

src/game/g_game.pas
src/game/g_language.pas
src/game/g_netmaster.pas

index 0d5a73cdc2fc772cd49063dd7987c594d8d0c176..2084d8876e43323c661c78b7f741a01567defe89 100644 (file)
@@ -2130,7 +2130,7 @@ begin
         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]);
+            g_Net_Slist_Connect(false); // non-blocking connection to the master
           end;
 
           g_Net_Slist_Update;
@@ -4888,9 +4888,10 @@ begin
     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]);
-
+      begin
+        // let the connection be blocking here, why not?
+        g_Net_Slist_Connect();
+      end;
       g_Net_Slist_Update;
     end;
 
@@ -5501,9 +5502,7 @@ begin
       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]);
+          if NetMPeer = nil then g_Net_Slist_Connect();
           g_Net_Slist_Update();
         end
         else
index 951ba6ee829172e5ba7399b2866ffea8de15537e..62361f3032e970f191bac3b8d3fced8104e90a17 100644 (file)
@@ -393,6 +393,7 @@ type
     I_NET_SLIST_FETCH,
     I_NET_SLIST_RETRIEVED,
     I_NET_SLIST_CONN,
+    I_NET_SLIST_WCONN,
     I_NET_SLIST_DISC,
     I_NET_SLIST_LOST,
     I_NET_SLIST_ERROR,
@@ -1001,7 +1002,7 @@ const
     ('MENU CONTROL TOUCH',             'Touchscreen Settings',
                                        'Íàñòðîéêè ñåíñðíîãî ýêðàíà'),
     ('MENU CONTROL TOUCH ALT',         'Alternative layout:',
-                                       'Àëüòåðíàòèâíàÿ ðàñêëàäêà:'),    
+                                       'Àëüòåðíàòèâíàÿ ðàñêëàäêà:'),
     ('MENU CONTROL TOUCH FIRE',        'Shoot Up/Down:',
                                        'Ñòðåëÿòü ââåðõ/âíèç:'),
     ('MENU CONTROL TOUCH SIZE',        'Button size:',
@@ -1355,6 +1356,8 @@ const
                                        'Ïîëó÷åíî ñåðâåðîâ: %d'),
     ('NET SLIST CONN',                 'Connected to masterserver.',
                                        'Ïîäêëþ÷èëèñü ê ìàñòåðñåðâåðó.'),
+    ('NET SLIST WCONN',                'Connecting to masterserver...',
+                                       'Ïîäêëþ÷àåìñÿ ê ìàñòåðñåðâåðó...'),
     ('NET SLIST DISC',                 'Disconnected from masterserver.',
                                        'Îòêëþ÷èëèñü îò ìàñòåðñåðâåðà.'),
     ('NET SLIST LOST',                 'Lost connection with masterserver.',
index 98f191cb232a2c78e7e056409789377136856325..beada6a9377c123a784b1c935bfa559f91db4d4d 100644 (file)
@@ -54,8 +54,8 @@ type
   TNetServerTable = array of TNetServerRow;
 
 var
-  NetMHost:       pENetHost = nil;
-  NetMPeer:       pENetPeer = nil;
+  NetMHost: pENetHost = nil;
+  NetMPeer: pENetPeer = nil;
 
   slCurrent:       TNetServerList = nil;
   slTable:         TNetServerTable = nil;
@@ -69,7 +69,7 @@ procedure g_Net_Slist_Set(IP: string; Port: Word);
 function  g_Net_Slist_Fetch(var SL: TNetServerList): Boolean;
 procedure g_Net_Slist_Update();
 procedure g_Net_Slist_Remove();
-function  g_Net_Slist_Connect(): Boolean;
+function  g_Net_Slist_Connect(blocking: Boolean=True): Boolean;
 procedure g_Net_Slist_Check();
 procedure g_Net_Slist_Disconnect();
 procedure g_Net_Slist_WriteInfo();
@@ -91,6 +91,10 @@ var
   slFetched:      Boolean = False;
   slDirPressed:   Boolean = False;
   slReadUrgent:   Boolean = False;
+  // inside the game, calling `g_Net_Slist_Connect()` is disasterous, as it is blocking.
+  // so we'll use this variable to indicate if "connected" event is received.
+  NetHostConnected: Boolean = false;
+  NetHostConReqTime: Int64 = 0; // to timeout `connect`
 
 function GetTimerMS(): Int64;
 begin
@@ -382,11 +386,40 @@ end;
 
 procedure g_Net_Slist_Update;
 var
-
   P: pENetPacket;
-
+  ct: Int64;
 begin
-  if (NetMHost = nil) or (NetMPeer = nil) then Exit;
+  if (NetMHost = nil) or (NetMPeer = nil) then exit;
+
+  // we are waiting for connection
+  if (not NetHostConnected) then
+  begin
+    // check for connection packet
+    if (enet_host_service(NetMHost, @NetMEvent, 0) > 0) then
+    begin
+      if NetMEvent.kind = ENET_EVENT_TYPE_CONNECT then
+      begin
+        NetHostConnected := True;
+        g_Console_Add(_lc[I_NET_MSG] + _lc[I_NET_SLIST_CONN]);
+      end
+      else
+      begin
+        if NetMEvent.kind = ENET_EVENT_TYPE_RECEIVE then enet_packet_destroy(NetMEvent.packet);
+      end;
+    end;
+    // check for connection timeout
+    if (not NetHostConnected) then
+    begin
+      ct := GetTimerMS();
+      if (ct-NetHostConReqTime >= 3000) then
+      begin
+        // do not spam with error messages, it looks like the master is down
+        //g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_SLIST_ERROR], True);
+        g_Net_Slist_Disconnect();
+        exit;
+      end;
+    end;
+  end;
 
   NetOut.Clear();
   NetOut.Write(Byte(NET_MMSG_UPD));
@@ -405,7 +438,7 @@ procedure g_Net_Slist_Remove;
 var
   P: pENetPacket;
 begin
-  if (NetMHost = nil) or (NetMPeer = nil) then Exit;
+  if (NetMHost = nil) or (NetMPeer = nil) or (not NetHostConnected) then Exit;
   NetOut.Clear();
   NetOut.Write(Byte(NET_MMSG_DEL));
   NetOut.Write(NetAddr.port);
@@ -417,9 +450,13 @@ begin
   NetOut.Clear();
 end;
 
-function g_Net_Slist_Connect: Boolean;
+function g_Net_Slist_Connect (blocking: Boolean=True): Boolean;
+var
+  delay: Integer;
 begin
   Result := False;
+  NetHostConnected := False; // just in case
+  NetHostConReqTime := 0; // just in case
 
   NetMHost := enet_host_create(nil, 1, NET_MCHANS, 0, 0);
   if (NetMHost = nil) then
@@ -437,10 +474,12 @@ begin
     Exit;
   end;
 
-  if (enet_host_service(NetMHost, @NetMEvent, 3000) > 0) then
+  if (blocking) then delay := 3000 else delay := 0;
+  if (enet_host_service(NetMHost, @NetMEvent, delay) > 0) then
     if NetMEvent.kind = ENET_EVENT_TYPE_CONNECT then
     begin
       Result := True;
+      NetHostConnected := True;
       g_Console_Add(_lc[I_NET_MSG] + _lc[I_NET_SLIST_CONN]);
       Exit;
     end
@@ -448,10 +487,22 @@ begin
       if NetMEvent.kind = ENET_EVENT_TYPE_RECEIVE then
         enet_packet_destroy(NetMEvent.packet);
 
-  g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_SLIST_ERROR], True);
+  if (blocking) then
+  begin
+    g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_SLIST_ERROR], True);
 
-  NetMHost := nil;
-  NetMPeer := nil;
+    if NetMPeer <> nil then enet_peer_reset(NetMPeer);
+    if NetMHost <> nil then enet_host_destroy(NetMHost);
+    NetMPeer := nil;
+    NetMHost := nil;
+    NetHostConnected := False;
+    NetHostConReqTime := 0;
+  end
+  else
+  begin
+    NetHostConReqTime := GetTimerMS();
+    g_Console_Add(_lc[I_NET_MSG] + _lc[I_NET_SLIST_WCONN]);
+  end;
 end;
 
 procedure g_Net_Slist_Disconnect;
@@ -468,13 +519,15 @@ begin
 
   NetMPeer := nil;
   NetMHost := nil;
+  NetHostConnected := False;
+  NetHostConReqTime := 0;
 
   g_Console_Add(_lc[I_NET_MSG] + _lc[I_NET_SLIST_DISC]);
 end;
 
 procedure g_Net_Slist_Check;
 begin
-  if (NetMHost = nil) or (NetMPeer = nil) then Exit;
+  if (NetMHost = nil) or (NetMPeer = nil) or (not NetHostConnected) then Exit;
 
   while (enet_host_service(NetMHost, @NetMEvent, 0) > 0) do
   begin
@@ -485,6 +538,8 @@ begin
       if NetMHost <> nil then enet_host_destroy(NetMHost);
       NetMPeer := nil;
       NetMHost := nil;
+      NetHostConnected := False;
+      NetHostConReqTime := 0;
       Break;
     end
     else
@@ -784,7 +839,7 @@ begin
     Exit;
   end;
 
-  // if there's a message on the screen, 
+  // if there's a message on the screen,
   if not slReadUrgent and (slUrgent <> '') then
   begin
     if e_KeyPressed(IK_RETURN) or e_KeyPressed(IK_KPRETURN) or e_KeyPressed(VK_FIRE) or e_KeyPressed(VK_OPEN) or