Using MessagingService to send information to all servers

There are posts but none of them address the problem I’m facing. Everything works fine except for the fact that if you create a new server it only updates the server list with the people in the server that you were in and the servers don’t save on leave. The system allows you to create a reserved server with a custom name and description and a voice chat option. It works by sending the information to the server and putting the server data (ServerID, Name, Description, etc.) into a StringValue and then putting it inside of a Folder which the GUI handler adds all the buttons and text.

ServersHandler:

local serversFolder = game.ReplicatedStorage:WaitForChild("Servers")
local Messenger = require(game.ReplicatedStorage:WaitForChild("Messenger"))
local events = game.ReplicatedStorage:WaitForChild("Events")
local rate = 1

local ms = Messenger.new("ServerList")

local serverData = {
	ServerName = nil,
	Description = nil,
	VCOn = nil,
	ID = nil
}

events.ToServer.Event:Connect(function(c, n, d, vc)
	serverData.ID = c
	serverData.ServerName = n
	serverData.Description = d
	serverData.VCOn = (vc == "ON")
end)


ms:SubscribeAsync(function(message)
	
	local data = message

	game.ReplicatedStorage:WaitForChild("Servers"):ClearAllChildren()
	
	if serverData.ServerName ~= nil and serverData.Description ~= nil and serverData.VCOn ~= nil then
		local serverValue = script.ServerName:Clone()
		serverValue.Name = "Server" .. #serversFolder:GetChildren() + 1
		serverValue.Parent = serversFolder    
		serverValue.Value = (data.serverId or "[UnknownID]") .. " " .. (data.players or "0") .. " " .. (serverData.ServerName or "[N/A]") .. " " .. (serverData.Description or "[No Description]") .. " " .. tostring(serverData.VCOn)
		print(unpack(game.Players:GetPlayers()))
		if data.players == 0 then
			serverValue:Destroy()
		end
	end
	
end)

while true do
	
	local success, err = pcall(function()
		ms:PublishAsync({
			serverId = serverData.ID,
			serverName = serverData.ServerName,
			description = serverData.Description,
			players = #game.Players:GetPlayers(), -- this line is the one that needs to get the player in the reserved server, not this one.
			vcOn = serverData.VCOn or false
		})
	end)

	if not success then
		warn("failed to publish server data: " .. tostring(err))
	end

task.wait(rate)
end

CreateHandler:

local TeleportService = game:GetService("TeleportService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")

local Events = ReplicatedStorage:WaitForChild("Events")
local CreateServer = Events:WaitForChild("CreateServer")

local PLACE_ID = game.PlaceId
local reservedServers = {}

CreateServer.OnServerEvent:Connect(function(player, Desc, Name, VCMode)
	local success, code = pcall(function()
		return TeleportService:ReserveServer(PLACE_ID)
	end)

	if success then
		reservedServers[code] = {
			Description = Desc,
			ServerName = Name,
			VCMode = VCMode,
		}

		game.ReplicatedStorage:WaitForChild("Events").ToServer:Fire(code, Name, Desc, VCMode)
		
		TeleportService:TeleportToPrivateServer(PLACE_ID, code, {player}, nil, {Description = Desc, ServerName = Name, VCMode = VCMode})
	else
		warn("Failed to reserve server; code: " .. tostring(code))
	end
end)

Below is the basic logic of what it does. (Doesn’t use attributes, uses the StringValues value instead. Sorry for bad formatting, i’m new to devforum.)

This could be

serversFolder:ClearAllChildren()

For temporary data to send to another server:
MemoryStoreService
And you can get the id of the private server from the creation of the private server to use as the key. In your case that is the code variable.
As it says in TeleportService | Documentation - Roblox Creator Hub,
all private servers have a id string in game.PrivateServerId, which is “” for public servers.

So basically, create a temporary variable in MemoryStore using code. And then retrieve it using game.PrivateServerId when your server loads.

I found this information from:

More on MemoryStoreService:

1 Like

