12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094 |
- /*
- ===========================================================================
- Doom 3 BFG Edition GPL Source Code
- Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
- Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
- If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
- ===========================================================================
- */
- #pragma hdrstop
- #include "../idlib/precompiled.h"
- #include "sys_session_local.h"
- #include "sys_voicechat.h"
- #include "sys_dedicated_server_search.h"
- idCVar ui_skinIndex( "ui_skinIndex", "0", CVAR_ARCHIVE, "Selected skin index" );
- idCVar ui_autoSwitch( "ui_autoSwitch", "1", CVAR_ARCHIVE | CVAR_BOOL, "auto switch weapon" );
- idCVar ui_autoReload( "ui_autoReload", "1", CVAR_ARCHIVE | CVAR_BOOL, "auto reload weapon" );
- idCVar net_maxSearchResults( "net_maxSearchResults", "25", CVAR_INTEGER, "Max results that are allowed to be returned in a search request" );
- idCVar net_maxSearchResultsToTry( "net_maxSearchResultsToTry", "5", CVAR_INTEGER, "Max results to try before giving up." ); // At 15 second timeouts per, 1 min 15 worth of connecting attempt time
- idCVar net_LobbyCoalesceTimeInSeconds( "net_LobbyCoalesceTimeInSeconds", "30", CVAR_INTEGER, "Time in seconds when a lobby will try to coalesce with another lobby when there is only one user." );
- idCVar net_LobbyRandomCoalesceTimeInSeconds( "net_LobbyRandomCoalesceTimeInSeconds", "3", CVAR_INTEGER, "Random time to add to net_LobbyCoalesceTimeInSeconds" );
- idCVar net_useGameStateLobby( "net_useGameStateLobby", "0", CVAR_BOOL, "" );
- //idCVar net_useGameStateLobby( "net_useGameStateLobby", "1", CVAR_BOOL, "" );
- #if !defined( ID_RETAIL ) || defined( ID_RETAIL_INTERNAL )
- idCVar net_ignoreTitleStorage( "net_ignoreTitleStorage", "0", CVAR_BOOL, "Ignore title storage" );
- #endif
- idCVar net_maxLoadResourcesTimeInSeconds( "net_maxLoadResourcesTimeInSeconds", "0", CVAR_INTEGER, "How long, in seconds, clients have to load resources. Used for loose asset builds." );
- idCVar net_migrateHost( "net_migrateHost", "-1", CVAR_INTEGER, "Become host of session (0 = party, 1 = game) for testing purposes" );
- extern idCVar net_debugBaseStates;
- idCVar net_testPartyMemberConnectFail( "net_testPartyMemberConnectFail", "-1", CVAR_INTEGER, "Force this party member index to fail to connect to games." );
- //FIXME: this could use a better name.
- idCVar net_offlineTransitionThreshold( "net_offlineTransitionThreshold", "1000", CVAR_INTEGER, "Time, in milliseconds, to wait before kicking back to the main menu when a profile losses backend connection during an online game");
- idCVar net_port( "net_port", "27015", CVAR_INTEGER, "host port number" ); // Port to host when using dedicated servers, port to broadcast on when looking for a dedicated server to connect to
- idCVar net_headlessServer( "net_headlessServer", "0", CVAR_BOOL, "toggle to automatically host a game and allow peer[0] to control menus" );
- const char * idSessionLocal::stateToString[ NUM_STATES ] = {
- ASSERT_ENUM_STRING( STATE_PRESS_START, 0 ),
- ASSERT_ENUM_STRING( STATE_IDLE, 1 ),
- ASSERT_ENUM_STRING( STATE_PARTY_LOBBY_HOST, 2 ),
- ASSERT_ENUM_STRING( STATE_PARTY_LOBBY_PEER, 3 ),
- ASSERT_ENUM_STRING( STATE_GAME_LOBBY_HOST, 4 ),
- ASSERT_ENUM_STRING( STATE_GAME_LOBBY_PEER, 5 ),
- ASSERT_ENUM_STRING( STATE_GAME_STATE_LOBBY_HOST, 6 ),
- ASSERT_ENUM_STRING( STATE_GAME_STATE_LOBBY_PEER, 7 ),
- ASSERT_ENUM_STRING( STATE_CREATE_AND_MOVE_TO_PARTY_LOBBY, 8 ),
- ASSERT_ENUM_STRING( STATE_CREATE_AND_MOVE_TO_GAME_LOBBY, 9 ),
- ASSERT_ENUM_STRING( STATE_CREATE_AND_MOVE_TO_GAME_STATE_LOBBY, 10 ),
- ASSERT_ENUM_STRING( STATE_FIND_OR_CREATE_MATCH, 11 ),
- ASSERT_ENUM_STRING( STATE_CONNECT_AND_MOVE_TO_PARTY, 12 ),
- ASSERT_ENUM_STRING( STATE_CONNECT_AND_MOVE_TO_GAME, 13 ),
- ASSERT_ENUM_STRING( STATE_CONNECT_AND_MOVE_TO_GAME_STATE, 14 ),
- ASSERT_ENUM_STRING( STATE_BUSY, 15 ),
- ASSERT_ENUM_STRING( STATE_LOADING, 16 ),
- ASSERT_ENUM_STRING( STATE_INGAME, 17 ),
- };
- struct netVersion_s {
- netVersion_s() { sprintf( string, "%s.%d", ENGINE_VERSION, BUILD_NUMBER ); }
- char string[256];
- } netVersion;
- /*
- ========================
- NetGetVersionChecksum
- ========================
- */
- unsigned long NetGetVersionChecksum() {
- #if 0
- return idStr( com_version.GetString() ).Hash();
- #else
- unsigned long ret = 0;
- CRC32_InitChecksum( ret );
- CRC32_UpdateChecksum( ret, netVersion.string, idStr::Length( netVersion.string ) );
- CRC32_FinishChecksum( ret );
- NET_VERBOSE_PRINT( "NetGetVersionChecksum - string : %s\n", netVersion.string );
- NET_VERBOSE_PRINT( "NetGetVersionChecksum - checksum : %i\n", ret );
- return ret;
- #endif
- }
- /*
- ========================
- idSessionLocal::idSessionLocal
- ========================
- */
- idSessionLocal::idSessionLocal() :
- processorSaveFiles( new (TAG_SAVEGAMES) idSaveGameProcessorSaveFiles ),
- processorLoadFiles( new (TAG_SAVEGAMES) idSaveGameProcessorLoadFiles ),
- processorDelete( new (TAG_SAVEGAMES) idSaveGameProcessorDelete ),
- processorEnumerate( new (TAG_SAVEGAMES) idSaveGameProcessorEnumerateGames ) {
- InitBaseState();
- }
- /*
- ========================
- idSessionLocal::idSessionLocal
- ========================
- */
- idSessionLocal::~idSessionLocal() {
- delete processorSaveFiles;
- delete processorLoadFiles;
- delete processorDelete;
- delete processorEnumerate;
- delete sessionCallbacks;
- }
- /*
- ========================
- idSessionLocal::InitBaseState
- ========================
- */
- void idSessionLocal::InitBaseState() {
-
- //assert( mem.IsGlobalHeap() );
- localState = STATE_PRESS_START;
- sessionOptions = 0;
- currentID = 0;
- sessionCallbacks = new (TAG_NETWORKING) idSessionLocalCallbacks( this );
- connectType = CONNECT_NONE;
- connectTime = 0;
-
- upstreamDropRate = 0.0f;
- upstreamDropRateTime = 0;
- upstreamQueueRate = 0.0f;
- upstreamQueueRateTime = 0;
- queuedBytes = 0;
- lastVoiceSendtime = 0;
- hasShownVoiceRestrictionDialog = false;
- isSysUIShowing = false;
- pendingInviteDevice = 0;
- pendingInviteMode = PENDING_INVITE_NONE;
- downloadedContent.Clear();
- marketplaceHasNewContent = false;
- offlineTransitionTimerStart = 0;
- showMigratingInfoStartTime = 0;
- nextGameCoalesceTime = 0;
- gameLobbyWasCoalesced = false;
- numFullSnapsReceived = 0;
- flushedStats = false;
- titleStorageLoaded = false;
- droppedByHost = false;
- loadingID = 0;
- storedPeer = -1;
- storedMsgType = -1;
- inviteInfoRequested = false;
- enumerationHandle = 0;
- waitingOnGameStateMembersToLeaveTime = 0;
- waitingOnGameStateMembersToJoinTime = 0;
- }
- /*
- ========================
- idSessionLocal::FinishDisconnect
- ========================
- */
- void idSessionLocal::FinishDisconnect() {
- GetPort().Close();
- while ( sendQueue.Peek() != NULL ) {
- sendQueue.RemoveFirst();
- }
- while ( recvQueue.Peek() != NULL ) {
- recvQueue.RemoveFirst();
- }
- }
- //====================================================================================
- idCVar net_connectTimeoutInSeconds( "net_connectTimeoutInSeconds", "15", CVAR_INTEGER, "timeout (in seconds) while connecting" );
- /*
- ========================
- idSessionLocal::CreatePartyLobby
- ========================
- */
- void idSessionLocal::CreatePartyLobby( const idMatchParameters & parms_ ) {
- NET_VERBOSE_PRINT( "NET: CreatePartyLobby\n" );
- // Shutdown any possible party lobby
- GetPartyLobby().Shutdown();
- GetPartyLobby().ResetAllMigrationState();
- // Shutdown any possible game lobby
- GetGameLobby().Shutdown();
- GetGameStateLobby().Shutdown();
- // Start hosting a new party lobby
- GetPartyLobby().StartHosting( parms_ );
- connectType = CONNECT_NONE;
- connectTime = Sys_Milliseconds();
- // Wait for it to complete
- SetState( STATE_CREATE_AND_MOVE_TO_PARTY_LOBBY );
- }
- /*
- ========================
- idSessionLocal::CreateMatch
- ========================
- */
- void idSessionLocal::CreateMatch( const idMatchParameters & p ) {
- NET_VERBOSE_PRINT( "NET: CreateMatch\n" );
- if ( ( p.matchFlags & MATCH_PARTY_INVITE_PLACEHOLDER ) && !GetPartyLobby().IsLobbyActive() ) {
- NET_VERBOSE_PRINT( "NET: CreateMatch MATCH_PARTY_INVITE_PLACEHOLDER\n" );
- CreatePartyLobby( p );
- connectType = CONNECT_NONE;
- return;
- }
- // Shutdown any possible game lobby
- GetGameLobby().Shutdown();
- GetGameStateLobby().Shutdown();
- GetGameLobby().ResetAllMigrationState();
- // Start hosting a new game lobby
- GetGameLobby().StartHosting( p );
- connectType = CONNECT_NONE;
- connectTime = Sys_Milliseconds();
- // Wait for it to complete
- SetState( STATE_CREATE_AND_MOVE_TO_GAME_LOBBY );
- }
- /*
- ========================
- idSessionLocal::CreateGameStateLobby
- ========================
- */
- void idSessionLocal::CreateGameStateLobby( const idMatchParameters & p ) {
- NET_VERBOSE_PRINT( "NET: CreateGameStateLobby\n" );
- // Shutdown any possible game state lobby
- GetGameStateLobby().Shutdown();
- GetGameStateLobby().ResetAllMigrationState();
- // Start hosting a new game lobby
- GetGameStateLobby().StartHosting( p );
- connectType = CONNECT_NONE;
- connectTime = Sys_Milliseconds();
- waitingOnGameStateMembersToLeaveTime = 0; // Make sure to reset
- waitingOnGameStateMembersToJoinTime = 0;
- // Wait for it to complete
- SetState( STATE_CREATE_AND_MOVE_TO_GAME_STATE_LOBBY );
- }
- /*
- ========================
- idSessionLocal::FindOrCreateMatch
- ========================
- */
- void idSessionLocal::FindOrCreateMatch( const idMatchParameters & p ) {
- NET_VERBOSE_PRINT( "NET: FindOrCreateMatch\n" );
- if ( ( p.matchFlags & MATCH_PARTY_INVITE_PLACEHOLDER ) && !GetPartyLobby().IsLobbyActive() ) {
- NET_VERBOSE_PRINT( "NET: FindOrCreateMatch MATCH_PARTY_INVITE_PLACEHOLDER\n" );
- CreatePartyLobby( p );
- connectType = CONNECT_FIND_OR_CREATE;
- return;
- }
- // Shutdown any possible game lobby
- GetGameLobby().Shutdown();
- GetGameStateLobby().Shutdown();
- GetGameLobby().ResetAllMigrationState();
- // Start searching for a game
- GetGameLobby().StartFinding( p );
- connectType = CONNECT_FIND_OR_CREATE;
- connectTime = Sys_Milliseconds();
- gameLobbyWasCoalesced = false;
- numFullSnapsReceived = 0;
- // Wait for searching to complete
- SetState( STATE_FIND_OR_CREATE_MATCH );
- }
- /*
- ========================
- idSessionLocal::StartLoading
- ========================
- */
- void idSessionLocal::StartLoading() {
- NET_VERBOSE_PRINT( "NET: StartLoading\n" );
- if ( MatchTypeIsOnline( GetActingGameStateLobby().parms.matchFlags ) ) {
- if ( !GetActingGameStateLobby().IsHost() ) {
- idLib::Warning( "Ignoring call to StartLoading because we are not the host. state is %s", stateToString[ localState ] );
- return;
- }
- for ( int p = 0; p < GetActingGameStateLobby().peers.Num(); p++ ) {
- if ( GetActingGameStateLobby().peers[p].IsConnected() ) {
- GetActingGameStateLobby().QueueReliableMessage( p, idLobby::RELIABLE_START_LOADING );
- GetActingGameStateLobby().peers[p].startResourceLoadTime = Sys_Milliseconds();
- }
- }
- }
- VerifySnapshotInitialState();
- SetState( STATE_LOADING );
- }
- /*
- ========================
- idSessionLocal::StartMatch
- ========================
- */
- void idSessionLocal::StartMatch() {
- NET_VERBOSE_PRINT( "NET: StartMatch\n" );
- if ( net_headlessServer.GetBool() ) {
- StartLoading(); // This is so we can force start matches on headless servers to test performance using bots
- return;
- }
- if ( localState != STATE_GAME_LOBBY_HOST ) {
- idLib::Warning( "idSessionLocal::StartMatch called when not hosting game lobby" );
- return;
- }
- assert( !GetGameStateLobby().IsLobbyActive() );
- // make absolutely sure we only call StartMatch once per migrate
- GetGameLobby().migrationInfo.persistUntilGameEndsData.hasRelaunchedMigratedGame = true;
-
- // Clear snap ack queue between games
- GetGameLobby().snapDeltaAckQueue.Clear();
- extern idCVar net_bw_challenge_enable;
- if ( session->GetTitleStorageBool( "net_bw_challenge_enable", net_bw_challenge_enable.GetBool() ) && GetGameLobby().HasActivePeers() ) {
- GetGameLobby().bandwidthChallengeFinished = false;
- StartOrContinueBandwidthChallenge( false );
- }
- if ( GetGameLobby().BandwidthTestStarted() ) {
- // Put session in busy state
- NET_VERBOSE_PRINT( "NET: StartMatch -> Start Bandwidth Challenge\n" );
- SetState( STATE_BUSY );
- } else {
- // Start loading
- StartLoading();
- }
- }
- /*
- ========================
- idSessionLocal::GetBackState
- ========================
- */
- idSessionLocal::sessionState_t idSessionLocal::GetBackState() {
- sessionState_t currentState = GetState();
- const bool isInGameLobby = currentState == GAME_LOBBY;
- const bool isInPartyLobby = currentState == PARTY_LOBBY;
- const bool isInGame = currentState == INGAME || currentState == LOADING; // Counting loading as ingame as far as what back state to go to
-
- if ( isInGame ) {
- return GAME_LOBBY; // If in the game, go back to game lobby
- }
- if ( !isInPartyLobby && isInGameLobby && ShouldHavePartyLobby() ) {
- return PARTY_LOBBY; // If in the game lobby, and we should have a party lobby, and we are the host, go back to party lobby
- }
- if ( currentState != IDLE ) {
- return IDLE; // From here, go to idle if we aren't there yet
- }
- return PRESS_START; // Otherwise, go back to press start
- }
- /*
- ========================
- idSessionLocal::Cancel
- ========================
- */
- void idSessionLocal::Cancel() {
- NET_VERBOSE_PRINT( "NET: Cancel\n" );
- if ( localState == STATE_PRESS_START ) {
- return; // We're as far back as we can go
- }
- ClearVoiceGroups(); // this is here as a catch-all
- // See what state we need to go to
- switch ( GetBackState() ) {
- case GAME_LOBBY:
- EndMatch(); // End current match to go to game lobby
- break;
- case PARTY_LOBBY:
- if ( GetPartyLobby().IsHost() ) {
- if ( sessionOptions & OPTION_LEAVE_WITH_PARTY ) {
- // NOTE - This will send a message on the team lobby channel,
- // so it won't be affected by the fact that we're shutting down the game lobby
- GetPartyLobby().NotifyPartyOfLeavingGameLobby();
- } else {
- // Host wants to be alone, disconnect all peers from the party
- GetPartyLobby().DisconnectAllPeers();
- }
- // End the game lobby, and go back to party lobby as host
- GetGameLobby().Shutdown();
- GetGameStateLobby().Shutdown();
- SetState( STATE_PARTY_LOBBY_HOST );
- // Always remove this flag. SendGoodbye uses this to determine if we should send a "leave with party"
- // and we don't want this flag hanging around, and causing false positives when it's called in the future.
- // Make them set this each time.
- sessionOptions &= ~OPTION_LEAVE_WITH_PARTY;
- } else {
- // If we aren't the host of a party and we want to go back to one, we need to create a party now
- CreatePartyLobby( GetPartyLobby().parms );
- }
- break;
- case IDLE:
- // Go back to main menu
- GetGameLobby().Shutdown();
- GetGameStateLobby().Shutdown();
- GetPartyLobby().Shutdown();
- SetState( STATE_IDLE );
- break;
- case PRESS_START:
- // Go back to press start/main
- GetGameLobby().Shutdown();
- GetGameStateLobby().Shutdown();
- GetPartyLobby().Shutdown();
- SetState( STATE_PRESS_START );
- break;
- }
- // Validate the current lobby immediately
- ValidateLobbies();
- }
- /*
- ========================
- idSessionLocal::MoveToPressStart
- ========================
- */
- void idSessionLocal::MoveToPressStart() {
- if ( localState != STATE_PRESS_START ) {
- assert( signInManager != NULL );
- signInManager->RemoveAllLocalUsers();
- hasShownVoiceRestrictionDialog = false;
- MoveToMainMenu();
- session->FinishDisconnect();
- SetState( STATE_PRESS_START );
- }
- }
- /*
- ========================
- idSessionLocal::ShouldShowMigratingDialog
- ========================
- */
- bool idSessionLocal::ShouldShowMigratingDialog() const {
- const idLobby * activeLobby = GetActivePlatformLobby();
- if ( activeLobby == NULL ) {
- return false;
- }
-
- return activeLobby->ShouldShowMigratingDialog();
- }
- /*
- ========================
- idSessionLocal::IsCurrentLobbyMigrating
- ========================
- */
- bool idSessionLocal::IsCurrentLobbyMigrating() const {
- const idLobby * activeLobby = GetActivePlatformLobby();
- if ( activeLobby == NULL ) {
- return false;
- }
- return activeLobby->IsMigrating();
- }
- /*
- ========================
- idSessionLocal::IsLosingConnectionToHost
- ========================
- */
- bool idSessionLocal::IsLosingConnectionToHost() const {
- return GetActingGameStateLobby().IsLosingConnectionToHost();
- }
- /*
- ========================
- idSessionLocal::WasMigrationGame
- returns true if we are hosting a migrated game and we had valid migration data
- ========================
- */
- bool idSessionLocal::WasMigrationGame() const {
- return GetGameLobby().IsMigratedStatsGame();
- }
- /*
- ========================
- idSessionLocal::ShouldRelaunchMigrationGame
- returns true if we are hosting a migrated game and we had valid migration data
- ========================
- */
- bool idSessionLocal::ShouldRelaunchMigrationGame() const {
- return GetGameLobby().ShouldRelaunchMigrationGame() && !IsCurrentLobbyMigrating();
- }
- /*
- ========================
- idSessionLocal::GetMigrationGameData
- ========================
- */
- bool idSessionLocal::GetMigrationGameData( idBitMsg & msg, bool reading ) {
- return GetGameLobby().GetMigrationGameData( msg, reading );
- }
- /*
- ========================
- idSessionLocal::GetMigrationGameDataUser
- ========================
- */
- bool idSessionLocal::GetMigrationGameDataUser( lobbyUserID_t lobbyUserID, idBitMsg & msg, bool reading ) {
- if ( GetGameStateLobby().IsHost() ) {
- return false;
- }
- return GetGameLobby().GetMigrationGameDataUser( lobbyUserID, msg, reading );
- }
- /*
- ========================
- idSessionLocal::GetMatchParamUpdate
- ========================
- */
- bool idSessionLocal::GetMatchParamUpdate( int &peer, int &msg ){
- if ( storedPeer != -1 && storedMsgType != -1 ) {
- peer = storedPeer;
- msg = storedMsgType;
- storedPeer = -1;
- storedMsgType = -1;
- return true;
- }
- return false;
- }
- /*
- ========================
- idSessionLocal::UpdatePartyParms
- Updates the party parameters when in a party lobby OR a game lobby in order to keep them always in sync.
- ========================
- */
- void idSessionLocal::UpdatePartyParms( const idMatchParameters & p ) {
- if ( ( GetState() != PARTY_LOBBY && GetState() != GAME_LOBBY ) || !GetPartyLobby().IsHost() ) {
- return;
- }
- // NET_VERBOSE_PRINT( "NET: UpdatePartyParms\n" );
- GetPartyLobby().UpdateMatchParms( p );
- }
- /*
- ========================
- idSessionLocal::UpdateMatchParms
- ========================
- */
- void idSessionLocal::UpdateMatchParms( const idMatchParameters & p ) {
- if ( GetState() != GAME_LOBBY || !GetGameLobby().IsHost() ) {
- return;
- }
- NET_VERBOSE_PRINT( "NET: UpdateMatchParms\n" );
- GetGameLobby().UpdateMatchParms( p );
- }
- /*
- ========================
- idSessionLocal::StartSessions
- ========================
- */
- void idSessionLocal::StartSessions() {
- if ( GetPartyLobby().lobbyBackend != NULL ) {
- GetPartyLobby().lobbyBackend->StartSession();
- }
- if ( GetGameLobby().lobbyBackend != NULL ) {
- GetGameLobby().lobbyBackend->StartSession();
- }
-
- SetLobbiesAreJoinable( false );
- }
- /*
- ========================
- idSessionLocal::EndSessions
- ========================
- */
- void idSessionLocal::EndSessions() {
- if ( GetPartyLobby().lobbyBackend != NULL ) {
- GetPartyLobby().lobbyBackend->EndSession();
- }
- if ( GetGameLobby().lobbyBackend != NULL ) {
- GetGameLobby().lobbyBackend->EndSession();
- }
- SetLobbiesAreJoinable( true );
- }
- /*
- ========================
- idSessionLocal::SetLobbiesAreJoinable
- ========================
- */
- void idSessionLocal::SetLobbiesAreJoinable( bool joinable ) {
- // NOTE - We don't manipulate the joinable state when we are supporting join in progress
- // Lobbies will naturally be non searchable when there are no free slots
- if ( GetPartyLobby().lobbyBackend != NULL && !MatchTypeIsJoinInProgress( GetPartyLobby().parms.matchFlags ) ) {
- NET_VERBOSE_PRINT( "Party lobbyBackend SetIsJoinable: %d\n", joinable );
- GetPartyLobby().lobbyBackend->SetIsJoinable( joinable );
- }
-
- if ( GetGameLobby().lobbyBackend != NULL && !MatchTypeIsJoinInProgress( GetGameLobby().parms.matchFlags ) ) {
- GetGameLobby().lobbyBackend->SetIsJoinable( joinable );
- NET_VERBOSE_PRINT( "Game lobbyBackend SetIsJoinable: %d\n", joinable );
- }
- }
- /*
- ========================
- idSessionLocal::MoveToMainMenu
- ========================
- */
- void idSessionLocal::MoveToMainMenu() {
- GetPartyLobby().Shutdown();
- GetGameLobby().Shutdown();
- GetGameStateLobby().Shutdown();
- SetState( STATE_IDLE );
- }
- /*
- ========================
- idSessionLocal::HandleVoiceRestrictionDialog
- ========================
- */
- void idSessionLocal::HandleVoiceRestrictionDialog() {
- // don't bother complaining about voice restrictions when in a splitscreen lobby
- if ( MatchTypeIsLocal( GetActivePlatformLobby()->parms.matchFlags ) ) {
- return;
- }
- // Pop a dialog up the first time we are in a lobby and have voice chat restrictions due to account privileges
- if ( voiceChat != NULL && voiceChat->IsRestrictedByPrivleges() && !hasShownVoiceRestrictionDialog ) {
- common->Dialog().AddDialog( GDM_VOICE_RESTRICTED, DIALOG_ACCEPT, NULL, NULL, false );
- hasShownVoiceRestrictionDialog = true;
- }
- }
- /*
- ========================
- idSessionLocal::WaitOnLobbyCreate
- Called from State_Create_And_Move_To_Party_Lobby and State_Create_And_Move_To_Game_Lobby and State_Create_And_Move_To_Game_State_Lobby.
- This function will create the lobby, then wait for it to either succeed or fail.
- ========================
- */
- bool idSessionLocal::WaitOnLobbyCreate( idLobby & lobby ) {
- assert( localState == STATE_CREATE_AND_MOVE_TO_PARTY_LOBBY || localState == STATE_CREATE_AND_MOVE_TO_GAME_LOBBY || localState == STATE_CREATE_AND_MOVE_TO_GAME_STATE_LOBBY );
- assert( connectType == CONNECT_FIND_OR_CREATE || connectType == CONNECT_NONE );
- if ( lobby.GetState() == idLobby::STATE_FAILED ) {
- NET_VERBOSE_PRINT( "NET: idSessionLocal::WaitOnLobbyCreate lobby.GetState() == idLobby::STATE_FAILED (%s)\n", lobby.GetLobbyName() );
- // If we failed to create a lobby, assume connection to backend service was lost
- MoveToMainMenu();
- common->Dialog().ClearDialogs( true );
- common->Dialog().AddDialog( GDM_CONNECTION_LOST, DIALOG_ACCEPT, NULL, NULL, true, "", 0, true );
- return false;
- }
-
- if ( DetectDisconnectFromService( true ) ) {
- return false;
- }
- if ( lobby.GetState() != idLobby::STATE_IDLE ) {
- return false; // Valid but busy
- }
- NET_VERBOSE_PRINT( "NET: idSessionLocal::WaitOnLobbyCreate SUCCESS (%s)\n", lobby.GetLobbyName() );
- return true;
- }
- /*
- ========================
- idSessionLocal::DetectDisconnectFromService
- Called from CreateMatch/CreatePartyLobby/FindOrCreateMatch state machines
- ========================
- */
- bool idSessionLocal::DetectDisconnectFromService( bool cancelAndShowMsg ) {
- const int DETECT_SERVICE_DISCONNECT_TIMEOUT_IN_SECONDS = session->GetTitleStorageInt( "DETECT_SERVICE_DISCONNECT_TIMEOUT_IN_SECONDS", 30 );
- // If we are taking too long, cancel the connection
- if ( DETECT_SERVICE_DISCONNECT_TIMEOUT_IN_SECONDS > 0 ) {
- if ( Sys_Milliseconds() - connectTime > 1000 * DETECT_SERVICE_DISCONNECT_TIMEOUT_IN_SECONDS ) {
- NET_VERBOSE_PRINT( "NET: idSessionLocal::DetectDisconnectFromService timed out\n" );
- if ( cancelAndShowMsg ) {
- MoveToMainMenu();
- common->Dialog().ClearDialogs( true );
- common->Dialog().AddDialog( GDM_CONNECTION_LOST, DIALOG_ACCEPT, NULL, NULL, false, "", 0, true );
- }
- return true;
- }
- }
- return false;
- }
- /*
- ========================
- idSessionLocal::HandleConnectionFailed
- Called anytime a connection fails, and does the right thing.
- ========================
- */
- void idSessionLocal::HandleConnectionFailed( idLobby & lobby, bool wasFull ) {
- assert( localState == STATE_CONNECT_AND_MOVE_TO_PARTY || localState == STATE_CONNECT_AND_MOVE_TO_GAME || localState == STATE_CONNECT_AND_MOVE_TO_GAME_STATE );
- assert( connectType == CONNECT_FIND_OR_CREATE || connectType == CONNECT_DIRECT );
- bool canPlayOnline = true;
-
- // Check for online status (this is only a problem on the PS3 at the moment. The 360 LIVE system handles this for us
- if ( GetSignInManager().GetMasterLocalUser() != NULL ) {
- canPlayOnline = GetSignInManager().GetMasterLocalUser()->CanPlayOnline();
- }
-
- if ( connectType == CONNECT_FIND_OR_CREATE ) {
- // Clear the "Lobby was Full" dialog in case it's up
- // We only want to see this msg when doing a direct connect (CONNECT_DIRECT)
- common->Dialog().ClearDialog( GDM_LOBBY_FULL );
- assert( localState == STATE_CONNECT_AND_MOVE_TO_GAME || localState == STATE_CONNECT_AND_MOVE_TO_GAME_STATE );
- assert( lobby.lobbyType == idLobby::TYPE_GAME );
- if ( !lobby.ConnectToNextSearchResult() ) {
- CreateMatch( GetGameLobby().parms ); // Assume any time we are connecting to a game lobby, it is from a FindOrCreateMatch call, so create a match
- }
- } else if ( connectType == CONNECT_DIRECT ) {
- if ( localState == STATE_CONNECT_AND_MOVE_TO_GAME && GetPartyLobby().IsPeer() ) {
- int flags = GetPartyLobby().parms.matchFlags;
- if ( MatchTypeIsOnline( flags ) && ( flags & MATCH_REQUIRE_PARTY_LOBBY ) && ( ( flags & MATCH_PARTY_INVITE_PLACEHOLDER ) == 0 ) ) {
- // We get here when our party host told us to connect to a game, but the game didn't exist.
- // Just drop back to the party lobby and wait for further orders.
- SetState( STATE_PARTY_LOBBY_PEER );
- return;
- }
- }
- if ( wasFull ) {
- common->Dialog().AddDialog( GDM_LOBBY_FULL, DIALOG_ACCEPT, NULL, NULL, false );
- } else if ( !canPlayOnline ) {
- common->Dialog().AddDialog( GDM_PLAY_ONLINE_NO_PROFILE, DIALOG_ACCEPT, NULL, NULL, false );
- } else {
- // TEMP HACK: We detect the steam lobby is full in idLobbyBackendWin, and then STATE_FAILED, which brings us here. Need to find a way to notify
- // session local that the game was full so we don't do this check here
- // eeubanks: Pollard, how do you think we should handle this?
- if ( !common->Dialog().HasDialogMsg( GDM_LOBBY_FULL, NULL ) ) {
- common->Dialog().AddDialog( GDM_INVALID_INVITE, DIALOG_ACCEPT, NULL, NULL, false );
- }
- }
- MoveToMainMenu();
- } else {
- // Shouldn't be possible, but just in case
- MoveToMainMenu();
- }
- }
- /*
- ========================
- idSessionLocal::HandleConnectAndMoveToLobby
- Called from State_Connect_And_Move_To_Party/State_Connect_And_Move_To_Game
- ========================
- */
- bool idSessionLocal::HandleConnectAndMoveToLobby( idLobby & lobby ) {
- assert( localState == STATE_CONNECT_AND_MOVE_TO_PARTY || localState == STATE_CONNECT_AND_MOVE_TO_GAME || localState == STATE_CONNECT_AND_MOVE_TO_GAME_STATE );
- assert( connectType == CONNECT_FIND_OR_CREATE || connectType == CONNECT_DIRECT );
- if ( lobby.GetState() == idLobby::STATE_FAILED ) {
- // If we get here, we were trying to connect to a lobby (from state State_Connect_And_Move_To_Party/State_Connect_And_Move_To_Game)
- HandleConnectionFailed( lobby, false );
- return true;
- }
- if ( lobby.GetState() != idLobby::STATE_IDLE ) {
- return HandlePackets(); // Valid but busy
- }
- assert( !GetPartyLobby().waitForPartyOk );
- //
- // Past this point, we've connected to the lobby
- //
- // If we are connecting to a game lobby, see if we need to keep waiting as either a host or peer while we're confirming all party members made it
- if ( lobby.lobbyType == idLobby::TYPE_GAME ) {
- if ( GetPartyLobby().IsHost() ) {
- // As a host, wait until all party members make it
- assert( !GetGameLobby().waitForPartyOk );
- const int timeoutMs = session->GetTitleStorageInt( "net_connectTimeoutInSeconds", net_connectTimeoutInSeconds.GetInteger() ) * 1000;
- if ( timeoutMs != 0 && Sys_Milliseconds() - lobby.helloStartTime > timeoutMs ) {
- // Took too long, move to next result, or create a game instead
- HandleConnectionFailed( lobby, false );
- return true;
- }
- int numUsersIn = 0;
- for ( int i = 0; i < GetPartyLobby().GetNumLobbyUsers(); i++ ) {
- if ( net_testPartyMemberConnectFail.GetInteger() == i ) {
- continue;
- }
- bool foundUser = false;
- lobbyUser_t * partyUser = GetPartyLobby().GetLobbyUser( i );
- for ( int j = 0; j < GetGameLobby().GetNumLobbyUsers(); j++ ) {
- lobbyUser_t * gameUser = GetGameLobby().GetLobbyUser( j );
- if ( GetGameLobby().IsSessionUserLocal( gameUser ) || gameUser->address.Compare( partyUser->address, true ) ) {
- numUsersIn++;
- foundUser = true;
- break;
- }
- }
-
- assert( !GetPartyLobby().IsSessionUserIndexLocal( i ) || foundUser );
- }
- if ( numUsersIn != GetPartyLobby().GetNumLobbyUsers() ) {
- return HandlePackets(); // All users not in, keep waiting until all user make it, or we time out
- }
-
- NET_VERBOSE_PRINT( "NET: All party members made it into the game lobby.\n" );
-
- // Let all the party members know everyone made it, and it's ok to stay at this server
- for ( int i = 0; i < GetPartyLobby().peers.Num(); i++ ) {
- if ( GetPartyLobby().peers[ i ].IsConnected() ) {
- GetPartyLobby().QueueReliableMessage( i, idLobby::RELIABLE_PARTY_CONNECT_OK );
- }
- }
- } else {
- if ( !verify ( lobby.host != -1 ) ) {
- MoveToMainMenu();
- connectType = CONNECT_NONE;
- return false;
- }
- // As a peer, wait for server to tell us everyone made it
- if ( GetGameLobby().waitForPartyOk ) {
- const int timeoutMs = session->GetTitleStorageInt( "net_connectTimeoutInSeconds", net_connectTimeoutInSeconds.GetInteger() ) * 1000;
- if ( timeoutMs != 0 && Sys_Milliseconds() - lobby.helloStartTime > timeoutMs ) {
- GetGameLobby().waitForPartyOk = false; // Just connect to this game lobby if we haven't heard from the party host for the entire timeout duration
- }
- }
- if ( GetGameLobby().waitForPartyOk ) {
- return HandlePackets(); // Waiting on party host to tell us everyone made it
- }
- }
- }
- // Success
- switch ( lobby.lobbyType ) {
- case idLobby::TYPE_PARTY:
- SetState( STATE_PARTY_LOBBY_PEER );
- break;
- case idLobby::TYPE_GAME:
- SetState( STATE_GAME_LOBBY_PEER );
- break;
- case idLobby::TYPE_GAME_STATE:
- waitingOnGameStateMembersToJoinTime = Sys_Milliseconds();
- // As a host of the game lobby, it's our duty to notify our members to also join this game state lobby
- GetGameLobby().SendMembersToLobby( GetGameStateLobby(), false );
- SetState( STATE_GAME_STATE_LOBBY_PEER );
- break;
- }
- connectType = CONNECT_NONE;
- return false;
- }
- /*
- ========================
- idSessionLocal::State_Create_And_Move_To_Party_Lobby
- ========================
- */
- bool idSessionLocal::State_Create_And_Move_To_Party_Lobby() {
- if ( WaitOnLobbyCreate( GetPartyLobby() ) ) {
- if ( GetPartyLobby().parms.matchFlags & MATCH_PARTY_INVITE_PLACEHOLDER ) {
- // If this party lobby was for a placeholder, continue on with either finding or creating a game lobby
- if ( connectType == CONNECT_FIND_OR_CREATE ) {
- FindOrCreateMatch( GetPartyLobby().parms );
- return true;
- } else if ( connectType == CONNECT_NONE ) {
- CreateMatch( GetPartyLobby().parms );
- return true;
- }
- }
- // Success
- SetState( STATE_PARTY_LOBBY_HOST );
- return true;
- }
- return HandlePackets(); // Valid but busy
- }
- /*
- ========================
- idSessionLocal::State_Create_And_Move_To_Game_Lobby
- ========================
- */
- bool idSessionLocal::State_Create_And_Move_To_Game_Lobby() {
- if ( WaitOnLobbyCreate( GetGameLobby() ) ) {
- // Success
- SetState( STATE_GAME_LOBBY_HOST );
- // Now that we've created our game lobby, send our own party users to it
- // NOTE - We pass in false to wait on party members since we are the host, and we know they can connect to us
- GetPartyLobby().SendMembersToLobby( GetGameLobby(), false );
- return true;
- }
- return false;
- }
- /*
- ========================
- idSessionLocal::State_Create_And_Move_To_Game_State_Lobby
- ========================
- */
- bool idSessionLocal::State_Create_And_Move_To_Game_State_Lobby() {
- if ( WaitOnLobbyCreate( GetGameStateLobby() ) ) {
- // Success
- SetState( STATE_GAME_STATE_LOBBY_HOST );
- // Now that we've created our game state lobby, send our own game users to it
- // NOTE - We pass in false to wait on party members since we are the host, and we know they can connect to us
- GetGameLobby().SendMembersToLobby( GetGameStateLobby(), false );
- // If we are the host of a game lobby, we know we are not using dedicated servers, so we want to start the match immediately
- // as soon as we detect all users have connected.
- if ( GetGameLobby().IsHost() ) {
- waitingOnGameStateMembersToJoinTime = Sys_Milliseconds();
- }
- return true;
- }
- return false;
- }
- /*
- ========================
- idSessionLocal::State_Find_Or_Create_Match
- ========================
- */
- bool idSessionLocal::State_Find_Or_Create_Match() {
- assert( connectType == CONNECT_FIND_OR_CREATE );
- if ( GetGameLobby().GetState() == idLobby::STATE_FAILED ) {
- // Failed to find any games. Create one instead (we're assuming this always gets called from FindOrCreateMatch
- CreateMatch( GetGameLobby().parms );
- return true;
- }
- if ( DetectDisconnectFromService( true ) ) {
- return false;
- }
- if ( GetGameLobby().GetState() != idLobby::STATE_IDLE ) {
- return HandlePackets(); // Valid but busy
- }
- // Done searching, connect to the first search result
- if ( !GetGameLobby().ConnectToNextSearchResult() ) {
- // Failed to find any games. Create one instead (we're assuming this always gets called from FindOrCreateMatch
- CreateMatch( GetGameLobby().parms );
- return true;
- }
- SetState( STATE_CONNECT_AND_MOVE_TO_GAME );
- return true;
- }
- /*
- ========================
- idSessionLocal::State_Connect_And_Move_To_Party
- ========================
- */
- bool idSessionLocal::State_Connect_And_Move_To_Party() {
- return HandleConnectAndMoveToLobby( GetPartyLobby() );
- }
- /*
- ========================
- idSessionLocal::State_Connect_And_Move_To_Game
- ========================
- */
- bool idSessionLocal::State_Connect_And_Move_To_Game() {
- return HandleConnectAndMoveToLobby( GetGameLobby() );
- }
- /*
- ========================
- idSessionLocal::State_Connect_And_Move_To_Game_State
- ========================
- */
- bool idSessionLocal::State_Connect_And_Move_To_Game_State() {
- return HandleConnectAndMoveToLobby( GetGameStateLobby() );
- }
- /*
- ========================
- idSessionLocal::State_InGame
- ========================
- */
- bool idSessionLocal::State_InGame() {
- return HandlePackets();
- }
- /*
- ========================
- idSessionLocal::State_Loading
- ========================
- */
- bool idSessionLocal::State_Loading() {
- HandlePackets();
- if ( !GetActingGameStateLobby().loaded ) {
- return false;
- }
- SetVoiceGroupsToTeams();
- if ( GetActingGameStateLobby().IsHost() ) {
- bool everyoneLoaded = true;
- for ( int p = 0; p < GetActingGameStateLobby().peers.Num(); p++ ) {
- idLobby::peer_t & peer = GetActingGameStateLobby().peers[p];
- if ( !peer.IsConnected() ) {
- continue; // We don't care about peers that aren't connected as a game session
- }
- if ( !peer.loaded ) {
- everyoneLoaded = false;
- continue; // Don't waste time sending resources to a peer who hasn't loaded the map yet
- }
- if ( GetActingGameStateLobby().SendResources( p ) ) {
- everyoneLoaded = false;
- // if client is taking a LONG time to load up - give them the boot: they're just holding up the lunch line. Useful for loose assets playtesting.
- int time = Sys_Milliseconds();
- int maxLoadTime = net_maxLoadResourcesTimeInSeconds.GetInteger();
- if ( maxLoadTime > 0 && peer.startResourceLoadTime + SEC2MS( maxLoadTime ) < time ) {
- NET_VERBOSERESOURCE_PRINT( "NET: dropping client %i - %s because they took too long to load resources.\n Check 'net_maxLoadResourcesTimeInSeconds' to adjust the time allowed.\n", p, GetPeerName( p ) );
- GetActingGameStateLobby().DisconnectPeerFromSession( p );
- continue;
- }
- }
- }
- if ( !everyoneLoaded ) {
- return false;
- }
- } else {
- // not sure how we got there, but we won't be receiving anything that could get us out of this state anymore
- // possible step towards fixing the join stalling/disconnect problems
- if ( GetActingGameStateLobby().peers.Num() == 0 ) {
- NET_VERBOSE_PRINT( "NET: no peers in idSessionLocal::State_Loading - giving up\n" );
- MoveToMainMenu();
- }
- // need at least a peer with a real connection
- bool haveOneGoodPeer = false;
- for ( int p = 0; p < GetActingGameStateLobby().peers.Num(); p++ ) {
- if ( GetActingGameStateLobby().peers[p].IsConnected() ) {
- haveOneGoodPeer = true;
- break;
- }
- }
- if ( !haveOneGoodPeer ) {
- NET_VERBOSE_PRINT( "NET: no good peers in idSessionLocal::State_Loading - giving up\n" );
- MoveToMainMenu();
- }
- return false;
- }
- GetActingGameStateLobby().ResetBandwidthStats();
- // if we got here then we're the host and everyone indicated map load finished
- NET_VERBOSE_PRINT( "NET: (loading) Starting Game\n" );
- SetState( STATE_INGAME ); // NOTE - Only the host is in-game at this point, all peers will start becoming in-game when they receive their first full snap
- return true;
- }
- /*
- ========================
- idSessionLocal::State_Busy
- ========================
- */
- bool idSessionLocal::State_Busy() {
- idLobby * activeLobby = GetActivePlatformLobby();
- if ( activeLobby == NULL ) {
- idLib::Warning("No active session lobby when idSessionLocal::State_Busy called");
- return false;
- }
- if ( activeLobby->bandwidthChallengeFinished ) {
- // Start loading
- NET_VERBOSE_PRINT( "NET: Bandwidth test finished - Start loading\n" );
- StartLoading();
- }
- return HandlePackets();
- }
- /*
- ========================
- idSessionLocal::VerifySnapshotInitialState
- ========================
- */
- void idSessionLocal::VerifySnapshotInitialState() {
- // Verify that snapshot state is reset
- for ( int p = 0; p < GetActingGameStateLobby().peers.Num(); p++ ) {
- if ( !GetActingGameStateLobby().peers[p].IsConnected() ) {
- assert( GetActingGameStateLobby().peers[p].snapProc == NULL );
- continue;
- }
- assert( GetActingGameStateLobby().peers[p].snapProc != NULL );
- if ( !verify( GetActingGameStateLobby().peers[p].needToSubmitPendingSnap == false ) ) {
- idLib::Error( "Invalid needToSubmitPendingSnap state\n" );
- }
- if ( !verify( GetActingGameStateLobby().peers[p].snapProc->HasPendingSnap() == false ) ) {
- idLib::Error( "Invalid HasPendingSnap state\n" );
- }
- if ( !verify( GetActingGameStateLobby().peers[p].snapProc->GetSnapSequence() == idSnapshotProcessor::INITIAL_SNAP_SEQUENCE ) ) {
- idLib::Error( "Invalid INITIAL_SNAP_SEQUENCE state %d for peer %d \n", GetActingGameStateLobby().peers[p].snapProc->GetSnapSequence(), p );
- }
- if ( !verify( GetActingGameStateLobby().peers[p].snapProc->GetBaseSequence() == -1 ) ) {
- idLib::Error( "Invalid GetBaseSequence state\n" );
- }
- }
- }
- /*
- ========================
- idSessionLocal::State_Party_Lobby_Host
- ========================
- */
- bool idSessionLocal::State_Party_Lobby_Host() {
- HandleVoiceRestrictionDialog();
- return HandlePackets();
- }
- /*
- ========================
- idSessionLocal::State_Game_Lobby_Host
- ========================
- */
- bool idSessionLocal::State_Game_Lobby_Host() {
- HandleVoiceRestrictionDialog();
- return HandlePackets();
- }
- /*
- ========================
- idSessionLocal::State_Game_State_Lobby_Host
- ========================
- */
- bool idSessionLocal::State_Game_State_Lobby_Host() {
- HandleVoiceRestrictionDialog();
- if ( waitingOnGameStateMembersToLeaveTime != 0 ) {
- const int MAX_LEAVE_WAIT_TIME_IN_SECONDS = 5;
- const bool forceDisconnectMembers = ( Sys_Milliseconds() - waitingOnGameStateMembersToLeaveTime ) > MAX_LEAVE_WAIT_TIME_IN_SECONDS * 1000;
- // Check to see if all peers have finally left
- if ( GetGameStateLobby().GetNumConnectedPeers() == 0 || forceDisconnectMembers ) {
- //
- // All peers left, we can stop waiting
- //
- waitingOnGameStateMembersToLeaveTime = 0;
- assert( !GetGameLobby().IsPeer() );
- if ( GetGameLobby().IsHost() ) {
- // If we aren't a dedicated game state host, then drop back to the game lobby as host
- GetGameStateLobby().Shutdown();
- SetState( STATE_GAME_LOBBY_HOST );
- } else {
- // A dedicated game state host will remain in State_Game_State_Lobby_Host mode while waiting for another set of users to join
- // DEDICATED_SERVER_FIXME: Notify master server we can server another game now
- GetGameStateLobby().DisconnectAllPeers();
- }
- }
- } else {
- // When all the players from the game lobby are in the game state lobby, StartLoading
- if ( GetGameLobby().IsHost() ) {
- if ( GetGameStateLobby().GetNumLobbyUsers() == GetGameLobby().GetNumLobbyUsers() ) {
- waitingOnGameStateMembersToJoinTime = 0;
- StartLoading();
- }
- } else {
- // The dedicated server host relies on the game host to say when all users are in
- if ( GetGameStateLobby().startLoadingFromHost ) {
- GetGameStateLobby().startLoadingFromHost = false;
- StartLoading();
- }
- }
- }
- return HandlePackets();
- }
- /*
- ========================
- idSessionLocal::State_Party_Lobby_Peer
- ========================
- */
- bool idSessionLocal::State_Party_Lobby_Peer() {
- HandleVoiceRestrictionDialog();
- return HandlePackets();
- }
- /*
- ========================
- idSessionLocal::State_Game_Lobby_Peer
- ========================
- */
- bool idSessionLocal::State_Game_Lobby_Peer() {
- HandleVoiceRestrictionDialog();
- bool saving = false;
- idPlayerProfile * profile = GetProfileFromMasterLocalUser();
- if ( profile != NULL && ( profile->GetState() == idPlayerProfile::SAVING || profile->GetRequestedState() == idPlayerProfile::SAVE_REQUESTED ) ) {
- saving = true;
- }
- if ( GetActingGameStateLobby().startLoadingFromHost && !saving ) {
- common->Dialog().ClearDialog( GDM_HOST_RETURNED_TO_LOBBY );
- common->Dialog().ClearDialog( GDM_HOST_RETURNED_TO_LOBBY_STATS_DROPPED );
- VerifySnapshotInitialState();
- // Set loading flag back to false
- GetActingGameStateLobby().startLoadingFromHost = false;
- // Set state to loading
- SetState( STATE_LOADING );
- loadingID++;
- return true;
- }
- return HandlePackets();
- }
- /*
- ========================
- idSessionLocal::State_Game_State_Lobby_Peer
- ========================
- */
- bool idSessionLocal::State_Game_State_Lobby_Peer() {
- // We are in charge of telling the dedicated host that all our members are in
- if ( GetGameLobby().IsHost() && waitingOnGameStateMembersToJoinTime != 0 ) {
- int foundMembers = 0;
- for ( int i = 0; i < GetGameLobby().GetNumLobbyUsers(); i++ ) {
- if ( GetGameStateLobby().GetLobbyUserByID( GetGameLobby().GetLobbyUser( i )->lobbyUserID, true ) != NULL ) {
- foundMembers++;
- }
- }
- // Give all of our game members 10 seconds to join, otherwise start without them
- const int MAX_JOIN_WAIT_TIME_IN_SECONDS = 10;
- const bool forceStart = ( Sys_Milliseconds() - waitingOnGameStateMembersToJoinTime ) > MAX_JOIN_WAIT_TIME_IN_SECONDS * 1000;
- if ( foundMembers == GetGameLobby().GetNumLobbyUsers() || forceStart ) {
- byte buffer[ idPacketProcessor::MAX_PACKET_SIZE ];
- idBitMsg msg( buffer, sizeof( buffer ) );
- // Write match paramaters to the game state host, and tell him to start
- GetGameLobby().parms.Write( msg );
- // Tell the game state lobby host we are ready
- GetGameStateLobby().QueueReliableMessage( GetGameStateLobby().host, idLobby::RELIABLE_START_MATCH_GAME_LOBBY_HOST, msg.GetReadData(), msg.GetSize() );
- waitingOnGameStateMembersToJoinTime = 0;
- }
- }
- return State_Game_Lobby_Peer();
- }
- /*
- ========================
- idSessionLocal::~idSession
- ========================
- */
- idSession::~idSession() {
- delete signInManager;
- signInManager = NULL;
- delete saveGameManager;
- saveGameManager = NULL;
- delete dedicatedServerSearch;
- dedicatedServerSearch = NULL;
- }
- idCVar net_verbose( "net_verbose", "0", CVAR_BOOL, "Print a bunch of message about the network session" );
- idCVar net_verboseResource( "net_verboseResource", "0", CVAR_BOOL, "Prints a bunch of message about network resources" );
- idCVar net_verboseReliable( "net_verboseReliable", "0", CVAR_BOOL, "Prints the more spammy messages about reliable network msgs" );
- idCVar si_splitscreen( "si_splitscreen", "0", CVAR_INTEGER, "force splitscreen" );
- idCVar net_forceLatency( "net_forceLatency", "0", CVAR_INTEGER, "Simulate network latency (milliseconds round trip time - applied equally on the receive and on the send)" );
- idCVar net_forceDrop( "net_forceDrop", "0", CVAR_INTEGER, "Percentage chance of simulated network packet loss" );
- idCVar net_forceUpstream( "net_forceUpstream", "0", CVAR_FLOAT, "Force a maximum upstream in kB/s (256kbps <-> 32kB/s)" ); // I would much rather deal in kbps but most of the code is written in bytes ..
- idCVar net_forceUpstreamQueue( "net_forceUpstreamQueue", "64", CVAR_INTEGER, "How much data is queued when enforcing upstream (in kB)" );
- idCVar net_verboseSimulatedTraffic( "net_verboseSimulatedTraffic", "0", CVAR_BOOL, "Print some stats about simulated traffic (net_force* cvars)" );
- /*
- ========================
- idSessionLocal::Initialize
- ========================
- */
- void idSessionLocal::Initialize() {
- }
- /*
- ========================
- idSessionLocal::Shutdown
- ========================
- */
- void idSessionLocal::Shutdown() {
- }
- /*
- ========================
- idSession interface semi-common between platforms (#ifdef's in sys_session_local.cpp)
- ========================
- */
- idCVar com_deviceZeroOverride( "com_deviceZeroOverride", "-1", CVAR_INTEGER, "change input routing for device 0 to poll a different device" );
- idCVar mp_bot_input_override( "mp_bot_input_override", "-1", CVAR_INTEGER, "Override local input routing for bot control" );
- /*
- ========================
- idSessionLocal::GetInputRouting
- This function sets up inputRouting to be a mapping from inputDevice index to session user index.
- ========================
- */
- int idSessionLocal::GetInputRouting( int inputRouting[ MAX_INPUT_DEVICES ] ) {
- int numLocalUsers = 0;
- for ( int i = 0; i < MAX_INPUT_DEVICES; i++ ) {
- inputRouting[i] = -1;
- }
-
- for ( int i = 0; i < GetActingGameStateLobby().GetNumLobbyUsers(); i++ ) {
- if ( GetActingGameStateLobby().IsSessionUserIndexLocal( i ) ) {
- // Find the local user that this session user maps to
- const idLocalUser * localUser = GetActingGameStateLobby().GetLocalUserFromLobbyUserIndex( i );
-
- if ( localUser != NULL ) {
- int localDevice = localUser->GetInputDevice();
- if ( localDevice == 0 && com_deviceZeroOverride.GetInteger() > 0 ) {
- localDevice = com_deviceZeroOverride.GetInteger();
- }
- assert( localDevice < MAX_INPUT_DEVICES );
- // Route the input device that this local user is mapped to
- assert( inputRouting[localDevice] == -1 ); // Make sure to only initialize each entry once
- inputRouting[localDevice] = i;
- if ( mp_bot_input_override.GetInteger() >= 0 ) {
- inputRouting[localDevice] = mp_bot_input_override.GetInteger();
- }
- numLocalUsers++;
- }
- }
- }
- // For testing swapping controllers
- if ( si_splitscreen.GetInteger() == 2 && numLocalUsers == 2 ) {
- SwapValues( inputRouting[0], inputRouting[1] );
- }
- return numLocalUsers;
- }
- /*
- ========================
- idSessionLocal::EndMatch
- EndMatch is meant for the host to cleanly end a match and return to the lobby page
- ========================
- */
- void idSessionLocal::EndMatch( bool premature /*=false*/ ) {
- if ( verify( GetActingGameStateLobby().IsHost() ) ) {
- // Host quits back to game lobby, and will notify peers internally to do the same
- EndMatchInternal( premature );
- }
- }
- /*
- ========================
- idSessionLocal::EndMatch
- this is for when the game is over before we go back to lobby. Need this incase the host leaves during this time
- ========================
- */
- void idSessionLocal::MatchFinished( ) {
- if ( verify( GetActingGameStateLobby().IsHost() ) ) {
- // host is putting up end game stats make sure other peers know and clear migration data
- MatchFinishedInternal();
- }
- }
- /*
- ========================
- idSessionLocal::QuitMatch
- QuitMatch is considered a premature ending of a match, and does the right thing depending on whether the host or peer is quitting
- ========================
- */
- void idSessionLocal::QuitMatch() {
- if ( GetActingGameStateLobby().IsHost() && !MatchTypeIsRanked( GetActingGameStateLobby().parms.matchFlags ) ) {
- EndMatch( true ); // When host quits private match, takes members back to game lobby
- } else {
- // Quitting a public match (or not being a host) before it ends takes you to an empty party lobby
- CreatePartyLobby( GetActingGameStateLobby().parms );
- }
- }
- /*
- ========================
- idSessionLocal::QuitMatchToTitle
- QuitMatchToTitle will forcefully quit the match and return to the title screen.
- ========================
- */
- void idSessionLocal::QuitMatchToTitle() {
- MoveToMainMenu();
- }
- /*
- ========================
- idSessionLocal::ClearMigrationState
- ========================
- */
- void idSessionLocal::ClearMigrationState() {
- // We are ending the match without migration, so clear that state
- GetPartyLobby().ResetAllMigrationState();
- GetGameLobby().ResetAllMigrationState();
- }
- /*
- ========================
- idSessionLocal::EndMatchInternal
- ========================
- */
- void idSessionLocal::EndMatchInternal( bool premature/*=false*/ ) {
- assert( GetGameStateLobby().IsLobbyActive() == net_useGameStateLobby.GetBool() );
- ClearVoiceGroups();
- for ( int p = 0; p < GetActingGameStateLobby().peers.Num(); p++ ) {
- // If we are the host, increment the session ID. The client will use a rolling check to catch it
- if ( GetActingGameStateLobby().IsHost() ) {
- if ( GetActingGameStateLobby().peers[p].IsConnected() ) {
- if ( GetActingGameStateLobby().peers[p].packetProc != NULL ) {
- GetActingGameStateLobby().peers[p].packetProc->VerifyEmptyReliableQueue( idLobby::RELIABLE_GAME_DATA, idLobby::RELIABLE_DUMMY_MSG );
- }
- GetActingGameStateLobby().peers[p].sessionID = GetActingGameStateLobby().IncrementSessionID( GetActingGameStateLobby().peers[p].sessionID );
- }
- }
- GetActingGameStateLobby().peers[p].ResetMatchData();
- }
- GetActingGameStateLobby().snapDeltaAckQueue.Clear();
- GetActingGameStateLobby().loaded = false;
- gameLobbyWasCoalesced = false; // Reset this back to false. We use this so the lobby code doesn't randomly choose a map when we coalesce
- numFullSnapsReceived = 0;
- ClearMigrationState();
- if ( GetActingGameStateLobby().IsLobbyActive() && ( GetActingGameStateLobby().GetMatchParms().matchFlags & MATCH_REQUIRE_PARTY_LOBBY ) ) {
- // All peers need to remove disconnected users to stay in sync
- GetActingGameStateLobby().CompactDisconnectedUsers();
- // Go back to the game lobby
- if ( GetActingGameStateLobby().IsHost() ) {
- // We want the game state host to go back to STATE_GAME_STATE_LOBBY_HOST, so he can wait on all his game state peers to leave
- SetState( GetGameStateLobby().IsHost() ? STATE_GAME_STATE_LOBBY_HOST : STATE_GAME_LOBBY_HOST ); // We want the dedicated host to go back to STATE_GAME_STATE_LOBBY_HOST
- } else {
- SetState( STATE_GAME_LOBBY_PEER );
- }
- } else {
- SetState( STATE_IDLE );
- }
- if ( GetActingGameStateLobby().IsHost() ) {
- // Send a reliable msg to all peers to also "EndMatch"
- for ( int p = 0; p < GetActingGameStateLobby().peers.Num(); p++ ) {
- GetActingGameStateLobby().QueueReliableMessage( p, premature ? idLobby::RELIABLE_ENDMATCH_PREMATURE : idLobby::RELIABLE_ENDMATCH );
- }
- } else if ( premature ) {
- // Notify client that host left early and thats why we are back in the lobby
- const bool stats = MatchTypeHasStats( GetActingGameStateLobby().GetMatchParms().matchFlags ) && ( GetFlushedStats() == false );
- common->Dialog().AddDialog( stats ? GDM_HOST_RETURNED_TO_LOBBY_STATS_DROPPED : GDM_HOST_RETURNED_TO_LOBBY, DIALOG_ACCEPT, NULL, NULL, false, __FUNCTION__, __LINE__, true );
- }
- if ( GetGameStateLobby().IsLobbyActive() ) {
- if ( GetGameStateLobby().IsHost() ) {
- // As a game state host, keep the lobby around, so we can make sure we know when everyone leaves (which means they got the reliable msg to EndMatch)
- waitingOnGameStateMembersToLeaveTime = Sys_Milliseconds();
- } else if ( GetGameStateLobby().IsPeer() ) {
- // Game state lobby peers should disconnect now
- GetGameStateLobby().Shutdown();
- }
- }
- }
- /*
- ========================
- idSessionLocal::MatchFinishedInternal
- ========================
- */
- void idSessionLocal::MatchFinishedInternal() {
- ClearMigrationState();
- if ( GetActingGameStateLobby().IsHost() ) {
- // Send a reliable msg to all peers to also "EndMatch"
- for ( int p = 0; p < GetActingGameStateLobby().peers.Num(); p++ ) {
- GetActingGameStateLobby().QueueReliableMessage( p, idLobby::RELIABLE_MATCHFINISHED );
- }
- }
- }
- /*
- ========================
- idSessionLocal::EndMatchForMigration
- ========================
- */
- void idSessionLocal::EndMatchForMigration() {
- ClearVoiceGroups();
- }
- /*
- ========================
- idSessionLocal::ShouldHavePartyLobby
- ========================
- */
- bool idSessionLocal::ShouldHavePartyLobby() {
- if ( GetActivePlatformLobby() == NULL ) {
- return false;
- }
- idMatchParameters & parms = GetActivePlatformLobby()->parms;
- int flags = parms.matchFlags;
- // Don't we always have a party lobby if we're online? At least in Doom 3?
- return MatchTypeIsOnline( flags ) && ( ( flags & MATCH_PARTY_INVITE_PLACEHOLDER ) == 0 );
- }
- /*
- ========================
- idSessionLocal::ValidateLobbies
- Determines if any of the session instances need to become the host
- ========================
- */
- void idSessionLocal::ValidateLobbies() {
- if ( localState == STATE_PRESS_START || localState == STATE_IDLE ) {
- // At press start or main menu, don't do anything
- return;
- }
- if ( GetActivePlatformLobby() == NULL ) {
- // If we're in between lobbies, don't do anything yet (the state transitioning code will handle error cases)
- return;
- }
- // Validate lobbies that should be alive and active
- if ( ShouldHavePartyLobby() && GetState() >= idSession::PARTY_LOBBY ) {
- ValidateLobby( GetPartyLobby() );
- }
- if ( GetState() >= idSession::GAME_LOBBY && !net_headlessServer.GetBool() ) {
- ValidateLobby( GetGameLobby() );
- }
- }
- /*
- ========================
- idSessionLocal::ValidateLobby
- ========================
- */
- void idSessionLocal::ValidateLobby( idLobby & lobby ) {
- if ( lobby.lobbyBackend == NULL || lobby.lobbyBackend->GetState() == idLobbyBackend::STATE_FAILED || lobby.GetState() == idLobby::STATE_FAILED ) {
- NET_VERBOSE_PRINT( "NET: ValidateLobby: FAILED (lobbyType = %i, state = %s)\n", lobby.lobbyType, stateToString[ localState ] );
- if ( lobby.failedReason == idLobby::FAILED_MIGRATION_CONNECT_FAILED || lobby.failedReason == idLobby::FAILED_CONNECT_FAILED ) {
- MoveToMainMenu();
- common->Dialog().AddDialog( GDM_INVALID_INVITE, DIALOG_ACCEPT, NULL, NULL, false ); // The game session no longer exists
- } else {
- // If the lobbyBackend goes bad under our feet for no known reason, assume we lost connection to the back end service
- MoveToMainMenu();
- common->Dialog().ClearDialogs( true );
- common->Dialog().AddDialog( GDM_CONNECTION_LOST, DIALOG_ACCEPT, NULL, NULL, false ); // Lost connection to XBox LIVE
- }
- }
- }
- /*
- ========================
- idSessionLocal::Pump
- ========================
- */
- void idSessionLocal::Pump() {
- SCOPED_PROFILE_EVENT( "Session::Pump" );
- static int lastPumpTime = -1;
- const int time = Sys_Milliseconds();
- const int elapsedPumpSeconds = ( time - lastPumpTime ) / 1000;
- if ( lastPumpTime != -1 && elapsedPumpSeconds > 2 ) {
- idLib::Warning( "idSessionLocal::Pump was not called for %i seconds", elapsedPumpSeconds );
- }
- lastPumpTime = time;
- if ( net_migrateHost.GetInteger() >= 0 ) {
- if ( net_migrateHost.GetInteger() <= 2 ) {
- if ( net_migrateHost.GetInteger() == 0 ) {
- GetPartyLobby().PickNewHost( true, true );
- } else {
- GetGameLobby().PickNewHost( true, true );
- }
- } else {
- GetPartyLobby().PickNewHost( true, true );
- GetGameLobby().PickNewHost( true, true );
- }
- net_migrateHost.SetInteger( -1 );
- }
- PlatformPump();
- if ( HasAchievementSystem() ) {
- GetAchievementSystem().Pump();
- }
- // Send any voice packets if it's time
- SendVoiceAudio();
- bool shouldContinue = true;
- while ( shouldContinue ) {
- // Each iteration, validate the session instances
- ValidateLobbies();
- // Pump state
- shouldContinue = HandleState();
- // Pump lobbies
- PumpLobbies();
- }
- if ( GetPartyLobby().lobbyBackend != NULL ) {
- // Make sure game properties aren't set on the lobbyBackend if we aren't in a game lobby.
- // This is so we show up properly in search results in Play with Friends option
- GetPartyLobby().lobbyBackend->SetInGame( GetGameLobby().IsLobbyActive() );
- // Temp location
- UpdateMasterUserHeadsetState();
- }
- // Do some last minute checks, make sure everything about the current state and lobbyBackend state is valid, otherwise, take action
- ValidateLobbies();
- GetActingGameStateLobby().UpdateSnaps();
- idLobby * activeLobby = GetActivePlatformLobby();
- // Pump pings for the active lobby
- if ( activeLobby != NULL ) {
- activeLobby->PumpPings();
- }
- // Pump packet processing for all lobbies
- GetPartyLobby().PumpPackets();
- GetGameLobby().PumpPackets();
- GetGameStateLobby().PumpPackets();
- int currentTime = Sys_Milliseconds();
- const int SHOW_MIGRATING_INFO_IN_SECONDS = 3; // Show for at least this long once we start showing it
- if ( ShouldShowMigratingDialog() ) {
- showMigratingInfoStartTime = currentTime;
- } else if ( showMigratingInfoStartTime > 0 && ( ( currentTime - showMigratingInfoStartTime ) > SHOW_MIGRATING_INFO_IN_SECONDS * 1000 ) ) {
- showMigratingInfoStartTime = 0;
- }
- bool isShowingMigrate = common->Dialog().HasDialogMsg( GDM_MIGRATING, NULL );
- if ( showMigratingInfoStartTime != 0 ) {
- if ( !isShowingMigrate ) {
- common->Dialog().AddDialog( GDM_MIGRATING, DIALOG_WAIT, NULL, NULL, false, "", 0, false, false, true );
- }
- } else if ( isShowingMigrate ) {
- common->Dialog().ClearDialog( GDM_MIGRATING );
- }
- // Update possible pending invite
- UpdatePendingInvite();
- // Check to see if we should coalesce the lobby
- if ( nextGameCoalesceTime != 0 ) {
- if ( GetGameLobby().IsLobbyActive() &&
- GetGameLobby().IsHost() &&
- GetState() == idSession::GAME_LOBBY &&
- GetPartyLobby().GetNumLobbyUsers() <= 1 &&
- GetGameLobby().GetNumLobbyUsers() == 1 &&
- MatchTypeIsRanked( GetGameLobby().parms.matchFlags ) &&
- Sys_Milliseconds() > nextGameCoalesceTime ) {
-
- // If the player doesn't care about the mode or map,
- // make sure the search is broadened.
- idMatchParameters newGameParms = GetGameLobby().parms;
- newGameParms.gameMap = GAME_MAP_RANDOM;
- // Assume that if the party lobby's mode is random,
- // the player chose "Quick Match" and doesn't care about the mode.
- // If the player chose "Find Match" and a specific mode,
- // the party lobby mode will be set to non-random.
- if ( GetPartyLobby().parms.gameMode == GAME_MODE_RANDOM ) {
- newGameParms.gameMode = GAME_MODE_RANDOM;
- }
- FindOrCreateMatch( newGameParms );
- gameLobbyWasCoalesced = true; // Remember that this round was coalesced. We so this so main menu doesn't randomize the map, which looks odd
- nextGameCoalesceTime = 0;
- }
- }
- }
- /*
- ========================
- idSessionLocal::ProcessSnapAckQueue
- ========================
- */
- void idSessionLocal::ProcessSnapAckQueue() {
- if ( GetActingGameStateLobby().IsLobbyActive() ) {
- GetActingGameStateLobby().ProcessSnapAckQueue();
- }
- }
- /*
- ========================
- idSessionLocal::UpdatePendingInvite
- ========================
- */
- void idSessionLocal::UpdatePendingInvite() {
- if ( pendingInviteMode == PENDING_INVITE_NONE ) {
- return; // No pending invite
- }
- idLocalUser * masterLocalUser = signInManager->GetMasterLocalUser();
- if ( masterLocalUser == NULL && signInManager->IsDeviceBeingRegistered( pendingInviteDevice ) ) {
- idLib::Printf( "masterLocalUser == NULL\n" );
- return; // Waiting on master to sign in to continue with invite
- }
- const bool wasFromInvite = pendingInviteMode == PENDING_INVITE_WAITING; // Remember if this was a real invite, or a self invitation (matters when lobby is invite only)
- // At this point, the invitee should be ready
- pendingInviteMode = PENDING_INVITE_NONE;
- if ( masterLocalUser == NULL || masterLocalUser->GetInputDevice() != pendingInviteDevice || !masterLocalUser->IsOnline() ) {
- idLib::Printf( "ignoring invite - master local user is not setup properly\n" );
- return; // If there is no master, if the invitee is not online, or different than the current master, then ignore invite
- }
- // Clear any current dialogs, as we're going into a state which will be unstable for any current dialogs.
- // Do we want to throw an assert if a dialog is currently up?
- common->Dialog().ClearDialogs( true );
- // Everything looks good, let's join the party
- ConnectAndMoveToLobby( GetPartyLobby(), pendingInviteConnectInfo, wasFromInvite );
- }
- /*
- ========================
- idSessionLocal::HandleState
- ========================
- */
- bool idSessionLocal::HandleState() {
- // Handle individual lobby states
- GetPartyLobby().Pump();
- GetGameLobby().Pump();
- GetGameStateLobby().Pump();
- // Let IsHost be authoritative on the qualification of peer/host state types
- if ( GetPartyLobby().IsHost() && localState == STATE_PARTY_LOBBY_PEER ) {
- SetState( STATE_PARTY_LOBBY_HOST );
- } else if ( GetPartyLobby().IsPeer() && localState == STATE_PARTY_LOBBY_HOST ) {
- SetState( STATE_PARTY_LOBBY_PEER );
- }
- // Let IsHost be authoritative on the qualification of peer/host state types
- if ( GetGameLobby().IsHost() && localState == STATE_GAME_LOBBY_PEER ) {
- SetState( STATE_GAME_LOBBY_HOST );
- } else if ( GetGameLobby().IsPeer() && localState == STATE_GAME_LOBBY_HOST ) {
- SetState( STATE_GAME_LOBBY_PEER );
- }
- switch ( localState ) {
- case STATE_PRESS_START: return false;
- case STATE_IDLE: HandlePackets(); return false; // Call handle packets, since packets from old sessions could still be in flight, which need to be emptied
- case STATE_PARTY_LOBBY_HOST: return State_Party_Lobby_Host();
- case STATE_PARTY_LOBBY_PEER: return State_Party_Lobby_Peer();
- case STATE_GAME_LOBBY_HOST: return State_Game_Lobby_Host();
- case STATE_GAME_LOBBY_PEER: return State_Game_Lobby_Peer();
- case STATE_GAME_STATE_LOBBY_HOST: return State_Game_State_Lobby_Host();
- case STATE_GAME_STATE_LOBBY_PEER: return State_Game_State_Lobby_Peer();
- case STATE_LOADING: return State_Loading();
- case STATE_INGAME: return State_InGame();
- case STATE_CREATE_AND_MOVE_TO_PARTY_LOBBY: return State_Create_And_Move_To_Party_Lobby();
- case STATE_CREATE_AND_MOVE_TO_GAME_LOBBY: return State_Create_And_Move_To_Game_Lobby();
- case STATE_CREATE_AND_MOVE_TO_GAME_STATE_LOBBY: return State_Create_And_Move_To_Game_State_Lobby();
- case STATE_FIND_OR_CREATE_MATCH: return State_Find_Or_Create_Match();
- case STATE_CONNECT_AND_MOVE_TO_PARTY: return State_Connect_And_Move_To_Party();
- case STATE_CONNECT_AND_MOVE_TO_GAME: return State_Connect_And_Move_To_Game();
- case STATE_CONNECT_AND_MOVE_TO_GAME_STATE: return State_Connect_And_Move_To_Game_State();
- case STATE_BUSY: return State_Busy();
- default:
- idLib::Error( "HandleState: Unknown state in idSessionLocal" );
- }
- }
- /*
- ========================
- idSessionLocal::GetState
- ========================
- */
- idSessionLocal::sessionState_t idSessionLocal::GetState() const {
- // Convert our internal state to one of the external states
- switch ( localState ) {
- case STATE_PRESS_START: return PRESS_START;
- case STATE_IDLE: return IDLE;
- case STATE_PARTY_LOBBY_HOST: return PARTY_LOBBY;
- case STATE_PARTY_LOBBY_PEER: return PARTY_LOBBY;
- case STATE_GAME_LOBBY_HOST: return GAME_LOBBY;
- case STATE_GAME_LOBBY_PEER: return GAME_LOBBY;
- case STATE_GAME_STATE_LOBBY_HOST: return GAME_LOBBY;
- case STATE_GAME_STATE_LOBBY_PEER: return GAME_LOBBY;
- case STATE_LOADING: return LOADING;
- case STATE_INGAME: return INGAME;
- case STATE_CREATE_AND_MOVE_TO_PARTY_LOBBY: return CONNECTING;
- case STATE_CREATE_AND_MOVE_TO_GAME_LOBBY: return CONNECTING;
- case STATE_CREATE_AND_MOVE_TO_GAME_STATE_LOBBY: return CONNECTING;
- case STATE_FIND_OR_CREATE_MATCH: return SEARCHING;
- case STATE_CONNECT_AND_MOVE_TO_PARTY: return CONNECTING;
- case STATE_CONNECT_AND_MOVE_TO_GAME: return CONNECTING;
- case STATE_CONNECT_AND_MOVE_TO_GAME_STATE: return CONNECTING;
- case STATE_BUSY: return BUSY;
- default: {
- idLib::Error( "GetState: Unknown state in idSessionLocal" );
- }
- };
- }
- const char * idSessionLocal::GetStateString() const {
- static const char * stateToString[] = {
- ASSERT_ENUM_STRING( STATE_PRESS_START, 0 ),
- ASSERT_ENUM_STRING( STATE_IDLE, 1 ),
- ASSERT_ENUM_STRING( STATE_PARTY_LOBBY_HOST, 2 ),
- ASSERT_ENUM_STRING( STATE_PARTY_LOBBY_PEER, 3 ),
- ASSERT_ENUM_STRING( STATE_GAME_LOBBY_HOST, 4 ),
- ASSERT_ENUM_STRING( STATE_GAME_LOBBY_PEER, 5 ),
- ASSERT_ENUM_STRING( STATE_GAME_STATE_LOBBY_HOST, 6 ),
- ASSERT_ENUM_STRING( STATE_GAME_STATE_LOBBY_PEER, 7 ),
- ASSERT_ENUM_STRING( STATE_CREATE_AND_MOVE_TO_PARTY_LOBBY, 8 ),
- ASSERT_ENUM_STRING( STATE_CREATE_AND_MOVE_TO_GAME_LOBBY, 9 ),
- ASSERT_ENUM_STRING( STATE_CREATE_AND_MOVE_TO_GAME_STATE_LOBBY, 10 ),
- ASSERT_ENUM_STRING( STATE_FIND_OR_CREATE_MATCH, 11 ),
- ASSERT_ENUM_STRING( STATE_CONNECT_AND_MOVE_TO_PARTY, 12 ),
- ASSERT_ENUM_STRING( STATE_CONNECT_AND_MOVE_TO_GAME, 13 ),
- ASSERT_ENUM_STRING( STATE_CONNECT_AND_MOVE_TO_GAME_STATE, 14 ),
- ASSERT_ENUM_STRING( STATE_BUSY, 15 ),
- ASSERT_ENUM_STRING( STATE_LOADING, 16 ),
- ASSERT_ENUM_STRING( STATE_INGAME, 17 )
- };
- return stateToString[ localState ];
- }
- // idSession interface
- /*
- ========================
- idSessionLocal::LoadingFinished
- Only called by idCommonLocal::FinalizeMapChange
- ========================
- */
- void idSessionLocal::LoadingFinished() {
- NET_VERBOSE_PRINT( "NET: Loading Finished\n" );
- assert( GetState() == idSession::LOADING );
- common->Dialog().ClearDialog( GDM_VOICE_RESTRICTED );
- GetActingGameStateLobby().loaded = true;
-
- if ( MatchTypeIsLocal( GetActingGameStateLobby().parms.matchFlags ) ) {
- SetState( STATE_INGAME );
- } else if ( !GetActingGameStateLobby().IsHost() ) { // Tell game host we're done loading
- byte buffer[ idPacketProcessor::MAX_PACKET_SIZE ];
- idBitMsg msg( buffer, sizeof( buffer ) );
- GetActingGameStateLobby().QueueReliableMessage( GetActingGameStateLobby().host, idLobby::RELIABLE_LOADING_DONE, msg.GetReadData(), msg.GetSize() );
- } else {
- SetState( STATE_INGAME );
- }
- SetFlushedStats( false );
- }
- /*
- ========================
- idSessionLocal::SendUsercmds
- ========================
- */
- void idSessionLocal::SendUsercmds( idBitMsg & msg ) {
- if ( localState != STATE_INGAME ) {
- return;
- }
-
- if ( GetActingGameStateLobby().IsPeer() ) {
- idLobby::peer_t & hostPeer = GetActingGameStateLobby().peers[GetActingGameStateLobby().host];
-
- // Don't send user cmds if we have unsent packet fragments
- // (This can happen if we have packets to send, but SendAnotherFragment got throttled)
- if ( hostPeer.packetProc->HasMoreFragments() ) {
- idLib::Warning( "NET: Client called SendUsercmds while HasMoreFragments(). Skipping userCmds for this frame." );
- return;
- }
- int sequence = hostPeer.snapProc->GetLastAppendedSequence();
- // Add incoming BPS for QoS
- float incomingBPS = hostPeer.receivedBps;
- if ( hostPeer.receivedBpsIndex != sequence ) {
- incomingBPS = idMath::ClampFloat( 0.0f, static_cast<float>( idLobby::BANDWIDTH_REPORTING_MAX ), hostPeer.packetProc->GetIncomingRateBytes() );
- hostPeer.receivedBpsIndex = sequence;
- hostPeer.receivedBps = incomingBPS;
- }
- uint16 incomingBPS_quantized = idMath::Ftoi( incomingBPS * ( ( BIT( idLobby::BANDWIDTH_REPORTING_BITS ) - 1 ) / idLobby::BANDWIDTH_REPORTING_MAX ) );
- byte buffer[idPacketProcessor::MAX_FINAL_PACKET_SIZE];
- lzwCompressionData_t lzwData;
- idLZWCompressor lzwCompressor( &lzwData );
- lzwCompressor.Start( buffer, sizeof( buffer ) );
- lzwCompressor.WriteAgnostic( sequence );
- lzwCompressor.WriteAgnostic( incomingBPS_quantized );
- lzwCompressor.Write( msg.GetReadData(), msg.GetSize() );
- lzwCompressor.End();
- GetActingGameStateLobby().ProcessOutgoingMsg( GetActingGameStateLobby().host, buffer, lzwCompressor.Length(), false, 0 );
-
- if ( net_debugBaseStates.GetBool() && sequence < 50 ) {
- idLib::Printf( "NET: Acking snap %d \n", sequence );
- }
- }
- }
- /*
- ========================
- idSessionLocal::SendSnapshot
- ========================
- */
- void idSessionLocal::SendSnapshot( idSnapShot & ss ) {
- for ( int p = 0; p < GetActingGameStateLobby().peers.Num(); p++ ) {
- idLobby::peer_t & peer = GetActingGameStateLobby().peers[p];
-
- if ( !peer.IsConnected() ) {
- continue;
- }
-
- if ( !peer.loaded ) {
- continue;
- }
- if ( peer.pauseSnapshots ) {
- continue;
- }
-
- GetActingGameStateLobby().SendSnapshotToPeer( ss, p );
- }
- }
- /*
- ========================
- idSessionLocal::UpdateSignInManager
- ========================
- */
- void idSessionLocal::UpdateSignInManager() {
- if ( !HasSignInManager() ) {
- return;
- }
- if ( net_headlessServer.GetBool() ) {
- return;
- }
-
- // FIXME: We need to ask the menu system for this info. Just making a best guess for now
- // (assume we are allowed to join the party as a splitscreen user if we are in the party lobby)
- bool allowJoinParty = ( localState == STATE_PARTY_LOBBY_HOST || localState == STATE_PARTY_LOBBY_PEER ) && GetPartyLobby().state == idLobby::STATE_IDLE;
- bool allowJoinGame = ( localState == STATE_GAME_LOBBY_HOST || localState == STATE_GAME_LOBBY_PEER ) && GetGameLobby().state == idLobby::STATE_IDLE;
- bool eitherLobbyRunning = GetActivePlatformLobby() != NULL && ( GetPartyLobby().IsLobbyActive() || GetGameLobby().IsLobbyActive() );
- bool onlineMatch = eitherLobbyRunning && MatchTypeIsOnline( GetActivePlatformLobby()->parms.matchFlags );
- //=================================================================================
- // Get the number of desired signed in local users depending on what mode we're in.
- //=================================================================================
- int minDesiredUsers = 0;
- int maxDesiredUsers = Max( 1, signInManager->GetNumLocalUsers() );
-
- if ( si_splitscreen.GetInteger() != 0 ) {
- // For debugging, force 2 splitscreen players
- minDesiredUsers = 2;
- maxDesiredUsers = 2;
- allowJoinGame = true;
- } else if ( onlineMatch || ( eitherLobbyRunning == false ) ) {
- // If this an online game, then only 1 user can join locally.
- // Also, if no sessions are active, remove any extra players.
- maxDesiredUsers = 1;
- } else if ( allowJoinParty || allowJoinGame ) {
- // If we are in the party lobby, allow 2 splitscreen users to join
- maxDesiredUsers = 2;
- }
- // Set the number of desired users
- signInManager->SetDesiredLocalUsers( minDesiredUsers, maxDesiredUsers );
-
- //=================================================================================
- // Update signin manager
- //=================================================================================
-
- // Update signin mgr. This manager tracks signed in local users, which the session then uses
- // to determine who should be in the lobby.
- signInManager->Pump();
-
- // Get the master local user
- idLocalUser * masterUser = signInManager->GetMasterLocalUser();
- if ( onlineMatch && masterUser != NULL && !masterUser->CanPlayOnline() && !masterUser->HasOwnerChanged() ) {
- if ( localState > STATE_IDLE ) {
- // User is still valid, just no longer online
- if ( offlineTransitionTimerStart == 0 ) {
- offlineTransitionTimerStart = Sys_Milliseconds();
- }
- if ( ( Sys_Milliseconds() - offlineTransitionTimerStart ) > net_offlineTransitionThreshold.GetInteger() ) {
- MoveToMainMenu();
- common->Dialog().ClearDialogs();
- common->Dialog().AddDialog( GDM_CONNECTION_LOST, DIALOG_ACCEPT, NULL, NULL, false, "", 0, true );
- }
- }
- return; // Bail out so signInManager->ValidateLocalUsers below doesn't prematurely remove the master user before we can detect loss of connection
- } else {
- offlineTransitionTimerStart = 0;
- }
- // Remove local users (from the signin manager) who aren't allowed to be online if this is an online match.
- // Remove local user (from the signin manager) who are not properly signed into a profile.
- signInManager->ValidateLocalUsers( onlineMatch );
- //=================================================================================
- // Check to see if we need to go to "Press Start"
- //=================================================================================
- // Get the master local user (again, after ValidateOnlineLocalUsers, to make sure he is still valid)
- masterUser = signInManager->GetMasterLocalUser();
-
- if ( masterUser == NULL ) {
- // If we don't have a master user at all, then we need to be at "Press Start"
- MoveToPressStart( GDM_SP_SIGNIN_CHANGE_POST );
- return;
- } else if ( localState == STATE_PRESS_START ) {
- // If we have a master user, and we are at press start, move to the menu area
- SetState( STATE_IDLE );
- }
- // See if the master user either isn't persistent (but needs to be), OR, if the owner changed
- // RequirePersistentMaster is poorly named, this really means RequireSignedInMaster
- if ( masterUser->HasOwnerChanged() || ( RequirePersistentMaster() && !masterUser->IsProfileReady() ) ) {
- MoveToPressStart( GDM_SP_SIGNIN_CHANGE_POST );
- return;
- }
- //=================================================================================
- // Sync lobby users with the signed in users
- // The initial list of session users are normally determined at connect or create time.
- // These functions allow splitscreen users to join in, or check to see if existing
- // users (including the master) need to be removed.
- //=================================================================================
- GetPartyLobby().SyncLobbyUsersWithLocalUsers( allowJoinParty, onlineMatch );
- GetGameLobby().SyncLobbyUsersWithLocalUsers( allowJoinGame, onlineMatch );
- GetGameStateLobby().SyncLobbyUsersWithLocalUsers( allowJoinGame, onlineMatch );
- }
- /*
- ========================
- idSessionLocal::GetProfileFromMasterLocalUser
- ========================
- */
- idPlayerProfile * idSessionLocal::GetProfileFromMasterLocalUser() {
- idPlayerProfile * profile = NULL;
- idLocalUser * masterUser = signInManager->GetMasterLocalUser();
-
- if ( masterUser != NULL ) {
- profile = masterUser->GetProfile();
- }
-
- if ( profile == NULL ) {
- // Whoops
- profile = signInManager->GetDefaultProfile();
- //idLib::Warning( "Returning fake profile until the code is fixed to handle NULL profiles." );
- }
-
- return profile;
- }
- /*
- ========================
- /*
- ========================
- idSessionLocal::MoveToPressStart
- ========================
- */
- void idSessionLocal::MoveToPressStart( gameDialogMessages_t msg ) {
- if ( localState != STATE_PRESS_START ) {
- MoveToPressStart();
- common->Dialog().ClearDialogs();
- common->Dialog().AddDialog( msg, DIALOG_ACCEPT, NULL, NULL, false, "", 0, true );
- }
- }
- /*
- ========================
- idSessionLocal::GetPeerName
- ========================
- */
- const char * idSessionLocal::GetPeerName( int peerNum ) {
- return GetActingGameStateLobby().GetPeerName( peerNum );
- }
- /*
- ========================
- idSessionLocal::SetState
- ========================
- */
- void idSessionLocal::SetState( state_t newState ) {
- assert( newState < NUM_STATES );
- assert( localState < NUM_STATES );
- verify_array_size( stateToString, NUM_STATES );
- if ( newState == localState ) {
- NET_VERBOSE_PRINT( "NET: SetState: State SAME %s\n", stateToString[ newState ] );
- return;
- }
- // Set the current state
- NET_VERBOSE_PRINT( "NET: SetState: State changing from %s to %s\n", stateToString[ localState ], stateToString[ newState ] );
- if ( localState < STATE_LOADING && newState >= STATE_LOADING ) {
- // Tell lobby instances that the match has started
- StartSessions();
- // Clear certain dialog boxes we don't want to see in-game
- common->Dialog().ClearDialog( GDM_LOBBY_DISBANDED ); // The lobby you were previously in has disbanded
- } else if ( localState >= STATE_LOADING && newState < STATE_LOADING ) {
- // Tell lobby instances that the match has ended
- if ( !WasMigrationGame() ) { // Don't end the session if we are going right back into the game
- EndSessions();
- }
- }
- if ( newState == STATE_GAME_LOBBY_HOST || newState == STATE_GAME_LOBBY_PEER ) {
- ComputeNextGameCoalesceTime();
- }
- localState = newState;
- }
- /*
- ========================
- idSessionLocal::HandlePackets
- ========================
- */
- bool idSessionLocal::HandlePackets() {
- SCOPED_PROFILE_EVENT( "Session::HandlePackets" );
- byte packetBuffer[ idPacketProcessor::MAX_FINAL_PACKET_SIZE ];
- lobbyAddress_t remoteAddress;
- int recvSize = 0;
- bool fromDedicated = false;
- while ( ReadRawPacket( remoteAddress, packetBuffer, recvSize, fromDedicated, sizeof( packetBuffer ) ) && recvSize > 0 ) {
-
- // fragMsg will hold the raw packet
- idBitMsg fragMsg;
- fragMsg.InitRead( packetBuffer, recvSize );
- // Peek at the session ID
- idPacketProcessor::sessionId_t sessionID = idPacketProcessor::GetSessionID( fragMsg );
- // idLib::Printf( "NET: HandlePackets - session %d, size %d \n", sessionID, recvSize );
- // Make sure it's valid
- if ( sessionID == idPacketProcessor::SESSION_ID_INVALID ) {
- idLib::Printf( "NET: Invalid sessionID %s.\n", remoteAddress.ToString() );
- continue;
- }
- //
- // Distribute the packet to the proper lobby
- //
- const int maskedType = sessionID & idPacketProcessor::LOBBY_TYPE_MASK;
- if ( !verify( maskedType > 0 ) ) {
- continue;
- }
- idLobby::lobbyType_t lobbyType = (idLobby::lobbyType_t)( maskedType - 1 );
- switch ( lobbyType ) {
- case idLobby::TYPE_PARTY: GetPartyLobby().HandlePacket( remoteAddress, fragMsg, sessionID ); break;
- case idLobby::TYPE_GAME: GetGameLobby().HandlePacket( remoteAddress, fragMsg, sessionID ); break;
- case idLobby::TYPE_GAME_STATE: GetGameStateLobby().HandlePacket( remoteAddress, fragMsg, sessionID ); break;
- default: assert( 0 );
- }
- }
- return false;
- }
- /*
- ========================
- idSessionLocal::GetActivePlatformLobby
- ========================
- */
- idLobby * idSessionLocal::GetActivePlatformLobby() {
- sessionState_t state = GetState();
- if ( ( state == GAME_LOBBY ) || ( state == BUSY ) || ( state == INGAME ) || ( state == LOADING ) ) {
- return &GetGameLobby();
- } else if ( state == PARTY_LOBBY ) {
- return &GetPartyLobby();
- }
-
- return NULL;
- }
- /*
- ========================
- idSessionLocal::GetActivePlatformLobby
- ========================
- */
- const idLobby * idSessionLocal::GetActivePlatformLobby() const {
- sessionState_t state = GetState();
- if ( ( state == GAME_LOBBY ) || ( state == BUSY ) || ( state == INGAME ) || ( state == LOADING ) ) {
- return &GetGameLobby();
- } else if ( state == PARTY_LOBBY ) {
- return &GetPartyLobby();
- }
-
- return NULL;
- }
- /*
- ========================
- idSessionLocal::GetActingGameStateLobby
- ========================
- */
- idLobby & idSessionLocal::GetActingGameStateLobby() {
- if ( net_useGameStateLobby.GetBool() ) {
- return GetGameStateLobby();
- }
- return GetGameLobby();
- }
- /*
- ========================
- idSessionLocal::GetActingGameStateLobby
- ========================
- */
- const idLobby & idSessionLocal::GetActingGameStateLobby() const {
- if ( net_useGameStateLobby.GetBool() ) {
- return GetGameStateLobby();
- }
- return GetGameLobby();
- }
- /*
- ========================
- idSessionLocal::GetLobbyFromType
- ========================
- */
- idLobby * idSessionLocal::GetLobbyFromType( idLobby::lobbyType_t lobbyType ) {
- switch ( lobbyType ) {
- case idLobby::TYPE_PARTY: return &GetPartyLobby();
- case idLobby::TYPE_GAME: return &GetGameLobby();
- case idLobby::TYPE_GAME_STATE: return &GetGameStateLobby();
- }
- return NULL;
- }
- /*
- ========================
- idSessionLocal::GetActivePlatformLobbyBase
- This returns the base version for the idSession version
- ========================
- */
- idLobbyBase & idSessionLocal::GetActivePlatformLobbyBase() {
- idLobby * activeLobby = GetActivePlatformLobby();
- if ( activeLobby != NULL ) {
- return *activeLobby;
- }
- return stubLobby; // So we can return at least something
- }
- /*
- ========================
- idSessionLocal::GetLobbyFromLobbyUserID
- ========================
- */
- idLobbyBase & idSessionLocal::GetLobbyFromLobbyUserID( lobbyUserID_t lobbyUserID ) {
- if ( !lobbyUserID.IsValid() ) {
- return stubLobby; // So we can return at least something
- }
- idLobby * lobby = GetLobbyFromType( (idLobby::lobbyType_t)lobbyUserID.GetLobbyType() );
- if ( lobby != NULL ) {
- return *lobby;
- }
- return stubLobby; // So we can return at least something
- }
- /*
- ========================
- idSessionLocal::TickSendQueue
- ========================
- */
- void idSessionLocal::TickSendQueue() {
- assert( !sendQueue.IsEmpty() );
- int now = Sys_Milliseconds();
- idQueuePacket * packet = sendQueue.Peek();
- while ( packet != NULL ) {
- if ( now < packet->time ) {
- break;
- }
- GetPort( packet->dedicated ).SendRawPacket( packet->address, packet->data, packet->size );
- if ( net_forceUpstream.GetFloat() != 0.0f && net_forceUpstreamQueue.GetFloat() != 0.0f ) {
- // FIXME: no can do both
- assert( net_forceLatency.GetInteger() == 0 );
- // compute / update an added traffic due to the queuing
- // we can't piggyback on upstreamDropRate because of the way it's computed and clamped to zero
- int time = Sys_Milliseconds();
- if ( time > upstreamQueueRateTime ) {
- upstreamQueueRate -= upstreamQueueRate * ( float )( time - upstreamQueueRateTime ) / 1000.0f;
- if ( upstreamQueueRate < 0.0f ) {
- upstreamQueueRate = 0.0f;
- }
- upstreamQueueRateTime = time;
- }
- // update queued bytes
- queuedBytes -= packet->size;
- if ( net_verboseSimulatedTraffic.GetBool() ) {
- idLib::Printf( "send queued packet size %d to %s\n", packet->size, packet->address.ToString() );
- }
- }
- sendQueue.RemoveFirst(); // we have it already, just push it off the queue before freeing
- packetAllocator.Free( packet );
- packet = sendQueue.Peek();
- }
- }
- /*
- ========================
- idSessionLocal::QueuePacket
- ========================
- */
- void idSessionLocal::QueuePacket( idQueue< idQueuePacket,&idQueuePacket::queueNode > & queue, int time, const lobbyAddress_t & to, const void * data, int size, bool dedicated ) {
- //mem.PushHeap();
- idQueuePacket * packet = packetAllocator.Alloc();
- packet->address = to;
- packet->size = size;
- packet->dedicated = dedicated;
- packet->time = time;
- memcpy( packet->data, data, size );
- queue.Add( packet );
- //mem.PopHeap();
- }
- /*
- ========================
- idSessionLocal::ReadRawPacketFromQueue
- ========================
- */
- bool idSessionLocal::ReadRawPacketFromQueue( int time, lobbyAddress_t & from, void * data, int & size, bool & outDedicated, int maxSize ) {
- idQueuePacket * packet = recvQueue.Peek();
- if ( packet == NULL || time < packet->time ) {
- return false; // Either there are no packets, or no packet is ready
- }
- //idLib::Printf( "NET: Packet recvd: %d ms\n", now );
- from = packet->address;
- size = packet->size;
- assert( size <= maxSize );
- outDedicated = packet->dedicated;
- memcpy( data, packet->data, packet->size );
- recvQueue.RemoveFirst(); // we have it already, just push it off the queue before freeing
- packetAllocator.Free( packet );
- return true;
- }
- /*
- ========================
- idSessionLocal::SendRawPacket
- ========================
- */
- void idSessionLocal::SendRawPacket( const lobbyAddress_t & to, const void * data, int size, bool dedicated ) {
- const int now = Sys_Milliseconds();
- if ( net_forceUpstream.GetFloat() != 0 ) {
- // the total bandwidth rate at which the networking systems are trying to push data through
- float totalOutgoingRate = (float)GetActingGameStateLobby().GetTotalOutgoingRate(); // B/s
- // update the rate at which we have been taking data out by dropping it
- int time = Sys_Milliseconds();
- if ( time > upstreamDropRateTime ) {
- upstreamDropRate -= upstreamDropRate * ( float )( time - upstreamDropRateTime ) / 1000.0f;
- if ( upstreamDropRate < 0.0f ) {
- upstreamDropRate = 0.0f;
- }
- upstreamDropRateTime = time;
- }
- if ( (float)( totalOutgoingRate - upstreamDropRate + upstreamQueueRate ) > net_forceUpstream.GetFloat() * 1024.0f ) { // net_forceUpstream is in kB/s, everything else in B/s
- if ( net_forceUpstreamQueue.GetFloat() == 0.0f ) {
- // just drop the packet - not representative, but simple
- if ( net_verboseSimulatedTraffic.GetBool() ) {
- idLib::Printf( "drop %d bytes to %s\n", size, to.ToString() );
- }
- // increase the instant drop rate with the data we just dropped
- upstreamDropRate += size;
- return;
- }
- // simulate a network device with a send queue
- // do we have room in the queue?
- assert( net_forceUpstreamQueue.GetFloat() > 0.0f );
- if ( (float)( queuedBytes + size ) > net_forceUpstreamQueue.GetFloat() * 1024.0f ) { // net_forceUpstreamQueue is in kB/s
- // too much queued, this is still a drop
- // FIXME: factorize
- // just drop the packet - not representative, but simple
- if ( net_verboseSimulatedTraffic.GetBool() ) {
- idLib::Printf( "full queue: drop %d bytes to %s\n", size, to.ToString() );
- }
- // increase the instant drop rate with the data we just dropped
- upstreamDropRate += size;
- return;
- }
- // there is room to buffer up in the queue
- queuedBytes += size;
- // with queuedBytes and the current upstream, when should this packet be sent?
- int queuedPacketSendDelay = 1000.0f * ( (float)queuedBytes / ( net_forceUpstream.GetFloat() * 1024.0f ) ); // in ms
- // queue for sending
- if ( net_verboseSimulatedTraffic.GetBool() ) {
- idLib::Printf( "queuing packet: %d bytes delayed %d ms\n", size, queuedPacketSendDelay );
- }
- QueuePacket( sendQueue, now + queuedPacketSendDelay, to, data, size, dedicated );
- // will abuse the forced latency code below to take care of the sending
- // FIXME: right now, can't have both on
- assert( net_forceLatency.GetInteger() == 0 );
- }
- }
- // short path
- // NOTE: network queuing: will go to tick the queue whenever sendQueue isn't empty, regardless of latency
- if ( net_forceLatency.GetInteger() == 0 && sendQueue.IsEmpty() ) {
- GetPort( dedicated ).SendRawPacket( to, data, size );
- return;
- }
- if ( net_forceUpstream.GetFloat() != 0.0f && net_forceUpstreamQueue.GetFloat() != 0.0f ) {
- // FIXME: not doing both just yet
- assert( net_forceLatency.GetInteger() == 0 );
- TickSendQueue();
- return; // we done (at least for queue only path)
- }
- // queue up
- assert( size != 0 && size <= idPacketProcessor::MAX_FINAL_PACKET_SIZE );
- QueuePacket( sendQueue, now + net_forceLatency.GetInteger() / 2, to, data, size, dedicated );
- TickSendQueue();
- }
- /*
- ========================
- idSessionLocal::ReadRawPacket
- ========================
- */
- bool idSessionLocal::ReadRawPacket( lobbyAddress_t & from, void * data, int & size, bool & outDedicated, int maxSize ) {
- SCOPED_PROFILE_EVENT( "Session::ReadRawPacket" );
- assert( maxSize <= idPacketProcessor::MAX_FINAL_PACKET_SIZE );
- if ( !sendQueue.IsEmpty() ) {
- TickSendQueue();
- }
- const int now = Sys_Milliseconds();
- // Make sure we give both ports equal time
- static bool currentDedicated = false;
- currentDedicated = !currentDedicated;
- for ( int i = 0; i < 2; i++ ) {
- // BRIAN_FIXME: Dedicated servers fuck up running 2 instances on the same machine
- // outDedicated = ( i == 0 ) ? currentDedicated : !currentDedicated;
- outDedicated = false;
- if ( GetPort( outDedicated ).ReadRawPacket( from, data, size, maxSize ) ) {
- if ( net_forceLatency.GetInteger() == 0 && recvQueue.IsEmpty() ) {
- // If we aren't forcing latency, and queue is empty, return result immediately
- return true;
- }
-
- // the cvar is meant to be a round trip latency so we're applying half on the send and half on the recv
- const int time = ( net_forceLatency.GetInteger() == 0 ) ? 0 : now + net_forceLatency.GetInteger() / 2;
- // Otherwise, queue result
- QueuePacket( recvQueue, time, from, data, size, outDedicated );
- }
- }
- // Return any queued results
- return ReadRawPacketFromQueue( now, from, data, size, outDedicated, maxSize );
- }
- /*
- ========================
- idSessionLocal::ConnectAndMoveToLobby
- ========================
- */
- void idSessionLocal::ConnectAndMoveToLobby( idLobby & lobby, const lobbyConnectInfo_t & connectInfo, bool fromInvite ) {
- // Since we are connecting directly to a lobby, make sure no search results are left over from previous FindOrCreateMatch results
- // If we don't do this, we might think we should attempt to connect to an old search result, and we don't want to in this case
- lobby.searchResults.Clear();
- // Attempt to connect to the lobby
- lobby.ConnectTo( connectInfo, fromInvite );
- connectType = CONNECT_DIRECT;
- // Wait for connection
- switch ( lobby.lobbyType ) {
- case idLobby::TYPE_PARTY: SetState( STATE_CONNECT_AND_MOVE_TO_PARTY ); break;
- case idLobby::TYPE_GAME: SetState( STATE_CONNECT_AND_MOVE_TO_GAME ); break;
- case idLobby::TYPE_GAME_STATE: SetState( STATE_CONNECT_AND_MOVE_TO_GAME_STATE ); break;
- }
- }
- /*
- ========================
- idSessionLocal::GoodbyeFromHost
- ========================
- */
- void idSessionLocal::GoodbyeFromHost( idLobby & lobby, int peerNum, const lobbyAddress_t & remoteAddress, int msgType ) {
- if ( !verify( localState > STATE_IDLE ) ) {
- idLib::Printf( "NET: Got disconnected from host %s on session %s when we were not in a lobby or game.\n", remoteAddress.ToString(), lobby.GetLobbyName() );
- MoveToMainMenu();
- return; // Ignore if we are not past the main menu
- }
- // Goodbye from host. See if we were connecting vs connected
- if ( ( localState == STATE_CONNECT_AND_MOVE_TO_PARTY || localState == STATE_CONNECT_AND_MOVE_TO_GAME ) && lobby.peers[peerNum].GetConnectionState() == idLobby::CONNECTION_CONNECTING ) {
- // We were denied a connection attempt
- idLib::Printf( "NET: Denied connection attempt from host %s on session %s. MsgType %i.\n", remoteAddress.ToString(), lobby.GetLobbyName(), msgType );
- // This will try to move to the next connection if one exists, otherwise will create a match
- HandleConnectionFailed( lobby, msgType == idLobby::OOB_GOODBYE_FULL );
- } else {
- // We were disconnected from a server we were previously connected to
- idLib::Printf( "NET: Disconnected from host %s on session %s. MsgType %i.\n", remoteAddress.ToString(), lobby.GetLobbyName(), msgType );
- const bool leaveGameWithParty = ( msgType == idLobby::OOB_GOODBYE_W_PARTY );
- if ( leaveGameWithParty && lobby.lobbyType == idLobby::TYPE_GAME && lobby.IsPeer() && GetState() == idSession::GAME_LOBBY && GetPartyLobby().host >= 0 &&
- lobby.peers[peerNum].address.Compare( GetPartyLobby().peers[GetPartyLobby().host].address, true ) ) {
- // If a host is telling us goodbye from a game lobby, and the game host is the same as our party host,
- // and we aren't in a game, and the host wants us to leave with him, then do so now
- GetGameLobby().Shutdown();
- GetGameStateLobby().Shutdown();
- SetState( STATE_PARTY_LOBBY_PEER );
- } else {
- // Host left, so pick a new host (possibly even us) for this lobby
- lobby.PickNewHost();
- }
- }
- }
- /*
- ========================
- idSessionLocal::WriteLeaderboardToMsg
- ========================
- */
- void idSessionLocal::WriteLeaderboardToMsg( idBitMsg & msg, const leaderboardDefinition_t * leaderboard, const column_t * stats ) {
- assert( Sys_FindLeaderboardDef( leaderboard->id ) == leaderboard );
-
- msg.WriteLong( leaderboard->id );
- for ( int i = 0; i < leaderboard->numColumns; ++i ) {
- uint64 value = stats[i].value;
- //idLib::Printf( "value = %i\n", (int32)value );
- for ( int j = 0; j < leaderboard->columnDefs[i].bits; j++ ) {
- msg.WriteBits( value & 1, 1 );
- value >>= 1;
- }
- //msg.WriteData( &stats[i].value, sizeof( stats[i].value ) );
- }
- }
- /*
- ========================
- idSessionLocal::ReadLeaderboardFromMsg
- ========================
- */
- const leaderboardDefinition_t * idSessionLocal::ReadLeaderboardFromMsg( idBitMsg & msg, column_t * stats ) {
- int id = msg.ReadLong();
-
- const leaderboardDefinition_t * leaderboard = Sys_FindLeaderboardDef( id );
-
- if ( leaderboard == NULL ) {
- idLib::Printf( "NET: Invalid leaderboard id: %i\n", id );
- return NULL;
- }
-
- for ( int i = 0; i < leaderboard->numColumns; ++i ) {
- uint64 value = 0;
- for ( int j = 0; j < leaderboard->columnDefs[i].bits; j++ ) {
- value |= (uint64)( msg.ReadBits( 1 ) & 1 ) << j;
- }
- stats[i].value = value;
- //idLib::Printf( "value = %i\n", (int32)value );
- //msg.ReadData( &stats[i].value, sizeof( stats[i].value ) );
- }
-
- return leaderboard;
- }
- /*
- ========================
- idSessionLocal::SendLeaderboardStatsToPlayer
- ========================
- */
- void idSessionLocal::SendLeaderboardStatsToPlayer( lobbyUserID_t lobbyUserID, const leaderboardDefinition_t * leaderboard, const column_t * stats ) {
- const int sessionUserIndex = GetActingGameStateLobby().GetLobbyUserIndexByID( lobbyUserID );
- if ( GetActingGameStateLobby().IsLobbyUserDisconnected( sessionUserIndex ) ) {
- idLib::Warning( "Tried to tell disconnected user to report stats" );
- return;
- }
-
- const int peerIndex = GetActingGameStateLobby().PeerIndexFromLobbyUser( lobbyUserID );
-
- if ( peerIndex == -1 ) {
- idLib::Warning( "Tried to tell invalid peer index to report stats" );
- return;
- }
- if ( !verify( GetActingGameStateLobby().IsHost() ) ||
- !verify( peerIndex < GetActingGameStateLobby().peers.Num() ) ||
- !verify( GetActingGameStateLobby().peers[ peerIndex ].IsConnected() ) ) {
- idLib::Warning( "Tried to tell invalid peer to report stats" );
- return;
- }
- NET_VERBOSE_PRINT( "Telling sessionUserIndex %i (peer %i) to report stats\n", sessionUserIndex, peerIndex );
- lobbyUser_t * gameUser = GetActingGameStateLobby().GetLobbyUser( sessionUserIndex );
- if ( !verify( gameUser != NULL ) ) {
- return;
- }
- byte buffer[ idPacketProcessor::MAX_PACKET_SIZE ];
- idBitMsg msg( buffer, sizeof( buffer ) );
- // Use the user ID
- gameUser->lobbyUserID.WriteToMsg( msg );
- WriteLeaderboardToMsg( msg, leaderboard, stats );
-
- GetActingGameStateLobby().QueueReliableMessage( peerIndex, idLobby::RELIABLE_POST_STATS, msg.GetReadData(), msg.GetSize() );
- }
- /*
- ========================
- idSessionLocal::RecvLeaderboardStatsForPlayer
- ========================
- */
- void idSessionLocal::RecvLeaderboardStatsForPlayer( idBitMsg & msg ) {
- column_t stats[ MAX_LEADERBOARD_COLUMNS ];
- lobbyUserID_t lobbyUserID;
- lobbyUserID.ReadFromMsg( msg );
- const leaderboardDefinition_t * leaderboard = ReadLeaderboardFromMsg( msg, stats );
-
- if ( leaderboard == NULL ) {
- idLib::Printf( "RecvLeaderboardStatsForPlayer: Invalid lb.\n" );
- return;
- }
- LeaderboardUpload( lobbyUserID, leaderboard, stats );
- }
- /*
- ========================
- idSessionLocal::RequirePersistentMaster
- ========================
- */
- bool idSessionLocal::RequirePersistentMaster() {
- return signInManager->RequirePersistentMaster();
- }
- /*
- ========================
- CheckAndUpdateValue
- ========================
- */
- template<typename T>
- bool CheckAndUpdateValue( T & value, const T & newValue ) {
- if ( value == newValue ) {
- return false;
- }
- value = newValue;
- return true;
- }
- /*
- ========================
- lobbyUser_t::UpdateClientMutableData
- ========================
- */
- bool lobbyUser_t::UpdateClientMutableData( const idLocalUser * localUser ) {
- bool updated = false;
- const idPlayerProfile * profile = localUser->GetProfile();
- if ( profile != NULL ) {
- updated |= CheckAndUpdateValue( level, profile->GetLevel() );
- }
- updated |= CheckAndUpdateValue( selectedSkin, ui_skinIndex.GetInteger() );
- updated |= CheckAndUpdateValue( weaponAutoSwitch, ui_autoSwitch.GetBool() );
- updated |= CheckAndUpdateValue( weaponAutoReload, ui_autoReload.GetBool() );
- return updated;
- }
- /*
- ========================
- idSessionLocal::ComputeNextGameCoalesceTime
- ========================
- */
- void idSessionLocal::ComputeNextGameCoalesceTime() {
- const int coalesceTimeInSeconds = session->GetTitleStorageInt( "net_LobbyCoalesceTimeInSeconds", net_LobbyCoalesceTimeInSeconds.GetInteger() );
- const int randomCoalesceTimeInSeconds = session->GetTitleStorageInt( "net_LobbyRandomCoalesceTimeInSeconds", net_LobbyRandomCoalesceTimeInSeconds.GetInteger() );
- if ( coalesceTimeInSeconds != 0 ) {
- static idRandom2 random( Sys_Milliseconds() );
- nextGameCoalesceTime = Sys_Milliseconds() + ( coalesceTimeInSeconds + random.RandomInt( randomCoalesceTimeInSeconds ) ) * 1000;
- } else {
- nextGameCoalesceTime = 0;
- }
- }
- /*
- ========================
- lobbyUser_t::Net_BandwidthChallenge
- ========================
- */
- CONSOLE_COMMAND( Net_BandwidthChallenge, "Test network bandwidth", 0 ) {
- session->StartOrContinueBandwidthChallenge( true );
- }
- /*
- ========================
- lobbyUser_t::Net_ThrottlePeer
- ========================
- */
- CONSOLE_COMMAND( Net_ThrottlePeer, "Test network bandwidth", 0 ) {
-
- int peerNum = -1;
- int snapRate = 0;
- if ( args.Argc() >= 3 ) {
- peerNum = atoi( args.Argv(1) );
- snapRate = atoi( args.Argv(2) );
- }
- // Note DebugSetPeerSnaprate will handle peerNum=-1 by printing out list of peers
- session->DebugSetPeerSnaprate( peerNum, snapRate );
- }
- // FIXME: Move to sys_stats.cpp
- idStaticList< leaderboardDefinition_t *, MAX_LEADERBOARDS > registeredLeaderboards;
- /*
- ========================
- Sys_FindLeaderboardDef
- ========================
- */
- const leaderboardDefinition_t * Sys_FindLeaderboardDef( int id ) {
- for ( int i = 0; i < registeredLeaderboards.Num() ; i++ ) {
- if ( registeredLeaderboards[i] && registeredLeaderboards[i]->id == id ) {
- return registeredLeaderboards[i];
- }
- }
-
- return NULL;
- }
- /*
- ========================
- Sys_CreateLeaderboardDef
- ========================
- */
- leaderboardDefinition_t * Sys_CreateLeaderboardDef( int id_, int numColumns_, const columnDef_t * columnDefs_,
- rankOrder_t rankOrder_, bool supportsAttachments_, bool checkAgainstCurrent_ ) {
-
- leaderboardDefinition_t * newDef = new (TAG_NETWORKING) leaderboardDefinition_t( id_, numColumns_, columnDefs_, rankOrder_, supportsAttachments_, checkAgainstCurrent_ );
- // try and reuse a free spot
- int leaderboardHandle = registeredLeaderboards.FindNull();
- if ( leaderboardHandle == -1 ) {
- leaderboardHandle = registeredLeaderboards.Append( NULL );
- }
- registeredLeaderboards[ leaderboardHandle ] = newDef;
- return newDef;
- }
- /*
- ========================
- Sys_CreateLeaderboardDef
- ========================
- */
- void Sys_DestroyLeaderboardDefs() {
- // delete and clear all the contents of the registeredLeaderboards static list.
- registeredLeaderboards.DeleteContents( true );
- }
- /*
- ========================
- idSessionLocal::StartOrContinueBandwidthChallenge
- This will start a bandwidth test if one is not active
- returns true if a test has completed
- ========================
- */
- bool idSessionLocal::StartOrContinueBandwidthChallenge( bool forceStart ) {
- idLobby * activeLobby = GetActivePlatformLobby();
- if ( activeLobby == NULL ) {
- idLib::Warning("No active session lobby when idSessionLocal::StartBandwidthChallenge called");
- return true;
- }
- if ( !forceStart && activeLobby->bandwidthChallengeFinished ) {
- activeLobby->bandwidthChallengeFinished = false;
- return true;
- }
- if ( !activeLobby->BandwidthTestStarted() ) {
- activeLobby->BeginBandwidthTest();
- }
- return false;
- }
- /*
- ========================
- idSessionLocal::DebugSetPeerSnaprate
- This is debug function for manually setting peer's snaprate in game
- ========================
- */
- void idSessionLocal::DebugSetPeerSnaprate( int peerIndex, int snapRateMS ) {
- idLobby * activeLobby = GetActivePlatformLobby();
- if ( activeLobby == NULL ) {
- idLib::Warning("No active session lobby when idSessionLocal::StartBandwidthChallenge called");
- return;
- }
- if ( peerIndex < 0 || peerIndex > activeLobby->peers.Num() ) {
- idLib::Printf("Invalid peer %d\n", peerIndex );
- for ( int i=0; i < activeLobby->peers.Num(); i++ ) {
- idLib::Printf( "Peer[%d] %s\n", i, activeLobby->GetPeerName(i) );
- }
- return;
- }
- activeLobby->peers[peerIndex].throttledSnapRate = snapRateMS * 1000;
- activeLobby->peers[peerIndex].receivedThrottle = 0;
- idLib::Printf( "Set peer %s new snapRate: %d\n", activeLobby->GetPeerName(peerIndex), activeLobby->peers[peerIndex].throttledSnapRate );
- }
- /*
- ========================
- idSessionLocal::DebugSetPeerSnaprate
- This is debug function for manually setting peer's snaprate in game
- ========================
- */
- float idSessionLocal::GetIncomingByteRate() {
- idLobby * activeLobby = GetActivePlatformLobby();
- if ( activeLobby == NULL ) {
- idLib::Warning("No active session lobby when idSessionLocal::GetIncomingByteRate called");
- return 0;
- }
- float total = 0;
- for ( int p=0; p < activeLobby->peers.Num(); p++ ) {
- if ( activeLobby->peers[p].IsConnected() ) {
- total += activeLobby->peers[p].packetProc->GetIncomingRateBytes();
- }
- }
- return total;
- }
- /*
- ========================
- idSessionLocal::OnLocalUserSignin
- ========================
- */
- void idSessionLocal::OnLocalUserSignin( idLocalUser * user ) {
- // Do stuff before calling OnMasterLocalUserSignin()
- session->GetAchievementSystem().RegisterLocalUser( user );
- // We may not have a profile yet, need to call user's version...
- user->LoadProfileSettings();
- // for all consoles except the PS3 we enumerate right away because they don't
- // take such a long time as the PS3. PS3 enumeration is done in the
- // background and kicked off when the profile callback is triggered
- if ( user == GetSignInManager().GetMasterLocalUser() ) {
- OnMasterLocalUserSignin();
- }
- }
- /*
- ========================
- idSessionLocal::OnLocalUserSignout
- ========================
- */
- void idSessionLocal::OnLocalUserSignout( idLocalUser * user ) {
- // Do stuff before calling OnMasterLocalUserSignout()
- session->GetAchievementSystem().RemoveLocalUser( user );
- if ( GetSignInManager().GetMasterLocalUser() == NULL ) {
- OnMasterLocalUserSignout();
- }
- }
- /*
- ========================
- idSessionLocal::OnMasterLocalUserSignout
- ========================
- */
- void idSessionLocal::OnMasterLocalUserSignout() {
- CancelSaveGameWithHandle( enumerationHandle );
- enumerationHandle = 0;
- GetSaveGameManager().GetEnumeratedSavegamesNonConst().Clear();
- }
- /*
- ========================
- idSessionLocal::OnMasterLocalUserSignin
- ========================
- */
- void idSessionLocal::OnMasterLocalUserSignin() {
- enumerationHandle = EnumerateSaveGamesAsync();
- }
- /*
- ========================
- idSessionLocal::OnLocalUserProfileLoaded
- ========================
- */
- void idSessionLocal::OnLocalUserProfileLoaded( idLocalUser * user ) {
- user->RequestSyncAchievements();
- }
- /*
- ========================
- idSessionLocal::SetVoiceGroupsToTeams
- ========================
- */
- void idSessionLocal::SetVoiceGroupsToTeams() {
- // move voice chat to team
- int myTeam = 0;
- for ( int i = 0; i < GetGameLobby().GetNumLobbyUsers(); ++i ) {
- const lobbyUser_t * gameUser = GetGameLobby().GetLobbyUser( i );
- if ( !verify( gameUser != NULL ) ) {
- continue;
- }
- if ( gameUser->IsDisconnected() ) {
- continue;
- }
- int userTeam = gameUser->teamNumber;
- voiceChat->SetTalkerGroup( gameUser, GetGameLobby().lobbyType, userTeam );
- if ( GetGameLobby().IsSessionUserIndexLocal( i ) ) {
- myTeam = userTeam;
- }
- }
- SetActiveChatGroup( myTeam );
- }
- /*
- ========================
- idSessionLocal::ClearVoiceGroups
- ========================
- */
- void idSessionLocal::ClearVoiceGroups() {
- for ( int i = 0; i < GetGameLobby().GetNumLobbyUsers(); ++i ) {
- const lobbyUser_t * gameUser = GetGameLobby().GetLobbyUser( i );
- if ( !verify( gameUser != NULL ) ) {
- continue;
- }
- if ( gameUser->IsDisconnected() ) {
- continue;
- }
- voiceChat->SetTalkerGroup( gameUser, GetGameLobby().lobbyType, 0 );
- }
- SetActiveChatGroup( 0 );
- }
- /*
- ========================
- idSessionLocal::SendVoiceAudio
- ========================
- */
- void idSessionLocal::SendVoiceAudio() {
- if ( voiceChat == NULL ) {
- return;
- }
- idLobby * activeLobby = GetActivePlatformLobby();
- int activeSessionIndex = ( activeLobby != NULL ) ? activeLobby->lobbyType : -1;
- voiceChat->SetActiveLobby( activeSessionIndex );
- voiceChat->Pump();
- if ( activeLobby == NULL ) {
- return;
- }
- int time = Sys_Milliseconds();
- const int VOICE_THROTTLE_TIME_IN_MS = session->GetTitleStorageInt( "VOICE_THROTTLE_TIME_IN_MS", 33) ; // Don't allow faster than 30hz send rate
- if ( time - lastVoiceSendtime < VOICE_THROTTLE_TIME_IN_MS ) {
- return;
- }
- lastVoiceSendtime = time;
- idStaticList< int, MAX_PLAYERS > localTalkers;
-
- voiceChat->GetActiveLocalTalkers( localTalkers );
-
- for ( int i = 0; i < localTalkers.Num(); i++ ) {
-
- // NOTE - For 360, we don't need more than XHV_MAX_VOICECHAT_PACKETS * XHV_VOICECHAT_MODE_PACKET_SIZE bytes
- const int MAX_VDP_DATA_SIZE = 1000;
- byte buffer[MAX_VDP_DATA_SIZE];
-
- const int titleStorageDataSize = session->GetTitleStorageInt( "MAX_VDP_DATA_SIZE", 1000 );
- const int dataSizeAvailable = Min< int >( titleStorageDataSize, sizeof( buffer ) );
- // in-out parameter
- int dataSize = dataSizeAvailable;
- if ( !voiceChat->GetLocalChatData( localTalkers[i], buffer, dataSize ) ) {
- continue;
- }
- assert( dataSize <= sizeof( buffer ) );
- idStaticList< const lobbyAddress_t *, MAX_PLAYERS > recipients;
-
- voiceChat->GetRecipientsForTalker( localTalkers[i], recipients );
- for ( int j = 0; j < recipients.Num(); j++ ) {
- activeLobby->SendConnectionLess( *recipients[j], idLobby::OOB_VOICE_AUDIO, buffer, dataSize );
- }
- }
- }
- /*
- ========================
- idSessionLocal::HandleOobVoiceAudio
- ========================
- */
- void idSessionLocal::HandleOobVoiceAudio( const lobbyAddress_t & from, const idBitMsg & msg ) {
- idLobby * activeLobby = GetActivePlatformLobby();
-
- if ( activeLobby == NULL ) {
- return;
- }
- voiceChat->SetActiveLobby( activeLobby->lobbyType );
- voiceChat->SubmitIncomingChatData( msg.GetReadData() + msg.GetReadCount(), msg.GetRemainingData() );
- }
- /*
- ========================
- idSessionLocal::SetActiveChatGroup
- ========================
- */
- void idSessionLocal::SetActiveChatGroup( int groupIndex ) {
- voiceChat->SetActiveChatGroup( groupIndex );
- }
- /*
- ========================
- idSessionLocal::GetLobbyUserVoiceState
- ========================
- */
- voiceState_t idSessionLocal::GetLobbyUserVoiceState( lobbyUserID_t lobbyUserID ) {
- idLobby * activeLobby = GetActivePlatformLobby();
- if ( activeLobby == NULL ) {
- return VOICECHAT_STATE_NOT_TALKING;
- }
- const lobbyUser_t * user = activeLobby->GetLobbyUserByID( lobbyUserID );
- if ( !verify( user != NULL ) ) {
- return VOICECHAT_STATE_NOT_TALKING;
- }
- return voiceChat->GetVoiceState( user );
- }
- /*
- ========================
- idSessionLocal::GetDisplayStateFromVoiceState
- ========================
- */
- voiceStateDisplay_t idSessionLocal::GetDisplayStateFromVoiceState( voiceState_t voiceState ) const {
- if ( ( GetState() == GAME_LOBBY && MatchTypeIsLocal( GetGameLobby().GetMatchParms().matchFlags ) )
- || ( GetState() == PARTY_LOBBY && MatchTypeIsLocal( GetPartyLobby().GetMatchParms().matchFlags ) ) ) {
- return VOICECHAT_DISPLAY_NONE; // never show voice stuff in splitscreen
- }
- switch ( voiceState ) {
- case VOICECHAT_STATE_MUTED_REMOTE:
- case VOICECHAT_STATE_MUTED_LOCAL:
- case VOICECHAT_STATE_MUTED_ALL:
- return VOICECHAT_DISPLAY_MUTED;
- case VOICECHAT_STATE_NOT_TALKING:
- return VOICECHAT_DISPLAY_NOTTALKING;
- case VOICECHAT_STATE_TALKING:
- return VOICECHAT_DISPLAY_TALKING;
- case VOICECHAT_STATE_TALKING_GLOBAL:
- return VOICECHAT_DISPLAY_TALKING_GLOBAL;
- case VOICECHAT_STATE_NO_MIC:
- default:
- return VOICECHAT_DISPLAY_NOTTALKING;
- }
- }
- /*
- ========================
- idSessionLocal::ToggleLobbyUserVoiceMute
- ========================
- */
- void idSessionLocal::ToggleLobbyUserVoiceMute( lobbyUserID_t lobbyUserID ) {
- idLobby * activeLobby = GetActivePlatformLobby();
- if ( activeLobby == NULL ) {
- return;
- }
- // Get the master local user
- idLocalUser * masterUser = signInManager->GetMasterLocalUser();
- if ( masterUser == NULL ) {
- return;
- }
- const lobbyUser_t * srcUser = activeLobby->GetLobbyUser( activeLobby->GetLobbyUserIndexByLocalUserHandle( masterUser->GetLocalUserHandle() ) );
- if ( srcUser == NULL ) {
- return;
- }
- const lobbyUser_t * targetUser = activeLobby->GetLobbyUserByID( lobbyUserID );
- if ( !verify( targetUser != NULL ) ) {
- return;
- }
- if ( srcUser == targetUser ) {
- return; // Can't toggle yourself
- }
- voiceChat->ToggleMuteLocal( srcUser, targetUser );
- }
- /*
- ========================
- idSessionLocal::UpdateMasterUserHeadsetState
- ========================
- */
- void idSessionLocal::UpdateMasterUserHeadsetState()
- {
- if ( GetState() != PARTY_LOBBY && GetState() != GAME_LOBBY && GetState() != INGAME ) {
- return;
- }
- lobbyUser_t * user = GetActivePlatformLobby()->GetSessionUserFromLocalUser( signInManager->GetMasterLocalUser() );
- // TODO: Is this possible?
- if ( user == NULL ) {
- return;
- }
- int talkerIndex = voiceChat->FindTalkerByUserId( user->lobbyUserID, GetActivePlatformLobby()->lobbyType );
- bool voiceChanged = voiceChat->HasHeadsetStateChanged( talkerIndex );
- if ( voiceChanged ) {
- byte buffer[ idPacketProcessor::MAX_MSG_SIZE ];
- idBitMsg msg( buffer, sizeof( buffer ) );
- msg.WriteLong( 1 );
- user->lobbyUserID.WriteToMsg( msg );
- msg.WriteBool( voiceChat->GetHeadsetState( talkerIndex ) );
- idLib::Printf( "Sending voicestate %d for user %d %s\n", voiceChat->GetHeadsetState( talkerIndex ), talkerIndex, user->gamertag );
- if ( GetActivePlatformLobby()->IsHost() ) {
- for ( int p = 0; p < GetActivePlatformLobby()->peers.Num(); p++ ) {
- if ( GetActivePlatformLobby()->peers[p].IsConnected() ) {
- GetActivePlatformLobby()->QueueReliableMessage( p, idLobby::RELIABLE_HEADSET_STATE, msg.GetReadData(), msg.GetSize() );
- }
- }
- } else {
- GetActivePlatformLobby()->QueueReliableMessage( GetActivePlatformLobby()->host, idLobby::RELIABLE_HEADSET_STATE, msg.GetReadData(), msg.GetSize() );
- }
- }
-
- }
- /*
- ========================
- idSessionLocal::GetNumContentPackages
- ========================
- */
- int idSessionLocal::GetNumContentPackages() const {
- return downloadedContent.Num();
- }
- /*
- ========================
- idSessionLocal::GetContentPackageID
- ========================
- */
- int idSessionLocal::GetContentPackageID( int contentIndex ) const {
- assert( contentIndex < MAX_CONTENT_PACKAGES );
- if ( downloadedContent[ contentIndex ].isMounted ) {
- return downloadedContent[ contentIndex ].dlcID;
- }
- return 0;
- }
- /*
- ========================
- idSessionLocal::GetContentPackagePath
- ========================
- */
- const char * idSessionLocal::GetContentPackagePath( int contentIndex ) const {
- assert( contentIndex < MAX_CONTENT_PACKAGES );
- if ( downloadedContent[ contentIndex ].isMounted ) {
- return downloadedContent[ contentIndex ].rootPath.c_str();
- }
- return NULL;
- }
- /*
- ========================
- idSessionLocal::GetContentPackageIndexForID
- ========================
- */
- int idSessionLocal::GetContentPackageIndexForID( int contentID ) const {
- int contentIndex = -1;
- for ( int i = 0; i < downloadedContent.Num(); i++ ) {
- if ( downloadedContent[i].dlcID == contentID ) {
- contentIndex = i;
- break;
- }
- }
- return contentIndex;
- }
- /*
- ========================
- idSessionLocal::SetLobbyUserRelativeScore
- ========================
- */
- void idSessionLocal::SetLobbyUserRelativeScore( lobbyUserID_t lobbyUserID, int relativeScore, int team ) {
- // All platforms but 360 stub this out
- }
- /*
- ========================
- idSessionLocal::ReadTitleStorage
- ========================
- */
- void idSessionLocal::ReadTitleStorage( void * buffer, int bufferLen ) {
- // https://ps3.scedev.net/projects/ps3_sdk_docs/docs/ps3-en,NP_Lookup-Reference,sceNpLookupTitleSmallStorageAsync/1
- // If the file is not on the server, this will be handled as though a file of 0 bytes were on the server.
- // This means that 0 will be set to contentLength and 0 (for normal termination) will return for the return value.
- // This situation can occur with problems in actual operation, so the application must be designed not to hang up even in such situations
- //bufferLen = 0;
- idLib::Printf( "ReadTitleStorage: %i bytes\n", bufferLen );
- #if !defined( ID_RETAIL ) || defined( ID_RETAIL_INTERNAL )
- if ( net_ignoreTitleStorage.GetBool() ) {//&& idLib::GetProduction() < PROD_PRODUCTION ) {
- idLib::Printf( "ReadTitleStorage: *********************** IGNORING ********************\n" );
- return;
- }
- #endif
- //idScopedGlobalHeap everythingHereGoesInTheGlobalHeap;
- idParser parser( LEXFL_NOERRORS | LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT );
- parser.LoadMemory( ( const char* )buffer, bufferLen, "default.tss" );
- bool valid = true;
- while ( true ) {
- idToken token;
- if ( !parser.ReadToken( &token ) ) {
- break;
- }
- if ( token.Icmp( "netvars" ) == 0 ) {
- if ( !titleStorageVars.Parse( parser ) ) {
- valid = false;
- break;
- }
- } else {
- valid = false;
- break;
- }
- }
- if ( valid ) {
- titleStorageLoaded = true;
- idLib::Printf( "ReadTitleStorage: SUCCESS\n" );
- titleStorageVars.Print();
- } else {
- titleStorageLoaded = false;
- idLib::Printf( "ReadTitleStorage: FAILED\n" );
- titleStorageVars.Clear();
- }
- }
- /*
- ========================
- idSessionLocal::ReadDLCInfo
- ========================
- */
- bool idSessionLocal::ReadDLCInfo( idDict & dlcInfo, void * buffer, int bufferLen ) {
- idParser parser( LEXFL_NOERRORS | LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT );
- parser.LoadMemory( ( const char* )buffer, bufferLen, "info.txt" );
- bool valid = true;
- while ( true ) {
- idToken token;
- if ( !parser.ReadToken( &token ) ) {
- break;
- }
- if ( token.Icmp( "dlcInfo" ) == 0 ) {
- if ( !dlcInfo.Parse( parser ) ) {
- valid = false;
- break;
- }
- } else {
- valid = false;
- break;
- }
- }
- return valid;
- }
- /*
- ========================
- idSessionLocal::IsPlatformPartyInLobby
- ========================
- */
- bool idSessionLocal::IsPlatformPartyInLobby() {
- idLocalUser * user = session->GetSignInManager().GetMasterLocalUser();
- idLobby * lobby = GetActivePlatformLobby();
- if ( user == NULL || lobby == NULL ) {
- return false;
- }
- if ( user->GetPartyCount() > MAX_PLAYERS || user->GetPartyCount() < 2 ) {
- return false;
- }
- // TODO: Implement PC
- return false;
- }
- /*
- ========================
- idSessionLocal::PrePickNewHost
- This is called when we have determined that we need to pick a new host.
- Call PickNewHostInternal to continue on with the host picking process.
- ========================
- */
- void idSessionLocal::PrePickNewHost( idLobby & lobby, bool forceMe, bool inviteOldHost ) {
- NET_VERBOSE_PRINT("idSessionLocal::PrePickNewHost: (%s)\n", lobby.GetLobbyName() );
- if ( GetActivePlatformLobby() == NULL ) {
- NET_VERBOSE_PRINT("idSessionLocal::PrePickNewHost: GetActivePlatformLobby() == NULL (%s)\n", lobby.GetLobbyName() );
- return;
- }
- // Check to see if we can migrate AT ALL
- // This is checking for coop, we should make this a specific option (MATCH_ALLOW_MIGRATION)
- if ( GetPartyLobby().parms.matchFlags & MATCH_PARTY_INVITE_PLACEHOLDER ) {
- NET_VERBOSE_PRINT("idSessionLocal::PrePickNewHost: MATCH_PARTY_INVITE_PLACEHOLDER (%s)\n", lobby.GetLobbyName() );
- // Can't migrate, shut both lobbies down, and create a new match using the original parms
- GetGameStateLobby().Shutdown();
- GetGameLobby().Shutdown();
- GetPartyLobby().Shutdown();
-
- // Throw up the appropriate dialog message so the player knows what happeend
- if ( localState >= idSessionLocal::STATE_LOADING ) {
- NET_VERBOSE_PRINT("idSessionLocal::PrePickNewHost: localState >= idSessionLocal::STATE_LOADING (%s)\n", lobby.GetLobbyName() );
- common->Dialog().AddDialog( GDM_BECAME_HOST_GAME_STATS_DROPPED, DIALOG_ACCEPT, NULL, NULL, false, __FUNCTION__, __LINE__, true );
- } else {
- NET_VERBOSE_PRINT("idSessionLocal::PrePickNewHost: localState < idSessionLocal::STATE_LOADING (%s)\n", lobby.GetLobbyName() );
- common->Dialog().AddDialog( GDM_LOBBY_BECAME_HOST_GAME, DIALOG_ACCEPT, NULL, NULL, false, __FUNCTION__, __LINE__, true );
- }
- CreateMatch( GetActivePlatformLobby()->parms );
- return;
- }
- // Check to see if the match is searchable
- if ( GetState() >= idSession::GAME_LOBBY && MatchTypeIsSearchable( GetGameLobby().parms.matchFlags ) ) {
- NET_VERBOSE_PRINT("idSessionLocal::PrePickNewHost: MatchTypeIsSearchable (%s)\n", lobby.GetLobbyName() );
- // Searchable games migrate lobbies independently, and don't need to stay in sync
- lobby.PickNewHostInternal( forceMe, inviteOldHost );
- return;
- }
- //
- // Beyond this point, game lobbies must be sync'd with party lobbies as far as host status
- // So to enforce that, we pull you out of the game lobby if you are in one when migration occurs
- //
- // Check to see if we should go back to a party lobby
- if ( GetBackState() >= idSessionLocal::PARTY_LOBBY || GetState() == idSession::PARTY_LOBBY ) {
- NET_VERBOSE_PRINT("idSessionLocal::PrePickNewHost: GetBackState() >= idSessionLocal::PARTY_LOBBY || GetState() == idSession::PARTY_LOBBY (%s)\n", lobby.GetLobbyName() );
- // Force the party lobby to start picking a new host if we lost the game lobby host
- GetPartyLobby().PickNewHostInternal( forceMe, inviteOldHost );
- // End the game lobby, and go back to party lobby
- GetGameStateLobby().Shutdown();
- GetGameLobby().Shutdown();
- SetState( GetPartyLobby().IsHost() ? idSessionLocal::STATE_PARTY_LOBBY_HOST : idSessionLocal::STATE_PARTY_LOBBY_PEER );
- } else {
- NET_VERBOSE_PRINT("idSessionLocal::PrePickNewHost: GetBackState() < idSessionLocal::PARTY_LOBBY && GetState() != idSession::PARTY_LOBBY (%s)\n", lobby.GetLobbyName() );
- if ( localState >= idSessionLocal::STATE_LOADING ) {
- common->Dialog().AddDialog( GDM_HOST_QUIT, DIALOG_ACCEPT, NULL, NULL, false, __FUNCTION__, __LINE__, true ); // The host has quit the session. Returning to the main menu.
- }
- // Go back to main menu
- GetGameLobby().Shutdown();
- GetGameStateLobby().Shutdown();
- GetPartyLobby().Shutdown();
- SetState( idSessionLocal::STATE_IDLE );
- }
- }
- /*
- ========================
- idSessionLocal::PreMigrateInvite
- This is called just before we get invited to a migrated session
- If we return false, the invite will be ignored
- ========================
- */
- bool idSessionLocal::PreMigrateInvite( idLobby & lobby )
- {
- if ( GetActivePlatformLobby() == NULL ) {
- return false;
- }
- // Check to see if we can migrate AT ALL
- // This is checking for coop, we should make this a specific option (MATCH_ALLOW_MIGRATION)
- if ( !verify( ( GetPartyLobby().parms.matchFlags & MATCH_PARTY_INVITE_PLACEHOLDER ) == 0 ) ) {
- return false; // Shouldn't get invites for coop (we should make this a specific option (MATCH_ALLOW_MIGRATION))
- }
- // Check to see if the match is searchable
- if ( MatchTypeIsSearchable( GetGameLobby().parms.matchFlags ) ) {
- // Searchable games migrate lobbies independently, and don't need to stay in sync
- return true;
- }
- //
- // Beyond this point, game lobbies must be sync'd with party lobbies as far as host status
- // So to enforce that, we pull you out of the game lobby if you are in one when migration occurs
- //
- if ( lobby.lobbyType != idLobby::TYPE_PARTY ) {
- return false; // We shouldn't be getting invites from non party lobbies when in a non searchable game
- }
- // Non placeholder Party lobbies can always migrate
- if ( GetBackState() >= idSessionLocal::PARTY_LOBBY ) {
- // Non searchable games go back to the party lobby
- GetGameLobby().Shutdown();
- SetState( GetPartyLobby().IsHost() ? idSessionLocal::STATE_PARTY_LOBBY_HOST : idSessionLocal::STATE_PARTY_LOBBY_PEER );
- }
- return true; // Non placeholder Party lobby invites joinable
- }
- /*
- ================================================================================================
- lobbyAddress_t
- ================================================================================================
- */
- /*
- ========================
- lobbyAddress_t::lobbyAddress_t
- ========================
- */
- lobbyAddress_t::lobbyAddress_t() {
- memset( &netAddr, 0, sizeof( netAddr ) );
- netAddr.type = NA_BAD;
- }
- /*
- ========================
- lobbyAddress_t::InitFromIPandPort
- ========================
- */
- void lobbyAddress_t::InitFromIPandPort( const char * ip, int port ) {
- Sys_StringToNetAdr( ip, &netAddr, true );
- if ( !netAddr.port ) {
- netAddr.port = port;
- }
- }
- /*
- ========================
- lobbyAddress_t::InitFromNetadr
- ========================
- */
- void lobbyAddress_t::InitFromNetadr( const netadr_t & netadr ) {
- assert( netadr.type != NA_BAD );
- netAddr = netadr;
- }
- /*
- ========================
- lobbyAddress_t::ToString
- ========================
- */
- const char * lobbyAddress_t::ToString() const {
- return Sys_NetAdrToString( netAddr );
- }
- /*
- ========================
- lobbyAddress_t::UsingRelay
- ========================
- */
- bool lobbyAddress_t::UsingRelay() const {
- return false;
- }
- /*
- ========================
- lobbyAddress_t::Compare
- ========================
- */
- bool lobbyAddress_t::Compare( const lobbyAddress_t & addr, bool ignoreSessionCheck ) const {
- return Sys_CompareNetAdrBase( netAddr, addr.netAddr );
- }
- /*
- ========================
- lobbyAddress_t::WriteToMsg
- ========================
- */
- void lobbyAddress_t::WriteToMsg( idBitMsg & msg ) const {
- msg.WriteData( &netAddr, sizeof( netAddr ) );
- }
- /*
- ========================
- lobbyAddress_t::ReadFromMsg
- ========================
- */
- void lobbyAddress_t::ReadFromMsg( idBitMsg & msg ) {
- msg.ReadData( &netAddr, sizeof( netAddr ) );
- }
- /*
- ================================================================================================
- idNetSessionPort
- ================================================================================================
- */
- /*
- ========================
- idNetSessionPort::idNetSessionPort
- ========================
- */
- idNetSessionPort::idNetSessionPort() :
- forcePacketDropPrev( 0.0f ),
- forcePacketDropCurr( 0.0f )
- {
- }
- /*
- ========================
- idNetSessionPort::InitPort
- ========================
- */
- bool idNetSessionPort::InitPort( int portNumber, bool useBackend ) {
- return UDP.InitForPort( portNumber );
- }
- /*
- ========================
- idNetSessionPort::ReadRawPacket
- ========================
- */
- bool idNetSessionPort::ReadRawPacket( lobbyAddress_t & from, void * data, int & size, int maxSize ) {
- bool result = UDP.GetPacket( from.netAddr, data, size, maxSize );
-
- static idRandom2 random( Sys_Milliseconds() );
- if ( net_forceDrop.GetInteger() != 0 ) {
- forcePacketDropCurr = random.RandomInt( 100 );
- if ( net_forceDrop.GetInteger() >= forcePacketDropCurr ) {
- return false;
- }
- }
- return result;
- }
- /*
- ========================
- idNetSessionPort::SendRawPacket
- ========================
- */
- void idNetSessionPort::SendRawPacket( const lobbyAddress_t & to, const void * data, int size ) {
- static idRandom2 random( Sys_Milliseconds() );
- if ( net_forceDrop.GetInteger() != 0 && net_forceDrop.GetInteger() >= random.RandomInt( 100 ) ) {
- return;
- }
- assert( size <= idPacketProcessor::MAX_FINAL_PACKET_SIZE );
-
- UDP.SendPacket( to.netAddr, data, size );
- }
- /*
- ========================
- idNetSessionPort::IsOpen
- ========================
- */
- bool idNetSessionPort::IsOpen() {
- return UDP.IsOpen();
- }
- /*
- ========================
- idNetSessionPort::Close
- ========================
- */
- void idNetSessionPort::Close() {
- UDP.Close();
- }
- /*
- ================================================================================================
- Commands
- ================================================================================================
- */
- //====================================================================================
- CONSOLE_COMMAND( voicechat_mute, "TEMP", 0 ) {
- if ( args.Argc() != 2 ) {
- idLib::Printf( "Usage: voicechat_mute <user index>\n" );
- return;
- }
- int i = atoi( args.Argv( 1 ) );
- session->ToggleLobbyUserVoiceMute( session->GetActivePlatformLobbyBase().GetLobbyUserIdByOrdinal( i ) );
- }
- /*
- ========================
- force_disconnect_all
- ========================
- */
- CONSOLE_COMMAND( force_disconnect_all, "force disconnect on all users", 0 ) {
- session->GetSignInManager().RemoveAllLocalUsers();
- }
- /*
- ========================
- void Net_DebugOutputSignedInUsers_f
- ========================
- */
- void Net_DebugOutputSignedInUsers_f( const idCmdArgs &args ) {
- session->GetSignInManager().DebugOutputLocalUserInfo();
- }
- idCommandLink Net_DebugOutputSignedInUsers( "net_debugOutputSignedInUsers", Net_DebugOutputSignedInUsers_f, "Outputs all the local users and other debugging information from the sign in manager" );
- /*
- ========================
- void Net_RemoveUserFromLobby_f
- ========================
- */
- void Net_RemoveUserFromLobby_f( const idCmdArgs &args ) {
- if ( args.Argc() > 1 ) {
- int localUserNum = atoi( args.Argv( 1 ) );
- if ( localUserNum < session->GetSignInManager().GetNumLocalUsers() ) {
- session->GetSignInManager().RemoveLocalUserByIndex( localUserNum );
- } else {
- idLib::Printf( "This user is not in the lobby\n" );
- }
- } else {
- idLib::Printf( "Usage: net_RemoveUserFromLobby <localUserNum>\n" );
- }
- }
- idCommandLink Net_RemoveUserFromLobby( "net_removeUserFromLobby", Net_RemoveUserFromLobby_f, "Removes the given user from the lobby" );
- /*
- ========================
- Net_dropClient
- ========================
- */
- CONSOLE_COMMAND( Net_DropClient, "Drop a client", 0 ) {
- if ( args.Argc() < 3 ) {
- idLib::Printf( "usage: Net_DropClient <clientnum> [<session>] 0/default: drop from game, 1: drop from party, otherwise drop from both\n" );
- return;
- }
- int lobbyType = 0;
- if ( args.Argc() > 2 ) {
- lobbyType = atoi( args.Argv( 2 ) );
- }
- session->DropClient( atoi( args.Argv(1) ), lobbyType );
- }
- /*
- ========================
- idSessionLocal::DropClient
- ========================
- */
- void idSessionLocal::DropClient( int peerNum, int session ) {
- if ( session == 1 || session >= 2 ) {
- GetPartyLobby().DisconnectPeerFromSession( peerNum );
- }
- if ( session == 0 || session >= 2 ) {
- GetGameLobby().DisconnectPeerFromSession( peerNum );
- }
- }
- /*
- ========================
- idSessionLocal::ListServersCommon
- ========================
- */
- void idSessionLocal::ListServersCommon() {
- netadr_t broadcast;
- memset( &broadcast, 0, sizeof( broadcast ) );
- broadcast.type = NA_BROADCAST;
- broadcast.port = net_port.GetInteger();
-
- lobbyAddress_t address;
- address.InitFromNetadr( broadcast );
- byte buffer[ idPacketProcessor::MAX_PACKET_SIZE - 2 ];
- idBitMsg msg( buffer, sizeof( buffer ) );
-
- // Add the current version info to the query
- const unsigned long localChecksum = NetGetVersionChecksum();
- NET_VERBOSE_PRINT( "ListServers: Hash checksum: %i, broadcasting to: %s\n", localChecksum, address.ToString() );
- msg.WriteLong( localChecksum );
- GetPort();
- // Send the query as a broadcast
- GetPartyLobby().SendConnectionLess( address, idLobby::OOB_MATCH_QUERY, msg.GetReadData(), msg.GetSize() );
- }
- /*
- ========================
- idSessionLocal::HandleDedicatedServerQueryRequest
- ========================
- */
- void idSessionLocal::HandleDedicatedServerQueryRequest( lobbyAddress_t & remoteAddr, idBitMsg & msg, int msgType ) {
- NET_VERBOSE_PRINT( "HandleDedicatedServerQueryRequest from %s\n", remoteAddr.ToString() );
-
- bool canJoin = true;
-
- const unsigned long localChecksum = NetGetVersionChecksum();
- const unsigned long remoteChecksum = msg.ReadLong();
- if ( remoteChecksum != localChecksum ) {
- NET_VERBOSE_PRINT( "HandleServerQueryRequest: Invalid version from %s\n", remoteAddr.ToString() );
- canJoin = false;
- }
- // Make sure we are the host of this party session
- if ( !GetPartyLobby().IsHost() ) {
- NET_VERBOSE_PRINT( "HandleServerQueryRequest: Not host of party\n" );
- canJoin = false;
- }
- // Make sure there is a session active
- if ( GetActivePlatformLobby() == NULL ) {
- canJoin = false;
- }
- // Make sure we have enough free slots
- if ( GetPartyLobby().NumFreeSlots() == 0 || GetGameLobby().NumFreeSlots() == 0 ) {
- NET_VERBOSE_PRINT( "No free slots\n" );
- canJoin = false;
- }
-
- if ( MatchTypeInviteOnly( GetPartyLobby().parms.matchFlags ) ) {
- canJoin = false;
- }
- // Buffer to hold reply msg
- byte buffer[ idPacketProcessor::MAX_PACKET_SIZE - 2 ];
- idBitMsg retmsg( buffer, sizeof( buffer ) );
-
- idLocalUser * masterUser = GetSignInManager().GetMasterLocalUser();
- if ( masterUser == NULL && !net_headlessServer.GetBool() ) {
- canJoin = false;
- }
-
- // Send the info about this game session to the caller
- retmsg.WriteBool( canJoin );
-
- if ( canJoin ) {
- serverInfo_t serverInfo;
- serverInfo.joinable = ( session->GetState() >= idSession::LOADING );
- if ( !net_headlessServer.GetBool() ) {
- serverInfo.serverName = masterUser->GetGamerTag();
- }
-
- if ( GetGameLobby().IsLobbyActive() ) {
- serverInfo.gameMap = GetGameLobby().parms.gameMap;
- serverInfo.gameMode = GetGameLobby().parms.gameMode;
- } else {
- serverInfo.gameMode = -1;
- }
- serverInfo.numPlayers = GetActivePlatformLobby()->GetNumLobbyUsers();
- serverInfo.maxPlayers = GetActivePlatformLobby()->parms.numSlots;
- serverInfo.Write( retmsg );
- for ( int i = 0; i < GetActivePlatformLobby()->GetNumLobbyUsers(); i++ ) {
- retmsg.WriteString( GetActivePlatformLobby()->GetLobbyUserName( GetActivePlatformLobby()->GetLobbyUserIdByOrdinal( i ) ) );
- }
- }
- // Send it
- GetPartyLobby().SendConnectionLess( remoteAddr, idLobby::OOB_MATCH_QUERY_ACK, retmsg.GetReadData(), retmsg.GetSize() );
- }
- /*
- ========================
- idSessionLocal::HandleDedicatedServerQueryAck
- ========================
- */
- void idSessionLocal::HandleDedicatedServerQueryAck( lobbyAddress_t & remoteAddr, idBitMsg & msg ) {
- NET_VERBOSE_PRINT( "HandleDedicatedServerQueryAck from %s\n", remoteAddr.ToString() );
- dedicatedServerSearch->HandleQueryAck( remoteAddr, msg );
- }
- /*
- ========================
- idSessionLocal::ServerPlayerList
- ========================
- */
- const idList< idStr > * idSessionLocal::ServerPlayerList( int i ) {
- return NULL;
- }
- /*
- ========================
- lobbyUserID_t::Serialize
- ========================
- */
- void lobbyUserID_t::Serialize( idSerializer & ser ) {
- localUserHandle.Serialize( ser );
- ser.Serialize( lobbyType );
- }
|