Download

Connect to Steam dedicated server via raw IP?

Hello there,
I am using Steam for multiplayer, so I can easily browse and connect to my dedicated servers using the Steam server browser or my in-game implementation. It is all working good, but recently I started integrating Amazon GameLift, a matchmaking tool by Amazon which hosts my dedicated servers on their EC2 instances. When matchmaking was successful, I get a raw IP and port back, and I now try to connect to it, but “open ip:port” won’t work, neither ClientTravel does. It tries to connect, then the log’s silent for a minute, and then the connection times out. I found out that Unreal connects to Steam servers by using “open steam.<steam id of the server>”, but I don’t have that ID, only the IP and port.

Is this normal that we can’t connect to a IP when using Steam, or am I just too dumb?

Thank you :slight_smile:

It is, indeed, “normal” to not be able to connect via IP when using the USteamNetDriver class in config.

I am facing the same problem, whats the solution ?

I am using playfab instead of Gamelift which worked fine, I use to get Port and IP from Playfab component and I just Open level with those details, but when I am using steam in client side, it does not connect anymore it throws “PreLogin failure: incompatible_unique_net_id”

Hey! As mentioned, you can only connect to servers if you have the Steam ID. That being said the way to connect to servers via the command line is “open steam.12345” where 12345 would be the Steam ID of the server.

To get the servers Steam ID from raw IP, there is a function in the Steam SDK here: ISteamMatchmakingServers Interface (Steamworks Documentation).
You’ll have to give him the IP and Port (the query port, often 27015! Not the game port), and after the async call called back (you’ll need to make your class inheriting ISteamMatchmakingPingResponse), you’ll get the server data, including the Steam ID. Then use the command line above to connect!

Hope that helped

I personally expose an IP field on my steam session, then have the client look through the sessions list until it finds the IP it wants to connect to.
That’s probably super dirty, and you need to add some anti-spoofing verifications, but it does work within the bounds if existing UE4 Steam SDK libraries.

iUltimateLP’s answer is very interesting though, I’m defintitely going to take a look at it :slight_smile:

Is there a way in which I can use steam for authentication and platform and not for creating game sessions coz I’m already using playfab for matchmaking, just want use the usual way of getting the ip and the port and join the game session.

Unfortunately not. Once you use the Steam net driver, connections via raw IP/Port aren’t possible anymore. It’s a security measure, and something Steam delivers: it protects servers behind IDs so it won’t expose their raw connection info. So either you disable Steam completely, or use my approach to ask the server about it’s IP. It’s not that hard implementing it, so I’d suggest it :slight_smile:

Ok, thanks for help, now I have only one way to go :slight_smile:

Well I tried everything, my server is registered with steam its showing in steam server list on LAN as well as Internet Tab but, somehow my client cant find that server via Find advance session also I implemented Steam Ping server, which server failed to respond. anyone any idea, what could have gone wrong.

The Steam PingServer function you mentioned seems to take in the ip and port in host order. Been struggling to try to convert FString to host order (which can apparently be held in a uint32 for the ip, and uint16 for the port). Would really appreciate knowing how you did this.

Hey! That’s fairly easy, with help from c - How to reverse byte of a hexadecimal number? - Stack Overflow I came up with this code:



    FString IPString;
    FString PortString;
    URL.Split(TEXT(":"), &IPString, &PortString);

    uint16 Port = FCString::Atoi(*PortString);

    uint32 Address = inet_addr(TCHAR_TO_UTF8(*IPString));

    // https://stackoverflow.com/questions/21038120/how-to-reverse-byte-of-a-hexadecimal-number
    uint32 AddressHostOrder = ((Address & 0x000000FF) << 24) | ((Address & 0x0000FF00) << 8) | ((Address & 0x00FF0000) >> 8) | ((Address & 0xFF000000) >> 24);

    SteamMatchmakingServers()->PingServer(AddressHostOrder, Port, this);