Thanks! I used this but now i’m not sure how to get the amount of players in the reserved servers (It’s the only problem I have now). I tried using MemoryStoreService like you suggested but now it just displays the amount of players inside of the current server i’m in instead of the actual. Could you help please? Someone said something about using the JobId but not sure how that would work.

local serversFolder = game.ReplicatedStorage:WaitForChild("Servers")
local Messenger = require(game.ReplicatedStorage:WaitForChild("Messenger"))
local events = game.ReplicatedStorage:WaitForChild("Events")
local CreateServer = events:WaitForChild("CreateServer")
local TeleportService = game:GetService("TeleportService")
local PLACE_ID = game.PlaceId
local rate = 5
local Players = game:GetService('Players')
local ms = Messenger.new("ServerList")
local si = Messenger.new("ServerInfo")
local MessagingService = game:GetService("MessagingService")
local JobID = game.JobId
local allServerData = {}
local MemoryStoreService = game:GetService('MemoryStoreService')
local Hashmap = MemoryStoreService:GetSortedMap('PlayersInServers')

local Expiration = 60 * 60 * 24 * 7

local PlrData = {
	PlayerCount = #Players:GetPlayers()
}

local function PlayerCountChanged(ServerId)
	Hashmap:UpdateAsync(ServerId, function(FetchedServerData)
		FetchedServerData.PlayerCount = #Players:GetPlayers()
		PlrData.PlayerCount = FetchedServerData.PlayerCount
		return PlrData
	end, Expiration)
end


CreateServer.OnServerEvent:Connect(function(player, Desc, Name, VCMode)
	local success, code = pcall(function()
		return TeleportService:ReserveServer(PLACE_ID)
	end)

	if success then
		
		Hashmap:SetAsync(code, PlrData, Expiration)
		
		si:PublishAsync({
			Code = code,
			Name = Name,
			Desc = Desc,
			VCMode = VCMode
		})

		TeleportService:TeleportToPrivateServer(PLACE_ID, code, {player}, nil, {
			Description = Desc,
			ServerName = Name,
			VCMode = VCMode
		})
		
	else
		warn("Failed to reserve server; code: " .. tostring(code))
	end
end)

si:SubscribeAsync(function(message)
	local data = message

	allServerData[data.Code] = {
		ID = data.Code,
		ServerName = data.Name,
		Description = data.Desc,
		VCOn = (data.VCMode == "ON")
	}
	
end)

ms:SubscribeAsync(function(message)
	local data = message
	local serverId = data.serverId

	if allServerData[serverId] then
		local serverInfo = allServerData[serverId]
		local serverValue = serversFolder:FindFirstChild("Server: " .. serverId) or script.ServerName:Clone()
		
		serverValue.Name = "Server: " .. serverId
		serverValue.Parent = serversFolder
		serverValue.Value = string.format(
			"%s %d %s %s %s",
			serverId,
			data.players,
			serverInfo.ServerName or "[N/A]",
			serverInfo.Description or "[No Description]",
			tostring(serverInfo.VCOn)
		)
		
		--[[
		if data.players == 0 then
			allServerData[serverId] = nil
			serverValue:Destroy()
		end
		--]]
		
	end
end)

while true do
	for serverId, serverInfo in pairs(allServerData) do
		local success, err = pcall(function()
			
			PlayerCountChanged(serverId)
			
			ms:PublishAsync({
				serverId = serverId,
				serverName = serverInfo.ServerName,
				description = serverInfo.Description,
				players = PlrData.PlayerCount,
				vcOn = serverInfo.VCOn or false
			})
		end)

		if not success then
			warn("Failed to publish server data: " .. tostring(err))
		end
	end
	task.wait(rate)
end

game:BindToClose(function()
	for serverId, serverInfo in pairs(allServerData) do
		local success, err = pcall(function()
			Hashmap:RemoveAsync(serverId)
		end)
	end
end)

The ToServer bindable event isn’t connected across servers. That firing of the new server information only overwrites the info for the current server.

When a reserved server opens, you can take the teleport data off the first player and use that as the server’s info. I don’t believe the ToServer bindable event is necessary here.

1 Like

So I should use MessagingService or MemoryStoreService? (On the new script I fixed it so i’m unsure what to do now.)

