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
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?
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
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
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
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