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)