WAN multiplayer server list(without steam)?

I have a game working right now. Theres a server list, LAN players can click and join the server they want.

One issue, is that the max connections is completely ignored. So however many people can join a full game after its started which i dont know why.

But my question is for WAN. So im at home and I want to play my game with randoms in the world that are currently hosting a game. If I go and and refresh the server list with LAN enabled OFF. How can it find games out there in the world that are hosting? Is there something special to set up? (not talking about hosts port forwarding or anything, I know about all that).

I’m not putting this as an answer because I don’t know for sure, but:

Without steam you have to set up some sort of central server for your WAN servers to post themselves on and for your clients to request the server list from. Right now I’m setting up my game to have servers use the FHTTPModule to POST to a central server their info. Client’s in the server browser would then make an HTTP REQUEST to this central server for a list of available servers. I haven’t gotten very far with this yet, but I’m building this on the OnlineSubystemNull.

I’m learning node.js to write my server, but there may be services available to do this already. Google things like unreal engine onlinesubsystemnull or server list. Also this stuff might lead you somewhere useful: https://answers.unrealengine.com/questions/153124/how-do-i-create-a-post-http-request-for-binary-fil.html

Anyway, my node.js server will basically setup an HTTP server that listens for servers posting their info every so often. If a server fails to post its info, it will get removed from a list. The server also listens for requests from clients and will send back an array of servers. Also, if your server is lan, then you just don’t send its info to the central server.

This might be easily doable, for at least testing, in Java as well. You will want to support multithreading though for multiple simultaneous postings and requests.

Well that sounds like exactly what I want to do…unfortunately I wouldnt even know where to start with that.

darn I was hoping this had been done lots so it was well documented now.

Hey Cobryis,

The server potion I think I have covered. How do I get the game in UE4 to SEND it’s game details… thats the information I need to maybe get this working. How to tell the game to send its data to my server as a JSON payload. It can then be posted… and others can see it to click and join. As you said, its just a hub that stores current session information. I dont know how to make UE4 send that information though.

This is what I have in my game mode. May not be the most correct solution, but it works.

void AUBGameMode::InitGame(const FString& MapName, const FString& Options, FString& ErrorMessage)
{
	Super::InitGame(MapName, Options, ErrorMessage);

	FTimerHandle DummyHandle;
	GetWorld()->GetTimerManager().SetTimer(DummyHandle, this, &AUBGameMode::PostToCentralServer,  2.0f, true);

	RecastGameSession = Cast<AUBGameSession>(GameSession);
}
void AUBGameMode::PostToCentralServer() const
{
	const bool bIsServer = GetNetMode() == NM_DedicatedServer || GetNetMode() == NM_ListenServer;
	if (bIsServer && RecastGameSession->bShouldAdvertise)
	{
		FString Name("No name");
		int32 PlayerCount = NumPlayers;

		FHttpModule* Http = &FHttpModule::Get();
		TSharedRef<IHttpRequest> Request = Http->CreateRequest();
		Request->SetURL("http://cobryis.ddns.net:7776"); //7776 is the port I set on my central server
		Request->SetVerb("POST");
		Request->SetHeader("Content-Type", "application/json");

		FString JsonStr;
		auto JsonWriter = TJsonWriterFactory<>::Create(&JsonStr);
		FOnlineJsonSerializerWriter Serializer(JsonWriter);
		Serializer.StartObject();
		Serializer.Serialize(TEXT("playerCount"), PlayerCount);
		Serializer.Serialize(TEXT("serverName"), Name);
		Serializer.EndObject();
		JsonWriter->Close();

		Request->SetContentAsString(JsonStr);
		Request->ProcessRequest();
	}
}

RecastGameSession is my custom GameSession (which you specify with GetGameSessionClass in the GameMode). In my GameSession class, I have:

class UBOATS_API AUBGameSession : public AGameSession
{
	GENERATED_BODY()
public:
	virtual void InitOptions(const FString& Options) override;
	bool bIsLanMatch;
	bool bShouldAdvertise;
	FString ServerName;
};

// CPP

void AUBGameSession::InitOptions(const FString& Options)
{
	Super::InitOptions(Options);
	AGameMode* const GameMode = GetWorld()->GetAuthGameMode();

	bIsLanMatch = !!GameMode->GetIntOption(Options, TEXT("bIsLanMatch"), bIsLanMatch); // lol compiler
	bShouldAdvertise = !bIsLanMatch && GameMode->GetIntOption(Options, TEXT("bShouldAdvertise"), GameMode->GetNetMode() == NM_DedicatedServer);

	FString PlayerName = GameMode->ParseOption(Options, TEXT("Name"));

	ServerName = GameMode->ParseOption(Options, TEXT("ServerName"));

	if (ServerName.IsEmpty())
	{
		if (!PlayerName.IsEmpty())
		{
			ServerName = PlayerName;
		}
		else
		{
			ServerName = TEXT("<none>");
		}
	}
}

And here’s my GameInstance class where players create listen servers or request a server list. I haven’t, however, gotten my callback to work (the server list is supposed to be used by UMG), but the list itself works.

void UUBGameInstance::RequestServerList(FServerListRetrievedDelegate ServerListDelegate) const
{
	FHttpModule* Http = &FHttpModule::Get();
	TSharedRef<IHttpRequest> Request = Http->CreateRequest();
	Request->SetURL("http://cobryis.ddns.net:7776");
	Request->SetVerb("GET");

	Request->OnProcessRequestComplete().BindLambda([ServerListDelegate](FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded)
	{
		if (bSucceeded)
		{
			FString JsonStr = HttpResponse->GetContentAsString();
			TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(JsonStr);
			// TArray< TSharedPtr<FJsonValue> > JsonPtrs;
			TSharedPtr< FJsonObject > JsonPtr;

			FJsonSerializer::Deserialize(Reader, JsonPtr);

			TArray<FServerInfo> ServerList;

			for (auto It = JsonPtr->Values.CreateConstIterator(); It; ++It)
			{
				const FString& Key = It.Key(); // The key is the IP in my server

				uint32 PlayerCount = 512;
				FString ServerName = TEXT("Error");

				const auto& Value = It.Value();
				const TSharedPtr<FJsonObject> *ServerInfo;
				if (Value->TryGetObject(ServerInfo))
				{
					(*ServerInfo)->TryGetNumberField(TEXT("playerCount"), PlayerCount);
					(*ServerInfo)->TryGetStringField(TEXT("serverName"), ServerName);
				}

				ServerList.Add(FServerInfo(Key, ServerName, PlayerCount));

				UE_LOG(UBLog, Display, TEXT("Listing %s from %s with %d players."), *ServerName, *Key, PlayerCount);
			}
			ServerListDelegate.Execute(ServerList);
		}
	});

	if (!Request->ProcessRequest())
	{
		UE_LOG(UBLog, Warning, TEXT("Failed to process"));
	}
}

Here’s the JSON object my central server builds. IPs are Keys, and they’re matched with a JSON object of server info.

{ '127.0.0.1': { playerCount: 0, serverName: 'Dummy' },
  '127.0.0.2': { playerCount: 2, serverName: 'Dummy' } }

Oh, if you’re trying to do this entirely in blueprint, you should try using this: A new, community-hosted Unreal Engine Wiki - Announcements - Unreal Engine Forums

Amazing. Thanks!
Helps get the flow right.

Yea… I’m trying to make it happen in blueprints. looking through the thread now.
Will post my results.

Thanks for sharing what you have so far.

Hello,
You can use this solution to to run a master server on Windows / Linux and get a list of game servers using the UE4 plug-in.