network items, interp boundaries
[carveJwlIkooP6JGAAIwe30JlM.git] / gameserver.c
index 8db34132f61adb0ebc5386bfcbe40492cc9a25ef..c0eca6757e5958c47830097d6393a7402ef8c939 100644 (file)
@@ -17,6 +17,7 @@ static void inthandler( int signum ) {
 #include "highscores.c"
 #include "servermonitor_server.c"
 #include "vg/vg_opt.h"
+#include "network_common.h"
 
 static const u64 k_connection_unauthorized = 0xffffffffffffffff;
 
@@ -34,43 +35,86 @@ static void set_connection_authsteamid(HSteamNetConnection con, u64_steamid id){
          hSteamNetworkingSockets, con, userdata );
 }
 
-static void gameserver_player_join( int index ){
+static void gameserver_send_to_all( int ignore, 
+                                    const void *pData, u32 cbData, 
+                                    int nSendFlags ){
    for( int i=0; i<vg_list_size(gameserver.clients); i++ ){
       struct gameserver_client *client = &gameserver.clients[i];
 
-      if( (i==index) || !client->active )
+      if( (i==ignore) || !client->active )
          continue;
 
-      netmsg_playerjoin join;
-      join.inetmsg_id = k_inetmsg_playerjoin;
-      join.index = index;
-      join.board_uid[0] = '\0';
-      join.playermodel_uid[0] = '\0';
-      join.username[0] = '\0';
-
       SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
             hSteamNetworkingSockets, client->connection,
-            &join, sizeof(join), k_nSteamNetworkingSend_Reliable, NULL );
+            pData, cbData, nSendFlags, NULL );
    }
 }
 
-static void gameserver_player_leave( int index ){
+static void gameserver_player_join( int index ){
+   struct gameserver_client *joiner = &gameserver.clients[index];
+   
+   netmsg_playerjoin join = { .inetmsg_id = k_inetmsg_playerjoin,
+                              .index = index };
+   gameserver_send_to_all( index, &join, sizeof(join),
+                           k_nSteamNetworkingSend_Reliable );
+
+   /* update the joining user about current connections */
+
+   netmsg_playerusername *username = 
+      alloca( sizeof(netmsg_playerusername) + NETWORK_USERNAME_MAX );
+   username->inetmsg_id = k_inetmsg_playerusername;
+
+   netmsg_playeritem *item = 
+      alloca( sizeof(netmsg_playeritem) + ADDON_UID_MAX );
+   item->inetmsg_id = k_inetmsg_playeritem;
+
    for( int i=0; i<vg_list_size(gameserver.clients); i++ ){
       struct gameserver_client *client = &gameserver.clients[i];
 
       if( (i==index) || !client->active )
          continue;
 
-      netmsg_playerjoin leave;
-      leave.inetmsg_id = k_inetmsg_playerjoin;
-      leave.index = index;
-
+      /* join */
+      netmsg_playerjoin init = { .inetmsg_id = k_inetmsg_playerjoin,
+                                 .index = i };
       SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
-            hSteamNetworkingSockets, client->connection,
-            &leave, sizeof(leave), k_nSteamNetworkingSend_Reliable, NULL );
+            hSteamNetworkingSockets, joiner->connection,
+            &init, sizeof(init), k_nSteamNetworkingSend_Reliable, NULL );
+
+      /* username */
+      username->index = i;
+      u32 chs = vg_strncpy( client->username, username->name, 
+                            NETWORK_USERNAME_MAX,
+                            k_strncpy_always_add_null );
+      u32 size = sizeof(netmsg_playerusername) + chs + 1;
+      SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
+            hSteamNetworkingSockets, joiner->connection,
+            username, size, k_nSteamNetworkingSend_Reliable, NULL );
+
+      /* items */
+      for( int j=0; j<k_netmsg_playeritem_max; j++ ){
+         chs = vg_strncpy( client->items[j], item->uid, ADDON_UID_MAX, 
+                           k_strncpy_always_add_null );
+         item->type_index = j;
+         item->client = i;
+         size = sizeof(netmsg_playeritem) + chs + 1;
+         SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
+               hSteamNetworkingSockets, joiner->connection,
+               item, size, k_nSteamNetworkingSend_Reliable, NULL );
+      }
    }
 }
 