Code:

local serversFolder = game.ReplicatedStorage:WaitForChild("Servers")
local Messenger = require(game.ReplicatedStorage:WaitForChild("Messenger"))
local events = game.ReplicatedStorage:WaitForChild("Events")
local CreateServer = events:WaitForChild("CreateServer")
local TeleportService = game:GetService("TeleportService")
local PLACE_ID = game.PlaceId
local rate = 5
local Players = game:GetService('Players')
local ms = Messenger.new("ServerList")
local si = Messenger.new("ServerInfo")
local MessagingService = game:GetService("MessagingService")
local JobID = game.JobId
local allServerData = {}
local MemoryStoreService = game:GetService('MemoryStoreService')
local Hashmap = MemoryStoreService:GetSortedMap('PlayersInServers')

local Expiration = 60 * 60 * 24 * 7

local PlrData = {
	PlayerCount = #Players:GetPlayers()
}

local function PlayerCountChanged(ServerId)
	Hashmap:UpdateAsync(ServerId, function(FetchedServerData)
		FetchedServerData.PlayerCount = #Players:GetPlayers()
		PlrData.PlayerCount = FetchedServerData.PlayerCount
		return PlrData
	end, Expiration)
end



CreateServer.OnServerEvent:Connect(function(player, Desc, Name, VCMode)
	local success, code = pcall(function()
		return TeleportService:ReserveServer(PLACE_ID)
	end)

	if success then
		
		Hashmap:SetAsync(code, PlrData, Expiration)
		
		si:PublishAsync({
			Code = code,
			Name = Name,
			Desc = Desc,
			VCMode = VCMode
		})

		TeleportService:TeleportToPrivateServer(PLACE_ID, code, {player}, nil, {
			Description = Desc,
			ServerName = Name,
			VCMode = VCMode
		})
		
	else
		warn("Failed to reserve server; code: " .. tostring(code))
	end
end)

si:SubscribeAsync(function(message)
	local data = message

	allServerData[data.Code] = {
		ID = data.Code,
		ServerName = data.Name,
		Description = data.Desc,
		VCOn = (data.VCMode == "ON")
	}
	
end)

ms:SubscribeAsync(function(message)
	local data = message
	local serverId = data.serverId

	if allServerData[serverId] then
		local serverInfo = allServerData[serverId]
		local serverValue = serversFolder:FindFirstChild("Server: " .. serverId) or script.ServerName:Clone()
		
		serverValue.Name = "Server: " .. serverId
		serverValue.Parent = serversFolder
		serverValue.Value = string.format(
			"%s %d %s %s %s",
			serverId,
			data.players,
			serverInfo.ServerName or "[N/A]",
			serverInfo.Description or "[No Description]",
			tostring(serverInfo.VCOn)
		)
		
		--[[
		if data.players == 0 then
			allServerData[serverId] = nil
			serverValue:Destroy()
		end
		--]]
		
	end
end)

while true do
	for serverId, serverInfo in pairs(allServerData) do
		local success, err = pcall(function()
			PlayerCountChanged(serverId)
			
			local serverData = Hashmap:GetAsync(serverId)
			local playerCount = serverData.PlayerCount or 1
			
			ms:PublishAsync({
				serverId = serverId,
				serverName = serverInfo.ServerName,
				description = serverInfo.Description,
				players = playerCount,
				vcOn = serverInfo.VCOn or false
			})
		end)

		if not success then
			warn("Failed to publish server data: " .. tostring(err))
		end
	end
	task.wait(rate)
end

game:BindToClose(function()
	for serverId, serverInfo in pairs(allServerData) do
		local success, err = pcall(function()
			Hashmap:RemoveAsync(serverId)
		end)
	end
end)

I mean either MessagingService or MemoryStoreService can accomplish your goal. Unless there’s another problem, you don’t need to change the implementation.

1 Like

Forgot to mention the problem, sorry. There’s this bug where it shows the current player count in your server instead of each separate reserved server. People suggested using the JobID instead of the reserved server code but i’m unsure on how to do that.

