X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=player_remote.c;h=4989b078c803cf77bc185bec583cfb04c6e8204f;hb=eb28dee29482c7ffe8bc0203d302e3ee6dbfd943;hp=69f148fb8cfa2e51d2756138a6f4184532933ff1;hpb=71aba6c4108d99f39379f54b04bb71a6d2dc09b5;p=carveJwlIkooP6JGAAIwe30JlM.git diff --git a/player_remote.c b/player_remote.c index 69f148f..4989b07 100644 --- a/player_remote.c +++ b/player_remote.c @@ -1,4 +1,6 @@ #include "player_remote.h" +#include "skeleton.h" +#include "player_render.h" static void player_remote_unwatch( struct network_player *player ){ addon_cache_unwatch( k_addon_type_player, player->playermodel_view_slot ); @@ -12,6 +14,14 @@ static void player_remote_clear( struct network_player *player ){ player->subsystem = k_player_subsystem_invalid; } +static void player_remote_clear_interp( u32 index ){ + struct interp_buffer *buf = &netplayers.interp_data[ index ]; + buf->t = -99999999.9; + for( u32 i=0; iframes); i ++ ){ + buf->frames[i].active = 0; + } +} + static void player_remote_rx_200_300( SteamNetworkingMessage_t *msg ){ netmsg_blank *tmp = msg->m_pData; @@ -27,11 +37,13 @@ static void player_remote_rx_200_300( SteamNetworkingMessage_t *msg ){ /* TODO: interpret the uids */ player->board_view_slot = 0; player->playermodel_view_slot = 0; + player_remote_clear_interp( playerjoin->index ); vg_strncpy( playerjoin->username, player->username, sizeof(player->username), k_strncpy_always_add_null ); - vg_info( "#%u joined with name: %s\n", player->username ); + vg_info( "#%u joined with name: %s\n", + playerjoin->index, player->username ); } else { vg_error( "inetmsg_playerjoin: player index out of range\n" ); @@ -66,9 +78,99 @@ static void player_remote_rx_200_300( SteamNetworkingMessage_t *msg ){ vg_error( "inetmsg_playerleave: player index out of range\n" ); } } + else if( tmp->inetmsg_id == k_inetmsg_playerframe ){ + u32 datasize = msg->m_cbSize - sizeof(netmsg_playerframe); + + if( datasize > sizeof(union interp_animdata) ){ + vg_error( "Player frame data exceeds animdata size\n" ); + return; + } + + netmsg_playerframe *frame = msg->m_pData; + if( frame->client >= vg_list_size(netplayers.list) ){ + vg_error( "inetmsg_playerframe: player index out of range\n" ); + return; + } + + if( frame->subsystem >= k_player_subsystem_max ){ + vg_error( "inetmsg_playerframe: subsystem out of range\n" ); + return; + } + + struct interp_buffer *ib = &netplayers.interp_data[ frame->client ]; + struct interp_frame *dest = NULL; + + f64 min_time = INFINITY; + for( u32 i=0; iframes); i++ ){ + struct interp_frame *ifr = &ib->frames[i]; + + if( !ifr->active ){ + dest = ifr; + break; + } + + if( ifr->timestamp < min_time ){ + min_time = ifr->timestamp; + dest = ifr; + } + } + + dest->active = 1; + dest->timestamp = frame->timestamp; + dest->subsystem = frame->subsystem; + + struct network_player *player = &netplayers.list[ frame->client ]; + memcpy( &dest->data, frame->animdata, datasize ); + player->subsystem = frame->subsystem; + player->down_bytes += msg->m_cbSize; + } } -static void remote_player_network_imgui(void){ +static void remote_player_send_playerframe(void){ + u8 sysid = localplayer.subsystem; + if( sysid >= k_player_subsystem_max ) return; + + 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); + frame->inetmsg_id = k_inetmsg_playerframe; + frame->client = 0; + frame->subsystem = localplayer.subsystem; + frame->timestamp = vg.time_real; + memcpy( frame->animdata, sys->animator_data, sys->animator_size ); + + netplayers.up_bytes += size; + + SteamAPI_ISteamNetworkingSockets_SendMessageToConnection( + hSteamNetworkingSockets, network_client.remote, + frame, size, + k_nSteamNetworkingSend_Unreliable, NULL ); + } +} + +static void remote_player_debug_update(void){ + if( (vg.time_real - netplayers.last_data_measurement) > 1.0 ){ + netplayers.last_data_measurement = vg.time_real; + u32 total_down = 0; + + for( u32 i=0; iactive ){ + total_down += player->down_bytes; + player->down_kbs = ((f32)player->down_bytes)/1024.0f; + player->down_bytes = 0; + } + } + + netplayers.down_kbs = ((f32)total_down)/1024.0f; + netplayers.up_kbs = ((f32)netplayers.up_bytes)/1024.0f; + netplayers.up_bytes = 0; + } +} + +static void remote_player_network_imgui( m4x4f pv ){ if( !network_client.network_info ) return; @@ -108,17 +210,41 @@ static void remote_player_network_imgui(void){ if( network_client.state == k_ESteamNetworkingConnectionState_Connected ){ ui_info( panel, "#-1: localplayer" ); + + snprintf( buf, 512, "U%.1f/D%.1fkbs", + netplayers.up_kbs, netplayers.down_kbs ); + ui_info( panel, buf ); + for( u32 i=0; iactive ){ const char *sysname = "invalid"; - if( (player->subsystem >= 0) && - (player->subsystem < k_player_subsystem_max) ){ + if( player->subsystem < k_player_subsystem_max ){ sysname = player_subsystems[ player->subsystem ]->name; } - snprintf( buf, 512, "#%u: %s [%s]", i, player->username, sysname ); + snprintf( buf, 512, "#%u: %s [%s] D%.1fkbs", + i, player->username, sysname, player->down_kbs ); ui_info( panel, buf ); + + v4f wpos = { 0.0f, 2.0f, 0.0f, 1.0f }; + struct player_avatar *av = localplayer.playeravatar; + m4x3_mulv( netplayers.final_mtx[av->sk.bone_count*i], wpos, wpos ); + m4x4_mulv( pv, wpos, wpos ); + + if( wpos[3] > 0.0f ){ + v2_muls( wpos, (1.0f/wpos[3]) * 0.5f, wpos ); + v2_add( wpos, (v2f){ 0.5f, 0.5f }, wpos ); + + ui_rect wr; + wr[0] = vg_clampf(wpos[0] * vg.window_x, -32000.0f,32000.0f)-150; + wr[1] = vg_clampf((1.0f-wpos[1]) * vg.window_y, + -32000.0f,32000.0f); + wr[2] = 300; + wr[3] = 17; + ui_fill( wr, (ui_colour(k_ui_bg)&0x00ffffff)|0x50000000 ); + ui_text( wr, buf, 1, k_ui_align_middle_center, 0 ); + } } } } @@ -126,3 +252,88 @@ static void remote_player_network_imgui(void){ ui_info( panel, "offline" ); } } + +static void pose_remote_player( u32 index, + struct interp_frame *f0, + struct interp_frame *f1 ){ + + struct interp_buffer *buf = &netplayers.interp_data[ index ]; + struct player_avatar *av = localplayer.playeravatar; + struct skeleton *sk = &localplayer.playeravatar->sk; + m4x3f *final_mtx = &netplayers.final_mtx[ av->sk.bone_count*index ]; + + struct player_subsystem_interface *sys0 = player_subsystems[f0->subsystem], + *sys1 = NULL; + + player_pose pose0, pose1, posed; + + sys0->pose( &f0->data, &pose0 ); + + if( f1 ){ + f32 t = (buf->t - f0->timestamp) / (f1->timestamp - f0->timestamp); + t = vg_clampf( t, 0.0f, 1.0f ); + + sys1 = player_subsystems[f1->subsystem]; + sys1->pose( &f1->data, &pose1 ); + + if( pose0.type != pose1.type ){ + /* it would be nice to apply IK pass in-keyframes. TOO BAD! */ + skeleton_copy_pose( sk, pose0.keyframes, posed.keyframes ); + } + else { + skeleton_lerp_pose( sk, pose0.keyframes, pose1.keyframes, t, + posed.keyframes ); + } + + apply_full_skeleton_pose( &av->sk, &posed, final_mtx ); + } + else { + apply_full_skeleton_pose( &av->sk, &pose0, final_mtx ); + } +} + +static void animate_remote_player( u32 index ){ + + f64 min_time = 999999999.9, + max_time = -999999999.9, + abs_max_time = -999999999.9; + + struct interp_frame *minframe = NULL, + *maxframe = NULL, + *abs_max_frame = NULL; + + struct interp_buffer *buf = &netplayers.interp_data[index]; + for( u32 i=0; iframes); i ++ ){ + struct interp_frame *ifr = &buf->frames[i]; + + if( ifr->active ){ + if( (ifr->timestamp < min_time) && (ifr->timestamp > buf->t) ){ + min_time = ifr->timestamp; + minframe = ifr; + } + + if( (ifr->timestamp > max_time) && (ifr->timestamp < buf->t) ){ + max_time = ifr->timestamp; + maxframe = ifr; + } + + if( ifr->timestamp > abs_max_time ){ + abs_max_time = ifr->timestamp; + abs_max_frame = ifr; + } + } + } + + if( minframe && maxframe ){ + pose_remote_player( index, minframe, maxframe ); + buf->t += vg.time_frame_delta; + } + else { + buf->t = abs_max_time - 0.25; + + if( abs_max_frame ) + pose_remote_player( index, abs_max_frame, NULL ); + else + return; + } +}