send chat messages to server
authorhgn <hgodden00@gmail.com>
Mon, 13 Nov 2023 01:04:22 +0000 (01:04 +0000)
committerhgn <hgodden00@gmail.com>
Mon, 13 Nov 2023 01:04:22 +0000 (01:04 +0000)
gameserver.c
input.h
network.c
network.h
network_common.h
network_msg.h
player_remote.c
player_remote.h
skaterift.c

index 9ac4b2f05ef3bbed94ee7e207058d11ddae88c54..3ff58f1d40936e2abea9daf5923691f8318b7571 100644 (file)
@@ -458,6 +458,19 @@ static void gameserver_rx_200_300( SteamNetworkingMessage_t *msg ){
       gameserver_send_to_all( client_id, prop, msg->m_cbSize, 
                               k_nSteamNetworkingSend_Reliable );
    }
+   else if( tmp->inetmsg_id == k_inetmsg_chat ){
+      netmsg_chat *chat = msg->m_pData,
+                  *prop = alloca( sizeof(netmsg_chat) + NETWORK_MAX_CHAT );
+      prop->inetmsg_id = k_inetmsg_chat;
+      prop->client = client_id;
+
+      u32 l = network_msgstring( chat->msg, msg->m_cbSize, sizeof(netmsg_chat),
+                                 prop->msg, NETWORK_MAX_CHAT );
+      vg_info( "[%d]: %s\n", client_id, prop->msg );
+
+      gameserver_send_to_all( client_id, prop, sizeof(netmsg_chat)+l, 
+                              k_nSteamNetworkingSend_Reliable );
+   }
    else {
       vg_warn( "Unknown inetmsg_id recieved from client. (%u)\n",
                tmp->inetmsg_id );
diff --git a/input.h b/input.h
index aa546c9bccb85804f316f1ce606152da553b98b7..ee7cbee9e5f9d5828e970998878d78c7a20ffa34 100644 (file)
--- a/input.h
+++ b/input.h
@@ -33,6 +33,7 @@ enum sr_bind{
    k_srbind_world_right,
    k_srbind_home,
    k_srbind_lobby,
+   k_srbind_chat,
    k_srbind_max,
 };
 
@@ -127,7 +128,8 @@ static const char *button_display_string( enum sr_bind button )
 [k_srbind_replay_freecam]=controller_glyph(SDL_CONTROLLER_BUTTON_Y ),
 [k_srbind_replay_resume]=controller_glyph( SDL_CONTROLLER_BUTTON_A ),
    [k_srbind_sit]     = controller_glyph( SDL_CONTROLLER_BUTTON_B ),
-    [k_srbind_lobby]  = controller_glyph( SDL_CONTROLLER_BUTTON_DPAD_LEFT )
+    [k_srbind_lobby]  = controller_glyph( SDL_CONTROLLER_BUTTON_DPAD_LEFT ),
+    [k_srbind_chat]   = ""
    };
 
    const char *keyboard_table[ k_srbind_max ] = {
@@ -153,7 +155,8 @@ static const char *button_display_string( enum sr_bind button )
 [k_srbind_replay_freecam] = KEYBOARD_GLYPH( "F" ),
 [k_srbind_replay_resume]= "\xa1",
     [k_srbind_sit]    = KEYBOARD_GLYPH( "Z" ),
-    [k_srbind_lobby] = KEYBOARD_GLYPH( "" ) // FIXME: what is tab?
+    [k_srbind_lobby] = KEYBOARD_GLYPH( "" ), // FIXME: what is tab?
+    [k_srbind_chat] = KEYBOARD_GLYPH( "Y" )
    };
 
    if( vg_input.display_input_method == k_input_method_controller )
@@ -210,10 +213,16 @@ static const char *joystick_display_string( enum sr_joystick joystick,
    else  return keyboard_table[ joystick ][axis];
 }
 
