I’m having an issue with saving the character’s position when the player leaves. I want to try to avoid a loop constantly saving the player’s position but if it’s the only way then so be it. Here’s my current code:
local function savePlayerPosition(plr)
plr.CharacterRemoving:Connect(function(char)
local hrp = char:FindFirstChild("HumanoidRootPart")
local pos = {hrp.Position.X, hrp.Position.Y, hrp.Position.Z}
print(pos) --doesn't print
datastore:SetAsync(plr.UserId.."_lastpos", pos)
end)
end
local function loadPlayerPosition(plr)
plr.CharacterAdded:Connect(function(char)
local pos = datastore:GetAsync(plr.UserId.."_lastpos")
if pos == nil then return end --stops here cuz no pos
local x, y, z = pos[1], pos[2], pos[3]
print(x,y,z)
char.HumanoidRootPart.Position = Vector3.new(x,y,z)
end)
end
Players.PlayerAdded:Connect(loadPlayerPosition)
Players.PlayerRemoving:Connect(savePlayerPosition)
Some other posts I looked at but didn’t seem to work:
Also tried using BindToClose with a task.wait(3) but it didn’t seem to change much. Let me know if my code is wrong or I’m missing something if that’s the case. Thanks
You didn’t really explain what the issue is, but looking at your code
This doesn’t print because CharacterRemoving is being connected as the player is leaving. What you can try doing, instead, is checking whether the player has a character or not as they are leaving, and consequentially saving the position of their character:
I also made sure to actually use the HRP variable properly since you were using FindFirstChild but not really doing anything with it. FindFirstChild is used to check whether an instance exists or not. You were using it but not checking if the HRP actually exists, so you could’ve just done char.HumanoidRootPart instead.
Thanks for the response. I should’ve explained better though, what I want is for the player’s position to save when they leave the game so that I can move them to the position when they join back. It doesn’t seem like plr.CharacterRemoving:Connect(function() is running at all when I leave the game, (placed a print() statement right after). The saving seems to work fine.
Yep, I figured that’s what you were trying to do. My method basically gets rid of CharacterRemoving since it’s not needed. Since we know the player is getting removed, we can just check if they have a character as they are leaving, and then use that to save its position. Unless my code doesn’t work then, I didn’t test it so let me know if you try it
Oh, my mistake. The code sample seems to work with PlayerRemoving but I’m still a bit iffy since I saw some people on the devforum say it occasionally doesn’t pickup on the character. I’ll do some testing, thanks
local function savePlayerPosition(plr)
print("char")
local char = plr.Character
if char == nil then return end
local hrp = char:FindFirstChild("HumanoidRootPart")
if hrp == nil then return end
local pos = {hrp.Position.X, hrp.Position.Y, hrp.Position.Z}
print(pos) --doesn't print
datastore:SetAsync(plr.UserId.."_lastpos", pos)
end
Alright then it’s possible the character is treated like when it falls under position -500 and every instance in it is removed (besides the humanoid). So another solution I can think of is to connect the CharacterRemoving function under the PlayerAdded one. Even tho this would mean the position is saved with every respawn, it shouldn’t be a big deal tho.
This should work to achieve what you’re looking for:
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local dataStore = DataStoreService:GetDataStore("Example") -- Change the name to match the real name of your DataStore
local function savePlayerPosition(player: Player)
if player.Character then
local position = player.Character:GetPivot().Position -- Same as doing player.Character.HumanoidRootPart.Position
local data = {position.X, position.Y, position.Z}
print(data)
local success, error = pcall(dataStore.SetAsync, dataStore, player.UserId.."_lastpos", data)
if success then return end
warn(`Unable to save position for Player {player.UserId} ({player.DisplayName})\nError: {error}`)
else
warn(`Unable to save position for Player {player.UserId} ({player.DisplayName}), as they currently have no character`)
end
end
game:BindToClose(function()
local x, y = 0, 0
local function onBindToClose(player: Player)
savePlayerPosition(player)
y += 1
end
for _, player in Players:GetPlayers() do
x += 1
task.spawn(onBindToClose, player)
end
repeat task.wait() until y == x
end)
Players.PlayerRemoving:Connect(savePlayerPosition)
I’m connecting the savePlayerPosition function to Players.PlayerRemoving at the last line, so it will save the data for any player that leaves the game, not just the last one to leave. The BindToClose is there to save the positions of each player present in the case that the server randomly shuts down
Seems like it cannot find the character still. Unable to save position for Player 861475515 (kekprod), as they currently have no character
Correct me if I inserted your code incorrectly.
local function savePlayerPosition(player: Player)
if player.Character then
local position = player.Character:GetPivot().Position -- Same as doing player.Character.HumanoidRootPart.Position
local data = {position.X, position.Y, position.Z}
print(data)
local success, error = pcall(datastore.SetAsync, datastore, player.UserId.."_lastpos", data)
if success then return end
warn(`Unable to save position for Player {player.UserId} ({player.DisplayName})\nError: {error}`)
else
warn(`Unable to save position for Player {player.UserId} ({player.DisplayName}), as they currently have no character`)
end
end
game:BindToClose(function()
local x, y = 0, 0
local function onBindToClose(player: Player)
savePlayerPosition(player)
y += 1
end
for _, player in Players:GetPlayers() do
x += 1
task.spawn(onBindToClose, player)
end
repeat task.wait() until y == x
end)
local function loadPlayerPosition(plr)
plr.CharacterAdded:Connect(function()
local char = plr.Character
local pos = datastore:GetAsync(plr.UserId.."_lastpos")
if pos == nil then return end --stops here cuz no pos
if char == nil then return end
local x, y, z = pos[1], pos[2], pos[3]
print(x,y,z)
char.HumanoidRootPart.Position = Vector3.new(x,y,z)
end)
end
Players.PlayerAdded:Connect(loadPlayerPosition)
Players.PlayerRemoving:Connect(savePlayerPosition)
Try setting Workspace’s PlayerCharacterDestroyBehavior to Disabled (needs to be done in the Properties tab). It could be that the player’s character is being destroyed as soon as the player attempts to leave the game, which would explain why all the code so far is failing to work
I was able to replicate the problem: It seems player.Character is always nil when used in the PlayerRemoving event
Doing this instead has fixed the issue for me:
local function savePlayerPosition(player: Player)
if player.Character then
local position = player.Character:GetPivot().Position -- Same as doing player.Character.HumanoidRootPart.Position
local data = {position.X, position.Y, position.Z}
print(data)
local success, error = pcall(datastore.SetAsync, datastore, player.UserId.."_lastpos", data)
if success then return end
warn(`Unable to save position for Player {player.UserId} ({player.DisplayName})\nError: {error}`)
else
warn(`Unable to save position for Player {player.UserId} ({player.DisplayName}), as they currently have no character`)
end
end
game:BindToClose(function()
local x, y = 0, 0
local function onBindToClose(player: Player)
savePlayerPosition(player)
y += 1
end
for _, player in Players:GetPlayers() do
x += 1
task.spawn(onBindToClose, player)
end
repeat task.wait() until y == x
end)
local function loadPlayerPosition(plr)
plr.CharacterAdded:Connect(function()
local char = plr.Character
local pos = datastore:GetAsync(plr.UserId.."_lastpos")
if pos == nil then return end --stops here cuz no pos
if char == nil then return end
local x, y, z = pos[1], pos[2], pos[3]
print(x,y,z)
char.HumanoidRootPart.Position = Vector3.new(x,y,z)
end)
plr.CharacterRemoving:Connect(function()
savePlayerPosition(plr)
end) -- This does mean the position will also be saved when the player resets, though
end
Players.PlayerAdded:Connect(loadPlayerPosition)
Although it will also save the position when the player resets, but at least it does save it right before the player leaves the game
Thanks for the help. But it doesn’t seem to be working even still. Unable to save position for Player 861475515 (kekprod), as they currently have no character on disconnect (studio playtest stop is how i’m disconnecting)
Works on reset though. (prints position, I think my loading code is probably poor)
local characters = {}
local function savePlayerPosition(player: Player)
if characters[player] then
local position = characters[player]:GetPivot().Position -- Same as doing player.Character.HumanoidRootPart.Position
local data = {position.X, position.Y, position.Z}
print(data)
characters[player] = nil -- So that the table is cleaned up
local success, error = pcall(datastore.SetAsync, datastore, player.UserId.."_lastpos", data)
if success then return end
warn(`Unable to save position for Player {player.UserId} ({player.DisplayName})\nError: {error}`)
else
warn(`Unable to save position for Player {player.UserId} ({player.DisplayName}), as they currently have no character saved in the characters table`)
end
end
game:BindToClose(function()
local x, y = 0, 0
local function onBindToClose(player: Player)
savePlayerPosition(player)
y += 1
end
for _, player in Players:GetPlayers() do
x += 1
task.spawn(onBindToClose, player)
end
repeat task.wait() until y == x
end)
local function loadPlayerPosition(plr)
plr.CharacterAdded:Connect(function(char)
characters[plr] = char
local success, pos = pcall(datastore.GetAsync, datastore, plr.UserId.."_lastpos")
if success then
if pos then
char:MoveTo(Vector3.new(pos[1], pos[2], pos[3]))
end
else
warn(`Failed to get data for Player {plr.UserId} ({plr.DisplayName})\nError: {pos}`)
end
end)
end
Players.PlayerAdded:Connect(loadPlayerPosition)
Players.PlayerRemoving:Connect(savePlayerPosition)
I’m storing the player’s character inside of a table that is updated each time the player spawns a new character, and when the player is leaving the game, I’m retrieving their character from that table instead of using player.Character
I also went ahead and cleaned up the function for when the data is being loaded