float MULTIPLAY::GetLatency(int player) { if (NumConnected() > player-1 && player >= 0) { return timeindex[0] - timeindex[player]; } else return 0; }
void MULTIPLAY::AddRecord(string newdofunction, float newval, int newstate) { if (MP_DISABLEADDRECORD) return; //if (replay && num_packets < MAX_PACKETS) if (NumConnected() > 0 && GetFuncMem(0) != NULL) { //packet int funcidx = 0; int i; for (i = 0; i < fnums[0]; i++) { if (GetFuncMem(0)[i].func_name == newdofunction) funcidx = i; } //put the values into their functional slot. this allows higher priority // commands to be considered over lower priority ones (as with the vamosworld // control processing code (effectively) if (newstate != 2) { GetFuncMem(0)[funcidx].lastupdateat = timeindex[0]; GetFuncMem(0)[funcidx].newval = newval; if (newstate == 1) GetFuncMem(0)[funcidx].held = true; else GetFuncMem(0)[funcidx].held = false; GetFuncMem(0)[funcidx].active = true; //if (newdofunction == "gas") //cout << newdofunction << ", lastupdate set at " << timeindex << endl; } } else { if (NET_DEBUG) { cout << "net: AddRecord: wrong state for addrecord or funcmems not created" << endl; } } }
bool MULTIPLAY::ExchangeWorldInfo() { char tc[32767]; 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()); //encode string length into the packet tc[2] = (char) ((Uint8) strlen(tc)); //encode function memories, starting at strlen(tc) int tclen = strlen(tc); int opos = tclen; //tc[opos] = (char)((Uint8) fnums[0]); opos = AddToData(tc, &(fnums[0]), sizeof(int), opos); int f; for (f = 0; f < fnums[0]; f++) { char fout[FUNCTION_CHARS]; strcpy(fout, GetFuncMem(0)[f].func_name.c_str()); //fwrite(fout,1,FUNCTION_CHARS, rf); opos = AddToData(tc, fout, FUNCTION_CHARS, opos); } net.Send(tc, opos); int ret = net.RecvBlock(tc, 32767, GENERIC_TIMEOUT); if (ret > 0) { int pos = 0; int err = 0; if (tc[pos] == (char) (replay.Get_FuncNetControl())) { pos++; if (tc[pos] == (char) (CONTROL_WORLDINFO)) { pos++; //decode string section length int slen = tc[2]; pos++; string car; string carpaint; string track; string numplayers; string myplayernum; char sc[2]; sc[1] = '\0'; while (pos < slen && tc[pos] != '\n') { sc[0] = tc[pos]; car.append(sc); pos++; } pos++; while (pos < slen && tc[pos] != '\n') { sc[0] = tc[pos]; carpaint.append(sc); pos++; } pos++; while (pos < slen && tc[pos] != '\n') { sc[0] = tc[pos]; track.append(sc); pos++; } pos++; while (pos < slen && tc[pos] != '\n') { sc[0] = tc[pos]; numplayers.append(sc); pos++; } pos++; while (pos < slen && tc[pos] != '\n') { sc[0] = tc[pos]; myplayernum.append(sc); pos++; } int icarpaint = atoi(carpaint.c_str()); int inumplayers = atoi(numplayers.c_str()); int imyplayernum = atoi(myplayernum.c_str()); if (MP_DEBUG) { /*tc[ret] = '\0'; cout << "raw worldinfo: " << tc << endl;*/ cout << "worldinfo size: " << ret << endl; cout << "got worldinfo: " << car << "," << icarpaint << "," << track << "," << inumplayers << "," << imyplayernum << endl; } //decode function memory //first clear it out int newpnum = NumConnected(); if (funcmems[newpnum] != NULL) { delete [] funcmems[newpnum]; funcmems[newpnum] = NULL; } pos = slen; pos = GetFromData(tc, &(fnums[newpnum]), sizeof(int), pos); funcmems[newpnum] = new FUNCTION_MEMORY [fnums[newpnum]]; for (f = 0; f < fnums[newpnum]; f++) { char fin[FUNCTION_CHARS]; pos = GetFromData(tc, fin, FUNCTION_CHARS, pos); GetFuncMem(newpnum)[f].func_name = fin; GetFuncMem(newpnum)[f].oldval = 0.0; GetFuncMem(newpnum)[f].held = false; GetFuncMem(newpnum)[f].active = false; } if (NET_DEBUG) { cout << "got functions: " << fnums[newpnum]; cout << " (" << fnums[0] << " local)" << endl; /*cout << "function list: "; for (f = 0; f < fnums[newpnum]; f++) { cout << GetFuncMem(newpnum)[f].func_name << ","; } cout << endl;*/ } if (!Server()) { state.SetTrackName(track); state.SetCarName(1, car); state.SetCarPaint(1, icarpaint); remote_players = inumplayers; remote_playernum = imyplayernum; LoadWorld(); } else { state.SetCarName(1, car); state.SetCarPaint(1, icarpaint); SelectCar(state.GetCarName(0), true); /*try { int numcars = NumConnected(); Vamos_Body::Gl_Car* car = 0; car = new Vamos_Body::Gl_Car (Vamos_Geometry::Three_Vector (11.0, 0.0, 0.6)); car->read ("data/", state.GetCarName(numcars)); car->SetPaint(state.GetCarPaint(numcars)); car->chassis ().translate (Vamos_Geometry::Three_Vector (10.0, 0.0, -car->chassis ().lowest_contact_position () + 0.5)); car->start_engine (); car->set_controller(2); world.add_car (car); } catch (Vamos_Geometry::XML_Exception& error) { std::cerr << error.message () << std::endl; std::exit (EXIT_FAILURE); }*/ } } else err = 2; } else err = 1; if (err) { //retry? //nah, just disconnect. net.Disconnect(); if (MP_DEBUG) { cout << "multiplay: Update: error parsing world info: error " << err << endl; } return false; } } else { //retry? //nah, just disconnect. net.Disconnect(); if (MP_DEBUG) { cout << "multiplay: Update: didn't receive world info: error " << ret << endl; } return false; } return true; }
void MULTIPLAY::Update(double inc) { if (MP_DBGDEEP) cout << "multiplay update" << endl; //create packet arrays if necessary int i; for (i = 0; i < NumConnected() + 1; i++) { if (packetarrays[i] == NULL) { packetarrays[i] = new REPLAY_PACKET [PACKET_ARRAY_SIZE]; } } if (MP_DBGDEEP) cout << "packet mem allocated" << endl; bool oldc = Connected(); net.Update(); if (!oldc && Connected()) { //wasn't connected before, connected now. if (Server()) remote_players++; ExchangeWorldInfo(); int i; for (i = 0; i < MAX_PLAYERS; i++) { timeindex[i] = 0.0; loadstates[i].time = 0.0; loadstatenow[i] = false; numpackets[i] = 0; //packetarraytime[i] = 0.0; nooptime[i] = 0; noopvalid[i] = false; tickthisframe[i] = false; nooptick[i] = false; } dbgnumstates = 0; dbgnumpackets = 0; mq1.Clear(); mq1.AddMessage("A client successfully connected"); } if (MP_DBGDEEP) cout << "net updated" << endl; //read incoming data /*if (Connected() && net.NumBufferedPackets() > 0) { int i; for (i = 0; i < net.GetMaxBuffers(); i++) { if (net.GetBuffer(i)->Valid()) ProcessPacket(net.GetBuffer(i)); } }*/ if (Connected()) { if (!MP_DISABLEGET) { ReceiveState(); if (MP_DBGDEEP) cout << "state receive" << endl; ReceivePacketArray(); if (MP_DBGDEEP) cout << "packet array receive" << endl; } if (!MP_DISABLEFUNCUPDATE) { double tval = 0; string ticktype = "packet array"; nooptick[1] = false; if (PacketArrayValid(1)) tval = GetPacketArrayTime(1); if (noopvalid[1] && nooptime[1] > tval) { tval = nooptime[1]; ticktype = "noop"; nooptick[1] = true; } if ((noopvalid[1] || PacketArrayValid(1)) && timeindex[1] < tval + PACKET_ARRAY_FREQUENCY - FrameTime()/2.0) { tickthisframe[1] = true; /*int nextpacket = curpackets[1]; if (nextpacket >= numpackets[1]) nextpacket = numpackets[1] - 1; if (ticktype == "packet array") cout << "ticking " << ticktype << ": " << GetFuncMem(1)[GetPacketArray(1)[nextpacket].chardata[CHAR_FUNCNUM]].func_name << " " << curpackets[1] << "/" << numpackets[1] << " packets for " << tval << " at " << timeindex[1] << endl; else cout << "ticking " << ticktype << " for " << tval << " at " << timeindex[1] << endl;*/ timeindex[1] += inc; //process packet data into the function memory (which is then given to DoOp by vamosworld) //if (PacketArrayValid(1))// && !(ticktype == "noop")) int i; for (i = 0; i < fnums[1]; i++) { if (!GetFuncMem(1)[i].held && GetFuncMem(1)[i].active) GetFuncMem(1)[i].active = false; } UpdateFuncmem(1); } else { tickthisframe[1] = false; //cout << "not ticking at " << timeindex[1] << endl; } } if (MP_DBGDEEP) cout << "ticked" << endl; //check to see if we need to increment /*for (i = 0; i < NumConnected(); i++) { if (loadstatevalid[i+1] && timeindex[i+1] < loadstates[i+1].time + STATE_FREQUENCY + FrameTime()/2.0) { timeindex[i+1] += inc; } }*/ //if (packetarrayvalid[1] && timeindex[1] < loadstates[1].time + STATE_FREQUENCY - FrameTime()/2.0) } //cout << "Latency: " << GetLatency(1) << " (" << timeindex[0] << "-" << timeindex[1] << ")" << endl; //disconnect if the latency is super high if (GetLatency(1) > CLIENT_DISCONNECT_TIMEOUT) { Disconnect(); } //update statistics UpdateStats(); if (MP_DBGDEEP) cout << "multiplay update done" << endl; }
// // haleyjd 20141022: [SVE] Alternate waiting on Steam clients // void NET_WaitForSteamLaunch(void) { boolean isServer = (net_SteamNodeType == NET_STEAM_SERVER); const char *strConn = "Connecting Netgame"; char numConn[64]; char pressStr[64]; char pressStr2[64]; int strConnWidth, pressStrWidth, pressStrX, numConnWidth; const char *keyActivateName = GetNameForKey(key_menu_activate); const char *keyForwardName = GetNameForKey(key_menu_forward); if(!keyActivateName) keyActivateName = "key_menu_activate"; if(!keyForwardName) keyForwardName = "key_menu_forward"; M_snprintf(pressStr, sizeof(pressStr), "(Press %s to cancel%c", keyActivateName, isServer ? ',' : ')'); if(isServer) { M_snprintf(pressStr2, sizeof(pressStr2), "%s to start now)", keyForwardName); } strConnWidth = V_BigFontStringWidth(strConn); pressStrWidth = M_StringWidth(pressStr); pressStrX = (SCREENWIDTH - pressStrWidth) / 2; expected_nodes = net_SteamNumNodes; while(net_waiting_for_launch) { event_t *ev; CheckAutoLaunch(); I_StartTic(); while((ev = D_PopEvent())) { switch(ev->type) { case ev_keydown: if(ev->data1 == key_menu_activate) I_Quit(); if(ev->data1 == key_menu_forward && isServer) StartGame(NULL, NULL); break; default: break; } } if(use3drenderer) RB_ClearBuffer(GLCB_COLOR); M_snprintf(numConn, sizeof(numConn), "%d of %d nodes connected", NumConnected(), net_SteamNumNodes); numConnWidth = M_StringWidth(numConn); V_DrawFilledBox(0, 0, SCREENWIDTH, SCREENHEIGHT, 0); V_WriteBigText(strConn, (SCREENWIDTH - strConnWidth)/2, 60); M_WriteText((SCREENWIDTH - numConnWidth)/2, 100, numConn); M_WriteText(pressStrX, 112, pressStr); if(isServer) M_WriteText(pressStrX+12, 124, pressStr2); NET_CL_Run(); NET_SV_Run(); if(!net_client_connected) I_Error("Lost connection to server"); I_FinishUpdate(); I_Sleep(100); } }