ReserveServer returning the wrong PrivateServerID

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? Keep it simple and clear!
    I want to send data to a server with my lobby system. I am using MessagingService (which is not the problem, on both ends the correct values are sent)

  2. What is the issue? Include screenshots / videos if possible!
    The PrivateServerID returned by the ReserveServer is different from the actual server’s PrivateServerID. Which means they don’t match which means the lobby server never sends data over to the game server which means it’s all left empty.

  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    There’s NOTHING on DevForum about my problem. Making a Topic is my last resort as I don’t know what to do.

The important code is here:
The lobby server

	if action == "start" then
		if lobbyobj.Host.Value == player and lobbyobj.Privacy.Value ~= "Teleporting" then
			game.Debris:AddItem(lobbyobj,10)
			lobbyobj.Privacy.Value = "Teleporting"
			local reserve,privateID = game["Teleport Service"]:ReserveServer(18541756425)
			print(reserve)
			print(privateID)
			local teleportedplayers = {}
			local playerobjects = lobbyobj.Players:GetChildren()
			for i = 1,#playerobjects do
				table.insert(teleportedplayers,playerobjects[i].Value)
				task.spawn(function()
					game.ReplicatedStorage.MiniNotification:FireClient(playerobjects[i].Value,Color3.new(1,1,1),"Teleporting...")
					game.ReplicatedStorage.SublevelChangeScreen:FireClient(playerobjects[i].Value,lobbyobj.Host.Value.Name.."'s Lobby")
				end)
			end
			local thehost = lobbyobj.Host.Value.UserId
			local lobbyname = lobbyobj.Name
			local event = script.GetAndSendData.Get.Event:Connect(function(payload)
				print(payload)
				local data = game:GetService("HttpService"):JSONDecode(payload)
				print("Servers got data")
				if data["ID"] == privateID and data["Type"] == "request" then
					print("data is a request from teleported server")
					local sentdata = {
						["ID"] = privateID,
						["Type"] = "data",
						["Name"] = lobbyname,
						["Host"] = thehost
					}
					local sentpayload = game:GetService("HttpService"):JSONEncode(sentdata)
					print(sentpayload)
					script.GetAndSendData.Send:Fire(sentpayload)
					print("sent requested data")
					print(data)
				end
			end)
			for i = 1,20 do
				game["Teleport Service"]:TeleportToPrivateServer(18541756425,reserve,teleportedplayers)
				wait(1)
			end
			event:Disconnect()
		else
			game.ReplicatedStorage.MiniNotification:FireClient(player,Color3.new(1,0,0),"You are not the host!")
		end
	end

The game server

wait(1)
local messagingservice = game:GetService("MessagingService")
local privateID = game.PrivateServerId
messagingservice:SubscribeAsync("Servers",function(payload)
	print(payload)
	local data = game:GetService("HttpService"):JSONDecode(payload)
	print("got data!")
	print(privateID)
	if data["ID"] == privateID and data["Type"] == "data" then
		print("got requested server data.")
		game.ServerStorage.Storage.SecretServerData.Host.Value = data["Host"]
		game.ServerStorage.Storage.SecretServerData.LobbyName.Value = data["Name"]
		game.ServerStorage.Storage.SecretServerData.HostName.Value = game.Players:GetNameFromUserIdAsync(data["Host"])
	end
end)
local payload = {
	["ID"] = privateID,
	["Type"] = "request"
}
local sentpayload = game:GetService("HttpService"):JSONEncode(payload)
print(sentpayload)
messagingservice:PublishAsync("Servers",sentpayload)

Is there something I am missing? It doesn’t matter if the lobby server is left empty or not, I’ve tested it by leaving my alt account in the lobby server and it doesnt change anything

1 Like

So this is just one of those times where the Roblox developer documentation could really do with improvements, since it’s not really explicitly mentioned. I had the exact same problem for a bit on one of my own games until I realized what was actually happening.

When you reserve a server - the code that is returned from ReserveServer() is NOT the PrivateServerID. It’s the code that you need in order to teleport players to that server. The PrivateServerID is completely disconnected and is more or less useless in this case.

So - in order for you to send players to the actual reserved server - you’re going to need to save that reserved server code somewhere. What I do is use SetTeleportData with a TeleportOptions instance, have the reserved server code in there, and then when the player joins, you call GetJoinData on the player, and they’ll have the actual access code for the reserved server.

This does theoretically leave you open to potential exploits - as even if you call GetJoinData() from the server, the client is actually what has the data, this is a really unlikely attack but it could still happen. You could employ data validation by storing the reserved server ID in a memory store for a little bit while the server is starting, and then on the server, when you call GetJoinData(), if the returned code does not match any active server, then you know it was tampered with.

All of this is a little bit elaborate and definitely kinda obnoxious - all the way through this myself when I had this problem I was muttering under my breath “Surely there must be a better way to do this.” but as far as I know, there is not.

I should note that if your goal is purely to make a server browser, and not some kind of password-protected server, or guaranteed new server - you don’t need to be reserving servers. You can simply get the Game.JobId of available servers and send that through with MessagingService. Since you can directly teleport to non-reserved servers with the JobId.

1 Like

It returns two values, so local reserve,privateID = game["Teleport Service"]:ReserveServer(18541756425) is supposed to get both the key and the private server ID.

Also, the data being sent to the game server is stuff like the player who created the lobby and the lobby name used in the code to identify it.

1 Like

How strange - I actually can’t replicate this behavior. I had the wrong idea and thought you were assuming that the ReservedServerAccessCode was the private server ID.

