src/multiplay.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *            multiplay.cpp
00003  *
00004  *  Sun Sep 11 10:15:34 2005
00005  *  Copyright  2005  Joe Venzon
00006  *  joe@venzon.net
00007  ****************************************************************************/
00008 
00009 /*
00010  *  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU Library General Public License for more details.
00019  *
00020  *  You should have received a copy of the GNU General Public License
00021  *  along with this program; if not, write to the Free Software
00022  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00023  */
00024  
00025 #include "multiplay.h"
00026 
00027 MULTIPLAY::MULTIPLAY()
00028 {
00029         remote_players = 0;
00030         remote_playernum = 0;
00031         
00032         int i;
00033         for (i = 0; i < MAX_PLAYERS; i++)
00034         {
00035                 funcmems[i] = NULL;
00036                 fnums[i] = 0;
00037         }
00038         
00039         for (i = 0; i < MAX_PLAYERS; i++)
00040         {
00041                 timeindex[i] = 0.0;
00042                 loadstates[i].time = 0.0;
00043                 loadstatenow[i] = false;
00044                 numpackets[i] = 0;
00045                 
00046                 packetarrays[i] = NULL;
00047                 //packetarraytime[i] = 0.0;
00048                 
00049                 nooptime[i] = 0;
00050                 noopvalid[i] = false;
00051                 tickthisframe[i] = false;
00052                 
00053                 nooptick[i] = false;
00054         }
00055         
00056         tx = 0;
00057         rx = 0;
00058         
00059         dbgnumstates = 0;
00060         dbgnumpackets = 0;
00061 }
00062 
00063 void MULTIPLAY::UpdateSettings()
00064 {
00065         settings.Get( "network.server_port", port );
00066 }
00067 
00068 bool MULTIPLAY::Server()
00069 {
00070         return net.Server();
00071 }
00072 
00073 bool MULTIPLAY::Connect(string host)
00074 {
00075         Disconnect();
00076         
00077         replay.BuildFuncMem(funcmems[0], fnums[0]);
00078         
00079         bool ret = net.Connect(host, port);
00080         if (!Server() && ret)
00081         {
00082                 remote_players = 0;
00083                 remote_players++;
00084                 
00085                 ret = ExchangeWorldInfo();
00086                 int i;
00087                 for (i = 0; i < MAX_PLAYERS; i++)
00088                 {
00089                         timeindex[i] = 0.0;
00090                         loadstates[i].time = 0.0;
00091                         loadstatenow[i] = false;
00092                         numpackets[i] = 0;
00093                         
00094                         //packetarraytime[i] = 0.0;
00095                         
00096                         nooptime[i] = 0;
00097                         noopvalid[i] = false;
00098                         tickthisframe[i] = false;
00099                         nooptick[i] = false;
00100                 }
00101                 
00102                 dbgnumstates = 0;
00103                 dbgnumpackets = 0;
00104                 
00105                 mq1.Clear();
00106                 mq1.AddMessage("Successfully connected to server");
00107         }
00108         return ret;
00109 }
00110 
00111 bool MULTIPLAY::Host()
00112 {
00113         Disconnect();
00114         
00115         replay.BuildFuncMem(funcmems[0], fnums[0]);
00116         
00117         remote_playernum = 0;
00118         return net.Connect("Server", port);
00119 }
00120 
00121 extern float FrameTime();
00122 
00123 void MULTIPLAY::Update(double inc)
00124 {       
00125         if (MP_DBGDEEP)
00126                 cout << "multiplay update" << endl;
00127         
00128         //create packet arrays if necessary
00129         int i;
00130         for (i = 0; i < NumConnected() + 1; i++)
00131         {
00132                 if (packetarrays[i] == NULL)
00133                 {
00134                         packetarrays[i] = new REPLAY_PACKET [PACKET_ARRAY_SIZE];
00135                 }
00136         }
00137         
00138         if (MP_DBGDEEP)
00139                 cout << "packet mem allocated" << endl;
00140         
00141         bool oldc = Connected();
00142         net.Update();
00143         if (!oldc && Connected())
00144         {
00145                 //wasn't connected before, connected now.
00146                 if (Server())
00147                         remote_players++;
00148                 
00149                 ExchangeWorldInfo();
00150                 
00151                 int i;
00152                 for (i = 0; i < MAX_PLAYERS; i++)
00153                 {
00154                         timeindex[i] = 0.0;
00155                         loadstates[i].time = 0.0;
00156                         loadstatenow[i] = false;
00157                         numpackets[i] = 0;
00158                         
00159                         //packetarraytime[i] = 0.0;
00160                         
00161                         nooptime[i] = 0;
00162                         noopvalid[i] = false;
00163                         tickthisframe[i] = false;
00164                         nooptick[i] = false;
00165                 }
00166                 
00167                 dbgnumstates = 0;
00168                 dbgnumpackets = 0;
00169                 
00170                 mq1.Clear();
00171                 mq1.AddMessage("A client successfully connected");
00172         }
00173         
00174         if (MP_DBGDEEP)
00175                 cout << "net updated" << endl;
00176         
00177         //read incoming data
00178         /*if (Connected() && net.NumBufferedPackets() > 0)
00179         {
00180                 int i;
00181                 for (i = 0; i < net.GetMaxBuffers(); i++)
00182                 {
00183                         if (net.GetBuffer(i)->Valid())
00184                                 ProcessPacket(net.GetBuffer(i));
00185                 }
00186         }*/
00187         if (Connected())
00188         {
00189                 if (!MP_DISABLEGET)
00190                 {               
00191                         ReceiveState();
00192                 
00193                         if (MP_DBGDEEP)
00194                                 cout << "state receive" << endl;
00195                         
00196                         ReceivePacketArray();
00197                         
00198                         if (MP_DBGDEEP)
00199                                 cout << "packet array receive" << endl;
00200                 }
00201                 
00202                 if (!MP_DISABLEFUNCUPDATE)
00203                 {
00204                         double tval = 0;
00205                         string ticktype = "packet array";
00206                         nooptick[1] = false;
00207                         if (PacketArrayValid(1))
00208                                 tval = GetPacketArrayTime(1);
00209                         if (noopvalid[1] && nooptime[1] > tval)
00210                         {
00211                                 tval = nooptime[1];
00212                                 ticktype = "noop";
00213                                 nooptick[1] = true;
00214                         }
00215                         if ((noopvalid[1] || PacketArrayValid(1)) && timeindex[1] < tval + PACKET_ARRAY_FREQUENCY - FrameTime()/2.0)
00216                         {
00217                                 tickthisframe[1] = true;
00218                                 
00219                                 /*int nextpacket = curpackets[1];
00220                                 if (nextpacket >= numpackets[1])
00221                                         nextpacket = numpackets[1] - 1;
00222                                 if (ticktype == "packet array")
00223                                         cout << "ticking " << ticktype << ": " << GetFuncMem(1)[GetPacketArray(1)[nextpacket].chardata[CHAR_FUNCNUM]].func_name << " " << curpackets[1] << "/" << numpackets[1] << " packets for " << tval << " at " << timeindex[1] << endl;
00224                                 else
00225                                         cout << "ticking " << ticktype << " for " << tval << " at " << timeindex[1] << endl;*/
00226                                 
00227                                 timeindex[1] += inc;
00228                                 
00229                                 //process packet data into the function memory (which is then given to DoOp by vamosworld)
00230                                 //if (PacketArrayValid(1))// && !(ticktype == "noop"))
00231                                 int i;
00232                                 for (i = 0; i < fnums[1]; i++)
00233                                 {
00234                                         if (!GetFuncMem(1)[i].held && GetFuncMem(1)[i].active)
00235                                                 GetFuncMem(1)[i].active = false;
00236                                 }
00237                                 
00238                                 UpdateFuncmem(1);
00239                         }
00240                         else
00241                         {
00242                                 tickthisframe[1] = false;
00243                                 //cout << "not ticking at " << timeindex[1] << endl;
00244                         }
00245                 }
00246                 
00247                 if (MP_DBGDEEP)
00248                         cout << "ticked" << endl;
00249                 
00250                 //check to see if we need to increment          
00251                 /*for (i = 0; i < NumConnected(); i++)
00252                 {
00253                         if (loadstatevalid[i+1] && timeindex[i+1] < loadstates[i+1].time + STATE_FREQUENCY + FrameTime()/2.0)
00254                         {
00255                                 timeindex[i+1] += inc;
00256                         }
00257                 }*/
00258                 //if (packetarrayvalid[1] && timeindex[1] < loadstates[1].time + STATE_FREQUENCY - FrameTime()/2.0)
00259         }
00260 
00261         //cout << "Latency: " << GetLatency(1) << " (" << timeindex[0] << "-" << timeindex[1] << ")" << endl;
00262         
00263         //disconnect if the latency is super high
00264         if (GetLatency(1) > CLIENT_DISCONNECT_TIMEOUT)
00265         {
00266                 Disconnect();
00267         }
00268         
00269         //update statistics
00270         UpdateStats();
00271         
00272         if (MP_DBGDEEP)
00273                         cout << "multiplay update done" << endl;
00274 }
00275 
00276 void MULTIPLAY::Disconnect()
00277 {
00278         bool wasconnected = Connected();
00279         
00280         net.Disconnect();
00281         remote_players = 0;
00282         remote_playernum = 0;
00283         
00284         int i;
00285         for (i = 0; i < MAX_PLAYERS; i++)
00286                 timeindex[i] = 0.0;
00287         
00288         if (MP_RECORD && dbgnumpackets > 0)
00289         {
00290                 int slot = 0;
00291                 
00292                 if (MP_REMOTE_RECORD)
00293                         slot = 1;
00294                 
00295                 FILE * dbgout = fopen("replays/mpdebug.vdr", "wb");
00296                 if (dbgout)
00297                 {
00298                         replay.WriteHeader(dbgout, GetFuncMem(slot), NumFuncs(slot), slot);
00299                         replay.WritePackets(dbgout, dbgpacket, dbgnumpackets, dbgstate, dbgnumstates);
00300                         fclose(dbgout);
00301                 }
00302                 
00303                 dbgnumpackets = 0;
00304                 dbgnumstates = 0;
00305         }
00306         
00307         if (wasconnected)
00308                 mq1.AddMessage("Disconnected");
00309 }
00310 
00311 extern bool LoadWorld();
00312 extern void SelectCar(string cfile, bool trim);
00313 
00314 MULTIPLAY::~MULTIPLAY()
00315 {
00316         int i;
00317         for (i = 0; i < MAX_PLAYERS; i++)
00318         {
00319                 if (funcmems[i] != NULL)
00320                         delete [] funcmems[i];
00321                 
00322                 funcmems[i] = NULL;
00323                 
00324                 if (packetarrays[i] != NULL)
00325                         delete [] packetarrays[i];
00326                 
00327                 packetarrays[i] = NULL;
00328         }
00329 }
00330 
00331 bool MULTIPLAY::ExchangeWorldInfo()
00332 {
00333         char tc[32767];
00334         sprintf(tc, "%c%c %s\n%i\n%s\n%i\n%i", (char) (replay.Get_FuncNetControl()), (char) CONTROL_WORLDINFO, state.GetCarName(0).c_str(), state.GetCarPaint(0), state.GetTrackName().c_str(), NumConnected(), NumConnected());
00335         
00336         //encode string length into the packet
00337         tc[2] = (char) ((Uint8) strlen(tc));
00338         
00339         //encode function memories, starting at strlen(tc)
00340         int tclen = strlen(tc);
00341         int opos = tclen;
00342         
00343         //tc[opos] = (char)((Uint8) fnums[0]);
00344         opos = AddToData(tc, &(fnums[0]), sizeof(int), opos);
00345         int f;
00346         for (f = 0; f < fnums[0]; f++)
00347         {
00348                 char fout[FUNCTION_CHARS];
00349                 strcpy(fout, GetFuncMem(0)[f].func_name.c_str());
00350                 //fwrite(fout,1,FUNCTION_CHARS, rf);
00351                 opos = AddToData(tc, fout, FUNCTION_CHARS, opos);
00352         }
00353         
00354         net.Send(tc, opos);
00355         
00356         int ret = net.RecvBlock(tc, 32767, GENERIC_TIMEOUT);
00357         if (ret > 0)
00358         {
00359                 int pos = 0;
00360                 int err = 0;
00361                 
00362                 if (tc[pos] == (char) (replay.Get_FuncNetControl()))
00363                 {
00364                         pos++;
00365                         if (tc[pos] == (char) (CONTROL_WORLDINFO))
00366                         {
00367                                 pos++;
00368                                 
00369                                 //decode string section length
00370                                 int slen = tc[2];
00371                                 pos++;
00372                                 
00373                                 string car;
00374                                 string carpaint;
00375                                 string track;
00376                                 string numplayers;
00377                                 string myplayernum;
00378                                 char sc[2];
00379                                 sc[1] = '\0';
00380                                 
00381                                 while (pos < slen && tc[pos] != '\n')
00382                                 {
00383                                         sc[0] = tc[pos];
00384                                         car.append(sc);
00385                                         
00386                                         pos++;
00387                                 }
00388                                 
00389                                 pos++;
00390                                 
00391                                 while (pos < slen && tc[pos] != '\n')
00392                                 {
00393                                         sc[0] = tc[pos];
00394                                         carpaint.append(sc);
00395                                         
00396                                         pos++;
00397                                 }
00398                                 
00399                                 pos++;
00400                                 
00401                                 while (pos < slen && tc[pos] != '\n')
00402                                 {
00403                                         sc[0] = tc[pos];
00404                                         track.append(sc);
00405                                         
00406                                         pos++;
00407                                 }
00408                                 
00409                                 pos++;
00410                                 
00411                                 while (pos < slen && tc[pos] != '\n')
00412                                 {
00413                                         sc[0] = tc[pos];
00414                                         numplayers.append(sc);
00415                                         
00416                                         pos++;
00417                                 }
00418                                 
00419                                 pos++;
00420                                 
00421                                 while (pos < slen && tc[pos] != '\n')
00422                                 {
00423                                         sc[0] = tc[pos];
00424                                         myplayernum.append(sc);
00425                                         
00426                                         pos++;
00427                                 }
00428                                 
00429                                 int icarpaint = atoi(carpaint.c_str());
00430                                 int inumplayers = atoi(numplayers.c_str());
00431                                 int imyplayernum = atoi(myplayernum.c_str());
00432                                 
00433                                 if (MP_DEBUG)
00434                                 {
00435                                         /*tc[ret] = '\0';
00436                                         cout << "raw worldinfo:  " << tc << endl;*/
00437                                         cout << "worldinfo size:  " << ret << endl;
00438                                         cout << "got worldinfo:  " << car << "," << icarpaint << "," << track << "," << inumplayers << "," << imyplayernum << endl;
00439                                 }
00440                                 
00441                                 //decode function memory
00442                                 //first clear it out
00443                                 int newpnum = NumConnected();
00444                                 if (funcmems[newpnum] != NULL)
00445                                 {
00446                                         delete [] funcmems[newpnum];
00447                                         funcmems[newpnum] = NULL;
00448                                 }
00449                                 pos = slen;
00450                                 pos = GetFromData(tc, &(fnums[newpnum]), sizeof(int), pos);
00451                                 funcmems[newpnum] = new FUNCTION_MEMORY [fnums[newpnum]];
00452                                 for (f = 0; f < fnums[newpnum]; f++)
00453                                 {
00454                                         char fin[FUNCTION_CHARS];
00455                                         pos = GetFromData(tc, fin, FUNCTION_CHARS, pos);
00456                                         GetFuncMem(newpnum)[f].func_name = fin;
00457                                         GetFuncMem(newpnum)[f].oldval = 0.0;
00458                                         GetFuncMem(newpnum)[f].held = false;
00459                                         GetFuncMem(newpnum)[f].active = false;
00460                                 }
00461                                 
00462                                 if (NET_DEBUG)
00463                                 {
00464                                         cout << "got functions:  " << fnums[newpnum];
00465                                         cout << " (" << fnums[0] << " local)" << endl;
00466                                         /*cout << "function list:  ";
00467                                         for (f = 0; f < fnums[newpnum]; f++)
00468                                         {
00469                                                 cout << GetFuncMem(newpnum)[f].func_name << ",";
00470                                         }
00471                                         cout << endl;*/
00472                                 }
00473                                 
00474                                 if (!Server())
00475                                 {
00476                                         state.SetTrackName(track);
00477                                         state.SetCarName(1, car);
00478                                         state.SetCarPaint(1, icarpaint);
00479                                         remote_players = inumplayers;
00480                                         remote_playernum = imyplayernum;
00481                                         
00482                                         LoadWorld();
00483                                 }
00484                                 else
00485                                 {
00486                                         state.SetCarName(1, car);
00487                                         state.SetCarPaint(1, icarpaint);
00488                                         
00489                                         SelectCar(state.GetCarName(0), true);
00490                                         /*try
00491                                         {
00492                                                 int numcars = NumConnected();
00493                                                 Vamos_Body::Gl_Car* car = 0;
00494                                                 car = new Vamos_Body::Gl_Car (Vamos_Geometry::Three_Vector (11.0, 0.0, 0.6));
00495                                                 car->read ("data/", state.GetCarName(numcars));
00496                                                 car->SetPaint(state.GetCarPaint(numcars));
00497                                                 car->chassis ().translate (Vamos_Geometry::Three_Vector (10.0, 0.0, 
00498                                                         -car->chassis ().lowest_contact_position () + 0.5));
00499                                                 car->start_engine ();
00500                                                 car->set_controller(2);
00501                                                 world.add_car (car);
00502                                         }
00503                                         catch (Vamos_Geometry::XML_Exception& error)
00504                                         {
00505                                           std::cerr << error.message () << std::endl;
00506                                           std::exit (EXIT_FAILURE);
00507                                         }*/
00508                                 }
00509                         }
00510                         else
00511                                 err = 2;
00512                 }
00513                 else
00514                         err = 1;
00515                 
00516                 if (err)
00517                 {
00518                         //retry?
00519                 
00520                         //nah, just disconnect.
00521                         net.Disconnect();
00522                         if (MP_DEBUG)
00523                         {
00524                                 cout << "multiplay:  Update:  error parsing world info:  error " << err << endl;
00525                         }
00526                         return false;
00527                 }
00528         }
00529         else
00530         {
00531                 //retry?
00532                 
00533                 //nah, just disconnect.
00534                 net.Disconnect();
00535                 if (MP_DEBUG)
00536                 {
00537                         cout << "multiplay:  Update:  didn't receive world info:  error " << ret << endl;
00538                 }
00539                 
00540                 return false;
00541         }
00542         
00543         return true;
00544 }
00545 
00546 int MULTIPLAY::NumConnected()
00547 {
00548         return remote_players;
00549 }
00550 
00551 //add source (size len) to dest, starting at start, and return the new length
00552 int MULTIPLAY::AddToData(void * dest, void * source, int len, int start)
00553 {
00554         int i;
00555         for (i = 0; i < len; i++)
00556         {
00557                 ((char *) dest)[i+start] = ((char *) source)[i];
00558         }
00559         
00560         return start + len;
00561 }
00562 
00563 //get dest (size len) from source, starting at start, and return len+start
00564 int MULTIPLAY::GetFromData(void * source, void * dest, int len, int start)
00565 {
00566         int i;
00567         for (i = 0; i < len; i++)
00568         {
00569                 ((char *) dest)[i] = ((char *) source)[i+start];
00570         }
00571         
00572         return start + len;
00573 }
00574 
00575 void MULTIPLAY::AddRecord(string newdofunction, float newval, int newstate)
00576 {
00577         if (MP_DISABLEADDRECORD)
00578                 return;
00579         
00580         //if (replay && num_packets < MAX_PACKETS)
00581         if (NumConnected() > 0 && GetFuncMem(0) != NULL)
00582         {
00583                 //packet
00584                 
00585                 int funcidx = 0;
00586                 int i;
00587                 for (i = 0; i < fnums[0]; i++)
00588                 {
00589                         if (GetFuncMem(0)[i].func_name == newdofunction)
00590                                 funcidx = i;
00591                 }
00592                 
00593                 //put the values into their functional slot.  this allows higher priority
00594                 // commands to be considered over lower priority ones (as with the vamosworld
00595                 // control processing code (effectively)
00596                 if (newstate != 2)
00597                 {
00598                         GetFuncMem(0)[funcidx].lastupdateat = timeindex[0];
00599                         GetFuncMem(0)[funcidx].newval = newval;
00600                         if (newstate == 1)
00601                                 GetFuncMem(0)[funcidx].held = true;
00602                         else
00603                                 GetFuncMem(0)[funcidx].held = false;
00604                         GetFuncMem(0)[funcidx].active = true;
00605                         //if (newdofunction == "gas")
00606                                 //cout << newdofunction << ", lastupdate set at " << timeindex << endl;
00607                 }
00608         }
00609         else
00610         {
00611                 if (NET_DEBUG)
00612                 {
00613                         cout << "net:  AddRecord:  wrong state for addrecord or funcmems not created" << endl;
00614                 }
00615         }
00616 }
00617 
00618 void MULTIPLAY::ProcessPacket(PBUFFER * p)
00619 {
00620         int pos = 0;
00621         
00622         Uint8 ptype;
00623         
00624         pos = GetFromData(p->data, &ptype, sizeof(Uint8), pos);
00625         
00626         if (NET_DEBUG)
00627                 cout << "net:  ProcessPacket:  got packet, size " << p->len << endl;            
00628         
00629         if (ptype == replay.Get_FuncStateInfo())
00630         {
00631                 if (NET_DEBUG)
00632                         cout << "net:  ProcessPacket:  packet type is State Info" << endl;
00633                 
00634                 double ptime;
00635                 pos = GetFromData(p->data, &ptime, sizeof(double), pos);
00636                 
00637                 if (NET_DEBUG)
00638                         cout << "net:  ProcessPacket:  packet time is " << ptime << endl;
00639         }
00640         else if (ptype == replay.Get_FuncNetControl())
00641         {
00642                 if (NET_DEBUG)
00643                         cout << "net:  ProcessPacket:  packet type is unexpected control sequence" << endl;
00644         }
00645         else
00646         {
00647                 if (NET_DEBUG)
00648                         cout << "net:  ProcessPacket:  packet type is unknown" << endl;
00649         }
00650         
00651         p->Clear();
00652 }
00653 
00654 void MULTIPLAY::SendState()
00655 {
00656         //send a state if necessary
00657         
00658         float remain;
00659         int mult;
00660         mult = (int) ((timeindex[0]+FrameTime()/2.0) / STATE_FREQUENCY);
00661         remain = (timeindex[0] + FrameTime()/2.0) - (float)(mult * STATE_FREQUENCY);
00662         
00663         if (remain < FrameTime())
00664         {
00665                 if (NET_DEBUG)
00666                 {
00667                         cout << "net:  SendState:  sending state at time " << GetCurState(0)->time << endl;
00668                         cout << "used buffers: " << net.NumBufferedPackets() << endl;
00669                 }
00670                 
00671                 //it's time to record a state
00672                 curstates[0].fnum = fnums[0]; //set the number of funcs
00673                 if (curstates[0].funcmem != NULL) //clear old func data
00674                 {
00675                         delete [] curstates[0].funcmem;
00676                         curstates[0].funcmem = NULL;
00677                 }
00678                 curstates[0].funcmem = new FUNCTION_MEMORY_SYNC [fnums[0]]; //allocate func data
00679                 int i;
00680                 for (i = 0; i < fnums[0]; i++) //record current func data
00681                 {
00682                         curstates[0].funcmem[i].oldval = GetFuncMem(0)[i].oldval;
00683                         curstates[0].funcmem[i].newval = GetFuncMem(0)[i].newval;
00684                         curstates[0].funcmem[i].held = GetFuncMem(0)[i].held;
00685                         curstates[0].funcmem[i].active = GetFuncMem(0)[i].active;
00686                         curstates[0].funcmem[i].lastupdateat = GetFuncMem(0)[i].lastupdateat;
00687                 }
00688                 
00689                 
00690                 //now, send a packet
00691                 Uint8 tp[MAX_PACKET_SIZE];
00692                 int tplen = 0;
00693                 Uint8 tempchar;
00694                 tempchar = replay.Get_FuncStateInfo();
00695                 tplen = AddToData(tp, &tempchar, sizeof(Uint8), tplen);
00696                 tplen = AddToData(tp, &GetCurState(0)->time, sizeof(double), tplen);
00697                 //fwrite(&time, sizeof(double), 1, fout);
00698                 tplen = WriteVector(GetCurState(0)->chassispos, tp, tplen);
00699                 tplen = WriteMatrix(GetCurState(0)->chassisorientation, tp, tplen);
00700                 tplen = WriteVector(GetCurState(0)->chassisvel, tp, tplen);
00701                 tplen = WriteVector(GetCurState(0)->chassisangvel, tp, tplen);
00702                 
00703                 for (i = 0; i < 4; i++)
00704                 {
00705                         tplen = AddToData(tp, &GetCurState(0)->suspdisp[i], sizeof(double), tplen);
00706                         tplen = AddToData(tp, &GetCurState(0)->suspcompvel[i], sizeof(double), tplen);
00707                         tplen = WriteVector(GetCurState(0)->whlangvel[i], tp, tplen);
00708                         tplen = AddToData(tp, &GetCurState(0)->tirespeed[i], sizeof(double), tplen);
00709                 }
00710                 
00711                 tplen = AddToData(tp, &GetCurState(0)->gear, sizeof(int), tplen);
00712                 tplen = AddToData(tp, &GetCurState(0)->enginespeed, sizeof(double), tplen);
00713                 tplen = AddToData(tp, &GetCurState(0)->clutchspeed, sizeof(double), tplen);
00714                 tplen = AddToData(tp, &GetCurState(0)->enginedrag, sizeof(double), tplen);
00715                 
00716                 tplen = AddToData(tp, &GetCurState(0)->segment, sizeof(int), tplen);
00717                 
00718                 //write a function state block
00719                 tplen = AddToData(tp, &(fnums[0]), sizeof(int), tplen);
00720                 
00721                 for (i = 0; i < fnums[0]; i++)
00722                 {
00723                         //fwrite(&(funcmem[i]), sizeof(struct FUNCTION_MEMORY_SYNC), 1, fout);
00724                         tplen = AddToData(tp, &(GetCurState(0)->funcmem[i]), sizeof(struct FUNCTION_MEMORY_SYNC), tplen);
00725                 }
00726                 
00727                 net.Send(tp, tplen);
00728                 
00729                 if (MP_RECORD && !MP_REMOTE_RECORD)
00730                 {
00731                         dbgstate[dbgnumstates].CopyFrom(curstates[0]);
00732                         dbgnumstates++;
00733                 }
00734         }
00735         //else cout << timeindex[0] << "," << mult << "," << remain << endl;
00736 }
00737 
00738 int MULTIPLAY::WriteVector(Vamos_Geometry::Three_Vector wv, Uint8 * dest, int start)
00739 {
00740         //fwrite(&wv[0], sizeof(double), 1, fout);
00741         
00742         int len = start;
00743         
00744         len = AddToData(dest, &wv[0], sizeof(double), len);
00745         len = AddToData(dest, &wv[1], sizeof(double), len);
00746         len = AddToData(dest, &wv[2], sizeof(double), len);
00747         
00748         return len;
00749 }
00750 
00751 int MULTIPLAY::WriteMatrix(Vamos_Geometry::Three_Matrix wv, Uint8 * dest, int start)
00752 {
00753         int len = start;
00754         
00755         //fwrite(&wv[0][0], sizeof(double), 1, fout);
00756         //fwrite(&wv[0][1], sizeof(double), 1, fout);
00757         //...
00758         len = AddToData(dest, &wv[0][0], sizeof(double), len);
00759         len = AddToData(dest, &wv[0][1], sizeof(double), len);
00760         len = AddToData(dest, &wv[0][2], sizeof(double), len);
00761         
00762         len = AddToData(dest, &wv[1][0], sizeof(double), len);
00763         len = AddToData(dest, &wv[1][1], sizeof(double), len);
00764         len = AddToData(dest, &wv[1][2], sizeof(double), len);
00765         
00766         len = AddToData(dest, &wv[2][0], sizeof(double), len);
00767         len = AddToData(dest, &wv[2][1], sizeof(double), len);
00768         len = AddToData(dest, &wv[2][2], sizeof(double), len);
00769         
00770         return len;
00771 }
00772 
00773 void MULTIPLAY::ReadState(Uint8 * s, int slot)
00774 {
00775         //read a state
00776 
00777         //allocate function sync memory
00778         loadstates[slot].fnum = fnums[slot]; //set the number of funcs
00779         if (loadstates[slot].funcmem != NULL) //clear old func data
00780         {
00781                 delete [] loadstates[slot].funcmem;
00782                 loadstates[slot].funcmem = NULL;
00783         }
00784         
00785         //now, read the state 
00786         int len = 0;
00787         Uint8 tempchar;
00788         len = GetFromData(s, &tempchar, sizeof(Uint8), len);
00789         if (tempchar != replay.Get_FuncStateInfo())
00790         {
00791                 if (NET_DEBUG)
00792                         cout << "net:  ReadState:  packet is not a state" << endl;
00793                 return;
00794         }
00795         
00796         len = GetFromData(s, &loadstates[slot].time, sizeof(double), len);
00797         //tplen = AddToData(tp, &GetCurState(0)->time, sizeof(double), tplen);
00798         //fwrite(&time, sizeof(double), 1, fout);
00799         len = ReadVector(loadstates[slot].chassispos, s, len);
00800         len = ReadMatrix(loadstates[slot].chassisorientation, s, len);
00801         len = ReadVector(loadstates[slot].chassisvel, s, len);
00802         len = ReadVector(loadstates[slot].chassisangvel, s, len);
00803 
00804         int i;  
00805         for (i = 0; i < 4; i++)
00806         {
00807                 len = GetFromData(s, &loadstates[slot].suspdisp[i], sizeof(double), len);
00808                 len = GetFromData(s, &loadstates[slot].suspcompvel[i], sizeof(double), len);
00809                 len = ReadVector(loadstates[slot].whlangvel[i], s, len);
00810                 len = GetFromData(s, &loadstates[slot].tirespeed[i], sizeof(double), len);
00811         }
00812         
00813         len = GetFromData(s, &loadstates[slot].gear, sizeof(int), len);
00814         len = GetFromData(s, &loadstates[slot].enginespeed, sizeof(double), len);
00815         len = GetFromData(s, &loadstates[slot].clutchspeed, sizeof(double), len);
00816         len = GetFromData(s, &loadstates[slot].enginedrag, sizeof(double), len);
00817         
00818         len = GetFromData(s, &loadstates[slot].segment, sizeof(int), len);
00819         
00820         //read the function state block
00821         len = GetFromData(s, &(fnums[slot]), sizeof(int), len);
00822         loadstates[slot].funcmem = new FUNCTION_MEMORY_SYNC [fnums[slot]]; //allocate func data
00823         //len = AddToData(tp, &(fnums[0]), sizeof(int), tplen);
00824         if (MP_DEBUG)
00825                 cout << "net:  ReadState:  " << fnums[slot] << " functions, active: ";
00826         
00827         for (i = 0; i < fnums[slot]; i++)
00828         {
00829                 //fwrite(&(funcmem[i]), sizeof(struct FUNCTION_MEMORY_SYNC), 1, fout);
00830                 //tplen = AddToData(tp, &(GetFuncMem(0)[i]), sizeof(struct FUNCTION_MEMORY_SYNC), tplen);
00831                 len = GetFromData(s, &loadstates[slot].funcmem[i], sizeof(struct FUNCTION_MEMORY_SYNC), len);
00832                         
00833                 if (MP_DEBUG && loadstates[slot].funcmem[i].active)
00834                         cout << GetFuncMem(slot)[i].func_name << "(" << i << ") ";
00835         }
00836         
00837         if (MP_DEBUG)
00838                 cout << endl;
00839 }
00840 
00841 int MULTIPLAY::ReadVector(Vamos_Geometry::Three_Vector &wv, Uint8 * source, int start)
00842 {
00843         //fwrite(&wv[0], sizeof(double), 1, fout);
00844         
00845         int len = start;
00846         
00847         len = GetFromData(source, &wv[0], sizeof(double), len);
00848         len = GetFromData(source, &wv[1], sizeof(double), len);
00849         len = GetFromData(source, &wv[2], sizeof(double), len);
00850         
00851         return len;
00852 }
00853 
00854 int MULTIPLAY::ReadMatrix(Vamos_Geometry::Three_Matrix &wv, Uint8 * source, int start)
00855 {
00856         int len = start;
00857         
00858         //fwrite(&wv[0][0], sizeof(double), 1, fout);
00859         //fwrite(&wv[0][1], sizeof(double), 1, fout);
00860         //...
00861         len = GetFromData(source, &wv[0][0], sizeof(double), len);
00862         len = GetFromData(source, &wv[0][1], sizeof(double), len);
00863         len = GetFromData(source, &wv[0][2], sizeof(double), len);
00864         
00865         len = GetFromData(source, &wv[1][0], sizeof(double), len);
00866         len = GetFromData(source, &wv[1][1], sizeof(double), len);
00867         len = GetFromData(source, &wv[1][2], sizeof(double), len);
00868         
00869         len = GetFromData(source, &wv[2][0], sizeof(double), len);
00870         len = GetFromData(source, &wv[2][1], sizeof(double), len);
00871         len = GetFromData(source, &wv[2][2], sizeof(double), len);
00872         return len;
00873 }
00874 
00875 void MULTIPLAY::Send(double inc)
00876 {
00877         if (MP_DBGDEEP)
00878                         cout << "multiplay send start" << endl;
00879         
00880         //send outgoing data
00881         if (Connected() && !MP_DISABLESEND)
00882         {
00883                 if (!in_menu)
00884                 {
00885                         SendState(); // only sends if necessary
00886                         
00887                         QueuePacket();
00888                         SendPacketArray(); // only sends if necessary
00889                 }
00890         }
00891         
00892         if (!in_menu)
00893         {
00894                 timeindex[0] += inc;
00895         }
00896         
00897         if (MP_DBGDEEP)
00898                         cout << "multiplay send done" << endl;
00899 }
00900 
00901 void MULTIPLAY::ReceiveState()
00902 {
00903         //check to see if it's time for a state packet
00904         int i;
00905         float remain;
00906         int mult;
00907         mult = (int) ((timeindex[1]+FrameTime()/2.0) / STATE_FREQUENCY);
00908         remain = (timeindex[1] + FrameTime()/2.0) - (float)(mult * STATE_FREQUENCY);
00909         
00910         //cout << timeindex[1] << "," << mult << "," << remain << endl;
00911         
00912         bool found = false;
00913         
00914         if (remain < FrameTime())
00915         {
00916                 //cout << "get state" << endl;
00917                 //search packets for correct time
00918                 int count = 0;
00919                 for (i = 0; i < net.GetMaxBuffers(); i++)
00920                 {
00921                         if (net.GetBuffer(i)->Valid())
00922                         {
00923                                 //ProcessPacket(net.GetBuffer(i));
00924                                 Uint8 ptype;
00925                                 GetFromData(net.GetBuffer(i)->data, &ptype, sizeof(Uint8), 0);
00926                                 double ptime;
00927                                 GetFromData(net.GetBuffer(i)->data, &ptime, sizeof(double), 1);
00928                                 if (ptype == replay.Get_FuncStateInfo())
00929                                 {
00930                                         //clean out old state packets
00931                                         if (ptime < timeindex[1] - STATE_FREQUENCY)
00932                                         {
00933                                                 net.GetBuffer(i)->Clear();
00934                                                 
00935                                                 if (NET_DEBUG)
00936                                                         cout << "net:  Update:  cleaned out old state packet with time " << ptime << endl;
00937                                         }
00938                                         
00939                                         if (ptime > timeindex[1] - FrameTime()/2.0 && ptime < timeindex[1] + FrameTime()/2.0)
00940                                         {
00941                                                 //exected time
00942                                                 net.GetBuffer(i)->Clear();
00943                                                 
00944                                                 if (NET_DEBUG)
00945                                                         cout << "net:  Update:  received state with time " << ptime << endl;
00946                                                 
00947                                                 loadstates[1].time = ptime;
00948                                                 //loadstatevalid[1] = true;
00949                                                 
00950                                                 ReadState(net.GetBuffer(i)->data, 1);
00951                                                 loadstatenow[1] = true;
00952 
00953                                                 //update funcmem from state
00954                                                 for (i = 0; i < fnums[1]; i++)
00955                                                 {
00956                                                         GetFuncMem(1)[i].oldval = loadstates[1].funcmem[i].oldval;
00957                                                         GetFuncMem(1)[i].newval = loadstates[1].funcmem[i].newval;
00958                                                         GetFuncMem(1)[i].held = loadstates[1].funcmem[i].held;
00959                                                         GetFuncMem(1)[i].active = loadstates[1].funcmem[i].active;
00960                                                         GetFuncMem(1)[i].lastupdateat = loadstates[1].funcmem[i].lastupdateat;
00961                                                 }
00962                                                 
00963                                                 if (MP_RECORD && MP_REMOTE_RECORD)
00964                                                 {
00965                                                         dbgstate[dbgnumstates].CopyFrom(loadstates[1]);
00966                                                         dbgnumstates++;
00967                                                 }
00968                                                 
00969                                                 found = true;
00970                                         }
00971                                         else
00972                                         {
00973                                                 //cout << "packet " << i << ": " << ptime << "," << timeindex[1] << endl;
00974                                                 
00975                                                 //increment timeout counter
00976                                                 count++;
00977                                         }
00978                                 }
00979                                 //else cout << "i: " << i << ", p: " << ptype << ", t: " << ptime << endl;
00980                         }
00981                 }
00982                 
00983                 /*//if the state packet is late and we have new packets waiting for us,
00984                 // give up waiting for the old one
00985                 if (!found && count >= STATE_TIMEOUT_COUNT)
00986                 {
00987                         if (NET_DEBUG)
00988                         {
00989                                 cout << "net:  Update:  timeout waiting for state at time " << timeindex[1] << endl;
00990                         }
00991                         
00992                         timeindex[1] += STATE_FREQUENCY;
00993                 }
00994                 else if (!found)
00995                 {
00996                         if (NET_DEBUG)
00997                         {
00998                                 cout << "waiting for timeout: " << count << " states in buffer" << endl;
00999                         }
01000                 }*/
01001                 
01002                 //if we have new packets waiting for us,
01003                 // give up waiting for the old one
01004                 // (moved back into the if (remain < frametime) part because packets can now be timed out)
01005                 int scount = 0;
01006                 double highesttime = 0;
01007                 for (i = 0; i < net.GetMaxBuffers(); i++)
01008                 {
01009                         if (net.GetBuffer(i)->Valid())
01010                         {
01011                                 //ProcessPacket(net.GetBuffer(i));
01012                                 Uint8 ptype;
01013                                 GetFromData(net.GetBuffer(i)->data, &ptype, sizeof(Uint8), 0);
01014                                 double ptime;
01015                                 GetFromData(net.GetBuffer(i)->data, &ptime, sizeof(double), 1);
01016                                 if (ptype == replay.Get_FuncStateInfo())
01017                                 {
01018                                         scount++;
01019                                         
01020                                         if (ptime > highesttime)
01021                                                 highesttime = ptime;
01022                                 }
01023                         }
01024                 }
01025                 
01026                 if (!found && scount >= STATE_TIMEOUT_COUNT)
01027                 {
01028                         double newt;
01029                         
01030                         newt = (double)((mult+1) * STATE_FREQUENCY);
01031                         //newt = highesttime;
01032                         
01033                         if (NET_DEBUG)
01034                         {
01035                                 cout << "net:  Update:  timeout waiting for state at time " << timeindex[1] << " skipping to " << newt << endl;
01036                         }
01037                         
01038                         //timeindex[1] += STATE_FREQUENCY;
01039                         timeindex[1] = newt;
01040                 }
01041         }
01042 }
01043 
01044 void MULTIPLAY::QueuePacket()
01045 {
01046         int i;
01047         for (i = 0; i < fnums[0]; i++)
01048         {
01049                 //only add a packet if it's non-held or if it's held but the value is different from the stored one
01050                 if (GetFuncMem(0)[i].active && (!GetFuncMem(0)[i].held || (GetFuncMem(0)[i].held && GetFuncMem(0)[i].oldval != GetFuncMem(0)[i].newval)))
01051                 {
01052                         GetPacketArray(0)[numpackets[0]].time = timeindex[0];
01053                         GetPacketArray(0)[numpackets[0]].val = GetFuncMem(0)[i].newval;
01054                         GetPacketArray(0)[numpackets[0]].chardata[CHAR_FUNCNUM] = i;
01055                         //strcpy(packet[num_packets].dofunction, funcmem[i].func_name.c_str());
01056                         int newstate = 0;
01057                         if (GetFuncMem(0)[i].held)
01058                                 newstate = 1;
01059                         GetPacketArray(0)[numpackets[0]].chardata[CHAR_STATE] = newstate;
01060                         
01061                         numpackets[0]++;
01062                         
01063                         //cou