Multi-place creator system

I’m creating a game that will feature a system where people can create games within the game and that game will then be available on a server list, essentially the core of retrostudio & similar games.

Do you have any ideas on how to make this idea a reality? I’m not too sure on how this complex-sounding system would function.

4 Likes

create a new place using the asset manager (the template for players to work on with all the building features) and let me know when you are ready for the next step

3 Likes

Apologies for the late reply, I have just created a barebones editor. I appreciate your willpower to assist me through this.

1 Like

Of course!
Alright, next step.
Copy your template id (the editor place id)
Insert a script in your MAIN game in serverscriptservice
this will be the script that handles creating places

local templateId = PASTEYOURTEMPLATEIDHERE
local ts = game:GetService("TeleportService")
local as = game:GetService("AssetService")
local ms = game:GetService("MessagingService")

--receive an event from client to create a server (what I think you are going to do)
local event = Instance.new("RemoteEvent")
event.Name = "CreatePlace"
event.Parent = game:GetService("ReplicatedStorage")

--tell client to update serverlist when new place added
local event2 = Instance.new("RemoteEvent")
event2.Name = "PlaceAdded"
event2.Parent = game:GetService("ReplicatedStorage")

ms:SubscribeAsync("PlaceCreated", function() --listen to others server to update server list
    event2:FireAllClients()
end)

event.OnServerEvent:Connect(function(player, placename)
    local id = as:CreatePlaceAsync(string.format("%d_%s", player.UserId, placename), templateId) --make a new place with the template
    --placename would look like this: userid_placename e.g 1220039795_coolio
    if id then --make sure the place exists
       ts:TeleportAsync(id, {player}) --teleport the player to the template
       event2:FireAllClients()
       ms:PublishAsync("PlaceCreated", "") --tell other servers to update server list
    end
end)
3 Likes

Thanks again for assisting me with this, I tried your provided code adjusting the templateId variable ensuring it is the template ID as well as fired the remote with a test name however it returns the following error:

Game:CreatePlace received and error: HTTP 403 (Forbidden).

Firing remote

local create = game.ReplicatedStorage:WaitForChild("CreatePlace")

local button = script.Parent
local n = "myepicgame"

button.MouseButton1Click:Connect(function()
	create:FireServer(n)
end)
2 Likes

wrap it inside a pcall

local templateId = PASTEYOURTEMPLATEIDHERE
local ts = game:GetService("TeleportService")
local as = game:GetService("AssetService")
local ms = game:GetService("MessagingService")

--receive an event from client to create a server (what I think you are going to do)
local event = Instance.new("RemoteEvent")
event.Name = "CreatePlace"
event.Parent = game:GetService("ReplicatedStorage")

--tell client to update serverlist when new place added
local event2 = Instance.new("RemoteEvent")
event2.Name = "PlaceAdded"
event2.Parent = game:GetService("ReplicatedStorage")

--remind client that place creation failed
local event3 = Instance.new("RemoteEvent")
event3.Name = "PlaceCreationFailed"
event3.Parent = game:GetService("ReplicatedStorage")

ms:SubscribeAsync("PlaceCreated", function() --listen to others server to update server list
    event2:FireAllClients()
end)

event.OnServerEvent:Connect(function(player, placename)
    local id = nil
    local success, err = pcall(function()
        id = as:CreatePlaceAsync(string.format("%d_%s", player.UserId, placename), templateId) --make a new place with the template
    end)
    --placename would look like this: userid_placename e.g 1220039795_coolio
    if not success then
       event3:FireClient(player) --tell player place creation failed
       warn("Place Creation Failed: "..err) --for debugging
       return --exit event
    end
    if id then --make sure the place exists
       ts:TeleportAsync(id, {player}) --teleport the player to the template
       event2:FireAllClients()
       ms:PublishAsync("PlaceCreated", "") --tell other servers to update server list
    end
end)
2 Likes

It seems to still occur pointing to this line with no further information

local id = as:CreatePlaceAsync(string.format("%d_%s", player.UserId, placename), templateId)

1 Like

sorry, that was my mistake for accidentally wrapping the pcall on the wrong part, I’ve edited it so that it shouldn’t error and instead warn a message and send an event to the client

1 Like

OH and if you haven’t already, enable HTTP requests and third party teleports

NEEDED: go to the template place and enable template copying

2 Likes

Thanks!

In this case only API access as well as template copying is required - I didn’t even know template copying was an option until now

I had to modify line 27

local id = as:CreatePlaceAsync(string.format("%d_%s", player.UserId, placename), templateId) --make a new place with the template

