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();
#define NETWORK_USERNAME_MAX 32
#define NETWORK_MAX_PLAYERS 20
+#define NETWORK_FRAMERATE 0.1
+#define NETWORK_BUFFERFRAMES 6
#include "addon_types.h"
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
#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;
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"
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;
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
* --------------------------------------------------
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 */
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 */
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,
.animator_data = &player_dead.animator,
.animator_size = sizeof(player_dead.animator),
+ .network_animator_exchange = player__dead_animator_exchange,
.name = "Dead"
};
}
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;
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 );
}
}
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 );
#include "network.h"
#include "network_common.h"
+#define NETWORK_SFX_QUEUE_LENGTH 12
+
struct {
struct network_player {
int active;
}
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 ];
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 );
}
}
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;
}
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 ){
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 */
}
}
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 );
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 */
}
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,
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 );
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);
.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),
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 );