working? interpolation
[carveJwlIkooP6JGAAIwe30JlM.git] / player_remote.c
1 #include "player_remote.h"
2 #include "skeleton.h"
3 #include "player_render.h"
4
5 static void player_remote_unwatch( struct network_player *player ){
6 addon_cache_unwatch( k_addon_type_player, player->playermodel_view_slot );
7 addon_cache_unwatch( k_addon_type_board, player->board_view_slot );
8 }
9
10 static void player_remote_clear( struct network_player *player ){
11 player_remote_unwatch( player );
12 memset( player, 0, sizeof(*player) );
13 strcpy( player->username, "unknown" );
14 player->subsystem = k_player_subsystem_invalid;
15 }
16
17 static void player_remote_clear_interp( u32 index ){
18 struct interp_buffer *buf = &netplayers.interp_data[ index ];
19 buf->t = -99999999.9;
20 for( u32 i=0; i<vg_list_size(buf->frames); i ++ ){
21 buf->frames[i].active = 0;
22 }
23 }
24
25 static void player_remote_rx_200_300( SteamNetworkingMessage_t *msg ){
26 netmsg_blank *tmp = msg->m_pData;
27
28 if( tmp->inetmsg_id == k_inetmsg_playerjoin ){
29 netmsg_playerjoin *playerjoin = msg->m_pData;
30 if( !packet_minsize( msg, sizeof(*playerjoin) )) return;
31
32 if( playerjoin->index < vg_list_size(netplayers.list) ){
33 struct network_player *player = &netplayers.list[ playerjoin->index ];
34 player_remote_clear( player );
35 player->active = 1;
36
37 /* TODO: interpret the uids */
38 player->board_view_slot = 0;
39 player->playermodel_view_slot = 0;
40 player_remote_clear_interp( playerjoin->index );
41
42 vg_strncpy( playerjoin->username, player->username,
43 sizeof(player->username), k_strncpy_always_add_null );
44
45 vg_info( "#%u joined with name: %s\n",
46 playerjoin->index, player->username );
47 }
48 else {
49 vg_error( "inetmsg_playerjoin: player index out of range\n" );
50 }
51 }
52 else if( tmp->inetmsg_id == k_inetmsg_playerleave ){
53 netmsg_playerleave *playerleave = msg->m_pData;
54 if( !packet_minsize( msg, sizeof(*playerleave) )) return;
55
56 if( playerleave->index < vg_list_size(netplayers.list) ){
57 struct network_player *player = &netplayers.list[ playerleave->index ];
58 player_remote_unwatch( player );
59 player->active = 0;
60 vg_info( "player leave (%d)\n", playerleave->index );
61 }
62 else {
63 vg_error( "inetmsg_playerleave: player index out of range\n" );
64 }
65 }
66 else if( tmp->inetmsg_id == k_inetmsg_playerusername ){
67 netmsg_playerusername *update = msg->m_pData;
68 if( !packet_minsize( msg, sizeof(*update) )) return;
69
70 if( update->index < vg_list_size(netplayers.list) ){
71 struct network_player *player = &netplayers.list[ update->index ];
72 vg_strncpy( update->username, player->username,
73 sizeof(player->username), k_strncpy_always_add_null );
74
75 vg_info( "#%u changed username: %s\n", player->username );
76 }
77 else {
78 vg_error( "inetmsg_playerleave: player index out of range\n" );
79 }
80 }
81 else if( tmp->inetmsg_id == k_inetmsg_playerframe ){
82 u32 datasize = msg->m_cbSize - sizeof(netmsg_playerframe);
83
84 if( datasize > sizeof(union interp_animdata) ){
85 vg_error( "Player frame data exceeds animdata size\n" );
86 return;
87 }
88
89 netmsg_playerframe *frame = msg->m_pData;
90 if( frame->client >= vg_list_size(netplayers.list) ){
91 vg_error( "inetmsg_playerframe: player index out of range\n" );
92 return;
93 }
94
95 if( frame->subsystem >= k_player_subsystem_max ){
96 vg_error( "inetmsg_playerframe: subsystem out of range\n" );
97 return;
98 }
99
100 struct interp_buffer *ib = &netplayers.interp_data[ frame->client ];
101 struct interp_frame *dest = NULL;
102
103 f64 min_time = INFINITY;
104 for( u32 i=0; i<vg_list_size(ib->frames); i++ ){
105 struct interp_frame *ifr = &ib->frames[i];
106
107 if( !ifr->active ){
108 dest = ifr;
109 break;
110 }
111
112 if( ifr->timestamp < min_time ){
113 min_time = ifr->timestamp;
114 dest = ifr;
115 }
116 }
117
118 dest->active = 1;
119 dest->timestamp = frame->timestamp;
120 dest->subsystem = frame->subsystem;
121
122 struct network_player *player = &netplayers.list[ frame->client ];
123 memcpy( &dest->data, frame->animdata, datasize );
124 player->subsystem = frame->subsystem;
125 player->down_bytes += msg->m_cbSize;
126 }
127 }
128
129 static void remote_player_send_playerframe(void){
130 u8 sysid = localplayer.subsystem;
131 if( sysid >= k_player_subsystem_max ) return;
132
133 struct player_subsystem_interface *sys = player_subsystems[sysid];
134
135 if( sys->animator_size ){
136 u32 size = sizeof(netmsg_playerframe)+sys->animator_size;
137 netmsg_playerframe *frame = alloca(size);
138 frame->inetmsg_id = k_inetmsg_playerframe;
139 frame->client = 0;
140 frame->subsystem = localplayer.subsystem;
141 frame->timestamp = vg.time_real;
142 memcpy( frame->animdata, sys->animator_data, sys->animator_size );
143
144 netplayers.up_bytes += size;
145
146 SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
147 hSteamNetworkingSockets, network_client.remote,
148 frame, size,
149 k_nSteamNetworkingSend_Unreliable, NULL );
150 }
151 }
152
153 static void remote_player_debug_update(void){
154 if( (vg.time_real - netplayers.last_data_measurement) > 1.0 ){
155 netplayers.last_data_measurement = vg.time_real;
156 u32 total_down = 0;
157
158 for( u32 i=0; i<vg_list_size(netplayers.list); i++ ){
159 struct network_player *player = &netplayers.list[i];
160 if( player->active ){
161 total_down += player->down_bytes;
162 player->down_kbs = ((f32)player->down_bytes)/1024.0f;
163 player->down_bytes = 0;
164 }
165 }
166
167 netplayers.down_kbs = ((f32)total_down)/1024.0f;
168 netplayers.up_kbs = ((f32)netplayers.up_bytes)/1024.0f;
169 netplayers.up_bytes = 0;
170 }
171 }
172
173 static void remote_player_network_imgui( m4x4f pv ){
174 if( !network_client.network_info )
175 return;
176
177 ui_rect panel = { (vg.window_x / 2) - 200, 0, 400, 600 };
178 ui_fill( panel, (ui_colour(k_ui_bg)&0x00ffffff)|0x50000000 );
179
180 char buf[512];
181 const char *netstatus = "PROGRAMMING ERROR";
182
183 struct { enum ESteamNetworkingConnectionState state; const char *str; }
184 states[] = {
185 { k_ESteamNetworkingConnectionState_None, "None" },
186 { k_ESteamNetworkingConnectionState_Connecting,
187 (const char *[]){"Connecting -",
188 "Connecting /",
189 "Connecting |",
190 "Connecting \\",
191 }[(u32)(vg.time_real/0.25) & 0x3 ] },
192 { k_ESteamNetworkingConnectionState_FindingRoute, "Finding Route" },
193 { k_ESteamNetworkingConnectionState_Connected, "Connected" },
194 { k_ESteamNetworkingConnectionState_ClosedByPeer, "Closed by peer" },
195 { k_ESteamNetworkingConnectionState_ProblemDetectedLocally,
196 "Problem Detected Locally" },
197 { k_ESteamNetworkingConnectionState_FinWait, "Fin Wait" },
198 { k_ESteamNetworkingConnectionState_Linger, "Linger" },
199 { k_ESteamNetworkingConnectionState_Dead, "Dead" }
200 };
201 for( u32 i=0; i<vg_list_size(states); i ++ ){
202 if( states[i].state == network_client.state ){
203 netstatus = states[i].str;
204 break;
205 }
206 }
207 snprintf( buf, 512, "Network: %s", netstatus );
208 ui_info( panel, buf );
209 ui_info( panel, "---------------------" );
210
211 if( network_client.state == k_ESteamNetworkingConnectionState_Connected ){
212 ui_info( panel, "#-1: localplayer" );
213
214 snprintf( buf, 512, "U%.1f/D%.1fkbs",
215 netplayers.up_kbs, netplayers.down_kbs );
216 ui_info( panel, buf );
217
218 for( u32 i=0; i<vg_list_size(netplayers.list); i++ ){
219 struct network_player *player = &netplayers.list[i];
220 if( player->active ){
221 const char *sysname = "invalid";
222
223 if( player->subsystem < k_player_subsystem_max ){
224 sysname = player_subsystems[ player->subsystem ]->name;
225 }
226 snprintf( buf, 512, "#%u: %s [%s] D%.1fkbs",
227 i, player->username, sysname, player->down_kbs );
228 ui_info( panel, buf );
229
230 v4f wpos = { 0.0f, 2.0f, 0.0f, 1.0f };
231 struct player_avatar *av = localplayer.playeravatar;
232 m4x3_mulv( netplayers.final_mtx[av->sk.bone_count*i], wpos, wpos );
233 m4x4_mulv( pv, wpos, wpos );
234
235 if( wpos[3] > 0.0f ){
236 v2_muls( wpos, (1.0f/wpos[3]) * 0.5f, wpos );
237 v2_add( wpos, (v2f){ 0.5f, 0.5f }, wpos );
238
239 ui_rect wr;
240 wr[0] = vg_clampf(wpos[0] * vg.window_x, -32000.0f,32000.0f)-150;
241 wr[1] = vg_clampf((1.0f-wpos[1]) * vg.window_y,
242 -32000.0f,32000.0f);
243 wr[2] = 300;
244 wr[3] = 17;
245 ui_fill( wr, (ui_colour(k_ui_bg)&0x00ffffff)|0x50000000 );
246 ui_text( wr, buf, 1, k_ui_align_middle_center, 0 );
247 }
248 }
249 }
250 }
251 else {
252 ui_info( panel, "offline" );
253 }
254 }
255
256 static void pose_remote_player( u32 index,
257 struct interp_frame *f0,
258 struct interp_frame *f1 ){
259
260 struct interp_buffer *buf = &netplayers.interp_data[ index ];
261 struct player_avatar *av = localplayer.playeravatar;
262 struct skeleton *sk = &localplayer.playeravatar->sk;
263 m4x3f *final_mtx = &netplayers.final_mtx[ av->sk.bone_count*index ];
264
265 struct player_subsystem_interface *sys0 = player_subsystems[f0->subsystem],
266 *sys1 = NULL;
267
268 player_pose pose0, pose1, posed;
269
270 sys0->pose( &f0->data, &pose0 );
271
272 if( f1 ){
273 f32 t = (buf->t - f0->timestamp) / (f1->timestamp - f0->timestamp);
274 t = vg_clampf( t, 0.0f, 1.0f );
275
276 sys1 = player_subsystems[f1->subsystem];
277 sys1->pose( &f1->data, &pose1 );
278
279 if( pose0.type != pose1.type ){
280 /* it would be nice to apply IK pass in-keyframes. TOO BAD! */
281 skeleton_copy_pose( sk, pose0.keyframes, posed.keyframes );
282 }
283 else {
284 skeleton_lerp_pose( sk, pose0.keyframes, pose1.keyframes, t,
285 posed.keyframes );
286 }
287
288 v3_lerp( pose0.root_co, pose1.root_co, t, posed.root_co );
289 q_nlerp( pose0.root_q, pose1.root_q, t, posed.root_q );
290 posed.type = pose0.type;
291 posed.board.lean = vg_lerpf( pose0.board.lean, pose1.board.lean, t );
292
293 apply_full_skeleton_pose( &av->sk, &posed, final_mtx );
294 }
295 else {
296 apply_full_skeleton_pose( &av->sk, &pose0, final_mtx );
297 }
298 }
299
300 static void animate_remote_player( u32 index ){
301
302 f64 min_time = -999999999.9,
303 max_time = 999999999.9,
304 abs_max_time = -999999999.9;
305
306 struct interp_frame *minframe = NULL,
307 *maxframe = NULL,
308 *abs_max_frame = NULL;
309
310 struct interp_buffer *buf = &netplayers.interp_data[index];
311 for( u32 i=0; i<vg_list_size(buf->frames); i ++ ){
312 struct interp_frame *ifr = &buf->frames[i];
313
314 if( ifr->active ){
315 if( (ifr->timestamp > min_time) && (ifr->timestamp < buf->t) ){
316 min_time = ifr->timestamp;
317 minframe = ifr;
318 }
319
320 if( (ifr->timestamp < max_time) && (ifr->timestamp > buf->t) ){
321 max_time = ifr->timestamp;
322 maxframe = ifr;
323 }
324
325 if( ifr->timestamp > abs_max_time ){
326 abs_max_time = ifr->timestamp;
327 abs_max_frame = ifr;
328 }
329 }
330 }
331
332 if( minframe && maxframe ){
333 pose_remote_player( index, minframe, maxframe );
334 buf->t += vg.time_frame_delta;
335 }
336 else {
337 buf->t = abs_max_time - 0.25;
338
339 if( abs_max_frame )
340 pose_remote_player( index, abs_max_frame, NULL );
341 else
342 return;
343 }
344 }