void plNetClientMgr::IDisableNet () { ASSERT(fDisableMsg); if (!GetFlagsBit(kDisabled)) { SetFlagsBit(kDisabled); // cause subsequent net operations to fail immediately, but don't block // waiting for net subsystem to shutdown (we'll do that later) NetCommEnableNet(false, false); // display a msg to the player if ( fDisableMsg->yes ) { if (!GetFlagsBit(plNetClientApp::kPlayingGame)) { // KI may not be loaded plString title = plFormat("{} Error", plProduct::CoreName()); hsMessageBox(fDisableMsg->str, title.c_str(), hsMessageBoxNormal, hsMessageBoxIconError ); plClientMsg *quitMsg = new plClientMsg(plClientMsg::kQuit); quitMsg->Send(hsgResMgr::ResMgr()->FindKey(kClient_KEY)); } else { pfKIMsg *msg = new pfKIMsg(pfKIMsg::kKIOKDialog); msg->SetString(fDisableMsg->str); msg->Send(); } } } hsRefCnt_SafeUnRef(fDisableMsg); fDisableMsg = nil; }
// // returns yes/no // for special cases, like sceneNodes. // int plNetClientMgr::IsLocallyOwned(const plUoid& uoid) const { // we're non-networked if ( GetFlagsBit(kDisabled)) return plSynchedObject::kYes; plNetGroupId netGroup = uoid.GetLocation(); int answer=GetNetGroups()->IsGroupLocal(netGroup); if (answer==-1) answer = IDeduceLocallyOwned(uoid); hsAssert(answer==plSynchedObject::kYes || answer==plSynchedObject::kNo, "invalid answer to IsLocallyOwned()"); return answer; }
void plNetClientMgr::IncNumInitialSDLStates() { fNumInitialSDLStates++; DebugMsg( "Received %d initial SDL states", fNumInitialSDLStates ); if ( GetFlagsBit( plNetClientApp::kNeedInitialAgeStateCount ) ) { DebugMsg( "Need initial SDL state count" ); return; } if ( GetNumInitialSDLStates()>=GetRequiredNumInitialSDLStates() ) { ICheckPendingStateLoad(hsTimer::GetSysSeconds()); NotifyRcvdAllSDLStates(); } }
// // check if this object is in a group which is owned (mastered) by this client. // returns yes/no // int plNetClientMgr::IsLocallyOwned(const plSynchedObject* obj) const { // we're non-networked if ( GetFlagsBit(kDisabled) ) return plSynchedObject::kYes; if( !obj ) return plSynchedObject::kNo; // object is flagged as local only if (!obj->IsNetSynched()) return plSynchedObject::kYes; plNetGroupId netGroup = GetEffectiveNetGroup(obj); int answer=GetNetGroups()->IsGroupLocal(netGroup); if (answer==-1) // not sure answer = IDeduceLocallyOwned(obj->GetKey()->GetUoid()); hsAssert(answer==plSynchedObject::kYes || answer==plSynchedObject::kNo, "invalid answer to IsLocallyOwned()"); return answer; }
// // initialize net client. returns hsFail on err. // int plNetClientMgr::Init() { int ret=hsOK; hsLogEntry( DebugMsg("*** plNetClientMgr::Init GMT:%s", plUnifiedTime::GetCurrent().Print()) ); IDumpOSVersionInfo(); if (GetFlagsBit(kNullSend)) SetNullSend(true); VaultInitialize(); IAddCloneRoom(); fNetGroups.Reset(); plgDispatch::Dispatch()->RegisterForExactType(plNetClientMgrMsg::Index(), GetKey()); plgDispatch::Dispatch()->RegisterForExactType(plAgeLoadedMsg::Index(), GetKey()); plgDispatch::Dispatch()->RegisterForExactType(plAgeLoaded2Msg::Index(), GetKey()); plgDispatch::Dispatch()->RegisterForExactType(plCCRPetitionMsg::Index(), GetKey()); plgDispatch::Dispatch()->RegisterForExactType(plPlayerPageMsg::Index(), GetKey()); plgDispatch::Dispatch()->RegisterForExactType(plInitialAgeStateLoadedMsg::Index(), GetKey()); plgDispatch::Dispatch()->RegisterForExactType(plNetVoiceListMsg::Index(), GetKey()); plgDispatch::Dispatch()->RegisterForExactType(plClientMsg::Index(), GetKey()); plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), GetKey()); plgDispatch::Dispatch()->RegisterForExactType(plNetCommAuthMsg::Index(), GetKey()); plgDispatch::Dispatch()->RegisterForExactType(plNetCommActivePlayerMsg::Index(), GetKey()); plgDispatch::Dispatch()->RegisterForExactType(plNetCommLinkToAgeMsg::Index(), GetKey()); // We need plVaultNotifyMsgs for the NetLinkingMgr plgDispatch::Dispatch()->RegisterForType(plVaultNotifyMsg::Index(), GetKey()); plgDispatch::Dispatch()->RegisterForExactType(plResPatcherMsg::Index(), GetKey()); IInitNetClientComm(); return ret; }
// // return true if we should send this msg // bool plNetClientMgr::CanSendMsg(plNetMessage * msg) { // TEMP if (GetFlagsBit(kSilencePlayer)) { if (plNetMsgVoice::ConvertNoRef(msg)) return false; plNetMsgGameMessage* gm=plNetMsgGameMessage::ConvertNoRef(msg); if (gm && gm->StreamInfo()->GetStreamType()==pfKIMsg::Index()) { hsReadOnlyStream stream(gm->StreamInfo()->GetStreamLen(), gm->StreamInfo()->GetStreamBuf()); pfKIMsg* kiMsg = pfKIMsg::ConvertNoRef(hsgResMgr::ResMgr()->ReadCreatable(&stream)); if (kiMsg && kiMsg->GetCommand()==pfKIMsg::kHACKChatMsg) { delete kiMsg; return false; } delete kiMsg; } } return true; }
// // main update fxn for net client code, return hsFail on err // int plNetClientMgr::Update(double secs) { int ret=hsOK; // ret code is unchecked, but what the hay if (GetFlagsBit(kDisableOnNextUpdate)) { SetFlagsBit(kDisableOnNextUpdate, false); IDisableNet(); } // Pump net messages NetCommUpdate(); static double lastUpdateTime=0; double curTime=hsTimer::GetSeconds(); if (curTime-lastUpdateTime > 1.f) { DebugMsg("NetClient hasn't updated for %f secs", curTime-lastUpdateTime); } lastUpdateTime=curTime; if (GetFlagsBit(kPlayingGame) ) { MaybeSendPendingPagingRoomMsgs(); ICheckPendingStateLoad(secs); ISendDirtyState(secs); IUpdateListenList(secs); if (GetFlagsBit(plNetClientApp::kShowLists)) IShowLists(); if (GetFlagsBit(plNetClientApp::kShowRooms)) IShowRooms(); if (GetFlagsBit(plNetClientApp::kShowAvatars)) IShowAvatars(); if (GetFlagsBit(plNetClientApp::kShowRelevanceRegions)) IShowRelevanceRegions(); } // Send dirty nodes, deliver vault callbacks, etc. VaultUpdate(); plNetLinkingMgr::GetInstance()->Update(); return ret; }
// // MsgReceive handler for plasma messages // bool plNetClientMgr::MsgReceive( plMessage* msg ) { if (plNetLinkingMgr::GetInstance()->MsgReceive( msg )) return true; plEvalMsg* evalMsg = plEvalMsg::ConvertNoRef(msg); if (evalMsg) { IPlaybackMsgs(); if ( GetFlagsBit( kNeedToSendAgeLoadedMsg ) ) { SetFlagsBit( kNeedToSendAgeLoadedMsg, false ); plAgeLoader::GetInstance()->NotifyAgeLoaded( true ); } if ( GetFlagsBit( kNeedToSendInitialAgeStateLoadedMsg ) ) { SetFlagsBit(kNeedToSendInitialAgeStateLoadedMsg, false); plInitialAgeStateLoadedMsg* m = new plInitialAgeStateLoadedMsg; m->Send(); } return true; } plGenRefMsg* ref = plGenRefMsg::ConvertNoRef(msg); if (ref) { if( ref->fType == kVaultImage ) { // Ignore, we just use it for reffing, don't care about the actual pointer return true; } hsAssert(ref->fType==kAgeSDLHook, "unknown ref msg context"); if (ref->GetContext()==plRefMsg::kOnCreate) { hsAssert(fAgeSDLObjectKey==nil, "already have a ref to age sdl hook"); fAgeSDLObjectKey = ref->GetRef()->GetKey(); DebugMsg("Age SDL hook object created, uoid=%s", fAgeSDLObjectKey->GetUoid().StringIze().c_str()); } else { fAgeSDLObjectKey=nil; DebugMsg("Age SDL hook object destroyed"); } return true; } if (plNetClientMgrMsg * ncmMsg = plNetClientMgrMsg::ConvertNoRef(msg)) { if (ncmMsg->type == plNetClientMgrMsg::kCmdDisableNet) { SetFlagsBit(kDisableOnNextUpdate); hsRefCnt_SafeUnRef(fDisableMsg); fDisableMsg = ncmMsg; fDisableMsg->Ref(); } return true; } if (plNetCommAuthMsg * authMsg = plNetCommAuthMsg::ConvertNoRef(msg)) { if (IS_NET_ERROR(authMsg->result)) { char str[256]; StrPrintf(str, arrsize(str), "Authentication failed: %S", NetErrorToString(authMsg->result)); QueueDisableNet(true, str); return false; // @@@ TODO: Handle this failure better } return true; } if (plNetCommActivePlayerMsg * activePlrMsg = plNetCommActivePlayerMsg::ConvertNoRef(msg)) { if (IS_NET_ERROR(activePlrMsg->result)) { char str[256]; StrPrintf(str, arrsize(str), "SetActivePlayer failed: %S", NetErrorToString(activePlrMsg->result)); QueueDisableNet(true, str); return false; // @@@ TODO: Handle this failure better. } return true; } plPlayerPageMsg *playerPageMsg = plPlayerPageMsg::ConvertNoRef(msg); if(playerPageMsg) { IHandlePlayerPageMsg(playerPageMsg); return true; // handled } plLoadCloneMsg* pCloneMsg = plLoadCloneMsg::ConvertNoRef(msg); if(pCloneMsg) { ILoadClone(pCloneMsg); return true; // handled } // player is petitioning a CCR plCCRPetitionMsg* petMsg=plCCRPetitionMsg::ConvertNoRef(msg); if (petMsg) { ISendCCRPetition(petMsg); return true; } // a remote CCR is turning invisible plCCRInvisibleMsg* invisMsg=plCCRInvisibleMsg::ConvertNoRef(msg); if (invisMsg) { LogMsg(kLogDebug, "plNetClientMgr::MsgReceive - Got plCCRInvisibleMsg"); MakeCCRInvisible(invisMsg->fAvKey, invisMsg->fInvisLevel); return true; } plCCRBanLinkingMsg* banLinking = plCCRBanLinkingMsg::ConvertNoRef(msg); if (banLinking) { DebugMsg("Setting BanLinking to %d", banLinking->fBan); SetFlagsBit(kBanLinking, banLinking->fBan); return true; } plCCRSilencePlayerMsg* silence = plCCRSilencePlayerMsg::ConvertNoRef(msg); if (silence) { DebugMsg("Setting Silence to %d", silence->fSilence); SetFlagsBit(kSilencePlayer, silence->fSilence); return true; } plNetVoiceListMsg* voxList = plNetVoiceListMsg::ConvertNoRef(msg); if (voxList) { IHandleNetVoiceListMsg(voxList); return true; } plSynchEnableMsg* synchEnable = plSynchEnableMsg::ConvertNoRef(msg); if (synchEnable) { if (synchEnable->fPush) { plSynchedObject::PushSynchDisabled(!synchEnable->fEnable); } else { plSynchedObject::PopSynchDisabled(); } return true; } plClientMsg* clientMsg = plClientMsg::ConvertNoRef(msg); if (clientMsg && clientMsg->GetClientMsgFlag()==plClientMsg::kInitComplete) { // add 1 debug object for age sdl if (plNetObjectDebugger::GetInstance()) { plNetObjectDebugger::GetInstance()->RemoveDebugObject("AgeSDLHook"); plNetObjectDebugger::GetInstance()->AddDebugObject("AgeSDLHook"); } // if we're linking to startup we don't need (or want) a player set plString ageName = NetCommGetStartupAge()->ageDatasetName; if (ageName.IsEmpty()) ageName = "StartUp"; if (ageName.CompareI("StartUp") == 0) NetCommSetActivePlayer(0, nullptr); plAgeLinkStruct link; link.GetAgeInfo()->SetAgeFilename(NetCommGetStartupAge()->ageDatasetName); link.SetLinkingRules(plNetCommon::LinkingRules::kOriginalBook); plNetLinkingMgr::GetInstance()->LinkToAge(&link); return true; } return plNetClientApp::MsgReceive(msg); }
// // See if there is state recvd from the network that needsto be delivered // void plNetClientMgr::ICheckPendingStateLoad(double secs) { // We only care if we're in an age or loading state if (!(GetFlagsBit(kPlayingGame) || (GetFlagsBit(kLoadingInitialAgeState) && !GetFlagsBit(kNeedInitialAgeStateCount)))) return; for (auto it = fPendingLoads.begin(); it != fPendingLoads.end();) { PendingLoad* load = *it; // If no key has been cached, we need to find it. if (!load->fKey) { load->fKey = hsgResMgr::ResMgr()->FindKey(load->fUoid); // By this point, we should have all the age's keys downloaded from filesrv // So, if fKey is null at this point, this state is garbage if (!load->fKey) { ErrorMsg("Key `%s` not found. Discarding state for `%s`", load->fUoid.GetObjectName().c_str(), load->fSDRec->GetDescriptor()->GetName().c_str()); it = fPendingLoads.erase(it); delete load; continue; } } // Time to deliver the state! plSynchedObject* synchObj = plSynchedObject::ConvertNoRef(load->fKey->ObjectIsLoaded()); if (synchObj && synchObj->IsFinal()) { plSDLModifierMsg* msg = new plSDLModifierMsg(load->fSDRec->GetDescriptor()->GetName(), plSDLModifierMsg::kRecv); msg->SetState(load->fSDRec, true); load->fSDRec = nullptr; msg->SetPlayerID(load->fPlayerID); #ifdef HS_DEBUGGING if (plNetObjectDebugger::GetInstance()->IsDebugObject(synchObj)) { DebugMsg("Delivering SDL State '%s' to %s owned key %s", msg->GetState()->GetDescriptor()->GetName().c_str(), (synchObj->IsLocallyOwned() == plSynchedObject::kYes) ? "locally" : "remote", load->fUoid.StringIze().c_str()); } #endif msg->Send(load->fKey); it = fPendingLoads.erase(it); delete load; } else if (GetFlagsBit(kPlayingGame)) { // If we're playing the game and object isn't loaded/final, then this state is probably // never going to be useful (it's from some paged in hack or something that's been deleted) // Throw it away. it = fPendingLoads.erase(it); delete load; } else ++it; } }
void plNetClientMgr::MaybeSendPendingPagingRoomMsgs() { if ( GetFlagsBit( kPlayingGame ) ) SendPendingPagingRoomMsgs(); }
// // show lists of members, listenList, and talkList // void plNetClientMgr::IShowLists() { plNetLinkingMgr * lm = plNetLinkingMgr::GetInstance(); plDebugText &txt = plDebugText::Instance(); int y,x,i; const int yOff=10, xOff=300, startY=70, startX=10; char str[256]; // My player info x=startX; y=startY; plSceneObject *player = plSceneObject::ConvertNoRef(GetLocalPlayer()); hsPoint3 pos = (player ? player->GetLocalToWorld() * hsPoint3(0, 0, 0) : hsPoint3(0, 0, 0)); sprintf(str, "%s%s PlyrName=%s PlyrID=%d AcctID=%d P2P=%d Join#=%d Peers=%d %.1f,%.1f,%.1f", GetFlagsBit(kSendingVoice) ? "V" : " ", GetFlagsBit(kSendingActions) ? "A" : " ", GetPlayerName().c_str(), GetPlayerID(), 0, IsPeerToPeer(), GetJoinOrder(), 0, pos.fX, pos.fY, pos.fZ); txt.DrawString(x,y,str,255,255,255,255); SetFlagsBit(kSendingVoice, 0); SetFlagsBit(kSendingActions, 0); y+=yOff; sprintf(str, " Server=%s ILIAS=%d", "foo", IsLoadingInitialAgeState()); txt.DrawString(x,y,str,255,255,255,255); // MEMBERS y+=yOff; int baseY=y; txt.DrawString(x,y," Members",255,255,255,255,plDebugText::kStyleBold); y+=yOff; plNetTransportMember** members=nil; fTransport.GetMemberListDistSorted(members); for(i=0;i<fTransport.GetNumMembers();i++) { plNetTransportMember* mbr=members[i]; hsAssert(mbr, "ShowLists: nil member?"); if (mbr->IsServer()) continue; player = (mbr->GetAvatarKey() ? plSceneObject::ConvertNoRef(mbr->GetAvatarKey()->ObjectIsLoaded()) : nil); sprintf(str, "%s%s %s p2p=%d dist=%.1f", mbr->GetTransportFlags() & plNetTransportMember::kSendingVoice ? "V" : " ", mbr->GetTransportFlags() & plNetTransportMember::kSendingActions ? "A" : " ", mbr->AsString().c_str(), mbr->IsPeerToPeer(), mbr->GetDistSq() != FLT_MAX ? sqrt(mbr->GetDistSq()) :-1.f); txt.DrawString(x,y,str); y+=yOff; mbr->SetTransportFlags(mbr->GetTransportFlags() & ~(plNetTransportMember::kSendingVoice|plNetTransportMember::kSendingActions)); } delete [] members; // LISTENLIST x+=xOff; y=baseY; txt.DrawString(x,y,"ListenList",255,255,255,255,plDebugText::kStyleBold); y+=yOff; for(i=0;i<GetListenList()->GetNumMembers();i++) { sprintf(str, "name=%s", GetListenList()->GetMember(i)->AsString().c_str()); txt.DrawString(x,y,str); y+=yOff; } // TALKLIST x+=xOff; y=baseY; txt.DrawString(x,y,"TalkList",255,255,255,255,plDebugText::kStyleBold); y+=yOff; for(i=0;i<GetTalkList()->GetNumMembers();i++) { sprintf(str, "name=%s", GetTalkList()->GetMember(i)->AsString().c_str()); txt.DrawString(x,y,str); y+=yOff; } }