Query players in reserved server

Feature request:
A method for querying players within a specific server. It would return a table of PlayerIDs.

Use Case:
As a developer, I want to be able to know what players are currently in my matches, so that I can repopulate the matches appropriately on the fly.

Example:

local players = teleportService:GetPlayersInReservedServer(reservedServerAccessCode)

Ideally, it will throw an error if the server doesn’t belong to the creator, or the server doesn’t exist (e.g. invalid reservedServerAccessCode).


Current Problem:
With reserved servers, I do not know who is still in them. I can send players to it, but I don’t know which players have left. Therefore, I don’t know the current number of players in the match. If I want the match to keep itself alive, I need to be able to query the players in the match so that I know how to repopulate it.

Current Workaround:
Currently, there are two ways to handle this situation. The first solution is to use DataStores to communicate this data. This seems to have been unreliable for other devs though. The second solution is using the HttpService (my preference), but that requires that a user can host a server and build a system to handle matchmaking–that’s a bit overkill for most.

Solution:
Supply a way for developers to query the players in a reserved server. Considering the main website displays users in each server, I would imagine this wouldn’t be a huge challenge, but I don’t know the underlying system that handles it.


Extended example:
A match is created. Every 10 seconds, the match is queried to see how many players are in the match. If not enough, players are added again.

local teleportService = game:GetService("TeleportService")

-- The Match class:
local Match = {}
Match.__index = Match

-- Create new match instance:
function Match.new(placeId)
	local match = setmetatable({
		AccessCode = teleportService:ReserveServer(placeId);
		PlaceId = placeId;
	}, Match)
	return match
end

-- Utilize suggested feature:
function Match:GetPlayers()
	return teleportService:GetPlayersFromReservedServer(self.AccessCode)
end

function Match:AddPlayers(...)
	local players = {...}
	teleportService:TeleportToPrivateServer(self.PlaceId, players)
end

------------------------------------

-- Create a new match:
local match = Match.new(000000)

-- Add players:
match:AddPlayers(player1, player, player3)

-- Continuously monitor server:
spawn(function()
	while (true) do
		wait(10)
		local playersInMatch = match:GetPlayers()
		if (#playersInMatch < 3) then
			for i = 1,3 - #playersInMatch do
				-- Add a player
			end
		end
	end
end)

Caveats:

  • What happens when the match server closes?
  • Should data also be queried about the max players allowed in the server?
  • Throttle limits?
  • Could :GetPlayerPlaceInstanceAsync() be a viable alternative?

Other features that would help facilitate matchmaking:

  • ReserveServer should return a JobId too

Final Note:

With the currently available APIs, it is not possible to do proper matchmaking. It feels as if we have been given a half-finished set of tools to do matchmaking. I do not say that to talk badly about the devs/engineers–you guys are awesome–but simply to point out the reality of the current condition.

19 Likes

Should be by jobId rather than solely for reserved servers so that we can fetch this information for any type of server.

7 Likes

Can we also please just get an API to check if a server is reserved and if so get its reserved server code form within that server?

8 Likes

The biggest problem with that is that reserving a server does not return a jobId, but only a reserved access code.

Therefore, I would absolutely agree with you if reserving a server gave us a jobId. In fact, it might be worth making a whole separate request for that entirely. I definitely feel that having ReserveServer() return a jobId too makes a lot of sense.

3 Likes

The problem with that is that the JobId changes every time the server starts, but one Reserved Server code can lead to multiple instances of servers.

So if a reserved server is full, subsequent teleports will create more servers assigned to that same reserved code? That seems like undesirable behavior. It’s a reserved server (singular). I would think more correct behavior would be to return a teleport fail due to the server being full.

You misunderstood my comment.
Let’s say a reserved server exists at 2:00 PM. The players in the server all leave by 3:30 PM that same day. Then by 3:35 PM, that server has closed, right? But let’s say you use the same reserved server code at 4:00 PM. It’s going to use the same reserved server code, but it will start a new instance, and hence a new JobId.

1 Like

To expand to the feature request, if we had a method to query a current reserved server’s JobId by its ReservedServerCode, the rest of the API could make use of the job id. If a server isn’t available for that reserved server code during the gaps, it can return an error, as there is no JobId available for the code.

I do think that allowing usage of a JobId is much more flexible, as it also allows the API to work on regular servers.

Lua uses nil instead of the error lower-level languages would use, so I would think that’d be more appropriate here.

Maybe. My logic just goes by that it’s network-dependent, like data store calls and GetPlayerPlaceInstanceAsync. Like the latter mentioned, it will error if anything goes wrong with the lookup.
Returning nil makes it easier to differentiate between the cause of the problem, but thus also creates more cases that needs to be checked.

DataStores’ GetAsync will return nil instead of erroring when a key is empty. They only error when there’s actually an error accessing web services.

GetPlayerPlaceInstanceAsync is just wrong. Lua is high level: attempts to access a nonexisting value returns nil – not an error.

1 Like