Get pings array results from region with best ping operation
I am trying to get the :
from the LoadBalancing :: Client ,but it is a private member, how do you do that?
Or...how can I get a list of pings per region if even if I overload the client the Peer is private as well?
Thanks!
Common::JVector<Common::JVector<unsigned int> > mPingResponses;
from the LoadBalancing :: Client ,but it is a private member, how do you do that?
Or...how can I get a list of pings per region if even if I overload the client the Peer is private as well?
Thanks!
0
Comments
-
Hi @juaxix.
This is not exposed in the API of class Client.
However class Client simply uses the public pingServer API of class PhotonPeer to implement its best region feature.
Your own code can do the same:
Simply create a PhotonPeer instance and ping the regions yourself via that instance. Then pass your selected region to class Client with RegionSelectionMode::SELECT.
For reference this is the current implementation of Client::pingBestRegion():void Client::pingBestRegion(unsigned int pingsPerRegion) { EGLOG(DebugLevel::INFO, L""); for(unsigned int i=0; i<mAvailableRegionServers.getSize(); ++i) { mpPeer->pingServer(mAvailableRegionServers[i], pingsPerRegion); mPingResponses.addElement(JVector<unsigned int>(pingsPerRegion)); } mPingsPerRegion = pingsPerRegion; }
As you can see, it simply iterates over the list of available regions and calls PhotonPeer::pingServer() for each entry in the list.
Just do the same in your own code.
The ping results arrive in PhotonListener::onPingResponse(), so don't forget to implement PhotonListener as well.
Note that the callback will not be called just once per region, but once for every ping that got sent to that region. So i.e. if you pass '5' for pingsPerRegion for region 'eu', then it will be called 5 times for that region.
For reference below is the current onPingResponse() implementation of class Client:void Client::onPingResponse(const JString& address, unsigned int result) { bool receivedAllRequests = true; for(unsigned int i=0; i<mAvailableRegionServers.getSize(); ++i) { if(address == mAvailableRegionServers[i]) mPingResponses[i].addElement(result); if(mPingResponses[i].getSize() < mPingsPerRegion) receivedAllRequests = false; } if(!receivedAllRequests) return; unsigned int bestPing = UINT_MAX; unsigned int indexOfRegionWithBestPing = 0; for(unsigned int i=0; i<mPingResponses.getSize(); ++i) { unsigned int ping = 0; for(unsigned int j=0; j<mPingsPerRegion; ++j) ping += mPingResponses[i][j]; ping /= mPingsPerRegion; if(ping < bestPing) { bestPing = ping; indexOfRegionWithBestPing = i; } } mPingResponses.removeAllElements(); // replace the cluster with the best ping with a random cluster in the same region as the cluster with the best ping int index = mAvailableRegions[indexOfRegionWithBestPing].indexOf(L'/'); mSelectedRegion = mRegionWithBestPing = (index==-1?mAvailableRegions[indexOfRegionWithBestPing]:mAvailableRegions[indexOfRegionWithBestPing].substring(0, index))+L"/*"; authenticate(); }
You could use that as a starting point for your own implementation of that callback and then adjust your implementation according to your needs.0 -
Ok, I see what I have to do but I still need to know more about the Peer, can I have another Peer instance just for the pings and overload the LoadBalancing::Client using this to request the pings?
Something like this:typedef TMap<FString, TArray<uint32> > TPingsResultMap; class PhotonCloudLoadBalancingClient: public ExitGames::LoadBalancing::Client { bool m_Pinging = false; int m_PingsPerServer = 5; ExitGames::Common::JVector<ExitGames::Common::JString> m_Servers; public: ExitGames::LoadBalancing::Peer* PingPeer; TPingsResultMap PingResults; FOnPingServersCompleted OnPingServersCompleted; PhotonCloudLoadBalancingClient(ExitGames::LoadBalancing::Listener& listener, const ExitGames::Common::JString& applicationID, const ExitGames::Common::JString& appVersion, nByte connectionProtocol= ExitGames::Photon::ConnectionProtocol::DEFAULT, bool autoLobbyStats=false, nByte regionSelectionMode= ExitGames::LoadBalancing::RegionSelectionMode::DEFAULT, bool useAlternativePorts=false) : Client(listener, applicationID, appVersion, connectionProtocol, autoLobbyStats, regionSelectionMode, useAlternativePorts), PingPeer(ExitGames::Common::MemoryManagement::allocate<ExitGames::LoadBalancing::Peer>(static_cast<PhotonListener&>(*this),ExitGames::Photon::ConnectionProtocol::UDP)), PingResults() { } ~PhotonCloudLoadBalancingClient() { ExitGames::Common::MemoryManagement::deallocate(PingPeer); } void PingServers(const ExitGames::Common::JVector<ExitGames::Common::JString>& Servers, int NumPings = 5) { if (m_Pinging || Servers.getSize() == 0) { return; } m_Pinging = true; PingResults.Empty(); m_PingsPerServer = NumPings; m_Servers = Servers; for (unsigned i = 0; i<m_Servers.getSize(); i++) { PingPeer->pingServer(m_Servers[i], m_PingsPerServer); } } void onPingResponse(const ExitGames::Common::JString& address, unsigned int result) override { FString AddressKey = address.UTF8Representation().cstr(); if (!PingResults.Contains(AddressKey)) { PingResults.Add(AddressKey, TArray<uint32>()); } TArray<uint32> *Pings = &PingResults[AddressKey]; if (Pings != nullptr) { Pings->Add(result); } bool completed = true; for(auto& PingResult: PingResults) { if (PingResult.Value.Num() < m_PingsPerServer) { completed = false; } } if (completed) { m_Pinging = false; OnPingServersCompleted.Broadcast(PingResults); } } };
this way I could just use this PingPeer but I think i need to move it to a background task to avoid blocking the game thread in unreal, i guess i can have a peer and a loadbalancing client without connect them ,only to do the pings , it needs PingPeer->service(dispatchIncomingCommands) though0 -
Hi @juaxix.can I have another Peer instance just for the pingsand overload the LoadBalancing::Client using this to request the pings?but I think i need to move it to a background task to avoid blocking the game thread in unreali guess i can have a peer and a loadbalancing client without connect them ,only to do the pingsit needs PingPeer->service(dispatchIncomingCommands) though0
-
thanks, so what I did is something like this:
class PhotonCloudLoadBalancingClient: public ExitGames::LoadBalancing::Client { ExitGames::Common::JVector<ExitGames::Common::JString> m_Servers; public: ExitGames::LoadBalancing::Peer* PingPeer; TPingsResultMap PingResults; PhotonCloudLoadBalancingClient(ExitGames::LoadBalancing::Listener& listener, const ExitGames::Common::JString& applicationID, const ExitGames::Common::JString& appVersion, nByte connectionProtocol= ExitGames::Photon::ConnectionProtocol::DEFAULT, bool autoLobbyStats=false, nByte regionSelectionMode= ExitGames::LoadBalancing::RegionSelectionMode::DEFAULT, bool useAlternativePorts=false) : Client(listener, applicationID, appVersion, connectionProtocol, autoLobbyStats, regionSelectionMode, useAlternativePorts), PingPeer(ExitGames::Common::MemoryManagement::allocate< ExitGames::LoadBalancing::Peer>( static_cast<PhotonListener&>(*this), connectionProtocol)), PingResults() { } void serviceBasic() override { Client::serviceBasic(); if (m_Pinging) { PingPeer->serviceBasic(); } } ~PhotonCloudLoadBalancingClient() { ExitGames::Common::MemoryManagement::deallocate(PingPeer); } void PingServers(const ExitGames::Common::JVector<ExitGames::Common::JString>& Servers, int NumPings = 5) { // use the PingPeer to ping the servers here } void onPingResponse(const ExitGames::Common::JString& address, unsigned int result) override { //broadcast the results } };
so i use this class as the listener class now0