network items, interp boundaries
[carveJwlIkooP6JGAAIwe30JlM.git] / gameserver.c
index c63711ab30883f6cfcea0d17f09e2f5b611635f7..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,21 +35,131 @@ static void set_connection_authsteamid(HSteamNetConnection con, u64_steamid id){
          hSteamNetworkingSockets, con, userdata );
 }
 
+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==ignore) || !client->active )
+         continue;
+
+      SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
+            hSteamNetworkingSockets, client->connection,
+            pData, cbData, nSendFlags, NULL );
+   }
+}
+
+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;
+
+      /* join */
+      netmsg_playerjoin init = { .inetmsg_id = k_inetmsg_playerjoin,
+                                 .index = i };
+      SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
+            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;
+
+   /* TODO: LRU */
+   for( int i=0; i<vg_list_size(gameserver.clients); i++ ){
+      if( !gameserver.clients[i].active ){
+         index = i;
+         break;
+      }
+   }
+
+   if( index == -1 ){
+      vg_error( "Server full\n" );
+      SteamAPI_ISteamNetworkingSockets_CloseConnection( 
+            hSteamNetworkingSockets, client, 
+            4500,
+            NULL, 1 );
+      return;
+   }
+
    EResult accept_status = SteamAPI_ISteamNetworkingSockets_AcceptConnection(
             hSteamNetworkingSockets, client );
-
    if( accept_status == k_EResultOK ){
-      vg_success( "Accepted client (id: %u)\n", client );
+      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;
+
       SteamAPI_ISteamNetworkingSockets_SetConnectionPollGroup(
             hSteamNetworkingSockets,
             client, gameserver.client_group );
       
       /* Just to be sure */
       set_connection_authsteamid( client, -1 );
+      gameserver_player_join( index );
    }
    else{
       vg_warn( "Error accepting client (id: %u)\n", client );
+      SteamAPI_ISteamNetworkingSockets_CloseConnection( 
+            hSteamNetworkingSockets, client, 
+            k_ESteamNetConnectionEnd_Misc_InternalError,
+            NULL, 1 );
+      gameserver.clients[index].active = 0;
+      gameserver.clients[index].connection = 0;
    }
 }
 
@@ -59,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 );
@@ -70,9 +194,27 @@ static void on_connect_status( CallbackMsg_t *msg ){
    if( info->m_info.m_eState==k_ESteamNetworkingConnectionState_Connecting ){
       new_client_connecting( info->m_hConn );
    }
+
+   if( (info->m_info.m_eState == 
+            k_ESteamNetworkingConnectionState_ClosedByPeer ) ||
+       (info->m_info.m_eState == 
+        k_ESteamNetworkingConnectionState_ProblemDetectedLocally ) ){
+
+      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 );
+      SteamAPI_ISteamNetworkingSockets_CloseConnection( 
+            hSteamNetworkingSockets, info->m_hConn, 0, NULL, 0 );
+   }
 }
 
-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 );
@@ -150,7 +292,7 @@ static int inet_require_auth( SteamNetworkingMessage_t *msg ){
 
    if( get_connection_authsteamid( msg ) == k_connection_unauthorized ){
       vg_warn( "Unauthorized request! Disconnecting client: %u\n", 
-            msg->m_conn );
+               msg->m_conn );
 
       SteamAPI_ISteamNetworkingSockets_CloseConnection(
             hSteamNetworkingSockets,
@@ -161,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;
 
@@ -215,18 +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;
-   vg_info( "... @: %.2f %.2f %.2f\n", 
-               //msg->m_identityPeer,
-               info->pos_temp[0], info->pos_temp[1], info->pos_temp[2] );
-}
+#endif
 
 static void poll_connections(void){
    SteamNetworkingMessage_t *messages[32];
@@ -251,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 );
       }