PlayerCountChanged updates the hash map for each server with the current server’s player count. The ‘while’ loop also does the same in MessagingService broadcasts.

1 Like

it only updates the server list with the people in the server that you were in and the servers don’t save on leave

I completly don’t understand.
Just tell what do you want achieve.

1 Like

I want the player count to display the amount of players in each reserved server. For some reason it displays the amount of players in your server.

just PublishAsync with serverID and amount of players and SubscribeAsync to receive.

I’m currently doing someting similar to that. The problem is I need it to constantly update.

You dont need. U can just update information when Player joins or leave this reserved server.

1 Like

Someting like this? I cleaned up the code so it works faster. (Still has player count bug)

local serversFolder = game.ReplicatedStorage:WaitForChild("Servers")
local Messenger = require(game.ReplicatedStorage:WaitForChild("Messenger"))
local events = game.ReplicatedStorage:WaitForChild("Events")
local CreateServer = events:WaitForChild("CreateServer")
local TeleportService = game:GetService("TeleportService")
local PLACE_ID = game.PlaceId
local rate = 5
local Players = game:GetService('Players')
local ms = Messenger.new("ServerList")
local si = Messenger.new("ServerInfo")
local MessagingService = game:GetService("MessagingService")
local JobID = game.JobId
local MemoryStoreService = game:GetService('MemoryStoreService')
local Hashmap = MemoryStoreService:GetSortedMap('PlayersInServers')

local Expiration = 60 * 60 * 24 * 7

local function PlayerCountChanged(ServerId)
	local success, serverData = pcall(function()
		return Hashmap:GetAsync(ServerId)
	end)

	if success and serverData then
		serverData.PlayerCount = #Players:GetPlayers()
		Hashmap:SetAsync(ServerId, serverData, Expiration)

		local serverValue = serversFolder:FindFirstChild("Server: " .. ServerId)
		if serverValue then
			serverValue.Value = string.format(
				"%s %d %s %s %s",
				ServerId,
				serverData.PlayerCount,
				serverData.Name or "[N/A]",
				serverData.Desc or "[No Description]",
				tostring(serverData.VCMode)
			)
		end
	end
end

CreateServer.OnServerEvent:Connect(function(player, Desc, Name, VCMode)
	local success, code = pcall(function()
		return TeleportService:ReserveServer(PLACE_ID)
	end)

	if success then
		print(code)
		Hashmap:SetAsync(code, {
			PlayerCount = 1,
			Name = Name,
			Desc = Desc,
			VCMode = VCMode
		}, Expiration)

		si:PublishAsync({
			Code = code,
			Name = Name,
			Desc = Desc,
			VCMode = VCMode
		})

		TeleportService:TeleportToPrivateServer(PLACE_ID, code, {player}, nil, {
			Description = Desc,
			ServerName = Name,
			VCMode = VCMode
		})

	else
		warn("Failed to reserve server; code: " .. tostring(code))
	end
end)

si:SubscribeAsync(function(message)
	local data = message
	local serverValue = script.ServerName:Clone()

	local success, serverData = pcall(function()
		return Hashmap:GetAsync(data.Code)
	end)
	
	print(serverData)
	
	local playerCount = (success and serverData and serverData.PlayerCount) or 1

	serverValue.Name = "Server: " .. data.Code
	serverValue.Parent = serversFolder
	serverValue.Value = string.format(
		"%s %d %s %s %s",
		data.Code,
		playerCount,
		data.Name or "[N/A]",
		data.Desc or "[No Description]",
		tostring(data.VCMode)
	)
end)

while true do
	for _, serverValue in pairs(serversFolder:GetChildren()) do
		local serverStats = string.split(serverValue.Value, " ")
		local reservationCode = serverStats[1]
		PlayerCountChanged(reservationCode)
	end
	task.wait(rate)
end

game:BindToClose(function()
	for serverId, serverInfo in pairs(serversFolder:GetChildren()) do
		local success, err = pcall(function()
			Hashmap:RemoveAsync(serverId)
		end)
	end
end)

Good. Also what are updateasync are doing? As I see u saving information about servers there?

1 Like

Yeah, its to update the server count