Removing the “local” part making it a global variable so that the teleport would work, however it works now!

How would I go about adding host (owner) changeable settings such as player limits, VC only servers, etc? I guess I shouldn’t bother with that until the rest of the system is complete, what would the next step be?

1 Like

customise your gui.
requirements:

  • a popup informing the client that the creation failed
  • the server list containing a template server (the thing that represents the server) including: the place name, the creator’s name + userid and a join button
  • make sure the template is a frame, not visible and not a child of the serverlist
  • have the server list use a UIListLayout (or any other ui layout, UIPadding, UIGridLayout etc)
  • have the popup utilise a button that clears the popup

might have been confusing :frowning:

inside the server list screengui, insert a local script

local id = TEMPLATEPLACEID
local serverList = pathtoserverlist
local serverListTemplate = pathtotemplate --e.g script.Parent.Template
local popup = pathtofailedpopup
local failedEvent = game:GetService("ReplicatedStorage"):WaitForChild("PlaceCreationFailed", 30)
local updateListEvent = game:GetService("ReplicatedStorage"):WaitForChild("PlaceAdded", 30)
local as = game:GetService("AssetService")

failedEvent.OnClientEvent:Connect(function()
    popup.Visible = true
end)

popup.Button.MouseButton1Click:Connect(function()
    popup.Visible = false
end)

updateListEvent.OnClientEvent:Connect(function()
    for _, v in serverList:GetChildren() do
       if not v:IsA("Frame") then continue end
       v:Destroy()
    end
    local places = as:GetGamePlacesAsync() --returns a StandardPages object
    task.spawn(function()
        while true do
           for _, place in places:GetCurrentPage() do
              if place.PlaceId == game.PlaceId or place.PlaceId == id then break end
              local server = serverListTemplate:Clone()
              local creatorId = string.split(place.Name, "_")[1]
              local placeName = string.split(place.Name, "_")[3]
              server.Name = place.Name
              server.Visible = true
              server.PlaceName.Text = placeName
              server.Creator.Text = string.format("By: %s (%d)", game.Players:GetNameFromUserIdAsync(creatorId), creatorId)
              server.Join.MouseButton1Click:Connect(function()
                  game:GetService("TeleportService"):TeleportAsync(place.PlaceId, {game.Players.LocalPlayer})
              end)
              server.Parent = serverList
           end
           if places.IsFinished then break end
           places:AdvanceToNextPageAsync()
        end
    end)
end)

I created a barebones UI & modified the script accordingly and there are no places popping up, even testing on two devices in the actual game (not studio). Does this structure seem about right?
image

I think it might be because of GetGamePlacesAsync()
let’s try a different method
oh and also, add a ‘Join’ button to the template
other than that, yes the structure is good

can you show the localscript

i might be annoying by replying very late :frowning:

I’ve added a button as a child of the template frame named “Join”, here is the current local script

local id = (the actual template place ID)
local serverList = script.Parent.serverlost
local serverListTemplate = script.Parent.template --e.g script.Parent.Template
local popup = script.Parent.failed
local failedEvent = game:GetService("ReplicatedStorage"):WaitForChild("PlaceCreationFailed", 30)
local updateListEvent = game:GetService("ReplicatedStorage"):WaitForChild("PlaceAdded", 30)
local as = game:GetService("AssetService")

failedEvent.OnClientEvent:Connect(function()
	popup.Visible = true
end)

popup.Button.MouseButton1Click:Connect(function()
	popup.Visible = false
end)

updateListEvent.OnClientEvent:Connect(function()
	for _, v in serverList:GetChildren() do
		if not v:IsA("Frame") then continue end
		v:Destroy()
	end
	local places = as:GetGamePlacesAsync() --returns a StandardPages object
	task.spawn(function()
		while true do
			for _, place in places:GetCurrentPage() do
				if place.PlaceId == game.PlaceId or place.PlaceId == id then break end
				local server = serverListTemplate:Clone()
				local creatorId = string.split(place.Name, "_")[1]
				local placeName = string.split(place.Name, "_")[3]
				server.Name = place.Name
				server.Visible = true
				server.PlaceName.Text = placeName
				server.Creator.Text = string.format("By: %s (%d)", game.Players:GetNameFromUserIdAsync(creatorId), creatorId)
				server.MouseButton1Click:Connect(function()
					game:GetService("TeleportService"):TeleportAsync(place.PlaceId, {game.Players.LocalPlayer})
				end)
				server.Parent = serverList
			end
			if places.IsFinished then break end
			places:AdvanceToNextPageAsync()
		end
	end)
end)

