Ok so the problem you’re having is that you cannot save accessories to the datastore. Creating a different table and adding the hats to them is the exact same thing as what you started with (you may not be getting an error because studio doesn’t always have time to save data when the server shuts down).
This would be a WHOLE LOT easier if you could save things other than numbers/strings to the datastore, but if each player is bringing in a new accessory then there’s really no point having every accessory saved to your game permanently, so you will need to use InsertService.
Definitely check the datastore article out
I had to do a few things to get this to work…First I needed to change your SetAsync index; you had the GetAsync
set as LocalPlayer.UserId.."-hats"
which is fine, but you will need to SetAsync to the same thing. Then, I needed to get the website ID’s for all accessories on the character; you cannot do this with the meshId because it is an AssetId, and will return nothing with InsertService. I used GetCharacterAppearanceInfoAsync()
to retrieve the info from the character, then indexed it searching for only accessories (whitelisted asset types stored in assetWhiteList
). The function getInfo
returns the ID’s of all of the player’s accessories in a table. When a player leaves, the function save()
takes the player’s info and userID before it disappears, then sets the datastore to the accessory list returned by getInfo()
.
When the player joins and there is data, just for example I made the script will delete the players hats, waits 2 seconds and uses the function spawnHats()
to use the InsertService to spawn the hats by their ID’s, then use the AddAccessory
function to the player’s Humanoid.
Of course you can do whatever you want with this info, but I didn’t know your end goal.
You may notice at the bottom I use game:BindToClose()
; this function allows the game to complete datastore saves before shutting down as the last player leaves. This is useful in studio since you are the last person to leave, but will be even more important in-game so that the game doesn’t shut down before data is saved.
All-in-all, I HIGHLY recommend against using a server script for datastores; use a modulescript. Also, make sure to autosave often, because there may be times when a player leaves and their data cannot be saved for one reason or another.
Code:
local DataStoreService = game:GetService("DataStoreService")
local ClothingData = DataStoreService:GetDataStore("ClothingSave")
local InsertService = game:GetService("InsertService")
local assetWhiteList = {
"Hat",
"Shoulder Accessory",
"Waist Accessory",
"Hair Accessory",
"Back Accessory",
"Face Accessory",
"Front Accessory"
}
function save(LocalPlayer)
local info = game.Players:GetCharacterAppearanceInfoAsync(LocalPlayer.UserId)
local userId = LocalPlayer.UserId
local success, errormessage = pcall(function()
ClothingData:SetAsync(LocalPlayer.UserId.."-hats", getInfo(userId, info))
end)
if success then
print("Success")
else
warn(errormessage)
end
end
function getInfo(userId, info)
if not info then
info = game.Players:GetCharacterAppearanceInfoAsync(userId)
end
local accessoryIdList = {
}
for i,v in ipairs(info['assets']) do
local whiteListed = false
for index, item in ipairs(assetWhiteList) do
if item == v.assetType.name then
whiteListed = true
end
end
if whiteListed then
local AssetId = v.id
table.insert(accessoryIdList, AssetId)
end
end
return accessoryIdList
end
function spawnHats(LocalPlayer, hats)
for i, v in ipairs(hats) do
local success, model = pcall(InsertService.LoadAsset, InsertService, v)
if success and model then
print("Model loaded successfully")
model.Parent = game.Lighting
LocalPlayer.Character:WaitForChild("Humanoid"):AddAccessory(model:FindFirstChildOfClass('Accessory'))
model:Remove()
else
print("Model failed to load!")
end
end
end
game.Players.PlayerAdded:Connect(function(LocalPlayer)
LocalPlayer.CharacterAppearanceLoaded:Connect(function(character)
local PlayerData
local success, data = pcall(function()
PlayerData = ClothingData:GetAsync(LocalPlayer.UserId.."-hats")
return PlayerData
end)
if data then --previous hat data exists
PlayerData = data
character:WaitForChild('Humanoid'):RemoveAccessories()
wait(2)
spawnHats(LocalPlayer, PlayerData)
print("success")
else
warn(data)
end
end)
end)
game.Players.PlayerRemoving:Connect(function(LocalPlayer)
save(LocalPlayer)
end)
game:BindToClose(function()
for _, LocalPlayer in ipairs(game:GetService('Players'):GetPlayers()) do
save(LocalPlayer)
print('done')
end
end)