Create Place Error

Hey guys, I’ve been looking up this error " 18:50:08.168 - Game:CreatePlace received and error: HTTP 0 (HTTP 403)." and have tried what people have suggested (like moving the models i made to my group and making them public) but the game still wont let me teleport.

This is where the Error is and this is players teleporting to the arena not after. So I don’t if there is going to be another error teleporting back to the lobby:

local arenaPlaceId = game:GetService("AssetService"):CreatePlaceAsync(
		"Arena place for " .. playerA.Name .. " and " .. playerB.Name, arenaPlaceTemplateId)
 
	-- Bind OnTeleport event to playerA (who is teleported first). If that teleport is successful
	-- then we want playerB to be teleported to the same instance
	local connection = playerA.OnTeleport:connect(function(teleportState, placeId)
		if teleportState == Enum.TeleportState.Started then
			local teleportStarted = os.time()
			-- Keep checking if playerA has arrived in other instance.
			while true do
				local success, error, placeId, arenaInstanceId = teleportService:GetPlayerPlaceInstanceAsync(playerAId)
				-- If playerA is in the correct place then we can teleport playerB there as well
				if placeId == arenaPlaceId then
					teleportService:TeleportToPlaceInstance(arenaPlaceId,playerB)
					return
				end
				wait()
			end	
		end
	end)
	wait(1)
	
	-- Teleport playerA to the arena
	teleportService:Teleport(arenaPlaceId, playerA)
end
 
-- Matchmaking loop. Cycles about every 5 seconds to match players.
while true do
	local now = os.time()
	-- Cycle through queue, try to find players in range
	for _, mmData in pairs(matchMakingQueue) do
		print("attempting to find match for " .. mmData.UserId)
		-- Get rank range to search
		local range = getRange(now - mmData.EnteredQueue)
		-- Use list to find a player in player's rank range
		local otherPlayerId = rankedList:FindPlayerInRange(mmData.UserId, range)
		if otherPlayerId then
			-- Another player was found. Remove both players from the queue and list so they
			-- can't be matched with anyone else
			print("found player: " .. otherPlayerId)
			rankedList:RemovePlayer(mmData.UserId)
			rankedList:RemovePlayer(otherPlayerId)
			removeFromMMQueue(mmData.UserId)
			removeFromMMQueue(otherPlayerId)
			-- Start game with the two players. This function can take some times, so start a
			-- coroutine so the loop can continue.
			local thread = coroutine.create(function() startGame(mmData.UserId, otherPlayerId) end)
			coroutine.resume(thread)

I have been looking at the wiki and following along their matchmaking guide as well

4 Likes

Have you enabled the SavePlaceAPI in game settings on the website?

yes, I just tried it again and it does not teleport

This has been a commonly reported issue with the CraetePlace API and there hasn’t been a concrete solution provided yet. I honestly think that the endpoints are locked but either way, these errors are rightfully received: this is where the Developer Community gets to step in and tell you not to use it.

If your intentions are to make a matchmaking queue, use reserved servers. Roblox can issue instances at no cost, whereas creating places also takes up storage space since it creates the place asset and everything. Do not use CreatePlace for matchmaking.

Yea, it seems CreatePlace is unofficially unsupported.

In general, I wouldn’t use it. (Some reasons for not using it include difficulties updating, etc)

With reserved servers, no one should have a use for Create/Save APIs anyway. I don’t understand what games would still need them. The only thing I can think of is build servers but even then, most of those build games either

A) Don’t exist.
B) Have a better system in place.

Reserved servers are the way to go. They don’t incur costs for Roblox either. Ditch CreatePlace.

How would I be able to implement reserved servers into the current code I have?

ReserveServer returns an access code that you use with TeleportService.TeleportToPrivateServer, so really the simple answer is to redo your code around these functions. Documentation is available in any linked pages and has some code examples as well. There are also several examples on the DevForum.

Instead of relying on the PlaceId returned by CreatePlaceAsync, you use the access code returned by ReserveServer and send players over. Use the arena place Id as the place to reserve a server from.

There’s not that much to changing from CreatePlaceAsync to ReserveServer. Give it a try and you can post any implementation troubles you might have (provided you debug/attempt fixes first).

So i fixed it and there is no longer that error, but it still does not teleport. It says in the output that they are teleporting but I wait 5 minutes and none of them do.

local arenaPlaceId = teleportService:TeleportToPrivateServer(arenaPlaceTemplateId)
 
	-- Bind OnTeleport event to playerA (who is teleported first). If that teleport is successful
	-- then we want playerB to be teleported to the same instance
	local connection = playerA.OnTeleport:connect(function(teleportState, placeId)
		if teleportState == Enum.TeleportState.Started then
			local teleportStarted = os.time()
			-- Keep checking if playerA has arrived in other instance.
			while true do
				local success, error, placeId, arenaInstanceId = teleportService:GetPlayerPlaceInstanceAsync(playerAId)
				-- If playerA is in the correct place then we can teleport playerB there as well
				if placeId == arenaPlaceId then
					teleportService:ReserveServer(arenaPlaceId, playerB)
					return
				end
				wait()
			end	
		end
	end)
	wait(1)
	
	-- Teleport playerA to the arena
	teleportService:Teleport(arenaPlaceId, playerA)
end
 