It takes the URL, splits it by the “:” so we have the IP and port string, then it converts the port string to an uint16 and the IP to a uint32 decimal address. Because inet_addr is returning it in the wrong order, I took the code from stackoverflow to reverse it. Then you have perfect data for PingServer()!

Cheers!

Ah was wondering why inet_addr wasn’t working right out of the box. As we say in Dublin, Ireland, you are a straight legend iUltimateLP!

I’m now getting the ServerResponded callback. Need to figure out how to get the WorldContext inside this steam callback class now so I can GetFirstLocalPlayerController to do a ClientTravel.
I tried creating an intermediary uobject class and overwriting its GetWorld function but just getting nullptr so far. Did you happen to have to deal with this aswell?

We made use of multiple inheritance and made our game instance inherit it:


class UShooterGameInstance : public UGameInstance, public ISteamMatchmakingPingResponse

Then you can implement the two functions as usual voids (not statics!)



public:
    // Begin ISteamMatchmakingPingResponse interface
    void ServerResponded(gameserveritem_t& server);
    void ServerFailedToRespond();
    // End ISteamMatchmakingPingResponse interface


Since you’re in game instance context, you can always call GetFirstLocalPlayerController(). Cheers!

Ah! Multiple inheritance I didn’t consider it as Unreal doesn’t support it with their internal macros, but since the steam class is not using the internal macros it’s possible.
I got it working though, thank you very much friend.

A warning for others, I got some horrible *.gen.cpp errors when I included the steam/isteammatchmaking.h. Had to add this after the steam includes


#define ARRAY_COUNT( array ) (sizeof(ArrayCountHelper(array)) - 1)

. Hopefully will save you some time.

Sorry to necro this thread but, even after following the instructions i can not get the “PingServer()” function to return the proper response it always fails, I am using the following function instead of the one in the thread to get the IP in host order so that might be something wrong with that but from what i’ve read i belive it should be working properly.


uint16 Port = FCString::Atoi(*port);

FIPv4Address adress;
FIPv4Address::Parse(IP, adress);

SteamMatchmakingServers()->PingServer(adress.Value, Port, this);

I am trying to connect to a PLAYFAB server, i can get the IP and port just fine but steam never returns the proper ID for me to connect, do i need to open a specific port for the query to work?

EDIT: tried opening the 27015 ports both tcp and udp in the playfab dashboard and the result is the same.

In order to connect via raw IP I had to first make sure both my client and server were compiled with the steam networking disabled in the DefaultEngine.ini

[OnlineSubsystemSteam]
bUseSteamNetworking=false
… other stuff

[/Script/Engine.GameEngine]
!NetDriverDefinitions=ClearArray
NetDriverDefinitions=(DefName=“GameNetDriver”,DriverClassName="/Script/OnlineSubsystemUtils.IpNetDriver",DriverClassNameFallback="/Script/OnlineSubsystemUtils.IpNetDriver")
+NetDriverDefinitions=(DefName=“DemoNetDriver”,DriverClassName="/Script/Engine.DemoNetDriver",DriverClassNameFallback="/Script/Engine.DemoNetDriver")

[OnlineSubsystem]
DefaultPlatformService=Steam
… other stuff

DO NOT HAVE THESE SECTIONS
[PacketHandlerComponents]
[/Script/OnlineSubsystemSteam.SteamNetDriver]

After doing that I was getting disconnected due to incompatible_unique_net_id
So I then had to hack the engine in PendingNetGame.cpp by commenting out the following line
//Connection->PlayerId = LocalPlayer->GetPreferredUniqueNetId();

WARNING: I have zero clue what other ramifications there are having a default PlayerId, but I know that’s whats happening if you run the game via editor or run the game without the steam client running. However since the id was simply Steam : DisplayName the value is not actually unique anyway.

I assume it does not work anymore in 2021 because no matter how I try it just wont connect