FS2_Open
Open source remastering of the Freespace 2 engine
multi_obj.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Volition, Inc. 1999. All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 
11 #include <algorithm>
12 
13 #include "network/multi_obj.h"
14 #include "globalincs/globals.h"
15 #include "freespace2/freespace.h"
16 #include "io/timer.h"
17 #include "io/key.h"
18 #include "globalincs/linklist.h"
19 #include "network/multimsgs.h"
20 #include "network/multiutil.h"
21 #include "network/multi_options.h"
22 #include "network/multi_rate.h"
23 #include "network/multi.h"
24 #include "object/object.h"
25 #include "ship/ship.h"
26 #include "playerman/player.h"
27 #include "math/spline.h"
28 #include "physics/physics.h"
29 #include "ship/afterburner.h"
30 #include "cfile/cfile.h"
31 #include "debugconsole/console.h"
32 
33 
34 // ---------------------------------------------------------------------------------------------------
35 // OBJECT UPDATE DEFINES/VARS
36 //
37 
38 // test stuff
39 float oo_arrive_time[MAX_SHIPS][5]; // the last 5 arrival times for each ship
40 int oo_arrive_time_count[MAX_SHIPS]; // size of the arrival queue
41 float oo_arrive_time_avg_diff[MAX_SHIPS]; // the average time between arrivals
42 float oo_arrive_time_next[MAX_SHIPS]; // how many seconds have gone by. should be equal to oo_arrive_time_avg_diff[] the next time we get an update
43 
44 // interp stuff
48 void multi_oo_calc_interp_splines(int ship_index, vec3d *cur_pos, matrix *cur_orient, physics_info *cur_phys_info, vec3d *new_pos, matrix *new_orient, physics_info *new_phys_info);
49 
50 // HACK!!!
52 
53 // how much data we're willing to put into a given oo packet
54 #define OO_MAX_SIZE 480
55 
56 // tolerance for bashing position
57 #define OO_POS_UPDATE_TOLERANCE 100.0f
58 
59 // new improved - more compacted info type
60 #define OO_POS_NEW (1<<0) //
61 #define OO_ORIENT_NEW (1<<1) //
62 #define OO_HULL_NEW (1<<2) // Hull AND shields
63 #define OO_AFTERBURNER_NEW (1<<3) //
64 #define OO_SUBSYSTEMS_AND_AI_NEW (1<<4) //
65 #define OO_PRIMARY_BANK (1<<5) // if this is set, fighter has selected bank one
66 #define OO_PRIMARY_LINKED (1<<6) // if this is set, banks are linked
67 #define OO_TRIGGER_DOWN (1<<7) // if this is set, trigger is DOWN
68 
69 #define OO_VIEW_CONE_DOT (0.1f)
70 #define OO_VIEW_DIFF_TOL (0.15f) // if the dotproducts differ this far between frames, he's coming into view
71 
72 // no timestamp should ever have sat for longer than this.
73 #define OO_MAX_TIMESTAMP 2500
74 
75 // distance class
76 #define OO_NEAR 0
77 #define OO_NEAR_DIST (200.0f)
78 #define OO_MIDRANGE 1
79 #define OO_MIDRANGE_DIST (600.0f)
80 #define OO_FAR 2
81 #define OO_FAR_DIST (1400.0f)
82 
83 // how often we should send full hull/shield updates
84 #define OO_HULL_SHIELD_TIME 600
85 #define OO_SUBSYS_TIME 1000
86 
87 // timestamp values for object update times based on client's update level.
89 {
90  100, // 15x a second
91  100, // 15x a second
92  66, // 30x a second
93  66,
94 };
95 
96 // for near ships
98 {
99  150, // low update
100  100, // medium update
101  66, // high update
102  66,
103 };
104 
105 // for medium ships
107 {
108  250, // low update
109  180, // medium update
110  120, // high update
111  66,
112 };
113 
114 // for far ships
116 {
117  750, // low update
118  350, // medium update
119  150, // high update
120  66,
121 };
122 
123 // for near ships
125 {
126  300, // low update
127  200, // medium update
128  100, // high update
129  66,
130 };
131 
132 // for medium ships
134 {
135  800, // low update
136  600, // medium update
137  300, // high update
138  66,
139 };
140 
141 // for far ships
143 {
144  2500, // low update
145  1500, // medium update
146  400, // high update
147  66,
148 };
149 
150 // ship index list for possibly sorting ships based upon distance, etc
152 
153 int OO_update_index = -1; // index into OO_update_records for displaying update record info
154 
155 // ---------------------------------------------------------------------------------------------------
156 // OBJECT UPDATE FUNCTIONS
157 //
158 
160 int OO_sort = 1;
161 
162 bool multi_oo_sort_func(const short &index1, const short &index2)
163 {
164  object *obj1, *obj2;
165  float dist1, dist2;
166  float dot1, dot2;
167  vec3d v1, v2;
168  vec3d vn1, vn2;
169 
170  // if the indices are bogus, or the objnums are bogus, return ">"
171  if((index1 < 0) || (index2 < 0) || (Ships[index1].objnum < 0) || (Ships[index2].objnum < 0)){
172  return false;
173  }
174 
175  // get the 2 objects
176  obj1 = &Objects[Ships[index1].objnum];
177  obj2 = &Objects[Ships[index2].objnum];
178 
179  // get the distance and dot product to the player obj for both
180  vm_vec_sub(&v1, &OO_player_obj->pos, &obj1->pos);
181  dist1 = vm_vec_copy_normalize(&vn1, &v1);
182  vm_vec_sub(&v2, &OO_player_obj->pos, &obj2->pos);
183  dist2 = vm_vec_copy_normalize(&vn2, &v2);
184  dot1 = vm_vec_dot(&OO_player_obj->orient.vec.fvec, &vn1);
185  dot2 = vm_vec_dot(&OO_player_obj->orient.vec.fvec, &vn2);
186 
187  // objects in front take precedence
188  if((dot1 < 0.0f) && (dot2 >= 0.0f)){
189  return false;
190  } else if((dot2 < 0.0f) && (dot1 >= 0.0f)){
191  return true;
192  }
193 
194  // otherwise go by distance
195  return (dist1 < dist2);
196 }
197 
198 // build the list of ship indices to use when updating for this player
200 {
201  int ship_index;
202  int idx;
203  ship_obj *moveup;
204  object *player_obj;
205 
206  // set all indices to be -1
207  for(idx = 0;idx<MAX_SHIPS; idx++){
208  OO_ship_index[idx] = -1;
209  }
210 
211  // get the player object
212  if(pl->m_player->objnum < 0){
213  return;
214  }
215  player_obj = &Objects[pl->m_player->objnum];
216 
217  // go through all other relevant objects
218  ship_index = 0;
219  for ( moveup = GET_FIRST(&Ship_obj_list); moveup != END_OF_LIST(&Ship_obj_list); moveup = GET_NEXT(moveup) ) {
220  // if it is an invalid ship object, skip it
221  if((moveup->objnum < 0) || (Objects[moveup->objnum].instance < 0) || (Objects[moveup->objnum].type != OBJ_SHIP)){
222  continue;
223  }
224 
225  // if we're a standalone server, don't send any data regarding its pseudo-ship
227  continue;
228  }
229 
230  // must be a ship, a weapon, and _not_ an observer
231  if (Objects[moveup->objnum].flags & OF_SHOULD_BE_DEAD){
232  continue;
233  }
234 
235  // don't send info for dying ships
236  if (Ships[Objects[moveup->objnum].instance].flags & SF_DYING){
237  continue;
238  }
239 
240  // never update the knossos device
241  if ((Ships[Objects[moveup->objnum].instance].ship_info_index >= 0) && (Ships[Objects[moveup->objnum].instance].ship_info_index < static_cast<int>(Ship_info.size())) && (Ship_info[Ships[Objects[moveup->objnum].instance].ship_info_index].flags & SIF_KNOSSOS_DEVICE)){
242  continue;
243  }
244 
245  // don't send him info for himself
246  if ( &Objects[moveup->objnum] == player_obj ){
247  continue;
248  }
249 
250  // don't send info for his targeted ship here, since its always done first
251  if((pl->s_info.target_objnum != -1) && (moveup->objnum == pl->s_info.target_objnum)){
252  continue;
253  }
254 
255  // add the ship
256  if(ship_index < MAX_SHIPS){
257  OO_ship_index[ship_index++] = (short)Objects[moveup->objnum].instance;
258  }
259  }
260 
261  // maybe sort the thing here
262  OO_player_obj = player_obj;
263  if (OO_sort) {
264  std::sort(OO_ship_index, OO_ship_index + ship_index, multi_oo_sort_func);
265  }
266 }
267 
268 // pack information for a client (myself), return bytes added
270 {
271  ubyte out_flags;
272  ushort tnet_signature;
273  char t_subsys, l_subsys;
274  int packet_size = 0;
275 
276  // get our firing stuff
277  out_flags = Net_player->s_info.accum_buttons;
278 
279  // zero these values for now
281 
282  // add any necessary targeting flags
284  out_flags |= OOC_TARGET_LOCKED;
285  }
286  if ( Player_ai->ai_flags & AIF_SEEK_LOCK ){
287  out_flags |= OOC_TARGET_SEEK_LOCK;
288  }
289  if ( Player->locking_on_center ){
290  out_flags |= OOC_LOCKING_ON_CENTER;
291  }
292  if ( (Player_ship != NULL) && (Player_ship->flags & SF_TRIGGER_DOWN) ){
293  out_flags |= OOC_TRIGGER_DOWN;
294  }
295 
296  if ( (Player_obj != NULL) && Player_obj->phys_info.flags & PF_AFTERBURNER_ON){
297  out_flags |= OOC_AFTERBURNER_ON;
298  }
299 
300  // send my bank info
301  if(Player_ship != NULL){
303  out_flags |= OOC_PRIMARY_BANK;
304  }
305 
306  // linked or not
308  out_flags |= OOC_PRIMARY_LINKED;
309  }
310  }
311 
312  // copy the final flags in
313  ADD_DATA( out_flags );
314 
315  // client targeting information
316  t_subsys = -1;
317  l_subsys = -1;
318 
319  // if nothing targeted
320  if(Player_ai->target_objnum == -1){
321  tnet_signature = 0;
322  }
323  // if something is targeted
324  else {
325  // target net signature
326  tnet_signature = Objects[Player_ai->target_objnum].net_signature;
327 
328  // targeted subsys index
329  if(Player_ai->targeted_subsys != NULL){
331  }
332 
333  // locked targeted subsys index
334  if(Player->locking_subsys != NULL){
336  }
337  }
338 
339  // add them all
340  ADD_USHORT( tnet_signature );
341  ADD_DATA( t_subsys );
342  ADD_DATA( l_subsys );
343 
344  return packet_size;
345 }
346 
347 // pack the appropriate info into the data
348 #define PACK_PERCENT(v) { ubyte upercent; if(v < 0.0f){v = 0.0f;} upercent = (v * 255.0f) <= 255.0f ? (ubyte)(v * 255.0f) : (ubyte)255; memcpy(data + packet_size + header_bytes, &upercent, sizeof(ubyte)); packet_size++; }
349 #define PACK_BYTE(v) { memcpy( data + packet_size + header_bytes, &v, 1 ); packet_size += 1; }
350 #define PACK_USHORT(v) { short swap = INTEL_SHORT(v); memcpy( data + packet_size + header_bytes, &swap, sizeof(short) ); packet_size += sizeof(short); }
351 #define PACK_SHORT(v) { ushort swap = INTEL_SHORT(v); memcpy( data + packet_size + header_bytes, &swap, sizeof(ushort) ); packet_size += sizeof(ushort); }
352 #define PACK_INT(v) { int swap = INTEL_INT(v); memcpy( data + packet_size + header_bytes, &swap, sizeof(int) ); packet_size += sizeof(int); }
353 int multi_oo_pack_data(net_player *pl, object *objp, ubyte oo_flags, ubyte *data_out)
354 {
355  ubyte data[255];
356  ubyte data_size = 0;
357  char percent;
358  ship *shipp;
359  ship_info *sip;
360  ubyte ret;
361  float temp;
362  int header_bytes;
363  int packet_size = 0;
364 
365  // make sure we have a valid ship
366  Assert(objp->type == OBJ_SHIP);
367  if((objp->instance >= 0) && (Ships[objp->instance].ship_info_index >= 0)){
368  shipp = &Ships[objp->instance];
369  sip = &Ship_info[shipp->ship_info_index];
370  } else {
371  return 0;
372  }
373 
374  // invalid player
375  if(pl == NULL){
376  return 0;
377  }
378 
379  // no flags -> do nothing
380  if(oo_flags == 0){
381  return 0;
382  }
383 
384  // if i'm the client, make sure I only send certain things
385  if(!MULTIPLAYER_MASTER){
386  Assert(oo_flags & (OO_POS_NEW | OO_ORIENT_NEW));
387  Assert(!(oo_flags & (OO_HULL_NEW | OO_SUBSYSTEMS_AND_AI_NEW)));
388  }
389  // server
390  else {
391  // Assert(oo_flags & OO_POS_NEW);
392  }
393 
394  // header sizes
395  if(MULTIPLAYER_MASTER){
396  header_bytes = 5;
397  } else {
398  header_bytes = 2;
399  }
400 
401  // if we're a client (and therefore sending control info), pack client-specific info
402  if((Net_player != NULL) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
403  packet_size += multi_oo_pack_client_data(data + packet_size + header_bytes);
404  }
405 
406  // position, velocity
407  if ( oo_flags & OO_POS_NEW ) {
408  ret = (ubyte)multi_pack_unpack_position( 1, data + packet_size + header_bytes, &objp->pos );
409  packet_size += ret;
410 
411  // global records
412  multi_rate_add(NET_PLAYER_NUM(pl), "pos", ret);
413 
414  ret = (ubyte)multi_pack_unpack_vel( 1, data + packet_size + header_bytes, &objp->orient, &objp->pos, &objp->phys_info );
415  packet_size += ret;
416 
417  // global records
418  multi_rate_add(NET_PLAYER_NUM(pl), "pos", ret);
419  }
420 
421  // orientation
422  if(oo_flags & OO_ORIENT_NEW){
423  ret = (ubyte)multi_pack_unpack_orient( 1, data + packet_size + header_bytes, &objp->orient );
424  // Assert(ret == OO_ORIENT_RET_SIZE);
425  packet_size += ret;
426  multi_rate_add(NET_PLAYER_NUM(pl), "ori", ret);
427 
428  ret = (ubyte)multi_pack_unpack_rotvel( 1, data + packet_size + header_bytes, &objp->orient, &objp->pos, &objp->phys_info );
429  packet_size += ret;
430 
431  // global records
432  multi_rate_add(NET_PLAYER_NUM(pl), "ori", ret);
433  }
434 
435  // forward thrust
436  percent = (char)(objp->phys_info.forward_thrust * 100.0f);
437  Assert( percent <= 100 );
438 
439  PACK_BYTE( percent );
440 
441  // global records
442  multi_rate_add(NET_PLAYER_NUM(pl), "fth", 1);
443 
444  // hull info
445  if ( oo_flags & OO_HULL_NEW ){
446  // add the hull value for this guy
447  temp = get_hull_pct(objp);
448  if ( (temp < 0.004f) && (temp > 0.0f) ) {
449  temp = 0.004f; // 0.004 is the lowest positive value we can have before we zero out when packing
450  }
451  PACK_PERCENT(temp);
452  multi_rate_add(NET_PLAYER_NUM(pl), "hul", 1);
453 
454  float quad = get_max_shield_quad(objp);
455 
456  for (int i = 0; i < objp->n_quadrants; i++) {
457  temp = (objp->shield_quadrant[i] / quad);
458  PACK_PERCENT(temp);
459  }
460 
461  multi_rate_add(NET_PLAYER_NUM(pl), "shl", objp->n_quadrants);
462  }
463 
464  // subsystem info
465  if( oo_flags & OO_SUBSYSTEMS_AND_AI_NEW ){
466  ubyte ns;
467  ship_subsys *subsysp;
468 
469  // just in case we have some kind of invalid data (should've been taken care of earlier in this function)
470  if(shipp->ship_info_index < 0){
471  ns = 0;
472  PACK_BYTE( ns );
473 
474  multi_rate_add(NET_PLAYER_NUM(pl), "sub", 1);
475  }
476  // add the # of subsystems, and their data
477  else {
478  ns = (ubyte)Ship_info[shipp->ship_info_index].n_subsystems;
479  PACK_BYTE( ns );
480 
481  multi_rate_add(NET_PLAYER_NUM(pl), "sub", 1);
482 
483  // now the subsystems.
484  for ( subsysp = GET_FIRST(&shipp->subsys_list); subsysp != END_OF_LIST(&shipp->subsys_list); subsysp = GET_NEXT(subsysp) ) {
485  temp = (float)subsysp->current_hits / (float)subsysp->max_hits;
486  PACK_PERCENT(temp);
487 
488  multi_rate_add(NET_PLAYER_NUM(pl), "sub", 1);
489  }
490  }
491 
492  // ai mode info
493  ubyte umode = (ubyte)(Ai_info[shipp->ai_index].mode);
494  short submode = (short)(Ai_info[shipp->ai_index].submode);
495  ushort target_signature;
496 
497  target_signature = 0;
498  if ( Ai_info[shipp->ai_index].target_objnum != -1 ){
499  target_signature = Objects[Ai_info[shipp->ai_index].target_objnum].net_signature;
500  }
501 
502  PACK_BYTE( umode );
503  PACK_SHORT( submode );
504  PACK_USHORT( target_signature );
505 
506  multi_rate_add(NET_PLAYER_NUM(pl), "aim", 5);
507 
508  // primary weapon energy
509  temp = shipp->weapon_energy / sip->max_weapon_reserve;
510  PACK_PERCENT(temp);
511  }
512 
513  // afterburner info
514  oo_flags &= ~PF_AFTERBURNER_ON;
515  if(objp->phys_info.flags & PF_AFTERBURNER_ON){
516  oo_flags |= OO_AFTERBURNER_NEW;
517  }
518 
519  // if this ship is a support ship, send some extra info
520  ubyte support_extra = 0;
521  if(MULTIPLAYER_MASTER && (sip->flags & SIF_SUPPORT) && (shipp->ai_index >= 0) && (shipp->ai_index < MAX_AI_INFO)){
522  ushort dock_sig;
523 
524  // flag
525  support_extra = 1;
526  PACK_BYTE( support_extra );
527  PACK_INT( Ai_info[shipp->ai_index].ai_flags );
528  PACK_INT( Ai_info[shipp->ai_index].mode );
529  PACK_INT( Ai_info[shipp->ai_index].submode );
530 
532  dock_sig = 0;
533  } else {
535  }
536 
537  PACK_USHORT( dock_sig );
538  } else {
539  support_extra = 0;
540  PACK_BYTE( support_extra );
541  }
542 
543  // make sure we have a valid chunk of data
544  // Clients: must be able to accomodate the data_size and shipp->np_updates[NET_PLAYER_NUM(pl)].seq before the data itself
545  // Server: TODO
546  Assert(packet_size < 255-1);
547  if(packet_size >= 255-1){
548  return 0;
549  }
550  data_size = (ubyte)packet_size;
551 
552  // add the object's net signature, type and oo_flags
553  packet_size = 0;
554  // don't add for clients
556  multi_rate_add(NET_PLAYER_NUM(pl), "sig", 2);
557  ADD_USHORT( objp->net_signature );
558 
559  multi_rate_add(NET_PLAYER_NUM(pl), "flg", 1);
560  ADD_DATA( oo_flags );
561  }
562 
563  multi_rate_add(NET_PLAYER_NUM(pl), "siz", 1);
564  ADD_DATA( data_size );
565 
566  multi_rate_add(NET_PLAYER_NUM(pl), "seq", 1);
567  ADD_DATA( shipp->np_updates[NET_PLAYER_NUM(pl)].seq );
568 
569  packet_size += data_size;
570 
571  // copy to the outgoing data
572  memcpy(data_out, data, packet_size);
573 
574  return packet_size;
575 }
576 
577 // unpack information for a client , return bytes processed
579 {
580  ubyte in_flags;
581  ship *shipp = NULL;
582  object *objp = NULL;
583  int offset = 0;
584 
585  if (pl == NULL)
586  Error(LOCATION, "Invalid net_player pointer passed to multi_oo_unpack_client\n");
587 
588  memcpy(&in_flags, data, sizeof(ubyte));
589  offset++;
590 
591  // get the player ship and object
592  if((pl->m_player->objnum >= 0) && (Objects[pl->m_player->objnum].type == OBJ_SHIP) && (Objects[pl->m_player->objnum].instance >= 0)){
593  objp = &Objects[pl->m_player->objnum];
594  shipp = &Ships[objp->instance];
595  }
596 
597  // if we have a valid netplayer pointer
598  if((pl != NULL) && !(pl->flags & NETINFO_FLAG_RESPAWNING) && !(pl->flags & NETINFO_FLAG_LIMBO)){
599  // primary fired
600  pl->m_player->ci.fire_primary_count = 0;
601 
602  // secondary fired
604  if ( in_flags & OOC_FIRE_SECONDARY ){
606  }
607 
608  // countermeasure fired
610 
611  // set up aspect locking information
612  pl->m_player->locking_on_center = 0;
613  if ( in_flags & OOC_LOCKING_ON_CENTER ){
614  pl->m_player->locking_on_center = 1;
615  }
616 
617  // trigger down, bank info
618  if(shipp != NULL){
619  if(in_flags & OOC_TRIGGER_DOWN){
620  shipp->flags |= SF_TRIGGER_DOWN;
621  } else {
622  shipp->flags &= ~SF_TRIGGER_DOWN;
623  }
624 
625  if(in_flags & OOC_PRIMARY_BANK){
626  shipp->weapons.current_primary_bank = 1;
627  } else {
628  shipp->weapons.current_primary_bank = 0;
629  }
630 
631  // linked or not
632  shipp->flags &= ~SF_PRIMARY_LINKED;
633  if(in_flags & OOC_PRIMARY_LINKED){
634  shipp->flags |= SF_PRIMARY_LINKED;
635  }
636  }
637 
638  // other locking information
639  if((shipp != NULL) && (shipp->ai_index != -1)){
640  Ai_info[shipp->ai_index].current_target_is_locked = ( in_flags & OOC_TARGET_LOCKED) ? 1 : 0;
641  if ( in_flags & OOC_TARGET_SEEK_LOCK ) {
643  } else {
645  }
646  }
647 
648  // afterburner status
649  if ( (objp != NULL) && (in_flags & OOC_AFTERBURNER_ON) ) {
651  }
652  }
653 
654  // client targeting information
655  ushort tnet_sig;
656  char t_subsys,l_subsys;
657  object *tobj;
658 
659  // get the data
660  GET_USHORT(tnet_sig);
661  GET_DATA(t_subsys);
662  GET_DATA(l_subsys);
663 
664  // try and find the targeted object
665  tobj = NULL;
666  if(tnet_sig != 0){
667  tobj = multi_get_network_object( tnet_sig );
668  }
669  // maybe fill in targeted object values
670  if((tobj != NULL) && (pl != NULL) && (pl->m_player->objnum != -1)){
671  // assign the target object
672  if(Objects[pl->m_player->objnum].type == OBJ_SHIP){
674  }
675  pl->s_info.target_objnum = OBJ_INDEX(tobj);
676 
677  // assign subsystems if possible
678  if(Objects[pl->m_player->objnum].type == OBJ_SHIP){
680  if((t_subsys != -1) && (tobj->type == OBJ_SHIP)){
682  }
683  }
684 
685  pl->m_player->locking_subsys = NULL;
686  if(Objects[pl->m_player->objnum].type == OBJ_SHIP){
687  if((l_subsys != -1) && (tobj->type == OBJ_SHIP)){
688  pl->m_player->locking_subsys = ship_get_indexed_subsys( &Ships[tobj->instance], l_subsys);
689  }
690  }
691  }
692 
693  return offset;
694 }
695 
696 // unpack the object data, return bytes processed
697 #define UNPACK_PERCENT(v) { ubyte temp_byte; memcpy(&temp_byte, data + offset, sizeof(ubyte)); v = (float)temp_byte / 255.0f; offset++;}
699 {
700  int offset = 0;
701  object *pobjp;
702  ushort net_sig = 0;
703  ubyte data_size, oo_flags;
704  ubyte seq_num;
705  char percent;
706  float fpct;
707  ship *shipp;
708  ship_info *sip;
709 
710  // add the object's net signature, type and oo_flags
712  GET_USHORT( net_sig );
713  GET_DATA( oo_flags );
714  }
715  // clients always pos and orient stuff only
716  else {
717  oo_flags = (OO_POS_NEW | OO_ORIENT_NEW);
718  }
719  GET_DATA( data_size );
720  GET_DATA( seq_num );
721 
722  // try and find the object
724  pobjp = multi_get_network_object(net_sig);
725  } else {
726  if((pl != NULL) && (pl->m_player->objnum != -1)){
727  pobjp = &Objects[pl->m_player->objnum];
728  } else {
729  pobjp = NULL;
730  }
731  }
732 
733  // if we can't find the object, set pointer to bogus object to continue reading the data
734  // ignore out of sequence packets here as well
735  if ( (pobjp == NULL) || (pobjp->type != OBJ_SHIP) || (pobjp->instance < 0) || (pobjp->instance >= MAX_SHIPS) || (Ships[pobjp->instance].ship_info_index < 0) || (Ships[pobjp->instance].ship_info_index >= static_cast<int>(Ship_info.size()))) {
736  offset += data_size;
737  return offset;
738  }
739 
740  // ship pointer
741  shipp = &Ships[pobjp->instance];
742  sip = &Ship_info[shipp->ship_info_index];
743 
744  // ---------------------------------------------------------------------------------------------------------------
745  // CRITICAL OBJECT UPDATE SHIZ
746  // ---------------------------------------------------------------------------------------------------------------
747 
748  // if the packet is out of order
749  if(seq_num < shipp->np_updates[NET_PLAYER_NUM(pl)].seq){
750  // non-wraparound case
751  if((shipp->np_updates[NET_PLAYER_NUM(pl)].seq - seq_num) <= 100){
752  offset += data_size;
753  return offset;
754  }
755  }
756 
757  // make sure the ab hack is reset before we read in new info
758  Multi_oo_afterburn_hack = false;
759 
760  // if this is from a player, read his button info
762  offset += multi_oo_unpack_client_data(pl, data + offset);
763  }
764 
765  // new info
766  vec3d new_pos = pobjp->pos;
767  physics_info new_phys_info = pobjp->phys_info;
768  matrix new_orient = pobjp->orient;
769 
770  // position
771  if ( oo_flags & OO_POS_NEW ) {
772  // AVERAGE TIME BETWEEN PACKETS FOR THIS SHIP
773  // store this latest time stamp
774  if(oo_arrive_time_count[shipp - Ships] == 5){
775  memmove(&oo_arrive_time[shipp - Ships][0], &oo_arrive_time[shipp - Ships][1], sizeof(float) * 4);
776  oo_arrive_time[shipp - Ships][4] = f2fl(Missiontime);
777  } else {
779  }
780  // if we've got 5 elements calculate the average
781  if(oo_arrive_time_count[shipp - Ships] == 5){
782  int idx;
783  oo_arrive_time_avg_diff[shipp - Ships] = 0.0f;
784  for(idx=0; idx<4; idx++){
785  oo_arrive_time_avg_diff[shipp - Ships] += oo_arrive_time[shipp - Ships][idx + 1] - oo_arrive_time[shipp - Ships][idx];
786  }
787  oo_arrive_time_avg_diff[shipp - Ships] /= 5.0f;
788  }
789  // next expected arrival time
790  oo_arrive_time_next[shipp - Ships] = 0.0f;
791 
792  // int r1 = multi_pack_unpack_position( 0, data + offset, &pobjp->pos );
793  int r1 = multi_pack_unpack_position( 0, data + offset, &new_pos );
794  offset += r1;
795 
796  // int r3 = multi_pack_unpack_vel( 0, data + offset, &pobjp->orient, &pobjp->pos, &pobjp->phys_info );
797  int r3 = multi_pack_unpack_vel( 0, data + offset, &pobjp->orient, &new_pos, &new_phys_info );
798  offset += r3;
799 
800  // bash desired vel to be velocity
801  // pobjp->phys_info.desired_vel = pobjp->phys_info.vel;
802  }
803 
804  // orientation
805  if ( oo_flags & OO_ORIENT_NEW ) {
806  // int r2 = multi_pack_unpack_orient( 0, data + offset, &pobjp->orient );
807  int r2 = multi_pack_unpack_orient( 0, data + offset, &new_orient );
808  offset += r2;
809 
810  // int r5 = multi_pack_unpack_rotvel( 0, data + offset, &pobjp->orient, &pobjp->pos, &pobjp->phys_info );
811  int r5 = multi_pack_unpack_rotvel( 0, data + offset, &new_orient, &new_pos, &new_phys_info );
812  offset += r5;
813 
814  // bash desired rotvel to be 0
815  // pobjp->phys_info.desired_rotvel = vmd_zero_vector;
816  }
817 
818  // forward thrust
819  percent = (char)(pobjp->phys_info.forward_thrust * 100.0f);
820  Assert( percent <= 100 );
821  GET_DATA(percent);
822 
823  // now stuff all this new info
824  if(oo_flags & OO_POS_NEW){
825  // if we're past the position update tolerance, bash.
826  // this should cause our 2 interpolation splines to be exactly the same. so we'll see a jump,
827  // but it should be nice and smooth immediately afterwards
828  if(vm_vec_dist(&new_pos, &pobjp->pos) > OO_POS_UPDATE_TOLERANCE){
829  pobjp->pos = new_pos;
830  }
831 
832  // recalc any interpolation info
833  if(oo_interp_count[shipp - Ships] < 2){
834  oo_interp_points[shipp - Ships][oo_interp_count[shipp - Ships]++] = new_pos;
835  } else {
836  oo_interp_points[shipp - Ships][0] = oo_interp_points[shipp - Ships][1];
837  oo_interp_points[shipp - Ships][1] = new_pos;
838 
839  multi_oo_calc_interp_splines(shipp - Ships, &pobjp->pos, &pobjp->orient, &pobjp->phys_info, &new_pos, &new_orient, &new_phys_info);
840  }
841 
842  pobjp->phys_info.vel = new_phys_info.vel;
843  pobjp->phys_info.desired_vel = new_phys_info.vel;
844  }
845 
846  // we'll just sim rotation straight. it works fine.
847  if(oo_flags & OO_ORIENT_NEW){
848  pobjp->orient = new_orient;
849  pobjp->phys_info.rotvel = new_phys_info.rotvel;
850  // pobjp->phys_info.desired_rotvel = vmd_zero_vector;
851  pobjp->phys_info.desired_rotvel = new_phys_info.rotvel;
852  }
853 
854 
855  // ---------------------------------------------------------------------------------------------------------------
856  // ANYTHING BELOW HERE WORKS FINE - nothing here which causes jumpiness or bandwidth problems :) WHEEEEE!
857  // ---------------------------------------------------------------------------------------------------------------
858 
859  // hull info
860  if ( oo_flags & OO_HULL_NEW ){
861  UNPACK_PERCENT(fpct);
862  pobjp->hull_strength = fpct * Ships[pobjp->instance].ship_max_hull_strength;
863 
864  float quad = get_max_shield_quad(pobjp);
865 
866  for (int i = 0; i < pobjp->n_quadrants; i++) {
867  UNPACK_PERCENT(fpct);
868  pobjp->shield_quadrant[i] = fpct * quad;
869  }
870  }
871 
872  if ( oo_flags & OO_SUBSYSTEMS_AND_AI_NEW ) {
873  ubyte n_subsystems, subsys_count;
874  float subsystem_percent[MAX_MODEL_SUBSYSTEMS];
875  ship_subsys *subsysp;
876  float val;
877  int i;
878 
879  // get the data for the subsystems
880  GET_DATA( n_subsystems );
881  for ( i = 0; i < n_subsystems; i++ ){
882  UNPACK_PERCENT( subsystem_percent[i] );
883  }
884 
885  // fill in the subsystem data
886  subsys_count = 0;
887  for ( subsysp = GET_FIRST(&shipp->subsys_list); subsysp != END_OF_LIST(&shipp->subsys_list); subsysp = GET_NEXT(subsysp) ) {
888  int subsys_type;
889 
890  val = subsystem_percent[subsys_count] * subsysp->max_hits;
891  subsysp->current_hits = val;
892 
893  // add the value just generated (it was zero'ed above) into the array of generic system types
894  subsys_type = subsysp->system_info->type; // this is the generic type of subsystem
895  Assert ( subsys_type < SUBSYSTEM_MAX );
896  if (!(subsysp->flags & SSF_NO_AGGREGATE)) {
897  shipp->subsys_info[subsys_type].aggregate_current_hits += val;
898  }
899  subsys_count++;
900 
901  // if we've reached max subsystems for some reason, bail out
902  if(subsys_count >= n_subsystems){
903  break;
904  }
905  }
906 
907  // recalculate all ship subsystems
908  ship_recalc_subsys_strength( shipp );
909 
910  // ai mode info
911  ubyte umode;
912  short submode;
913  ushort target_signature;
914  object *target_objp;
915 
916  GET_DATA( umode );
917  GET_SHORT( submode );
918  GET_USHORT( target_signature );
919 
920  if(shipp->ai_index >= 0){
921  Ai_info[shipp->ai_index].mode = umode;
922  Ai_info[shipp->ai_index].submode = submode;
923 
924  // set this guys target objnum
925  target_objp = multi_get_network_object( target_signature );
926  if ( target_objp == NULL ){
927  Ai_info[shipp->ai_index].target_objnum = -1;
928  } else {
929  Ai_info[shipp->ai_index].target_objnum = OBJ_INDEX(target_objp);
930  }
931  }
932 
933  // primary weapon energy
934  float weapon_energy_pct;
935  UNPACK_PERCENT(weapon_energy_pct);
936  shipp->weapon_energy = sip->max_weapon_reserve * weapon_energy_pct;
937  }
938 
939  // support ship extra info
940  ubyte support_extra;
941  GET_DATA(support_extra);
942  if(support_extra){
943  ushort dock_sig;
944  int ai_flags, ai_mode, ai_submode;
945 
946  // flag
947  GET_INT(ai_flags);
948  GET_INT(ai_mode);
949  GET_INT(ai_submode);
950  GET_USHORT(dock_sig);
951 
952  // valid ship?
953  if((shipp != NULL) && (shipp->ai_index >= 0) && (shipp->ai_index < MAX_AI_INFO)){
954  Ai_info[shipp->ai_index].ai_flags = ai_flags;
955  Ai_info[shipp->ai_index].mode = ai_mode;
956  Ai_info[shipp->ai_index].submode = ai_submode;
957 
958  object *objp = multi_get_network_object( dock_sig );
959  if(objp != NULL){
961  }
962  }
963  }
964 
965  // afterburner info
966  if ( (oo_flags & OO_AFTERBURNER_NEW) || Multi_oo_afterburn_hack ) {
967  // maybe turn them on
968  if(!(pobjp->phys_info.flags & PF_AFTERBURNER_ON)){
969  afterburners_start(pobjp);
970  }
971 
972  // make sure the ab hack is reset before we read in new info
973  Multi_oo_afterburn_hack = false;
974  } else {
975  // maybe turn them off
976  if(pobjp->phys_info.flags & PF_AFTERBURNER_ON){
977  afterburners_stop(pobjp);
978  }
979  }
980 
981  // primary info (only clients care about this)
982  if( !MULTIPLAYER_MASTER && (shipp != NULL) ){
983  // what bank
984  if(oo_flags & OO_PRIMARY_BANK){
985  shipp->weapons.current_primary_bank = 1;
986  } else {
987  shipp->weapons.current_primary_bank = 0;
988  }
989 
990  // linked or not
991  shipp->flags &= ~SF_PRIMARY_LINKED;
992  if(oo_flags & OO_PRIMARY_LINKED){
993  shipp->flags |= SF_PRIMARY_LINKED;
994  }
995 
996  // trigger down or not - server doesn't care about this. he'll get it from clients anyway
997  shipp->flags &= ~SF_TRIGGER_DOWN;
998  if(oo_flags & OO_TRIGGER_DOWN){
999  shipp->flags |= SF_TRIGGER_DOWN;
1000  }
1001  }
1002 
1003  // if we're the multiplayer server, set eye position and orient
1004  if(MULTIPLAYER_MASTER && (pl != NULL) && (pobjp != NULL)){
1005  pl->s_info.eye_pos = pobjp->pos;
1006  pl->s_info.eye_orient = pobjp->orient;
1007  }
1008 
1009  // update the sequence #
1010  shipp->np_updates[NET_PLAYER_NUM(pl)].seq = seq_num;
1011 
1012  // flag the object as just updated
1013  // pobjp->flags |= OF_JUST_UPDATED;
1014 
1015  return offset;
1016 }
1017 
1018 // reset the timestamp appropriately for the passed in object
1019 void multi_oo_reset_timestamp(net_player *pl, object *objp, int range, int in_cone)
1020 {
1021  int stamp = 0;
1022 
1023  // if this is the guy's target,
1024  if((pl->s_info.target_objnum != -1) && (pl->s_info.target_objnum == OBJ_INDEX(objp))){
1026  } else {
1027  // reset the timestamp appropriately
1028  if(in_cone){
1029  // base it upon range
1030  switch(range){
1031  case OO_NEAR:
1033  break;
1034 
1035  case OO_MIDRANGE:
1037  break;
1038 
1039  case OO_FAR:
1041  break;
1042  }
1043  } else {
1044  // base it upon range
1045  switch(range){
1046  case OO_NEAR:
1048  break;
1049 
1050  case OO_MIDRANGE:
1052  break;
1053 
1054  case OO_FAR:
1056  break;
1057  }
1058  }
1059  }
1060 
1061  // reset the timestamp for this object
1062  if(objp->type == OBJ_SHIP){
1064  }
1065 }
1066 
1067 // reset the timestamp appropriately for the passed in object
1068 void multi_oo_reset_status_timestamp(object *objp, int player_index)
1069 {
1071 }
1072 
1073 // reset the timestamp appropriately for the passed in object
1074 void multi_oo_reset_subsys_timestamp(object *objp, int player_index)
1075 {
1077 }
1078 
1079 // determine what needs to get sent for this player regarding the passed object, and when
1081 {
1082  ubyte oo_flags;
1083  int stamp;
1084  int player_index;
1085  vec3d player_eye;
1086  vec3d obj_dot;
1087  float eye_dot, dist;
1088  int in_cone;
1089  int range;
1090  ship *shipp;
1091  ship_info *sip;
1092  ushort cur_pos_chksum = 0;
1093  ushort cur_orient_chksum = 0;
1094 
1095  // if the timestamp has elapsed for this guy, send stuff
1096  player_index = NET_PLAYER_INDEX(pl);
1097  if(!(player_index >= 0) || !(player_index < MAX_PLAYERS)){
1098  return 0;
1099  }
1100 
1101  // determine what the timestamp is for this object
1102  if(obj->type == OBJ_SHIP){
1104  } else {
1105  return 0;
1106  }
1107 
1108  // stamp hasn't popped yet
1109  if((stamp != -1) && !timestamp_elapsed_safe(stamp, OO_MAX_TIMESTAMP)){
1110  return 0;
1111  }
1112 
1113  // if we're supposed to update this guy
1114 
1115  // get the ship pointer
1116  shipp = &Ships[obj->instance];
1117 
1118  // get ship info pointer
1119  sip = NULL;
1120  if(shipp->ship_info_index >= 0){
1121  sip = &Ship_info[shipp->ship_info_index];
1122  }
1123 
1124  // check dot products
1125  player_eye = pl->s_info.eye_orient.vec.fvec;
1126  vm_vec_sub(&obj_dot, &obj->pos, &pl->s_info.eye_pos);
1127  in_cone = 0;
1128  if (!(IS_VEC_NULL(&obj_dot))) {
1129  vm_vec_normalize(&obj_dot);
1130  eye_dot = vm_vec_dot(&obj_dot, &player_eye);
1131  in_cone = (eye_dot >= OO_VIEW_CONE_DOT) ? 1 : 0;
1132  }
1133 
1134  // determine distance (near, medium, far)
1135  vm_vec_sub(&obj_dot, &obj->pos, &pl->s_info.eye_pos);
1136  dist = vm_vec_mag(&obj_dot);
1137  if(dist < OO_NEAR_DIST){
1138  range = OO_NEAR;
1139  } else if(dist < OO_MIDRANGE_DIST){
1140  range = OO_MIDRANGE;
1141  } else {
1142  range = OO_FAR;
1143  }
1144 
1145  // reset the timestamp for the next update for this guy
1146  multi_oo_reset_timestamp(pl, obj, range, in_cone);
1147 
1148  // base oo_flags
1149  oo_flags = OO_POS_NEW | OO_ORIENT_NEW;
1150 
1151  // if its a small ship, add weapon link info
1152  if((sip != NULL) && (sip->flags & (SIF_FIGHTER | SIF_BOMBER))){
1153  // primary bank 0 or 1
1154  if(shipp->weapons.current_primary_bank > 0){
1155  oo_flags |= OO_PRIMARY_BANK;
1156  }
1157 
1158  // linked or not
1159  if(shipp->flags & SF_PRIMARY_LINKED){
1160  oo_flags |= OO_PRIMARY_LINKED;
1161  }
1162 
1163  // trigger down or not
1164  if(shipp->flags & SF_TRIGGER_DOWN){
1165  oo_flags |= OO_TRIGGER_DOWN;
1166  }
1167  }
1168 
1169  // if the object's hull/shield timestamp has expired
1171  oo_flags |= (OO_HULL_NEW);
1172 
1173  // reset the timestamp
1174  multi_oo_reset_status_timestamp(obj, player_index);
1175  }
1176 
1177  // if the object's hull/shield timestamp has expired
1179  oo_flags |= OO_SUBSYSTEMS_AND_AI_NEW;
1180 
1181  // reset the timestamp
1182  multi_oo_reset_subsys_timestamp(obj, player_index);
1183  }
1184 
1185  // add info for a targeted object
1186  if((pl->s_info.target_objnum != -1) && (OBJ_INDEX(obj) == pl->s_info.target_objnum)){
1187  oo_flags |= (OO_POS_NEW | OO_ORIENT_NEW | OO_HULL_NEW);
1188  }
1189  // all other cases
1190  else {
1191  // add info which is contingent upon being "in front"
1192  if(in_cone){
1193  oo_flags |= OO_ORIENT_NEW;
1194  }
1195  }
1196 
1197  // get current position and orient checksums
1198  cur_pos_chksum = cf_add_chksum_short(cur_pos_chksum, (ubyte*)(&obj->pos), sizeof(vec3d));
1199  cur_orient_chksum = cf_add_chksum_short(cur_orient_chksum, (ubyte*)(&obj->orient), sizeof(matrix));
1200 
1201  // if position or orientation haven't changed
1202  if((shipp->np_updates[player_index].pos_chksum != 0) && (shipp->np_updates[player_index].pos_chksum == cur_pos_chksum)){
1203  // if we otherwise would have been sending it, keep track of it (debug only)
1204 #ifndef NDEBUG
1205  if(oo_flags & OO_POS_NEW){
1206  multi_rate_add(player_index, "skp_p", OO_POS_RET_SIZE + OO_VEL_RET_SIZE);
1207  }
1208 #endif
1209  oo_flags &= ~(OO_POS_NEW);
1210  }
1211  if((shipp->np_updates[player_index].orient_chksum != 0) && (shipp->np_updates[player_index].orient_chksum == cur_orient_chksum)){
1212  // if we otherwise would have been sending it, keep track of it (debug only)
1213 #ifndef NDEBUG
1214  if(oo_flags & OO_ORIENT_NEW){
1215  multi_rate_add(player_index, "skp_o", OO_ORIENT_RET_SIZE + OO_ROTVEL_RET_SIZE);
1216  }
1217 #endif
1218  oo_flags &= ~(OO_ORIENT_NEW);
1219  }
1220  shipp->np_updates[player_index].pos_chksum = cur_pos_chksum;
1221  shipp->np_updates[player_index].orient_chksum = cur_orient_chksum;
1222 
1223  // pack stuff only if we have to
1224  int packed = multi_oo_pack_data(pl, obj, oo_flags ,data);
1225 
1226  // increment sequence #
1228 
1229  // bytes packed
1230  return packed;
1231 }
1232 
1233 // process all other objects for this player
1235 {
1237  ubyte data_add[MAX_PACKET_SIZE];
1238  ubyte stop;
1239  int add_size;
1240  int packet_size = 0;
1241  int idx;
1242 
1243  object *moveup;
1244 
1245  // if the player has an invalid objnum..
1246  if(pl->m_player->objnum < 0){
1247  return;
1248  }
1249 
1250  object *targ_obj;
1251 
1252  // build the list of ships to check against
1254 
1255  // do nothing if he has no object targeted, or if he has a weapon targeted
1256  if((pl->s_info.target_objnum != -1) && (Objects[pl->s_info.target_objnum].type == OBJ_SHIP)){
1257  // build the header
1259 
1260  // get a pointer to the object
1261  targ_obj = &Objects[pl->s_info.target_objnum];
1262 
1263  // run through the maybe_update function
1264  add_size = multi_oo_maybe_update(pl, targ_obj, data_add);
1265 
1266  // copy in any relevant data
1267  if(add_size){
1268  stop = 0xff;
1269  multi_rate_add(NET_PLAYER_NUM(pl), "stp", 1);
1270  ADD_DATA(stop);
1271 
1272  memcpy(data + packet_size, data_add, add_size);
1273  packet_size += add_size;
1274  }
1275  } else {
1276  // just build the header for the rest of the function
1278  }
1279 
1280  idx = 0;
1281  // rely on logical-AND shortcut evaluation to prevent array out-of-bounds read of OO_ship_index[idx]
1282  while((idx < MAX_SHIPS) && (OO_ship_index[idx] >= 0)){
1283  // if this guy is over his datarate limit, do nothing
1284  if(multi_oo_rate_exceeded(pl)){
1285  nprintf(("Network","Capping client\n"));
1286  idx++;
1287 
1288  continue;
1289  }
1290 
1291  // get the object
1292  moveup = &Objects[Ships[OO_ship_index[idx]].objnum];
1293 
1294  // maybe send some info
1295  add_size = multi_oo_maybe_update(pl, moveup, data_add);
1296 
1297  // if this data is too much for the packet, send off what we currently have and start over
1298  if(packet_size + add_size > OO_MAX_SIZE){
1299  stop = 0x00;
1300  multi_rate_add(NET_PLAYER_NUM(pl), "stp", 1);
1301  ADD_DATA(stop);
1302 
1303  multi_io_send(pl, data, packet_size);
1304  pl->s_info.rate_bytes += packet_size + UDP_HEADER_SIZE;
1305 
1306  packet_size = 0;
1308  }
1309 
1310  if(add_size){
1311  stop = 0xff;
1312  multi_rate_add(NET_PLAYER_NUM(pl), "stp", 1);
1313  ADD_DATA(stop);
1314 
1315  // copy in the data
1316  memcpy(data + packet_size,data_add,add_size);
1317  packet_size += add_size;
1318  }
1319 
1320  // next ship
1321  idx++;
1322  }
1323 
1324  // if we have anything more than 3 byte in the packet, send the last one off
1325  if(packet_size > 3){
1326  stop = 0x00;
1327  multi_rate_add(NET_PLAYER_NUM(pl), "stp", 1);
1328  ADD_DATA(stop);
1329 
1330  multi_io_send(pl, data, packet_size);
1331  pl->s_info.rate_bytes += packet_size + UDP_HEADER_SIZE;
1332  }
1333 }
1334 
1335 // process all object update details for this frame
1337 {
1338  int idx;
1339 
1340  // process each player
1341  for(idx=0; idx<MAX_PLAYERS; idx++){
1342  if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (Net_player != &Net_players[idx]) /*&& !MULTI_OBSERVER(Net_players[idx])*/ ){
1343  // now process the rest of the objects
1345 
1346  // do firing stuff for this player
1347  if((Net_players[idx].m_player != NULL) && (Net_players[idx].m_player->objnum >= 0) && !(Net_players[idx].flags & NETINFO_FLAG_LIMBO) && !(Net_players[idx].flags & NETINFO_FLAG_RESPAWNING)){
1350  }
1351  }
1352  }
1353  }
1354 }
1355 
1356 // process incoming object update data
1358 {
1359  ubyte stop;
1360  int player_index;
1361  int offset = HEADER_LENGTH;
1362  net_player *pl = NULL;
1363 
1364  // determine what player this came from
1365  player_index = find_player_id(hinfo->id);
1366  if(player_index != -1){
1367  pl = &Net_players[player_index];
1368  }
1369  // otherwise its a "regular" object update packet on a client from the server. use "myself" as the reference player
1370  else {
1371  pl = Net_player;
1372  }
1373 
1374  GET_DATA(stop);
1375 
1376  while(stop == 0xff){
1377  // process the data
1378  offset += multi_oo_unpack_data(pl, data + offset);
1379 
1380  GET_DATA(stop);
1381  }
1382  PACKET_SET_SIZE();
1383 }
1384 
1385 // initialize all object update timestamps (call whenever entering gameplay state)
1387 {
1388  int cur, s_idx, idx;
1389  //ship_obj *so;
1390  ship *shipp;
1391  /*
1392  int num_ships = ship_get_num_ships();
1393 
1394  if(num_ships <= 0){
1395  return;
1396  }
1397  split = 3000 / num_ships;
1398  */
1399  //split = 1;
1400  //split = 150;
1401 
1402  // server should setup initial update timestamps
1403  // stagger initial updates over 3 seconds or so
1404  cur = 0;
1405  //for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
1406  //if(Objects[so->objnum].type == OBJ_SHIP){
1407  for(s_idx=0; s_idx<MAX_SHIPS; s_idx++){
1408  shipp = &Ships[s_idx];
1409 
1410  // update the timestamps
1411  for(idx=0;idx<MAX_PLAYERS;idx++){
1412  shipp->np_updates[idx].update_stamp = timestamp(cur);
1415  shipp->np_updates[idx].seq = 0;
1416  shipp->np_updates[idx].pos_chksum = 0;
1417  shipp->np_updates[idx].orient_chksum = 0;
1418  }
1419 
1420  oo_arrive_time_count[shipp - Ships] = 0;
1421  oo_interp_count[shipp - Ships] = 0;
1422 
1423  // increment the time
1424 // cur += split;
1425  }
1426  //}
1427 
1428  // reset datarate stamp now
1429  extern int OO_gran;
1430  for(idx=0; idx<MAX_PLAYERS; idx++){
1431  Net_players[idx].s_info.rate_stamp = timestamp( (int)(1000.0f / (float)OO_gran) );
1432  }
1433 }
1434 
1435 // send control info for a client (which is basically a "reverse" object update)
1437 {
1438  ubyte data[MAX_PACKET_SIZE], stop;
1439  ubyte data_add[MAX_PACKET_SIZE];
1440  ubyte oo_flags;
1441  int add_size;
1442  int packet_size = 0;
1443 
1444  // if I'm dying or my object type is not a ship, bail here
1445  if((Player_obj != NULL) && (Player_ship->flags & SF_DYING)){
1446  return;
1447  }
1448 
1449  // build the header
1451 
1452  // pos and orient always
1453  oo_flags = (OO_POS_NEW | OO_ORIENT_NEW);
1454 
1455  // pack the appropriate info into the data
1456  add_size = multi_oo_pack_data(Net_player, Player_obj, oo_flags, data_add);
1457 
1458  // copy in any relevant data
1459  if(add_size){
1460  stop = 0xff;
1462 
1463  ADD_DATA(stop);
1464 
1465  memcpy(data + packet_size, data_add, add_size);
1466  packet_size += add_size;
1467  }
1468 
1469  // add the final stop byte
1470  stop = 0x0;
1472  ADD_DATA(stop);
1473 
1474  // increment sequence #
1476 
1477  // send to the server
1478  if(Netgame.server != NULL){
1479  multi_io_send(Net_player, data, packet_size);
1480  }
1481 }
1482 
1483 // Sends a packet from the server to the client, syncing the player's position/orientation to the
1484 // Server's. Allows for use of certain SEXPs in multiplayer.
1485 void multi_oo_send_changed_object(object *changedobj)
1486 {
1487  ubyte data[MAX_PACKET_SIZE], stop;
1488  ubyte data_add[MAX_PACKET_SIZE];
1489  ubyte oo_flags;
1490  int add_size;
1491  int packet_size = 0;
1492  int idx = 0;
1493 #ifndef NDEBUG
1494  nprintf(("Network","Attempting to affect player object.\n"));
1495 #endif
1496  for (; idx < MAX_PLAYERS; idx++)
1497  {
1498  if( changedobj == &(Objects[Net_players[idx].m_player->objnum]) ) {
1499  break;
1500  }
1501  }
1502 #ifndef NDEBUG
1503  nprintf(("Network","Index for changed object found: [%d].\n",idx));
1504 #endif
1505  if( idx >= MAX_PLAYERS ) {
1506  return;
1507  }
1508  // build the header
1510 
1511  // pos and orient always
1512  oo_flags = (OO_POS_NEW | OO_ORIENT_NEW);
1513 
1514  // pack the appropriate info into the data
1515  add_size = multi_oo_pack_data(&Net_players[idx], changedobj, oo_flags, data_add);
1516 
1517  // copy in any relevant data
1518  if(add_size){
1519  stop = 0xff;
1520  multi_rate_add(idx, "stp", 1);
1521 
1522  ADD_DATA(stop);
1523 
1524  memcpy(data + packet_size, data_add, add_size);
1525  packet_size += add_size;
1526  }
1527 
1528  // add the final stop byte
1529  stop = 0x0;
1530  multi_rate_add(idx, "stp", 1);
1531  ADD_DATA(stop);
1532 
1533  // increment sequence #
1534 // Player_ship->np_updates[idx].seq++;
1535 
1536  multi_io_send(&Net_players[idx], data, packet_size);
1537 }
1538 
1539 
1540 // display any oo info on the hud
1542 {
1543 #ifndef NDEBUG
1544 #endif
1545 }
1546 
1547 
1548 // ---------------------------------------------------------------------------------------------------
1549 // DATARATE DEFINES/VARS
1550 //
1551 
1552 // low object update datarate limit
1553 #define OO_LIMIT_LOW 1800
1554 #define OO_LIMIT_MED 3400
1555 #define OO_LIMIT_HIGH 100000000
1556 
1557 // timestamp for sending control info (movement only - we'll send button info all the time)
1558 #define OO_CIRATE 85 // 15x a second
1559 int Multi_cirate_stamp = -1; // timestamp for waiting on control info time
1560 int Multi_cirate_can_send = 1; // if we can send control info this frame
1561 
1562 // global max rates
1563 int OO_server_rate = -1; // max _total_ bandwidth to send to all clients
1564 int OO_client_rate = -1; // max bandwidth to go to an individual client
1565 
1566 // update timestamp for server datarate checking
1567 #define RATE_UPDATE_TIME 1250 // in ms
1569 
1570 // bandwidth granularity
1571 int OO_gran = 1;
1572 DCF(oog, "Sets bandwidth granularity (Multiplayer)")
1573 {
1574  if (dc_optional_string_either("help", "--help")) {
1575  dc_printf("Usage: oog <OO_gran>\n");
1576  dc_printf("Sets bandwidth granularity\n");
1577  return;
1578  }
1579 
1580  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
1581  dc_printf("Current Granularity is '%i' (default is 1)", OO_gran);
1582  return;
1583  }
1584 
1586  dc_printf("Ganularity set to %i", OO_gran);
1587 }
1588 
1589 // process datarate limiting stuff for the server
1591 
1592 // process datarate limiting stuff for the client
1594 
1595 // update the server datarate
1597 
1598 
1599 // ---------------------------------------------------------------------------------------------------
1600 // DATARATE FUNCTIONS
1601 //
1602 
1603 // process all object update datarate details
1605 {
1606  // if I have no valid player, drop out here
1607  if(Net_player == NULL){
1608  return;
1609  }
1610 
1611  // if we're not in mission, don't do anything
1612  if(!(Game_mode & GM_IN_MISSION)){
1613  return;
1614  }
1615 
1616  // if I'm the server of a game, process server stuff
1619  }
1620  // otherwise process client-side stuff
1621  else {
1623  }
1624 }
1625 
1626 // process datarate limiting stuff for the server
1628 {
1629  int idx;
1630 
1631  // go through all players
1632  for(idx=0;idx<MAX_PLAYERS;idx++){
1634  // if his timestamp is -1 or has expired, reset it and zero his rate byte count
1636  Net_players[idx].s_info.rate_stamp = timestamp( (int)(1000.0f / (float)OO_gran) );
1638  }
1639  }
1640  }
1641 
1642  // determine if we should be updating the server datarate
1644  // reset the timestamp
1646 
1647  // update the server datarate
1649 
1650  // nprintf(("Network","UPDATING SERVER DATARATE\n"));
1651  }
1652 }
1653 
1654 // process datarate limiting stuff for the client
1656 {
1657  // if the timestamp is -1 or has elapsed, reset it
1661  }
1662 }
1663 
1664 
1665 // datarate limiting system for server -------------------------------------
1666 
1667 // initialize the rate limiting system for all players
1669 {
1670  int idx;
1671 
1672  // if I don't have a net_player, bail here
1673  if(Net_player == NULL){
1674  return;
1675  }
1676 
1677  // if I'm the server of the game
1679  // go through all players
1680  for(idx=0;idx<MAX_PLAYERS;idx++){
1681  if(MULTI_CONNECTED(Net_players[idx])){
1683  }
1684  }
1685 
1686  OO_server_rate_stamp = -1;
1687  }
1688  // if i'm the client, initialize my control info datarate stuff
1689  else {
1690  Multi_cirate_stamp = -1;
1692  }
1693 }
1694 
1695 // initialize the rate limiting for the passed in player
1697 {
1698  // reinitialize his datarate timestamp
1699  pl->s_info.rate_stamp = -1;
1700  pl->s_info.rate_bytes = 0;
1701 }
1702 
1703 // if the given net-player has exceeded his datarate limit
1705 {
1706  int rate_compare;
1707 
1708  // check against the guy's object update level
1709  switch(pl->p_info.options.obj_update_level){
1710  // low update level
1711  case OBJ_UPDATE_LOW:
1712  // the low object update limit
1713  rate_compare = OO_LIMIT_LOW;
1714  break;
1715 
1716  // medium update level
1717  case OBJ_UPDATE_MEDIUM:
1718  // the low object update limit
1719  rate_compare = OO_LIMIT_MED;
1720  break;
1721 
1722  // high update level - super high datarate (no capping, just intelligent updating)
1723  case OBJ_UPDATE_HIGH:
1724  rate_compare = OO_LIMIT_HIGH;
1725  break;
1726 
1727  // LAN - no rate max
1728  case OBJ_UPDATE_LAN:
1729  return 0;
1730 
1731  // default level
1732  default:
1733  Int3();
1734  rate_compare = OO_LIMIT_LOW;
1735  break;
1736  }
1737 
1738  // if the server global rate PER CLIENT (OO_client_rate) is actually lower
1739  if(OO_client_rate < rate_compare){
1740  rate_compare = OO_client_rate;
1741  }
1742 
1743  // compare his bytes sent against the allowable amount
1744  if(pl->s_info.rate_bytes >= rate_compare){
1745  return 1;
1746  }
1747 
1748  // we're allowed to send
1749  return 0;
1750 }
1751 
1752 // if it is ok for me to send a control info (will be ~N times a second)
1754 {
1755  // if we're allowed to send
1758  return 1;
1759  }
1760 
1761  return 0;
1762 }
1763 
1764 // dynamically update the server capped bandwidth rate
1766 {
1767  int num_connections;
1768 
1769  // bail conditions
1770  if((Net_player == NULL) || !(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1771  return;
1772  }
1773 
1774  // get the # of connections
1775  num_connections = multi_num_connections();
1777  num_connections--;
1778  }
1779  // make sure we always pretend there's at least one guy available
1780  if(num_connections <= 0){
1781  num_connections = 1;
1782  }
1783 
1784  // set the data rate
1786  // LAN update level
1787  case OBJ_UPDATE_LAN:
1788  // set to something super big so we don't limit anything
1789  OO_server_rate = 500000000;
1790  break;
1791 
1792  // high update level
1793  case OBJ_UPDATE_HIGH:
1794  // set to 0 so we don't limit anything
1796  break;
1797 
1798  // medium update level
1799  case OBJ_UPDATE_MEDIUM:
1800  // set the rate to be "medium" update level
1802  break;
1803 
1804  // low update level
1805  case OBJ_UPDATE_LOW:
1806  // set the rate to be the "low" update level
1808  break;
1809 
1810  default:
1811  Int3();
1812  return;
1813  }
1814 
1815  // set the individual client level
1816  OO_client_rate = (int)(((float)OO_server_rate / (float)OO_gran) / (float)num_connections);
1817 }
1818 
1819 // reset all sequencing info (obsolete for new object update stuff)
1821 {
1822 }
1823 
1824 // is this object one which needs to go through the interpolation
1826 {
1827  // if not multiplayer, skip it
1828  if(!(Game_mode & GM_MULTIPLAYER)){
1829  return 0;
1830  }
1831 
1832  // if its not a ship, skip it
1833  if(objp->type != OBJ_SHIP){
1834  return 0;
1835  }
1836 
1837  // other bogus cases
1838  if((objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
1839  return 0;
1840  }
1841 
1842  // if I'm a client and this is not me, I need to interp it
1843  if(!MULTIPLAYER_MASTER){
1844  if(objp != Player_obj){
1845  return 1;
1846  } else {
1847  return 0;
1848  }
1849  }
1850 
1851  // servers only interpolate other player ships
1852  if(!(objp->flags & OF_PLAYER_SHIP)){
1853  return 0;
1854  }
1855 
1856  // here we know its a player ship - is it mine?
1857  if(objp == Player_obj){
1858  return 0;
1859  }
1860 
1861  // interp it
1862  return 1;
1863 }
1864 
1865 // interp
1866 void multi_oo_interp(object *objp)
1867 {
1868  // make sure its a valid ship
1870  if(objp->type != OBJ_SHIP){
1871  return;
1872  }
1873  if((objp->instance < 0) || (objp->instance >= MAX_SHIPS)){
1874  return;
1875  }
1876 
1877  // increment his approx "next" time
1879 
1880  // do stream weapon firing for this ship
1881  Assert(objp != Player_obj);
1882  if(objp != Player_obj){
1883  ship_fire_primary(objp, 1, 0);
1884  }
1885 
1886  // if this ship doesn't have enough data points yet, skip it
1887  if((oo_interp_count[objp->instance] < 2) || (oo_arrive_time_count[objp->instance] < 5)){
1888  return;
1889  }
1890 
1891  // store the magnitude of his velocity
1892  // float vel_mag = vm_vec_mag(&objp->phys_info.vel);
1893 
1894  // determine how far along we are (0.0 to 1.0) until we should be getting the next packet
1896 
1897  // gr_set_color_fast(&Color_bright);
1898  // gr_printf(100, 10, "%f\n", t);
1899 
1900  // we've overshot. hmm. just keep the sim running I guess
1901  if(t > 1.0f){
1902  physics_sim(&objp->pos, &objp->orient, &objp->phys_info, flFrametime);
1903  return;
1904  }
1905 
1906  // otherwise, blend the two curves together to get the new point
1907  float u = 0.5f + (t * 0.5f);
1908  vec3d p_bad, p_good;
1909  oo_interp_splines[objp->instance][0].bez_get_point(&p_bad, u);
1910  oo_interp_splines[objp->instance][1].bez_get_point(&p_good, u);
1911  vm_vec_scale(&p_good, t);
1912  vm_vec_scale(&p_bad, 1.0f - t);
1913  vm_vec_add(&objp->pos, &p_bad, &p_good);
1914 
1915  // set new velocity
1916  // vm_vec_sub(&objp->phys_info.vel, &objp->pos, &objp->last_pos);
1917 
1918  // run the sim for rotation
1919  physics_sim_rot(&objp->orient, &objp->phys_info, flFrametime);
1920 
1921  // blend velocity vectors together with an average weight
1922  /*
1923  vec3d v_bad, v_good;
1924  oo_interp_splines[objp->instance][0].herm_get_deriv(&v_bad, u, 0);
1925  oo_interp_splines[objp->instance][1].herm_get_deriv(&v_good, u, 0);
1926 
1927  // t -= 1.0f;
1928  vm_vec_scale(&v_good, t);
1929  vm_vec_scale(&v_bad, 1.0f - t);
1930  vm_vec_avg(&objp->phys_info.vel, &v_bad, &v_good);
1931 
1932  // run the sim
1933  physics_sim(&objp->pos, &objp->orient, &objp->phys_info, flFrametime);
1934  */
1935 
1936  /*
1937  vec3d v_bad, v_good;
1938  oo_interp_splines[objp->instance][0].herm_get_point(&v_bad, u, 0);
1939  oo_interp_splines[objp->instance][1].herm_get_point(&v_good, u, 0);
1940 
1941  // t -= 1.0f;
1942  vm_vec_scale(&v_good, t);
1943  vm_vec_scale(&v_bad, 1.0f - t);
1944  vm_vec_avg(&objp->pos, &v_bad, &v_good);
1945 
1946  // run the sim
1947  // physics_sim(&objp->pos, &objp->orient, &objp->phys_info, flFrametime);
1948  physics_sim_rot(&objp->orient, &objp->phys_info, flFrametime);
1949  */
1950 }
1951 
1952 float oo_error = 0.8f;
1953 DCF(oo_error, "Sets error factor for flight path prediction physics (Multiplayer)")
1954 {
1955  if (dc_optional_string_either("help", "--help")) {
1956  dc_printf("Usage: oo_error <value>\n");
1957  return;
1958  }
1959 
1960  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
1961  dc_printf("oo_error is currently %f", oo_error);
1962  return;
1963  }
1964 
1966 
1967  dc_printf("oo_error set to %f", oo_error);
1968 }
1969 
1970 void multi_oo_calc_interp_splines(int ship_index, vec3d *cur_pos, matrix *cur_orient, physics_info *cur_phys_info, vec3d *new_pos, matrix *new_orient, physics_info *new_phys_info)
1971 {
1972  vec3d a, b, c;
1973  matrix m_copy;
1974  physics_info p_copy;
1975  vec3d *pts[3] = {&a, &b, &c};
1976 
1977  // average time between packets
1978  float avg_diff = oo_arrive_time_avg_diff[ship_index];
1979 
1980  // would this cause us to rubber-band?
1981  vec3d v_norm = cur_phys_info->vel;
1982  vec3d v_dir;
1983  vm_vec_sub(&v_dir, new_pos, cur_pos);
1984  if(!IS_VEC_NULL_SQ_SAFE(&v_norm) && !IS_VEC_NULL_SQ_SAFE(&v_dir)){
1985  vm_vec_normalize(&v_dir);
1986  vm_vec_normalize(&v_norm);
1987  if(vm_vec_dot(&v_dir, &v_norm) < 0.0f){
1988  *new_pos = *cur_pos;
1989  }
1990  }
1991 
1992  // get the spline representing our "bad" movement. its better to be little bit off than to overshoot altogether
1993  a = oo_interp_points[ship_index][0];
1994  b = *cur_pos;
1995  c = *cur_pos;
1996  m_copy = *cur_orient;
1997  p_copy = *cur_phys_info;
1998  physics_sim(&c, &m_copy, &p_copy, avg_diff * oo_error); // next point, assuming we followed our current path
1999  oo_interp_splines[ship_index][0].bez_set_points(3, pts);
2000 
2001  // get the spline representing where this new point tells us we'd be heading
2002  a = oo_interp_points[ship_index][0]; //-V519
2003  b = oo_interp_points[ship_index][1]; //-V519
2004  c = oo_interp_points[ship_index][1];
2005  m_copy = *new_orient;
2006  p_copy = *new_phys_info;
2007  physics_sim(&c, &m_copy, &p_copy, avg_diff); // next point, given this new info
2008  oo_interp_splines[ship_index][1].bez_set_points(3, pts);
2009 
2010  // now we've got a spline representing our "new" path and where we would've gone had we been perfect before
2011  // we'll modify our velocity to move along a blend of these splines.
2012 }
2013 
2015 {
2016 }
2017 
2019 DCF(bez, "Toggles rendering of player ship trajectory interpolation splines (Multiplayer) *disabled*")
2020 {
2021  if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
2022  dc_printf("Rendering of interpolation splines is '%s'", display_oo_bez ? "ON" : "OFF");
2023  return;
2024  }
2025 
2027 
2028  dc_printf("%showing interp splines", display_oo_bez ? "S" : "Not s");
2029 }
2030 
2032 {
2033 /* int idx;
2034 
2035 
2036  gr_set_color_fast(&Color_bright);
2037 
2038  for(idx=0; idx<MAX_SHIPS; idx++){
2039  // invalid ship
2040  if(Ships[idx].objnum < 0){
2041  continue;
2042  }
2043 
2044  // time between updates
2045  if( (oo_arrive_time_count[idx] == 5) && (idx != (Player_ship - Ships)) ){
2046  gr_printf(20, 40, "avg time between updates : %f", oo_arrive_time_avg_diff[idx]);
2047  }
2048 
2049  // interpolation splines
2050  if( (oo_interp_count[idx] == 2) && (display_oo_bez) ){
2051  oo_interp_splines[idx][0].bez_render(10, &Color_bright_red); // bad path
2052  oo_interp_splines[idx][1].bez_render(10, &Color_bright_green); // good path
2053  }
2054  }
2055  */
2056 }
int fire_countermeasure_count
Definition: physics.h:112
#define RATE_UPDATE_TIME
Definition: multi_obj.cpp:1567
#define OOC_LOCKING_ON_CENTER
Definition: multi_obj.h:30
#define OO_VIEW_CONE_DOT
Definition: multi_obj.cpp:69
int oo_interp_count[MAX_SHIPS]
Definition: multi_obj.cpp:45
int timestamp(int delta_ms)
Definition: timer.cpp:226
#define PACK_SHORT(v)
Definition: multi_obj.cpp:351
#define MY_NET_PLAYER_NUM
Definition: multi.h:127
int i
Definition: multi_pxo.cpp:466
fix Missiontime
Definition: systemvars.cpp:19
float get_max_shield_quad(object *objp)
Definition: object.cpp:260
#define GET_DATA(d)
Definition: multimsgs.h:47
model_subsystem * system_info
Definition: ship.h:314
void multi_oo_server_process()
Definition: multi_obj.cpp:1627
int multi_oo_rate_exceeded(net_player *pl)
Definition: multi_obj.cpp:1704
#define timestamp_elapsed_safe(_a, _b)
Definition: timer.h:114
int multi_oo_maybe_update(net_player *pl, object *obj, ubyte *data)
Definition: multi_obj.cpp:1080
void bez_set_points(int _num_pts, vec3d *_pts[MAX_BEZ_PTS])
Definition: spline.cpp:71
#define OO_HULL_SHIELD_TIME
Definition: multi_obj.cpp:84
float max_weapon_reserve
Definition: ship.h:1276
ai_info * Player_ai
Definition: ai.cpp:24
control_info ci
Definition: player.h:126
#define OO_LIMIT_LOW
Definition: multi_obj.cpp:1553
np_update np_updates[MAX_PLAYERS]
Definition: ship.h:731
int objnum
Definition: ship.h:537
int Game_mode
Definition: systemvars.cpp:24
int Multi_oo_rear_medium_update_times[MAX_OBJ_UPDATE_LEVELS]
Definition: multi_obj.cpp:133
vec3d rotvel
Definition: physics.h:78
int multi_num_connections()
Definition: multiutil.cpp:1832
#define PACK_PERCENT(v)
Definition: multi_obj.cpp:348
int multi_pack_unpack_orient(int write, ubyte *data, matrix *orient)
Definition: multiutil.cpp:3677
#define OOC_TRIGGER_DOWN
Definition: multi_obj.h:31
ship_weapon weapons
Definition: ship.h:658
net_player * Net_player
Definition: multi.cpp:94
float vm_vec_mag(const vec3d *v)
Definition: vecmat.cpp:325
float flFrametime
Definition: fredstubs.cpp:22
#define PACKET_SET_SIZE()
Definition: multimsgs.h:57
vec3d desired_vel
Definition: physics.h:70
physics_info phys_info
Definition: object.h:157
player * m_player
Definition: multi.h:459
#define OOC_TARGET_SEEK_LOCK
Definition: multi_obj.h:29
#define OO_LIMIT_HIGH
Definition: multi_obj.cpp:1555
#define MAX_SHIPS
Definition: globals.h:37
int fire_secondary_count
Definition: physics.h:111
float max_hits
Definition: ship.h:320
#define ADD_DATA(d)
Definition: multimsgs.h:37
#define MULTI_STANDALONE(np)
Definition: multi.h:139
void multi_io_send(net_player *pl, ubyte *data, int len)
Definition: multimsgs.cpp:371
Assert(pm!=NULL)
int target_objnum
Definition: ai.h:339
int submode
Definition: ai.h:394
int fire_primary_count
Definition: physics.h:110
Definition: pstypes.h:88
#define OOC_PRIMARY_BANK
Definition: multi_obj.h:32
int ai_index
Definition: ship.h:538
ushort net_signature
Definition: object.h:163
int ship_fire_primary(object *obj, int stream_weapons, int force)
Definition: ship.cpp:10760
float oo_arrive_time[MAX_SHIPS][5]
Definition: multi_obj.cpp:39
int find_player_id(short player_id)
Definition: multiutil.cpp:465
int timestamp_ticker
Definition: timer.cpp:199
GLclampf f
Definition: Glext.h:7097
#define MAX_OBJECTS
Definition: globals.h:83
GLuint GLenum GLsizei GLsizei GLint GLint GLboolean packed
Definition: Glext.h:8742
int Multi_cirate_can_send
Definition: multi_obj.cpp:1560
ai_info Ai_info[MAX_AI_INFO]
Definition: ai.cpp:23
#define MULTI_SERVER(np)
Definition: multi.h:138
int multi_oo_unpack_data(net_player *pl, ubyte *data)
Definition: multi_obj.cpp:698
#define f2fl(fx)
Definition: floating.h:37
int multi_pack_unpack_vel(int write, ubyte *data, matrix *orient, vec3d *pos, physics_info *pi)
Definition: multiutil.cpp:3893
enum_h * u
Definition: lua.cpp:12649
int status_update_stamp
Definition: multi_obj.h:41
int current_primary_bank
Definition: ship.h:106
int update_stamp
Definition: multi_obj.h:40
ship_subsys * targeted_subsys
Definition: ai.h:472
int n_quadrants
Definition: object.h:158
void multi_oo_reset_sequencing()
Definition: multi_obj.cpp:1820
#define AIF_SEEK_LOCK
Definition: ai.h:42
float weapon_energy
Definition: ship.h:640
uint flags
Definition: ship.h:644
int flags
Definition: multi.h:463
#define OF_PLAYER_SHIP
Definition: object.h:109
int OO_sort
Definition: multi_obj.cpp:160
bez_spline oo_interp_splines[MAX_SHIPS][2]
Definition: multi_obj.cpp:47
object * objp
Definition: lua.cpp:3105
GLfloat GLfloat GLfloat v2
Definition: Glext.h:5640
#define Int3()
Definition: pstypes.h:292
#define OBJ_UPDATE_LAN
Definition: multi_options.h:20
char stamp[STAMP_STRING_LENGTH]
Definition: fredview.cpp:74
void multi_oo_send_control_info()
Definition: multi_obj.cpp:1436
ship * shipp
Definition: lua.cpp:9162
int support_ship_objnum
Definition: ai.h:479
vec3d pos
Definition: object.h:152
float oo_arrive_time_next[MAX_SHIPS]
Definition: multi_obj.cpp:42
int packet_size
Definition: multi_sexp.cpp:41
ship_subsys_info subsys_info[SUBSYSTEM_MAX]
Definition: ship.h:632
void multi_oo_process_all(net_player *pl)
Definition: multi_obj.cpp:1234
int ai_flags
Definition: ai.h:330
#define STANDALONE_SHIP_SIG
Definition: multi.h:738
#define IS_VEC_NULL(v)
Definition: vecmat.h:28
void obj_player_fire_stuff(object *objp, control_info ci)
Definition: object.cpp:720
#define OO_CIRATE
Definition: multi_obj.cpp:1558
#define DCF(function_name, help_text)
The potent DCF macro, used to define new debug commands for the console.
Definition: console.h:60
#define IS_VEC_NULL_SQ_SAFE(v)
Definition: vecmat.h:24
#define OOC_AFTERBURNER_ON
Definition: multi_obj.h:34
int multi_oo_cirate_can_send()
Definition: multi_obj.cpp:1753
bool Multi_oo_afterburn_hack
Definition: multi_obj.cpp:51
int objnum
Definition: ship.h:1483
ship_subsys subsys_list
Definition: ship.h:630
void multi_oo_display()
Definition: multi_obj.cpp:1541
int OO_update_index
Definition: multi_obj.cpp:153
void multi_oo_build_ship_list(net_player *pl)
Definition: multi_obj.cpp:199
#define SIF_BOMBER
Definition: ship.h:886
#define OO_MIDRANGE
Definition: multi_obj.cpp:78
#define MAX_PACKET_SIZE
Definition: psnet2.h:34
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
#define OO_VEL_RET_SIZE
Definition: multiutil.h:200
int instance
Definition: object.h:150
#define OOC_PRIMARY_LINKED
Definition: multi_obj.h:33
void afterburners_stop(object *objp, int key_released)
GLenum GLint * range
Definition: Glext.h:7096
GLintptr offset
Definition: Glext.h:5497
#define NET_PLAYER_INDEX(np)
Definition: multi.h:125
net_player_info p_info
Definition: multi.h:473
void multi_oo_process_update(ubyte *data, header *hinfo)
Definition: multi_obj.cpp:1357
ship_subsys * ship_get_indexed_subsys(ship *sp, int index, vec3d *attacker_pos)
Definition: ship.cpp:13340
int flags
Definition: ship.h:322
#define OO_POS_NEW
Definition: multi_obj.cpp:60
void multi_oo_reset_status_timestamp(object *objp, int player_index)
Definition: multi_obj.cpp:1068
vec3d desired_rotvel
Definition: physics.h:71
#define OO_SUBSYS_TIME
Definition: multi_obj.cpp:85
struct matrix::@228::@230 vec
#define NETINFO_FLAG_AM_MASTER
Definition: multi.h:599
float ship_max_hull_strength
Definition: ship.h:597
int OO_server_rate
Definition: multi_obj.cpp:1563
void vm_vec_scale(vec3d *dest, float s)
Definition: vecmat.cpp:248
#define nprintf(args)
Definition: pstypes.h:239
dc_printf("Ganularity set to %i", OO_gran)
#define GM_MULTIPLAYER
Definition: systemvars.h:18
#define OO_HULL_NEW
Definition: multi_obj.cpp:62
#define BUILD_HEADER(t)
Definition: multimsgs.h:36
GLboolean GLboolean GLboolean GLboolean a
Definition: Glext.h:5781
vec3d oo_interp_points[MAX_SHIPS][2]
Definition: multi_obj.cpp:46
void bez_get_point(vec3d *out, float u)
Definition: spline.cpp:97
int flags
Definition: ship.h:1227
float get_hull_pct(object *objp)
Definition: object.cpp:271
#define OO_PRIMARY_BANK
Definition: multi_obj.cpp:65
int ship_get_index_from_subsys(ship_subsys *ssp, int objnum, int error_bypass)
Definition: ship.cpp:13390
#define OO_LIMIT_MED
Definition: multi_obj.cpp:1554
netgame_info Netgame
Definition: multi.cpp:97
void physics_sim_rot(matrix *orient, physics_info *pi, float sim_time)
Definition: physics.cpp:151
int mode
Definition: ai.h:336
#define OO_NEAR
Definition: multi_obj.cpp:76
#define MAX_OBJ_UPDATE_LEVELS
Definition: multi_options.h:16
int OO_client_rate
Definition: multi_obj.cpp:1564
#define OO_MAX_TIMESTAMP
Definition: multi_obj.cpp:73
object * OO_player_obj
Definition: multi_obj.cpp:159
float hull_strength
Definition: object.h:160
int multi_oo_is_interp_object(object *objp)
Definition: multi_obj.cpp:1825
#define MAX_MODEL_SUBSYSTEMS
Definition: model.h:103
int multi_pack_unpack_position(int write, ubyte *data, vec3d *pos)
Definition: multiutil.cpp:3586
#define OO_SUBSYSTEMS_AND_AI_NEW
Definition: multi_obj.cpp:64
bool multi_oo_sort_func(const short &index1, const short &index2)
Definition: multi_obj.cpp:162
int Multi_oo_front_near_update_times[MAX_OBJ_UPDATE_LEVELS]
Definition: multi_obj.cpp:97
#define SF_PRIMARY_LINKED
Definition: ship.h:458
short OO_ship_index[MAX_SHIPS]
Definition: multi_obj.cpp:151
net_player_server_info s_info
Definition: multi.h:472
int Multi_oo_front_medium_update_times[MAX_OBJ_UPDATE_LEVELS]
Definition: multi_obj.cpp:106
float vm_vec_dist(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:355
#define MAX_PLAYERS
Definition: pstypes.h:32
float aggregate_current_hits
Definition: ship.h:419
bool dc_optional_string_either(const char *str1, const char *str2)
Searches for an optional string and it's alias.
int Multi_cirate_stamp
Definition: multi_obj.cpp:1559
float current_hits
Definition: ship.h:319
Definition: ship.h:534
#define OO_PRIMARY_LINKED
Definition: multi_obj.cpp:66
int idx
Definition: multiui.cpp:761
#define OO_TRIGGER_DOWN
Definition: multi_obj.cpp:67
GLdouble GLdouble t
Definition: Glext.h:5329
int OO_server_rate_stamp
Definition: multi_obj.cpp:1568
#define OO_ORIENT_RET_SIZE
Definition: multiutil.h:195
#define OO_ROTVEL_RET_SIZE
Definition: multiutil.h:210
void ship_recalc_subsys_strength(ship *shipp)
Definition: ship.cpp:6020
void multi_oo_send_changed_object(object *changedobj)
Definition: multi_obj.cpp:1485
#define OO_AFTERBURNER_NEW
Definition: multi_obj.cpp:63
#define OO_POS_UPDATE_TOLERANCE
Definition: multi_obj.cpp:57
object Objects[MAX_OBJECTS]
Definition: object.cpp:62
unsigned char ubyte
Definition: pstypes.h:62
uint flags
Definition: physics.h:37
int multi_rate_add(int np_index, char *type, int size)
ubyte seq
Definition: multi_obj.h:39
void oo_update_time()
Definition: multi_obj.cpp:2014
int objnum
Definition: player.h:124
#define OBJ_INDEX(objp)
Definition: object.h:235
#define NETINFO_FLAG_LIMBO
Definition: multi.h:607
ship * Player_ship
Definition: ship.cpp:124
void multi_oo_reset_subsys_timestamp(object *objp, int player_index)
Definition: multi_obj.cpp:1074
#define GM_IN_MISSION
Definition: systemvars.h:23
matrix orient
Definition: object.h:153
#define OBJ_SHIP
Definition: object.h:32
GLfloat GLfloat v1
Definition: Glext.h:5639
void _cdecl void void _cdecl Error(const char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
#define GM_STANDALONE_SERVER
Definition: systemvars.h:27
void multi_oo_process()
Definition: multi_obj.cpp:1336
void dc_stuff_float(float *f)
Stuffs a float to the given variable.
#define OOC_FIRE_SECONDARY
Definition: multi_obj.h:27
void multi_oo_rate_init(net_player *pl)
Definition: multi_obj.cpp:1696
#define PACK_INT(v)
Definition: multi_obj.cpp:352
#define OO_POS_RET_SIZE
Definition: multiutil.h:190
#define ADD_USHORT(d)
Definition: multimsgs.h:39
void dc_stuff_int(int *i)
Stuffs an int to the given variable. Supports binary (0b), hexadecimal (0x), and octal (0o) formats...
GLuint GLfloat * val
Definition: Glext.h:6741
void vm_vec_sub(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:168
vec3d vel
Definition: physics.h:77
#define SIF_SUPPORT
Definition: ship.h:878
GLboolean GLboolean GLboolean b
Definition: Glext.h:5781
void multi_oo_update_server_rate()
Definition: multi_obj.cpp:1765
ship Ships[MAX_SHIPS]
Definition: ship.cpp:122
void physics_sim(vec3d *position, matrix *orient, physics_info *pi, float sim_time)
Definition: physics.cpp:364
#define OBJECT_UPDATE
Definition: multi.h:258
void afterburners_start(object *objp)
Definition: afterburner.cpp:68
typedef float(SCP_EXT_CALLCONV *SCPTRACKIR_PFFLOATVOID)()
void multi_oo_client_process()
Definition: multi_obj.cpp:1655
#define MAX_AI_INFO
Definition: ai.h:564
float oo_error
Definition: multi_obj.cpp:1952
int multi_oo_unpack_client_data(net_player *pl, ubyte *data)
Definition: multi_obj.cpp:578
#define SSF_NO_AGGREGATE
Definition: ship.h:294
void multi_oo_interp(object *objp)
Definition: multi_obj.cpp:1866
#define MULTI_CONNECTED(np)
Definition: multi.h:136
#define OBJ_UPDATE_MEDIUM
Definition: multi_options.h:18
player * Player
ushort orient_chksum
Definition: multi_obj.h:44
#define GET_USHORT(d)
Definition: multimsgs.h:49
#define PACK_USHORT(v)
Definition: multi_obj.cpp:350
Definition: multi.h:385
unsigned short ushort
Definition: pstypes.h:63
#define NETINFO_FLAG_RESPAWNING
Definition: multi.h:609
float vm_vec_copy_normalize(vec3d *dest, const vec3d *src)
Definition: vecmat.cpp:427
ship_subsys * locking_subsys
Definition: player.h:176
ship_obj Ship_obj_list
Definition: ship.cpp:162
#define OO_FAR
Definition: multi_obj.cpp:80
int ship_info_index
Definition: ship.h:539
int HEADER_LENGTH
Definition: multi.cpp:106
#define MULTIPLAYER_MASTER
Definition: multi.h:130
An overhauled/updated debug console to allow monitoring, testing, and general debugging of new featur...
SCP_vector< ship_info > Ship_info
Definition: ship.cpp:164
#define LOCATION
Definition: pstypes.h:245
#define SIF_KNOSSOS_DEVICE
Definition: ship.h:912
#define OBJ_UPDATE_HIGH
Definition: multi_options.h:19
void multi_oo_reset_timestamp(net_player *pl, object *objp, int range, int in_cone)
Definition: multi_obj.cpp:1019
#define SIF_FIGHTER
Definition: ship.h:885
#define PACK_BYTE(v)
Definition: multi_obj.cpp:349
GLenum GLsizei GLenum GLenum const GLvoid * data
Definition: Gl.h:1509
SCP_vector< float > shield_quadrant
Definition: object.h:159
#define OF_SHOULD_BE_DEAD
Definition: object.h:106
short id
Definition: multi.h:390
#define OOC_TARGET_LOCKED
Definition: multi_obj.h:28
#define OO_MAX_SIZE
Definition: multi_obj.cpp:54
GLsizei GLsizei GLuint * obj
Definition: Glext.h:5619
object * multi_get_network_object(ushort net_signature)
Definition: multiutil.cpp:220
float vm_vec_dot(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:312
int subsys_update_stamp
Definition: multi_obj.h:42
void multi_oo_gameplay_init()
Definition: multi_obj.cpp:1386
#define OBJ_UPDATE_LOW
Definition: multi_options.h:17
void oo_display()
Definition: multi_obj.cpp:2031
float oo_arrive_time_avg_diff[MAX_SHIPS]
Definition: multi_obj.cpp:41
#define OO_NEAR_DIST
Definition: multi_obj.cpp:77
object * Player_obj
Definition: object.cpp:56
#define GET_SHORT(d)
Definition: multimsgs.h:48
int Multi_oo_rear_far_update_times[MAX_OBJ_UPDATE_LEVELS]
Definition: multi_obj.cpp:142
int locking_on_center
Definition: player.h:178
#define SF_DYING
Definition: ship.h:447
int temp
Definition: lua.cpp:4996
#define OO_ORIENT_NEW
Definition: multi_obj.cpp:61
#define PF_AFTERBURNER_ON
Definition: physics.h:20
int Multi_oo_front_far_update_times[MAX_OBJ_UPDATE_LEVELS]
Definition: multi_obj.cpp:115
int OO_gran
Definition: multi_obj.cpp:1571
void multi_oo_rate_init_all()
Definition: multi_obj.cpp:1668
#define GET_INT(d)
Definition: multimsgs.h:50
#define UNPACK_PERCENT(v)
Definition: multi_obj.cpp:697
uint flags
Definition: object.h:151
#define SUBSYSTEM_MAX
Definition: model.h:64
void multi_oo_rate_process()
Definition: multi_obj.cpp:1604
#define SF_TRIGGER_DOWN
Definition: ship.h:462
char type
Definition: object.h:146
#define OO_MIDRANGE_DIST
Definition: multi_obj.cpp:79
int oo_arrive_time_count[MAX_SHIPS]
Definition: multi_obj.cpp:40
int Multi_oo_target_update_times[MAX_OBJ_UPDATE_LEVELS]
Definition: multi_obj.cpp:88
net_player Net_players[MAX_PLAYERS]
Definition: multi.cpp:93
ushort pos_chksum
Definition: multi_obj.h:43
void vm_vec_add(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:159
net_player * server
Definition: multi.h:505
#define UDP_HEADER_SIZE
Definition: psnet2.h:56
void multi_oo_calc_interp_splines(int ship_index, vec3d *cur_pos, matrix *cur_orient, physics_info *cur_phys_info, vec3d *new_pos, matrix *new_orient, physics_info *new_phys_info)
Definition: multi_obj.cpp:1970
multi_global_options Multi_options_g
const GLubyte * c
Definition: Glext.h:8376
int Multi_oo_rear_near_update_times[MAX_OBJ_UPDATE_LEVELS]
Definition: multi_obj.cpp:124
int multi_oo_pack_client_data(ubyte *data)
Definition: multi_obj.cpp:269
#define NET_PLAYER_NUM(np)
Definition: multi.h:126
multi_local_options options
Definition: multi.h:452
int display_oo_bez
Definition: multi_obj.cpp:2018
int current_target_is_locked
Definition: ai.h:490
float forward_thrust
Definition: physics.h:72
ushort cf_add_chksum_short(ushort seed, ubyte *buffer, int size)
Definition: cfile.cpp:1614
float vm_vec_normalize(vec3d *v)
Definition: vecmat.cpp:460
int multi_oo_pack_data(net_player *pl, object *objp, ubyte oo_flags, ubyte *data_out)
Definition: multi_obj.cpp:353
int multi_pack_unpack_rotvel(int write, ubyte *data, matrix *orient, vec3d *pos, physics_info *pi)
Definition: multiutil.cpp:4041