-- Matchmaking loop. Cycles about every 5 seconds to match players.
while true do
	local now = os.time()
	-- Cycle through queue, try to find players in range
	for _, mmData in pairs(matchMakingQueue) do
		print("attempting to find match for " .. mmData.UserId)
		-- Get rank range to search
		local range = getRange(now - mmData.EnteredQueue)
		-- Use list to find a player in player's rank range
		local otherPlayerId = rankedList:FindPlayerInRange(mmData.UserId, range)
		if otherPlayerId then
			-- Another player was found. Remove both players from the queue and list so they
			-- can't be matched with anyone else
			print("found player: " .. otherPlayerId)
			rankedList:RemovePlayer(mmData.UserId)
			rankedList:RemovePlayer(otherPlayerId)
			removeFromMMQueue(mmData.UserId)
			removeFromMMQueue(otherPlayerId)
			-- Start game with the two players. This function can take some times, so start a
			-- coroutine so the loop can continue.
			local thread = coroutine.create(function() startGame(mmData.UserId, otherPlayerId) end)
			coroutine.resume(thread)
		end
	end
	wait(5)
end

Is this the correct way to implement it?

No. You’re still making use of old teleport methods and passing in no arguments to TeleportToPrivateServer. TeleportToPrivateServer is a teleport method, ReserveServer creates an instance at the target place. You might in fact have used them backwards judging from a brief review.

Another note: the beauty of TeleportToPrivateServer is that you can use it like TeleportPartyAsync. You don’t need to rely on all that OnTeleport nonsense. You can teleport both players to the same instance at once, as TeleportToPrivateServer accepts a table of players.

Watch. You can do the whole operation in three or less lines.

local serverAccessCode = teleportService:ReserveServer(arenaPlaceId)
local playersToTeleport = {playerA, playerB}

teleportService:TeleportToPrivateServer(arenaPlaceId, serverAccessCode, playersToTeleport)

-- The rest below is your matchmaking code. No need to change any of that.

The point: get the two players who are being matchmade (playerA and playerB) through your matchmaking loop, that stays the same. The only part that changes is the teleporting to the server. Instead of relying on another player’s teleport, we flatten that down because of the awesomeness of working with reserved servers.

Old workflow (your current workflow):

  • Create a place (or reserve a server)
  • Teleport one player
  • Wait until that player telepotrs, keep checking their InstanceId
  • Teleport the second player if the first one makes it

New workflow (what I suggest):

  • Gather the players that are in the queue
  • Reserve a server and get the access code
  • Teleport both the players at once

Won’t list the caveats or benefits, they should be self explanatory. You can check player arrivals at the receiving place itself through any method you like. For example, you can send some data over that determines who should be in the server and then wait until both of them are in.


Some future planning worth noting:

In the future (potentially this year), developers (may/will) get access to ephemeral DataStores. These are DataStores except with high read and write times and are typically used for temporary data transferring or storage. If and when these are available, you could set up an ephemeral DataStore for data.

The workflow will essentially be using the second return value of ReserveServer, the JobId of the server you just reserved. Then, you can save the queued players as values to the DataStore using the JobId as a key. When the players arrive, you pull this data and make sure that both players arrive. If not, clean up and return the players who did teleport to the lobby.

All of this is just for reference in the future and things I thought were worth noting. Don’t worry too much about the bottom half of this post for now. That’s a topic worth revisiting if and when ephemeral DataStores are made available.

2 Likes

Thank you for this, really. For some reason though it 's still not teleporting. I saw two other errors but i don’t think its related.
20:47:41.257 - ServerStorage.NoviceF.RankListN:26: attempt to index local ‘node’ (a nil value) and
20:50:00.824 - Barriers is not a valid member of Workspace

Yeah, those aren’t related to the thread. Those ones may be worth skimming over your code for. As for not teleporting, are you aware of any issues with the presented code or a conflicting line of code that’s preventing the teleport? Errors in the same script can hamper functionality.

The only other errors the come up are because group rank, Error checking in group: Player:GetRankInGroup failed because HTTP 0 (HTTP 400), other than that maybe this part of the code could be the problem? (This comes right before the code you gave me)

-- Creates place for game and teleports both players to it
local startGame = function(playerAId, playerBId)
	local message = ""
	print("starting game with " .. playerAId .. " and " .. playerBId)
	
	-- Get both player objects
	local playerA = nil
	local playerB = nil
	for _, player in pairs(game.Players:GetPlayers()) do
		if player.userId == playerAId then
			playerA = player
		end
		if player.userId == playerBId then
			playerB = player
		end
	end

if you want me to post my whole main script, I could do that.

That error only appears in Roblox Studio in a local test server. A live server shouldn’t present you with that HTTP error. If I recall correctly, this error occurs because your local machine can’t send requests directly to a Roblox server which is what happens with local tests. Only Roblox game servers can do that.

Grab a friend or an extra device and try working with it online. Alternatively though, if you don’t want to do that or can’t, I suggest handling this error with your own debug condition and return pseudovalues that can be used in local tests. The first thing is to pcall the function, which should be done with any web calls. By debug condition, I mean something like a value you can add or remove in Studio to toggle behaviours you add to your script.

-- Player is of course to be replaced with the player you're checking
local success, result = pcall(Player.GetRankInGroup, Player, GroupId)

Once you have the success boolean from the pcall, you can handle that error case. For example, if you have a callback that returns the value from GetRankInGroup, your non-success case can return 255 or the required rank to bypass the conditions.

It’s all about working around those errors. Pcall is the best way to help you work around such issues. Set up your regular cases, then in case of error use the bypass values.

oh I’ve tried it with another client ( having Roblox in the Microsoft store) and it still won’t teleport.

I’ll forward a message via DM so that the conversation can be continued. Don’t want to fill the thread up while trying to prod at the problem. I find that result to be interesting.