+static void gameserver_player_leave( int index ){
+   netmsg_playerjoin leave;
+   leave.inetmsg_id = k_inetmsg_playerleave;
+   leave.index = index;
+
+   vg_info( "Player leave (%d)\n", index );
+   gameserver_send_to_all( index, &leave, sizeof(leave),
+                           k_nSteamNetworkingSend_Reliable );
+}
+
 static void new_client_connecting( HSteamNetConnection client ){
    int index = -1;
 
@@ -95,6 +139,7 @@ static void new_client_connecting( HSteamNetConnection client ){
             hSteamNetworkingSockets, client );
    if( accept_status == k_EResultOK ){
       vg_success( "Accepted client (id: %u, index: %d)\n", client, index );
+      memset( &gameserver.clients[index], 0, sizeof(struct gameserver_client) );
 
       gameserver.clients[index].active = 1;
       gameserver.clients[index].connection = client;
@@ -125,6 +170,19 @@ static void on_auth_status( CallbackMsg_t *msg ){
    vg_info( "  %s\n", info->m_debugMsg );
 }
 
+static int gameserver_client_index( HSteamNetConnection hconn ){
+   for( int i=0; i<vg_list_size(gameserver.clients); i++ ){
+      struct gameserver_client *client = &gameserver.clients[i];
+
+      if( client->active ){
+         if( client->connection == hconn ){
+            return i;
+         }
+      }
+   }
+   return -1;
+}
+
 static void on_connect_status( CallbackMsg_t *msg ){
    SteamNetConnectionStatusChangedCallback_t *info = (void *)msg->m_pubParam;
    vg_info( "  Connection status changed for %lu\n", info->m_hConn );
@@ -142,17 +200,12 @@ static void on_connect_status( CallbackMsg_t *msg ){
        (info->m_info.m_eState == 
         k_ESteamNetworkingConnectionState_ProblemDetectedLocally ) ){
 
-      for( int i=0; i<vg_list_size(gameserver.clients); i++ ){
-         struct gameserver_client *client = &gameserver.clients[i];
-
-         if( client->active ){
-            if( client->connection == info->m_hConn ){
-               client->connection = 0;
-               client->active = 0;
-               gameserver_player_leave(i);
-               break;
-            }
-         }
+      int client_id = gameserver_client_index( info->m_hConn );
+      if( client_id != -1 ){
+         struct gameserver_client *client = &gameserver.clients[client_id];
+         client->connection = 0;
+         client->active = 0;
+         gameserver_player_leave(client_id);
       }
 
       vg_info( "End reason: %d\n", info->m_info.m_eEndReason );
@@ -161,7 +214,7 @@ static void on_connect_status( CallbackMsg_t *msg ){
    }
 }
 
-static void on_inet_auth( SteamNetworkingMessage_t *msg ){
+static void gameserver_rx_auth( SteamNetworkingMessage_t *msg ){
    if( gameserver.auth_mode != eServerModeAuthentication ){
       vg_error( "Running server without authentication. "
                 "Connection %u tried to authenticate.\n", msg->m_conn );
@@ -250,6 +303,97 @@ static int inet_require_auth( SteamNetworkingMessage_t *msg ){
    else return 1;
 }
 
+/*
+ * Player updates sent to us
+ * -----------------------------------------------------------------------------
+ */
+
+static int packet_minsize( SteamNetworkingMessage_t *msg, u32 size ){
+   if( msg->m_cbSize < size ) {
+      vg_error( "Invalid packet size (must be at least %u)\n", size );
+      return 0;
+   }
+   else{
+      return 1;
+   }
+}
+
+static void gameserver_rx_200_300( SteamNetworkingMessage_t *msg ){
+   netmsg_blank *tmp = msg->m_pData;
+
+   int client_id = gameserver_client_index( msg->m_conn );
+   if( client_id == -1 ) return;
+
+   if( tmp->inetmsg_id == k_inetmsg_playerusername ){
+      if( !packet_minsize( msg, sizeof(netmsg_playerusername)+1 ))
+         return;
+      
+      struct gameserver_client *client = &gameserver.clients[ client_id ];
+      netmsg_playerusername *src = msg->m_pData;
+
+      u32 name_len = network_msgstring( src->name, msg->m_cbSize, 
+                                        sizeof(netmsg_playerusername),
+                                        client->username, 
+                                        NETWORK_USERNAME_MAX );
+
+      /* update other users about this change */
+      netmsg_playerusername *prop = alloca(sizeof(netmsg_playerusername)+
+                                             NETWORK_USERNAME_MAX );
+                                           
+      prop->inetmsg_id = k_inetmsg_playerusername;
+      prop->index = client_id;
+      u32 chs = vg_strncpy( client->username, prop->name, NETWORK_USERNAME_MAX,
+                            k_strncpy_always_add_null );
+
+      vg_info( "client #%d changed name to: %s\n", client_id, prop->name );
+
+      u32 propsize = sizeof(netmsg_playerusername) + chs + 1;
+      gameserver_send_to_all( client_id, prop, propsize,
+                              k_nSteamNetworkingSend_Reliable );
+   }
+   else if( tmp->inetmsg_id == k_inetmsg_playerframe ){
+      /* propogate */
+      netmsg_playerframe *frame = alloca(msg->m_cbSize);
+      memcpy( frame, msg->m_pData, msg->m_cbSize );
+      frame->client = client_id;
+      gameserver_send_to_all( client_id, frame, msg->m_cbSize, 
+                              k_nSteamNetworkingSend_Unreliable );
+   }
+   else if( tmp->inetmsg_id == k_inetmsg_playeritem ){
+      netmsg_playeritem *item = msg->m_pData;
+
+      /* record */
+      struct gameserver_client *client = &gameserver.clients[ client_id ];
+
+      if( item->type_index >= k_netmsg_playeritem_max ){
+         vg_warn( "Client #%d invalid equip type %u\n", 
+                  client_id, (u32)item->type_index );
+         return;
+      }
+      
+      char *dest = client->items[ item->type_index ];
+
+      network_msgstring( item->uid, msg->m_cbSize, sizeof(netmsg_playeritem),
+                         dest, ADDON_UID_MAX );
+
+      vg_info( "Client #%d equiped: [%s] %s\n", 
+               item->client, 
+               (const char *[]){[k_netmsg_playeritem_board]="board",
+                                [k_netmsg_playeritem_player]="player",
+                                [k_netmsg_playeritem_world0]="world0",
+                                [k_netmsg_playeritem_world1]="world1"
+               }[item->type_index], item->uid );
+                           
+      /* propogate */
+      netmsg_playeritem *prop = alloca(msg->m_cbSize);
+      memcpy( prop, msg->m_pData, msg->m_cbSize );
+      prop->client = client_id;
+      gameserver_send_to_all( client_id, prop, msg->m_cbSize, 
+                              k_nSteamNetworkingSend_Reliable );
+   }
+}
+
+#if 0
 static void on_inet_score_request( SteamNetworkingMessage_t *msg ){
    if( !inet_require_auth(msg) ) return;
 
@@ -304,14 +448,7 @@ static void on_inet_set_score( SteamNetworkingMessage_t *msg ){
       highscores_push_record( &temp );
    }
 }
-
-static void on_inet_playerframe( SteamNetworkingMessage_t *msg ){
-   if( msg->m_cbSize < sizeof(netmsg_playerframe) ){
-      return;
-   }
-
-   netmsg_playerframe *info = msg->m_pData;
-}
+#endif
 
 static void poll_connections(void){
    SteamNetworkingMessage_t *messages[32];
@@ -336,20 +473,28 @@ static void poll_connections(void){
 
          netmsg_blank *tmp = msg->m_pData;
 
-         if( tmp->inetmsg_id == k_inetmsg_auth )
-            on_inet_auth( msg );
-         else if( tmp->inetmsg_id == k_inetmsg_scores_request )
-            on_inet_score_request( msg );
-         else if( tmp->inetmsg_id == k_inetmsg_set_nickname )
-            on_inet_set_nickname( msg );
-         else if( tmp->inetmsg_id == k_inetmsg_set_score )
-            on_inet_set_score( msg );
-         else if( tmp->inetmsg_id == k_inetmsg_playerframe )
-            on_inet_playerframe( msg );
-         else {
-            vg_warn( "Unknown inetmsg_id recieved from client. (%u)\n",
-                     tmp->inetmsg_id );
+         if( (tmp->inetmsg_id >= 200) && (tmp->inetmsg_id < 300) ){
+            gameserver_rx_200_300( msg );
          }
+         else{
+            if( tmp->inetmsg_id == k_inetmsg_auth )
+               gameserver_rx_auth( msg );
+#if 0
+            else if( tmp->inetmsg_id == k_inetmsg_scores_request )
+               on_inet_score_request( msg );
+            else if( tmp->inetmsg_id == k_inetmsg_set_nickname )
+               on_inet_set_nickname( msg );
+            else if( tmp->inetmsg_id == k_inetmsg_set_score )
+               on_inet_set_score( msg );
+            else if( tmp->inetmsg_id == k_inetmsg_playerframe )
+               on_inet_playerframe( msg );
+#endif
+            else {
+               vg_warn( "Unknown inetmsg_id recieved from client. (%u)\n",
+                        tmp->inetmsg_id );
+            }
+         }
+
 
          SteamAPI_SteamNetworkingMessage_t_Release( msg );
       }