Don’t worry about replying late, I’m grateful either way!

yes, the id is supposed to be the actual template place

In the actual script it is, however in this snapshot I removed it just because :slight_smile:

ah lol I see
let’s take a different approach
ill modify the scripts

1 Like

da server script

local templateId = PASTEYOURTEMPLATEIDHERE
local ts = game:GetService("TeleportService")
local as = game:GetService("AssetService")
local ms = game:GetService("MessagingService")
local ds = game:GetService("DataStoreService"):GetDataStore("Places")

local placesTable
local suc = pcall(function()
    placesTable = ds:GetAsync("Places")
end)

if not suc then
   task.spawn(function()
       repeat task.wait(2)
          suc = pcall(function()
              placesTable = ds:GetAsync("Places")
          end)
       until suc
   end)
end

suc = nil

--receive an event from client to create a server
local event = Instance.new("RemoteEvent")
event.Name = "CreatePlace"
event.Parent = game:GetService("ReplicatedStorage")

--tell client to update serverlist when new place added
local event2 = Instance.new("RemoteEvent")
event2.Name = "PlaceAdded"
event2.Parent = game:GetService("ReplicatedStorage")

--remind client that place creation failed
local event3 = Instance.new("RemoteEvent")
event3.Name = "PlaceCreationFailed"
event3.Parent = game:GetService("ReplicatedStorage")

ms:SubscribeAsync("PlaceCreated", function(name) --listen to others server to update server list
    table.insert(placesTable, name)
    local success = pcall(function()
        ds:SetAsync("Places", placesTable)
    end)
    event2:FireAllClients()
end)

event.OnServerEvent:Connect(function(player, placename)
    local name = string.format("%d_%s", player.UserId, placename)
    local id = nil
    local success, err = pcall(function()
        id = as:CreatePlaceAsync(name, templateId) --make a new place with the template
    end)
    --placename would look like this: userid_placename_placeid e.g 1220039795_coolio_1929383
    if not success then
       event3:FireClient(player) --tell player place creation failed
       warn("Place Creation Failed: "..err) --for debugging
       return --exit event
    end
    if id then --make sure the place exists
       table.insert(placesTable, string.format("%s_%d", name, id)
       local success = pcall(function()
           ds:SetAsync("Places", placesTable)
       end)
       event2:FireAllClients()
       ms:PublishAsync("PlaceCreated", name) --tell other servers to update server list
       ts:TeleportAsync(id, {player}) --teleport the player to the template
    end
end)

localscript

local id = (the actual template place ID)
local serverList = script.Parent.serverlost
local serverListTemplate = script.Parent.template --e.g script.Parent.Template
local popup = script.Parent.failed
local failedEvent = game:GetService("ReplicatedStorage"):WaitForChild("PlaceCreationFailed", 30)
local updateListEvent = game:GetService("ReplicatedStorage"):WaitForChild("PlaceAdded", 30)
local as = game:GetService("AssetService")

failedEvent.OnClientEvent:Connect(function()
	popup.Visible = true
end)

popup.Button.MouseButton1Click:Connect(function()
	popup.Visible = false
end)

updateListEvent.OnClientEvent:Connect(function()
	for _, v in serverList:GetChildren() do
		if not v:IsA("Frame") then continue end
		v:Destroy()
	end
        local places
        local success = pcall(function()
            places = game:GetService("DataStoreService"):GetDataStore("Places"):GetAsync("Places")
        end)
		for _, place in places do
		   if place:split("_")[5] == game.PlaceId or place:split("_")[5] == id then break end
			local server = serverListTemplate:Clone()
			local creatorId = string.split(place, "_")[1]
			local placeName = string.split(place, "_")[3]
            local placeId = string.split(place, "_")[5]
			server.Name = place
			server.Visible = true
			server.PlaceName.Text = placeName
			server.Creator.Text = string.format("By: %s (%d)", game.Players:GetNameFromUserIdAsync(creatorId), creatorId)
			server.MouseButton1Click:Connect(function()
				game:GetService("TeleportService"):TeleportAsync(place, {game.Players.LocalPlayer})
			end)
		server.Parent = serverList
	end
end)

You forgot a closing bracket on server script line 60 :slight_smile:
I tested the code you provided and it is returning a 403 forbidden from server script line 56

yeah im typing this out on mobile, errors should be fixed easily (i hope its easy for you to fix)

wait my code only has 39 lines

1 Like