In my own testing - the private server ID that was returned, and the private server ID of the server I joined was always the same. (even if I left the server I joined, and rejoined it using the same reserved code.)


image
(I did try using the deprecated TeleportToPrivateServer() as well and it was the same result)

I would say that you should try going into your published game, try teleporting to it using the command bar as I’ve done here, and when you’re in the target server, print the PrivateServerId to see if it’s still different, if it is then there’s some serious Roblox bug going on here.

Also I’d like to see the output log in a published server to see what the actual result is when teleporting using the current scripts.

This concerns me, I don’t know if other people have stumbled upon this bug, and if they haven’t, I don’t know how I would fix it.

Is there any other value I can grab that would be identical that i can get in both servers?

I do have an idea to just send a message out when a server is created with it’s ID, and then use that. The only problem is that’s a terrible solution



Both sides are identical but it doesnt match
17322379722648891347790029607017
the top one is the private server id
what happened to my image

I think I see what’s going on here.

In your game server script you publish a message to “Servers” which is then picked up by your SubscribeAsync connection.

	if data["ID"] == privateID and data["Type"] == "data" then

This equates to false for your initial publish because the type is request, which seems to be intentional, so that’s fine.

However - I expect to see two calls to this function - one from the game server, and then one from the lobby server. However, in your output log, I only see one “got data!” printed, this tells me that your lobby server isn’t actually sending anything to the game server at all. Which I expect given that the lobby server is shutting down after you leave (since there’s nobody left in it) so there’s no way for it to actually send anything.

You did say that leaving an alt account in the lobby didn’t fix the problem, and while we could relentlessly pursue that, it doesn’t sit well with me to offer a bandaid fix to you, so I propose a rewrite of how you handle this:

LOBBY SERVER:
	if action == "start" then
		
		if lobbyobj.Host.Value == player and lobbyobj.Privacy.Value ~= "Teleporting" then
			
			
			lobbyobj.Privacy.Value = "Teleporting"
			
			local reservedID = game["Teleport Service"]:ReserveServer(18541756425)

			
			local teleportedplayers = {}
			local playerobjects = lobbyobj.Players:GetChildren()
			
			for i = 1,#playerobjects do
				table.insert(teleportedplayers,playerobjects[i].Value)
				-- task.spawn here was unnecessary.
				game.ReplicatedStorage.MiniNotification:FireClient(playerobjects[i].Value,Color3.new(1,1,1),"Teleporting...")
				game.ReplicatedStorage.SublevelChangeScreen:FireClient(playerobjects[i].Value,lobbyobj.Host.Value.Name.."'s Lobby")
			end
			
			
			
			local thehost = lobbyobj.Host.Value.UserId
			local lobbyname = lobbyobj.Name
			
			-- You no longer need the server ID or type since we don't need to identify the server.
			local ServerData = {
				Name = lobbyname,
				Host = thehost
			}
			
			local TeleportOptions = Instance.new("TeleportOptions")
			TeleportOptions.ReservedServerAccessCode = reservedID
			TeleportOptions:SetTeleportData(ServerData)
			
			game:GetService("TeleportService"):TeleportAsync(18541756425, teleportedplayers, TeleportOptions)
			
			game.Debris:AddItem(lobbyobj,10)
			
		else
			
			game.ReplicatedStorage.MiniNotification:FireClient(player,Color3.new(1,0,0),"You are not the host!")
			
		end
	end
GAME SERVER:
local PlayerService = game:GetService("Players")
local SecretServerData = game.ServerStorage.Storage.SecretServerData
local AlreadyStarted = false

local function StartServer(player : Player)
	if AlreadyStarted == true then
		return
	else
		AlreadyStarted = true
	end
	
	local JoinData = player:GetJoinData()
	
	if JoinData == nil then
		warn("Join data was nil!")
		-- If your game relies on this data being present, then you may want to shut down the server if this happens.
		return
	else
		local TeleportData = JoinData.TeleportData
		
		SecretServerData.Host.Value = TeleportData.Host
		SecretServerData.LobbyName.Value = TeleportData.Name
		SecretServerData.HostName.Value = PlayerService:GetNameFromUserIdAsync(TeleportData.Host)
		
	end
	
end

PlayerService.PlayerAdded:Connect(function(player)
	StartServer(player)
end)

A quick note about this though:

I used SetTeleportData and GetJoinData for this, this does inherently leave a slight security risk in the code, as even though teleport data is set on the server, the client is ultimately the one responsible for transmitting it, which means that they could use it to maybe send erroneous/cheated data.

In your case, it appears that you’re using a private lobby system judging by the fact that there’s lobby hosts, and given that we only send the lobby name and who the host is, it’s probably fine as is since the only thing a cheater could do here is change the name or host, which isn’t that impactful in an invite only lobby. Just keep this in mind if you need to use more teleports with more important data being sent across later on down the line.

1 Like

The request is to get the lobby server to send data over to the game server

That’s because the IDs don’t match, so the lobby server never realizes it has to send data back.

Luckily, I don’t need to send any important data lol. Exploiters could only really change the host to someone else.

There are three privacy settings, one of them is public (meaning everyone can join) so it’s not really invite only.

I’ll give it a shot, but one problem.
I used TeleportToPrivateServer because I the documents say TeleportAsync only supports 50 people, and you can choose the player size of your lobbies (up to 200)

I might be able to get around this by splitting the players into groups of 50 and teleporting each group to the same server

If data is nil, it might be because they’re using my legacy lobby system which won’t be transmitting any data.

By the way, your script worked like a charm.

The data is being transmitted correctly and it got received in the game server

1 Like