network oneshots
authorhgn <hgodden00@gmail.com>
Wed, 4 Oct 2023 08:38:31 +0000 (09:38 +0100)
committerhgn <hgodden00@gmail.com>
Wed, 4 Oct 2023 08:38:31 +0000 (09:38 +0100)
12 files changed:
network.c
network_common.h
network_msg.h
player.c
player.h
player_dead.c
player_dead.h
player_remote.c
player_remote.h
player_skate.c
player_skate.h
player_walk.c

index 3878ef2f1bc2d7ec787b04409af7f140e2dd8e11..838653c33e8208b1174aa319e2a0b1977933bfe4 100644 (file)
--- a/network.c
+++ b/network.c
@@ -379,9 +379,10 @@ static void network_update(void){
       poll_remote_connection();
       f64 frame_delta = vg.time_real - network_client.last_frame;
 
-      if( frame_delta > 0.1 ){
+      if( frame_delta > NETWORK_FRAMERATE ){
          network_client.last_frame = vg.time_real;
          remote_player_send_playerframe();
+         player__clear_sfx_buffer();
       }
 
       remote_player_debug_update();
index 988afb2cdb63e021923ea0f880dafb9f6aaefa49..ad5fb56337cd3f38e723bf21ba815d5dbff33da6 100644 (file)
@@ -6,6 +6,8 @@
 
 #define NETWORK_USERNAME_MAX 32
 #define NETWORK_MAX_PLAYERS 20
+#define NETWORK_FRAMERATE 0.1
+#define NETWORK_BUFFERFRAMES 6
 
 #include "addon_types.h"
 
index ba1fefef309bc6a62cebdb0a2ea2829277425203..c28f5b3c5607b2762574323ee189b274568f634c 100644 (file)
@@ -87,7 +87,7 @@ struct netmsg_playerframe{
    f64 timestamp;
 
    u8 client, subsystem, 
-      instance_id;
+      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 
index 78449ad1e04b2a80338948ccff385cccc4df7abb..9938de6507c7aa7963e32906424c6c32b051963c 100644 (file)
--- a/player.c
+++ b/player.c
@@ -9,6 +9,7 @@
 #include "audio.h"
 #include "player_replay.h"
 #include "network.h"
+#include "network_common.h"
 
 static int localplayer_cmd_respawn( int argc, const char *argv[] ){
    ent_spawn *rp = NULL, *r;
@@ -268,6 +269,56 @@ static void player__begin_holdout(void){
    localplayer.holdout_time = 1.0f;
 }
 
+static void net_sfx_exchange( bitpack_ctx *ctx, struct net_sfx *sfx ){
+   bitpack_bytes( ctx, 1, &sfx->system );
+   bitpack_bytes( ctx, 1, &sfx->priority );
+   bitpack_bytes( ctx, 1, &sfx->id );
+   bitpack_qf32( ctx, 8, 0.0f, 1.0f, &sfx->subframe );
+   bitpack_qf32( ctx, 8, 0.0f, 1.0f, &sfx->volume );
+   bitpack_qv3f( ctx, 16, -1024.0f, 1024.0f, sfx->location );
+}
+
+static void net_sfx_play( struct net_sfx *sfx ){
+   if( sfx->system < k_player_subsystem_max ){
+      struct player_subsystem_interface *sys = player_subsystems[sfx->system];
+      if( sys->sfx_oneshot ){
+         sys->sfx_oneshot( sfx->id, sfx->location, sfx->volume );
+      }
+   }
+};
+
+static void player__networked_sfx( u8 system, u8 priority, u8 id, 
+                                   v3f pos, f32 volume ){
+   struct net_sfx null, *sfx = &null;
+
+   if( localplayer.sfx_buffer_count < vg_list_size(localplayer.sfx_buffer) )
+      sfx = &localplayer.sfx_buffer[ localplayer.sfx_buffer_count ++ ];
+   else {
+      for( u32 i=0; i<vg_list_size(localplayer.sfx_buffer); i++ ){
+         struct net_sfx *a = &localplayer.sfx_buffer[i];
+         if( a->priority < priority ){
+            sfx = a;
+            break;
+         }
+      }
+   }
+
+   sfx->id = id;
+   sfx->priority = priority;
+   sfx->volume = volume;
+   v3_copy( pos, sfx->location );
+   sfx->system = system;
+
+   f32 t = (vg.time_real - network_client.last_frame) / NETWORK_FRAMERATE;
+   sfx->subframe = vg_clampf( t, 0.0f, 1.0f );
+
+   net_sfx_play( sfx );
+}
+
+static void player__clear_sfx_buffer(void){
+   localplayer.sfx_buffer_count = 0;
+}
+
 /* implementation */
 #include "player_common.c"
 #include "player_walk.c"
index bb870288f9ce1971ce181c42dd431d206bfcc974..6ee3112b701165ff9a401c6ed1961d140d3f4fa5 100644 (file)
--- a/player.h
+++ b/player.h
@@ -45,6 +45,7 @@ struct player_subsystem_interface{
    void(*pose)( void *animator, player_pose *pose );
    void(*post_animate)(void);
    void(*network_animator_exchange)( bitpack_ctx *ctx, void *data );
+   void(*sfx_oneshot)( u8 id, v3f pos, f32 volume );
 
    void *animator_data;
    u32 animator_size;
@@ -94,10 +95,21 @@ struct {
 
    v3f cam_land_punch, cam_land_punch_v;
    ent_gate *gate_waiting;
-   u16 boundary_hash;
-
    int immobile;
 
+   /* 
+    * Network
+    * --------------------------------------------------
+    */
+   u16 boundary_hash;
+   struct net_sfx {
+      u8 system, priority, id;
+      f32 subframe, volume;
+      v3f location;
+   }
+   sfx_buffer[4];
+   u32 sfx_buffer_count;
+
    /*
     * Animation
     * --------------------------------------------------
@@ -166,4 +178,10 @@ static void player__begin_holdout(void);
 static int localplayer_cmd_respawn( int argc, const char *argv[] );
 static void player_apply_transport_to_cam( m4x3f transport );
 
+static void player__clear_sfx_buffer(void);
+static void player__networked_sfx( u8 system, u8 priority, u8 id, 
+                                   v3f pos, f32 volume );
+static void net_sfx_exchange( bitpack_ctx *ctx, struct net_sfx *sfx );
+static void net_sfx_play( struct net_sfx *sfx );
+
 #endif /* PLAYER_H */
index 957f38d409894c2533b9a027e14e7c3fa7bf5801..8c558eeb33f1e77e12f00018f480c98aeaf50c60 100644 (file)
@@ -136,4 +136,13 @@ static void player__dead_transition(void){
    v3_copy( part->obj.rb.w,  player_dead.w_lpf );
 }
 
+static void player__dead_animator_exchange( bitpack_ctx *ctx, void *data ){
+   struct player_dead_animator *animator = data;
+
+   for( u32 i=0; i<localplayer.playeravatar->sk.bone_count; i ++ ){
+      bitpack_qv3f( ctx, 24, -1024.0f, 1024.0f, animator->transforms[i].co );
+      bitpack_qquat( ctx, animator->transforms[i].q );
+   }
+}
+
 #endif /* PLAYER_DEAD_C */
index 0c1de4133872c51800fcdf7a9b175fcf3cf796c9..19d6e5900c3eaa96cd664cf39d0746edce9e6a06 100644 (file)
@@ -25,6 +25,7 @@ static void player__dead_pose        (void *animator, player_pose *pose);
 static void player__dead_post_animate(void);
 static void player__dead_im_gui      (void);
 static void player__dead_transition  (void);
+static void player__dead_animator_exchange( bitpack_ctx *ctx, void *data );
 
 struct player_subsystem_interface static player_subsystem_dead = {
    .update = player__dead_update,
@@ -36,6 +37,7 @@ struct player_subsystem_interface static player_subsystem_dead = {
 
    .animator_data = &player_dead.animator,
    .animator_size = sizeof(player_dead.animator),
+   .network_animator_exchange = player__dead_animator_exchange,
    .name = "Dead"
 };
 
index a818be12abe42af439400a0d6d3f22b5db3e2da4..3e78d506488a3f7603c71d5b2d7b3a7c2851cc55 100644 (file)
@@ -151,29 +151,43 @@ static void player_remote_rx_200_300( SteamNetworkingMessage_t *msg ){
       }
 
       dest->active = 1;
-      dest->timestamp = frame->timestamp;
       dest->subsystem = frame->subsystem;
       dest->instance_id = frame->instance_id;
+
+      bitpack_ctx ctx = {
+         .mode = k_bitpack_decompress,
+         .buffer = frame->animdata,
+         .buffer_len = datasize,
+         .bytes = 0,
+      };
+         
+
+      /* sfx
+       * -------------------------------------------------------------*/
+      
+      for( u32 i=0; i<frame->sound_effects; i ++ ){
+         /* CHEATING for now */
+         struct net_sfx sfx;
+         net_sfx_exchange( &ctx, &sfx );
+         net_sfx_play( &sfx );
+      }
+      
+      /* animation 
+       * -------------------------------------------------------------*/
+
+      dest->timestamp = frame->timestamp;
       dest->boundary_hash = frame->boundary_hash;
 
       struct network_player *player = &netplayers.list[ frame->client ];
-
       struct player_subsystem_interface *sys = 
          player_subsystems[ frame->subsystem ];
 
       if( sys->network_animator_exchange ){
-         bitpack_ctx ctx = {
-            .mode = k_bitpack_decompress,
-            .buffer = frame->animdata,
-            .buffer_len = datasize,
-            .bytes = 0,
-         };
-         
          memset( &dest->data, 0, sys->animator_size );
          sys->network_animator_exchange( &ctx, &dest->data );
       }
       else {
-         memcpy( &dest->data, frame->animdata, datasize );
+         bitpack_bytes( &ctx, sys->animator_size, sys->animator_data );
       }
 
       player->subsystem = frame->subsystem;
@@ -236,35 +250,46 @@ static void remote_player_send_playerframe(void){
    struct player_subsystem_interface *sys = player_subsystems[sysid];
 
    if( sys->animator_size ){
-      u32 size = sizeof(netmsg_playerframe)+sys->animator_size;
-      netmsg_playerframe *frame = alloca(size);
+      u32 max_buf_size = sys->animator_size + sizeof(localplayer.sfx_buffer),
+          base_size = sizeof(struct netmsg_playerframe),
+          max_packet = base_size + max_buf_size;
+
+      netmsg_playerframe *frame = alloca( max_packet );
       frame->inetmsg_id = k_inetmsg_playerframe;
       frame->client = 0xff;
       frame->subsystem = localplayer.subsystem;
-      frame->timestamp = vg.time_real;
-      frame->boundary_hash = localplayer.boundary_hash;
       frame->instance_id = world_static.active_instance;
 
-      if( sys->network_animator_exchange ){
-         bitpack_ctx ctx = {
-            .mode = k_bitpack_compress,
-            .buffer = frame->animdata,
-            .buffer_len = sys->animator_size,
-            .bytes = 0,
-         };
-         
+      bitpack_ctx ctx = {
+         .mode = k_bitpack_compress,
+         .buffer = frame->animdata,
+         .buffer_len = max_buf_size,
+         .bytes = 0
+      };
+
+      /* sfx
+       * ---------------------------------------------*/
+
+      frame->sound_effects = localplayer.sfx_buffer_count;
+      for( u32 i=0; i<localplayer.sfx_buffer_count; i ++ )
+         net_sfx_exchange( &ctx, &localplayer.sfx_buffer[i] );
+
+      /* animation 
+       * -----------------------------------------------*/
+
+      frame->timestamp = vg.time_real;
+      frame->boundary_hash = localplayer.boundary_hash;
+      if( sys->network_animator_exchange )
          sys->network_animator_exchange( &ctx, sys->animator_data );
-         size = sizeof(netmsg_playerframe)+ctx.bytes;
-      }
-      else{
-         memcpy( frame->animdata, sys->animator_data, sys->animator_size );
-      }
+      else
+         bitpack_bytes( &ctx, sys->animator_size, sys->animator_data );
 
-      netplayers.up_bytes += size;
+      u32 wire_size = base_size + ctx.bytes;
+      netplayers.up_bytes += wire_size;
 
       SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
             hSteamNetworkingSockets, network_client.remote, 
-            frame, size,
+            frame, wire_size,
             k_nSteamNetworkingSend_Unreliable, NULL );
    }
 }
@@ -336,7 +361,7 @@ static void remote_player_network_imgui( m4x4f pv ){
    if( network_client.state == k_ESteamNetworkingConnectionState_Connected ){
       ui_info( panel, "#-1: localplayer" );
       
-      snprintf( buf, 512, "U%.1f/D%.1fkbs", 
+      snprintf( buf, 512, "U%.3f/D%.3fkbs", 
                 netplayers.up_kbs, netplayers.down_kbs );
       ui_info( panel, buf );
 
index afef269aec7ee42eb1e18c7c154a43d2458d03cc..a35e22ce1f0e897c032ab12259195dcf2927dfd6 100644 (file)
@@ -5,6 +5,8 @@
 #include "network.h"
 #include "network_common.h"
 
+#define NETWORK_SFX_QUEUE_LENGTH 12
+
 struct {
    struct network_player {
       int active;
@@ -41,12 +43,15 @@ struct {
          } 
          data;
       }
-      frames[6];
+      frames[ NETWORK_BUFFERFRAMES ];
 
       f64 t;
    }
    interp_data[ NETWORK_MAX_PLAYERS ];
 
+   struct net_sfx sfx_queue[ NETWORK_SFX_QUEUE_LENGTH ];
+   u8 sfx_availible[ NETWORK_SFX_QUEUE_LENGTH ];
+
    m4x3f *final_mtx;
    struct player_board_pose board_poses[ NETWORK_MAX_PLAYERS ];
 
index 4bad1deb30cbda0b2db1d8577a744d468467afc4..b39b016be42c4f95dd2830addbb1693d6d69731f 100644 (file)
@@ -974,11 +974,9 @@ static void skate_apply_jump_model(void){
       v3_muladds( localplayer.rb.v, jumpdir, force, localplayer.rb.v );
       state->jump_charge = 0.0f;
       state->jump_time = vg.time;
-
-      audio_lock();
-      audio_oneshot_3d( &audio_jumps[vg_randu32()%2], 
-                        localplayer.rb.co,40.0f,1.0f);
-      audio_unlock();
+      player__networked_sfx( k_player_subsystem_skate, 32, 
+                             k_player_skate_soundeffect_jump,
+                             localplayer.rb.co, 1.0f );
    }
 }
 
@@ -2039,7 +2037,11 @@ static void player__skate_update(void){
 
    if( world->water.enabled ){
       if( localplayer.rb.co[1]+0.25f < world->water.height ){
-         audio_oneshot_3d( &audio_splash, localplayer.rb.co, 40.0f, 1.0f );
+#if 0
+         player__networked_sfx( k_player_subsystem_walk, 32, 
+                                k_player_walk_soundeffect_splash,
+                                localplayer.rb.co, 1.0f );
+#endif
          player__skate_kill_audio();
          player__dead_transition();
          return;
@@ -2160,15 +2162,15 @@ static void player__skate_update(void){
    }
 
    if( (prev_contacts[0]+prev_contacts[1] == 1) && (contact_count == 2) ){
-      audio_lock();
       for( int i=0; i<2; i++ ){
          if( !prev_contacts[i] ){
             v3f co;
             m4x3_mulv( localplayer.rb.to_world, wheels[i].pos, co );
-            audio_oneshot_3d( &audio_taps[vg_randu32()%4], co, 40.0f, 0.75f );
+            player__networked_sfx( k_player_subsystem_skate, 32, 
+                                   k_player_skate_soundeffect_tap,
+                                   localplayer.rb.co, 0.75f );
          }
       }
-      audio_unlock();
    }
 
    if( contact_count ){
@@ -2558,28 +2560,30 @@ begin_collision:;
    if( stick_frames > 5 ) stick_frames =  5;
 
    if( stick_frames == 4 ){
-      audio_lock();
-
       if( state->activity == k_skate_activity_ground ){
          if( (fabsf(state->slip) > 0.75f) ){
-            audio_oneshot_3d( &audio_lands[vg_randu32()%2+3], localplayer.rb.co, 
-                              40.0f, 1.0f );
+            player__networked_sfx( k_player_subsystem_skate, 128, 
+                                   k_player_skate_soundeffect_land_bad,
+                                   localplayer.rb.co, 0.6f );
          }
          else{
-            audio_oneshot_3d( &audio_lands[vg_randu32()%3], localplayer.rb.co, 
-                              40.0f, 1.0f );
+            player__networked_sfx( k_player_subsystem_skate, 128, 
+                                   k_player_skate_soundeffect_land_good,
+                                   localplayer.rb.co, 1.0f );
          }
       }
       else if( player_skate.surface == k_surface_prop_metal ){
-         audio_oneshot_3d( &audio_board[3], localplayer.rb.co, 40.0f, 1.0f );
+         player__networked_sfx( k_player_subsystem_skate, 128, 
+                                k_player_skate_soundeffect_grind_metal,
+                                localplayer.rb.co, 1.0f );
       }
       else{
-         audio_oneshot_3d( &audio_board[8], localplayer.rb.co, 40.0f, 1.0f );
+         player__networked_sfx( k_player_subsystem_skate, 128, 
+                                k_player_skate_soundeffect_grind_wood,
+                                localplayer.rb.co, 1.0f );
       }
-
-      audio_unlock();
    } else if( stick_frames == 0 ){
-      
+      /* TODO: EXIT SOUNDS */
    }
 }
 
@@ -3190,7 +3194,7 @@ static void player__skate_reset( ent_spawn *rp ){
 static void player__skate_animator_exchange( bitpack_ctx *ctx, void *data ){
    struct player_skate_animator *animator = data;
    
-   bitpack_qv3f( ctx, 16, -1024.0f, 1024.0f, animator->root_co );
+   bitpack_qv3f( ctx, 24, -1024.0f, 1024.0f, animator->root_co );
    bitpack_qquat( ctx, animator->root_q );
 
    bitpack_qv3f( ctx, 8, -1.0f, 1.0f, animator->offset );
@@ -3236,4 +3240,29 @@ static void player__skate_animator_exchange( bitpack_ctx *ctx, void *data ){
    bitpack_qf32( ctx, 16,  0.0f, 120.0f, &animator->jump_time );
 }
 
+static void player__skate_sfx_oneshot( u8 id, v3f pos, f32 volume ){
+   audio_lock();
+
+   if( id == k_player_skate_soundeffect_jump ){
+      audio_oneshot_3d( &audio_jumps[vg_randu32()%2], pos, 40.0f, volume );
+   }
+   else if( id == k_player_skate_soundeffect_tap ){
+      audio_oneshot_3d( &audio_taps[vg_randu32()%4], pos, 40.0f, volume );
+   }
+   else if( id == k_player_skate_soundeffect_land_good ){
+      audio_oneshot_3d( &audio_lands[vg_randu32()%3], pos, 40.0f, volume );
+   }
+   else if( id == k_player_skate_soundeffect_land_bad ){
+      audio_oneshot_3d( &audio_lands[vg_randu32()%2+3], pos, 40.0f, volume );
+   }
+   else if( id == k_player_skate_soundeffect_grind_metal ){
+      audio_oneshot_3d( &audio_board[3], pos, 40.0f, volume );
+   }
+   else if( id == k_player_skate_soundeffect_grind_wood ){
+      audio_oneshot_3d( &audio_board[8], pos, 40.0f, volume );
+   }
+
+   audio_unlock();
+}
+
 #endif /* PLAYER_SKATE_C */
index e5cc42f3500988a00d78fe353f04b2e756649b7c..0f5c70cac6d6303a7e2b3704fea4afdd67984d91 100644 (file)
@@ -196,6 +196,15 @@ struct player_skate{
 }
 static player_skate;
 
+enum player_skate_soundeffect {
+   k_player_skate_soundeffect_jump,
+   k_player_skate_soundeffect_tap,
+   k_player_skate_soundeffect_land_good,
+   k_player_skate_soundeffect_land_bad,
+   k_player_skate_soundeffect_grind_metal,
+   k_player_skate_soundeffect_grind_wood,
+};
+
 static float 
    k_friction_lat          = 12.0f,
    k_friction_resistance   = 0.01f,
@@ -248,8 +257,7 @@ static float
    
    k_grind_balance         = -40.0f;
 
-static void player__skate_register(void)
-{
+static void player__skate_register(void){
    VG_VAR_F32( k_grind_dampener,       flags=VG_VAR_CHEAT );
    VG_VAR_F32( k_grind_spring,         flags=VG_VAR_CHEAT );
    VG_VAR_F32( k_grind_aligment,       flags=VG_VAR_CHEAT );
@@ -288,6 +296,7 @@ static void player__skate_pose         (void *animator, player_pose *pose);
 static void player__skate_post_animate (void);
 static void player__skate_reset        (ent_spawn *rp);
 static void player__skate_animator_exchange( bitpack_ctx *ctx, void *data );
+static void player__skate_sfx_oneshot  ( u8 id, v3f pos, f32 volume );
 
 static void player__skate_clear_mechanics(void);
 static void player__skate_reset_animator(void);
@@ -305,6 +314,7 @@ struct player_subsystem_interface static player_subsystem_skate = {
    .pose = player__skate_pose,
    .post_animate = player__skate_post_animate,
    .network_animator_exchange = player__skate_animator_exchange,
+   .sfx_oneshot = player__skate_sfx_oneshot,
 
    .animator_data = &player_skate.animator,
    .animator_size = sizeof(player_skate.animator),
index 4619c2e995f2b6334ece0fb97e411a5bf955ce9c..8b493a8e49a7c1856ab7cfeb94f824e6e19b3c47 100644 (file)
@@ -965,7 +965,7 @@ static void player__walk_reset( ent_spawn *rp ){
 static void player__walk_animator_exchange( bitpack_ctx *ctx, void *data ){
    struct player_walk_animator *animator = data;
 
-   bitpack_qv3f( ctx, 16, -1024.0f, 1024.0f, animator->root_co );
+   bitpack_qv3f( ctx, 24, -1024.0f, 1024.0f, animator->root_co );
    bitpack_qquat( ctx, animator->root_q );
    bitpack_qf32( ctx, 8, 0.0f, 1.0f, &animator->fly );
    bitpack_qf32( ctx, 8, 0.0f, 1.0f, &animator->run );