Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

Can't find the logical error in my code [Datastores]?

Asked by 8 years ago

Hello.I've spent at least a few hours now trying to debug/find the error of what is causing the issue to occur,but to no avail.Here is my issue:

When a Player joins the game,their data is loaded from the datastore and put into their data folder in ServerStorage.

When a Player leaves the game,their data is put into a metatable and saved to the datastore.

Pretty straightforward,until the bug comes in.

For some odd reason,the weapons and pets that the player owns are cloned repeatedly inside the datastore.Also,data between two players gets mixed together for some odd reason..

For example:

Player A owns the weapon "LinkedSword".It is saved in the 'Weapons' metatable,and inside the 'Weapons' folder when loaded into his/her datafolder.Player A owns the pet "Doge",which is saved inside the 'Pets' metatable,and inside the 'Pets' folder when loaded into the datafolder.

With Player B,the same scenario is in place with how the data is stored. Player B owns the weapon "GolfClub",and owns the pet "Kitty".

All runs well,when the player joins their data is loaded into the server,when they leave the data is put inside a metatable and saved to the datastore.But here's the problem:

Next time Player A's data is loaded,he/she now owns the pets "Doge" and "Kitty" and "Kitty" and "Kitty" (Yes,the cloning is what happens).Same with the saved weapons.The data seems to "Cross" between the two players,even though they have their own seperate datafolders.

I am completely stumped.If someone can point out the logic error,please do. Thanks!

Here is the code:

DataService script:

--[[

    Data Service
    Handles the loading,saving,and handling of user data.   

--]]

--Waiting for the main framework to load.
_G.DataServiceReady=false
while _G.ServerReady==nil or _G.ServerReady==false do
wait()
end
--Calling the datastore service
local DataStore=game:GetService("DataStoreService"):GetDataStore(_G.Config.DataStoreName)

--Declaring vairables and functions
_G.BaseData={
ChosenWeapon="", --The weapon that the user is actively using
Version=1,            --The users data version.Used to add more metatables if the base data is updated.
Money=0,              --The users current amount of NoobCoins
Level=1,              --The users current level
ChosenPet="",     --The current pet the user has chosen
NoobChance=1,         --How likely the user will become a noob.
Pets={},              --A table holding the pets the user owns
Weapons={}            --A table holding the weapons the user owns
}

--Gets the specified users data,and returns it.WILL return nil if it doesn't
--exist.
--Usage: _G.GetUserData(Object PLAYER)
--Example:_G.GetUserData(game.Players.Reshiram110)
_G.GetUserData=function(Player)
if DataStore:GetAsync("User_"..Player.userId)==nil then
local dat=_G.BaseData
dat.ChosenWeapon="LinkedSword"
table.insert(dat.Weapons,"LinkedSword")
return dat
else
return DataStore:GetAsync("User_"..Player.userId)
end
end

--Saves the specified users data.WILL return nil if it doesn't exist.
--Usage:_G.SaveUserData(Object PLAYER,Table DATATABLE)
--Example:_G.SaveUserData(game.Players.Reshiram110,UserDataTable)
_G.SaveUserData=function(Player,NewValue)
DataStore:SetAsync("User_"..Player.userId,NewValue)
end

--Unpacks the users data loaded from the datastore into the 'UserData' folder.
--Usage:_G.UnpackUserData(Table Data,Object Player)
--Example:_G.UnpackUserData(_G.GetUserData(game.Players.Reshiram110))
_G.UnpackUserData=function(Data,Player)
local f=Instance.new('Folder',game.ServerStorage.UserData)
f.Name=Player.Name
local v=Instance.new('StringValue',f)
v.Name="ChosenWeapon"
v.Value=Data.ChosenWeapon
local v=Instance.new('IntValue',f)
v.Name="Version"
v.Value=Data.Version
local v=Instance.new('IntValue',f)
v.Name="Money"
v.Value=Data.Money
local v=Instance.new('IntValue',f)
v.Name="Level"
v.Value=Data.Level
local v=Instance.new('StringValue',f)
v.Name="ChosenPet"
v.Value=Data.ChosenPet
local v=Instance.new('IntValue',f)
v.Name="NoobChance"
v.Value=Data.NoobChance
--Iterating through the metatables Data
local v=Instance.new('Folder',f)
v.Name="Pets"
for i,v in pairs(Data.Pets) do
local va=Instance.new('StringValue',f.Pets)
va.Name="Pet"
va.Value=v
end
local v=Instance.new('Folder',f)
v.Name="Weapons"
for i,v in pairs(Data.Weapons) do
local va=Instance.new('StringValue',f.Weapons)
va.Name="Weapon"
va.Value=v
end
end

--Packs the users data from the userdata folder into a table,ready to be saved to the games datastore.
--Usage:_G.PackuserData(Folder DataFolder)
--Example:_G.PackUserData(game.ServerStorage.UserData.Reshiram110)
_G.PackUserData=function(DataFolder)
local data=_G.BaseData --Defining a 'Frame' for the users data.
data.ChosenWeapon=DataFolder.ChosenWeapon.Value
data.Money=DataFolder.Money.Value
data.Level=DataFolder.Level.Value
data.ChosenPet=DataFolder.ChosenPet.Value
--Iterating through the metatable folders
for i,v in pairs(DataFolder.Pets:GetChildren()) do
table.insert(data.Pets,v.Value)
end
for i,v in pairs(DataFolder.Weapons:GetChildren()) do
table.insert(data.Weapons,v.Value)
end
return data
end


--Data Service is ready,mark it as ready.
_G.DataServiceReady=true

PlayerEvents script:

--[[

    Player Service
    Handles player events,such as spawning,joining,dyeing,etc.  

--]]

--Defining Services and vairables
local PlayerService=game:GetService("Players")

--Configuring the services and vairables
PlayerService.CharacterAutoLoads=false

--Player joined event
PlayerService.PlayerAdded:connect(function(Player)
print("[Player Service] "..Player.Name.." has joined the game.")

--Waiting for the framework to load.
while _G.ServerReady==nil or _G.ServerReady==false do
wait()
end
_G.WaitForServices()

Player:LoadCharacter() --Load the player's character for the first time.
if _G.Config.Maintence==false then --If maintence mode is turned off...
_G.UnpackUserData(_G.GetUserData(Player),Player) --Loading their data into the server.
_G.LoadPet(Player,true) --Loading the players pet
end
end)


--Player leaving event
PlayerService.PlayerRemoving:connect(function(Player)
print("[Player Service] ".. Player.Name.." has left the game.")
_G.LoadPet(Player,false)
_G.SaveUserData(Player,_G.PackUserData(game.ServerStorage.UserData[Player.Name]))
end)

0
There is a lot that needs to be looked at here, none of your data store processing is 'safe' and there is no need to use global variable her at all. User#5423 17 — 8y
0
I use global functions so I don't have to type in the same code again and again. Reshiram110 147 — 8y
0
We use module scripts. User#5423 17 — 8y
0
I use module scripts as well. I tend to use them as a library. Reshiram110 147 — 8y

Answer this question