-static int buttons_filter_fixed(void)
-{
-   if( !srinput.enabled ) return 1;
-   if( vg_ui.wants_mouse ) return 1;
+static int input_filter_generic(void){
+   if( !srinput.enabled || vg_ui.wants_mouse || vg_console.enabled )
+      return 1;
+   else 
+      return 0;
+}
+
+static int buttons_filter_fixed(void){
+   if( input_filter_generic() ) 
+      return 1;
 
    if( vg.engine_stage == k_engine_stage_update_fixed )
       if( vg.fixed_iterations > 0 )
@@ -223,8 +232,7 @@ static int buttons_filter_fixed(void)
 }
 
 /* Rising edge of button */
-static int button_down( enum sr_bind button )
-{
+static int button_down( enum sr_bind button ){
    if( buttons_filter_fixed() ) return 0;
    
    if(  srinput.button_states[ button ][0] && 
@@ -235,8 +243,7 @@ static int button_down( enum sr_bind button )
 }
 
 /* Falling edge of button */
-static int button_up( enum sr_bind button )
-{
+static int button_up( enum sr_bind button ){
    if( buttons_filter_fixed() ) return 0;
    
    if( !srinput.button_states[ button ][0] && 
@@ -247,23 +254,25 @@ static int button_up( enum sr_bind button )
 }
 
 /* State of button */
-static int button_press( enum sr_bind button )
-{
-   if( vg_ui.wants_mouse ) return 0;
-   return srinput.button_states[ button ][0];
+static int button_press( enum sr_bind button ){
+   if( input_filter_generic() )
+      return 0;
+   return 
+      srinput.button_states[ button ][0];
 }
 
-static void joystick_state( enum sr_joystick joystick, v2f state )
-{
-   if( vg_ui.wants_mouse )
+static void joystick_state( enum sr_joystick joystick, v2f state ){
+   if( input_filter_generic() )
       v2_zero( state );
    else
       v2_copy( srinput.joystick_states[ joystick ][0], state );
 }
 
 static float axis_state( enum sr_axis axis ){
-   if( vg_ui.wants_mouse ) return 0.0f;
-   else return srinput.axis_states[axis][0];
+   if( input_filter_generic() )
+      return 0.0f;
+   else 
+      return srinput.axis_states[axis][0];
 }
 
 static void setbtn( enum sr_bind button, u8 value )
@@ -319,6 +328,7 @@ static void skaterift_preupdate_inputs(void)
    setbtn( k_srbind_replay_resume, vg_getkey(SDLK_SPACE) );
    setbtn( k_srbind_sit, vg_getkey(SDLK_z) );
    setbtn( k_srbind_lobby, vg_getkey(SDLK_TAB) );
+   setbtn( k_srbind_chat, vg_getkey(SDLK_y) );
 
    /* axis
     * --------------------------------------------*/
@@ -381,6 +391,7 @@ static void skaterift_preupdate_inputs(void)
       setbtn( k_srbind_replay_freecam, buttons[ SDL_CONTROLLER_BUTTON_Y ] );
       setbtn( k_srbind_sit, buttons[ SDL_CONTROLLER_BUTTON_B ] );
       setbtn( k_srbind_lobby, buttons[ SDL_CONTROLLER_BUTTON_DPAD_LEFT ] );
+      // k_srbind_chat 
 
       float *axis = controller->axises;
       float *steer = srinput.joystick_states[ k_srjoystick_steer ][0],
index 9bf240046db3c20d02ba3c44669a32223286ae31..2219a1ce8cedd8b3b8e9999ad1f3c2fcee1ca7cd 100644 (file)
--- a/network.c
+++ b/network.c
@@ -447,6 +447,40 @@ static void network_update(void){
    }
 }
 
+static void chat_send_message( const char *message ){
+   if( !network_connected() ){
+      return;
+   }
+
+   netmsg_chat *chat = alloca( sizeof(netmsg_chat) + NETWORK_MAX_CHAT );
+   chat->inetmsg_id = k_inetmsg_chat;
+   chat->client = 0;
+
+   u32 l = vg_strncpy( message, chat->msg, NETWORK_MAX_CHAT, 
+                       k_strncpy_always_add_null );
+
+   SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
+         hSteamNetworkingSockets, network_client.remote, 
+         chat, sizeof(netmsg_chat)+l+1,
+         k_nSteamNetworkingSend_Reliable, NULL );
+}
+
+static int cmd_network_send_message( int argc, const char *argv[] ){
+   char buf[ NETWORK_MAX_CHAT ];
+   vg_str str;
+   vg_strnull( &str, buf, NETWORK_MAX_CHAT );
+
+   for( int i=0; i<argc; i ++ ){
+      vg_strcat( &str, argv[i] );
+
+      if( i < argc-1 )
+         vg_strcatch( &str, ' ' );
+   }
+
+   chat_send_message( buf );
+   return 0;
+}
+
 static void network_init(void){
    vg_console_reg_var( "network_info", &network_client.network_info,
                        k_var_dtype_i32, VG_VAR_PERSISTENT );
@@ -468,6 +502,8 @@ static void network_init(void){
       steam_register_callback( k_iPersonaStateChange, 
                                on_persona_state_change );
       request_auth_ticket();
+
+      vg_console_reg_cmd( "say", cmd_network_send_message, NULL );
    }
 }
 
index 3495c6a798a997f4cacc333d427ec9049f4e479c..3b445d5639a7c4106a380a3c05b83d97624f9d7b 100644 (file)
--- a/network.h
+++ b/network.h
@@ -75,6 +75,7 @@ static void network_request_scoreboard( const char *mod_uid,
                                         u32 week, u64 userdata );
 static void network_publish_laptime( const char *mod_uid, 
                                      const char *route_uid, f64 lap_time );
+static void chat_send_message( const char *message );
 
 static int network_connected(void){
    return network_client.state == k_ESteamNetworkingConnectionState_Connected;
index d3e1ab4c1d34af217905ae24c00fb1210fd7e1f5..5191c95b43ac26fc6bc4d35e696a351a9d8aafa9 100644 (file)
@@ -9,6 +9,7 @@
 #define NETWORK_FRAMERATE 0.1
 #define NETWORK_BUFFERFRAMES 6
 #define NETWORK_LEADERBOARD_MAX_SIZE 1024
+#define NETWORK_MAX_CHAT 128
 
 #define NETWORK_LEADERBOARD_ALLTIME 0
 #define NETWORK_LEADERBOARD_CURRENT_WEEK 1
index 46aeab4115fe50ff970929e337085f7bb2e46b47..d3b49fd26e3101a6321a2a51567a5e737b0790eb 100644 (file)
@@ -46,12 +46,7 @@ struct netmsg_playerframe{
       instance_id, sound_effects;
    u16 boundary_hash; /* used for animating correctly through gates, teleport..
                          msb is a flip flop for teleporting
-                         second msb is flip flop for gate 
-
-TODO: disable oblique clipping on cam mtx when rendering remote players
-      also render over the portal stencil? somehow.
-
-      detransform, interp, retransform. render in dest world. */
+                         second msb is flip flop for gate */
 
    u8 animdata[];
 };
index c816a26d48ade3b307de9b94c1480f3992a085f9..3e2aa5b9b1cd051c44b5d93afc3d478a369d2f9e 100644 (file)
@@ -652,15 +652,12 @@ enum remote_player_gui_type {
    k_remote_player_gui_type_you,
 };
 
-/* TODO: 
- *   line of sight / distance culling
+/*
+ * Given players' root_co, get the screen point where we should draw tag info.
  */
-static void remote_player_nametag( m4x4f pv, v3f co, const char *name,
-                                   enum remote_player_gui_type type,
-                                   u32 medals[3] ){
-   vg_ui.font = &vg_ui_font_big;
+static int player_tag_position( m4x4f pv, v3f root_co, ui_point out_point ){
    v4f wpos;
-   v3_copy( co, wpos );
+   v3_copy( root_co, wpos );
    wpos[1] += 2.0f;
    wpos[3] = 1.0f;
 
@@ -669,54 +666,100 @@ static void remote_player_nametag( m4x4f pv, v3f co, const char *name,
    if( wpos[3] > 0.0f ){
       v2_muls( wpos, (1.0f/wpos[3]) * 0.5f, wpos );
       v2_add( wpos, (v2f){ 0.5f, 0.5f }, wpos );
+
+      float k_max = 32000.0f;
       
-      vg_ui.font = &vg_ui_font_big;
-      ui_rect wr;
-      wr[2] = VG_MAX( ui_text_line_width( name ), 140 ) + 8;
-      wr[0] = vg_clampf(wpos[0] * vg.window_x, -32000.0f,32000.0f)-(wr[2]/2);
-      wr[1] = vg_clampf((1.0f-wpos[1]) * vg.window_y, -32000.0f, 32000.0f );
-      wr[3] = 32;
-
-      ui_fill( wr, ui_opacity( ui_colour(k_ui_bg), 0.23f ) );
-      ui_text( wr, name, 1, k_ui_align_middle_center, 0 );
-
-      vg_ui.font = &vg_ui_font_small;
-
-      /* medals */
-      int cols = 0;
-      if( medals ){
-         for( int i=0; i<3; i ++ )
-            if( medals[i] ) 
-               cols ++;
-
-         char buf[32];
-         vg_str str;
-
-         if( cols ){
-            f32 w = (f32)wr[2] / (f32)cols;
-            cols = 0;
-
-            for( int i=0; i<3; i ++ ){
-               if( medals[i] ){
-                  ui_rect col = { wr[0] + (f32)cols*w, wr[1] + wr[3], w, 
-                                 vg_ui.font->glyph_height };
-
-                  vg_strnull( &str, buf, 32 );
-                  vg_strcatch( &str, (char)k_SRglyph_vg_circle );
-                  vg_strcati32( &str, medals[i] );
-
-                  ui_text( col, buf, 1, k_ui_align_middle_center, 
-                           ui_colour( (enum ui_scheme_colour[]){ 
-                              k_ui_yellow, k_ui_gray, k_ui_orange }[i] ) );
-                  
-                  cols ++;
-               }
-            }
+      out_point[0] = vg_clampf(wpos[0] * vg.window_x, -k_max, k_max );
+      out_point[1] = vg_clampf((1.0f-wpos[1]) * vg.window_y, -k_max, k_max );
+      return 1;
+   }
+   else
+      return 0;
+}
+
+/*
+ * Draw chat box relative to the root tag position on the screen
+ */
+static void chat_box( ui_point tag_root, f64 time, const char *message ){
+   if( (vg.time_real - time) > 15.0 ) 
+      return;
+
+   ui_rect wr;
+   wr[2] = ui_text_line_width( message ) + 8;
+   wr[3] = vg_ui.font->glyph_height + 2;
+   wr[0] = tag_root[0]-(wr[2]/2);
+   wr[1] = tag_root[1] - wr[3] - 8;
+
+   ui_fill( wr, ui_opacity( ui_colour(k_ui_bg), 0.23f ) );
+   ui_text( wr, message, 1, k_ui_align_middle_center, 0 );
+}
+
+/*
+ * Draw full imgui for remote player
+ */
+static void remote_player_nametag( ui_point tag_root, 
+                                   struct network_player *player ){
+   vg_ui.font = &vg_ui_font_big;
+
+   ui_rect wr;
+   wr[2] = VG_MAX( ui_text_line_width( player->username ), 140 ) + 8;
+   wr[3] = 32;
+   wr[0] = tag_root[0]-(wr[2]/2);
+   wr[1] = tag_root[1]-(wr[3]/2);
+
+   ui_fill( wr, ui_opacity( ui_colour(k_ui_bg), 0.23f ) );
+   ui_text( wr, player->username, 1, k_ui_align_middle_center, 0 );
+
+   vg_ui.font = &vg_ui_font_small;
+
+   /* medals */
+   int cols = 0;
+   for( int i=0; i<3; i ++ )
+      if( player->medals[i] ) 
+         cols ++;
+
+   char buf[32];
+   vg_str str;
+
+   if( cols ){
+      f32 w = (f32)wr[2] / (f32)cols;
+      cols = 0;
+
+      for( int i=0; i<3; i ++ ){
+         if( player->medals[i] ){
+            ui_rect col = { wr[0] + (f32)cols*w, wr[1] + wr[3], w, 
+                           vg_ui.font->glyph_height };
+
+            vg_strnull( &str, buf, 32 );
+            vg_strcatch( &str, (char)k_SRglyph_vg_circle );
+            vg_strcati32( &str, player->medals[i] );
+
+            ui_text( col, buf, 1, k_ui_align_middle_center, 
+                     ui_colour( (enum ui_scheme_colour[]){ 
+                        k_ui_yellow, k_ui_gray, k_ui_orange }[i] ) );
+            
+            cols ++;
          }
       }
+   }
+}
+
+static void remote_player_world_gui( m4x4f pv, v3f root_co, 
+                                     struct network_player *player  ){
+   ui_point tag_root;
+   if( !player_tag_position( pv, root_co, tag_root ) )
+      return;
 
+   if( player ){
+      remote_player_nametag( tag_root, player );
+      chat_box( tag_root, player->chat_time, player->chat );
+   }
+   else {
+      if( netplayers.chatting )
+         chat_box( tag_root, vg.time_real, netplayers.chat_buffer );
+      else
+         chat_box( tag_root, netplayers.chat_time, netplayers.chat_message );
    }
-   vg_ui.font = &vg_ui_font_small;
 }
 
 static void remote_player_gui_info( ui_rect box, 
@@ -825,11 +868,10 @@ static void remote_players_imgui_world( world_instance *world, m4x4f pv,
 
          player->opacity = vg_lerpf( player->opacity, opacity,
                                      vg.time_frame_delta * 2.0f );
-
-         remote_player_nametag( 
-               pv, 
-               netplayers.final_mtx[localplayer.skeleton.bone_count*i][3], 
-               player->username, player->isfriend, player->medals );
+         
+         remote_player_world_gui( 
+               pv, netplayers.final_mtx[localplayer.skeleton.bone_count*i][3], 
+               player );
 
          vg_ui.colour[3] = player->opacity;
          ui_flush( k_ui_shader_colour );
@@ -837,4 +879,50 @@ static void remote_players_imgui_world( world_instance *world, m4x4f pv,
    }
 
    vg_ui.colour[3] = 1.0f;
+
+   remote_player_world_gui( pv, localplayer.rb.co, NULL );
+   ui_flush( k_ui_shader_colour );
+}
+
+static void chat_escape(void){
+   netplayers.chatting = -1;
+}
+
+static void chat_enter( char *buf, u32 len ){
+   vg_strncpy( buf, netplayers.chat_message, NETWORK_MAX_CHAT, 
+               k_strncpy_always_add_null );
+   netplayers.chatting = -1;
+   netplayers.chat_time = vg.time_real;
+   chat_send_message( buf );
+}
+
+static void remote_players_chat_imgui(void){
+   if( netplayers.chatting == 1 ){
+      ui_rect box = { 0, 0, 400, 40 },
+              window = { 0, 0, vg.window_x, vg.window_y };
+      ui_rect_center( window, box );
+
+      struct ui_textbox_callbacks callbacks = {
+         .enter = chat_enter,
+         .escape = chat_escape
+      };
+
+      ui_textbox( box, NULL, 
+                  netplayers.chat_buffer, NETWORK_MAX_CHAT, 1,
+                  UI_TEXTBOX_AUTOFOCUS, &callbacks );
+   }
+   else {
+      /* TODO: we gotta fix this input fighting crap. */
+      if( netplayers.chatting == -1 ){
+         netplayers.chatting = 0;
+      }
+      else {
+         if( (skaterift.activity == k_skaterift_default) && 
+               button_down( k_srbind_chat ) ){
+            netplayers.chatting = 1;
+            netplayers.chat_buffer[0] = '\0';
+            srinput.enabled = 0;
+         }
+      }
+   }
 }
index 3e66aff776cc5891227c8b6d884e9c521a21a8ae..d29ffa387d44e6550215e70a99f88d7d5560de96 100644 (file)
@@ -22,6 +22,8 @@ struct {
       /* TODO: Compression with server code */
       char username[ NETWORK_USERNAME_MAX ];
       char items[k_netmsg_playeritem_max][ADDON_UID_MAX];
+      char chat[ NETWORK_MAX_CHAT ];
+      f64 chat_time;
 
       /* ui */
       u32 medals[3];
@@ -63,6 +65,10 @@ struct {
    u32 up_bytes;
    f32 up_kbs, down_kbs;
    f64 last_data_measurement;
+
+   int chatting;
+   char chat_buffer[ NETWORK_MAX_CHAT ], chat_message[ NETWORK_MAX_CHAT ];
+   f64 chat_time;
 }
 static netplayers;
 
index b4b5258c5f69b73b73903fdd104c409808954e54..edbfb23fa3829ab7d4b0a419f44a0306e703935f 100644 (file)
@@ -306,7 +306,9 @@ static void skaterift_change_client_world_preupdate(void);
  * ---------------------------------------------------------------------------*/
 
 static void vg_pre_update(void){
-   srinput.enabled = 1;
+   if( !netplayers.chatting ) /* FIXME */
+      srinput.enabled = 1;
+
    skaterift_preupdate_inputs();
 
    if( k_tools_mode ) return;
@@ -676,6 +678,7 @@ static void vg_gui(void){
       remote_players_imgui_lobby();
    }
    else {
+      remote_players_chat_imgui(); /* TODO: conditional */
       remote_players_imgui_world( world_current_instance(), vg.pv, 100.0f, 1 );
    }
 }