Been spending 1 hour on this annoying table thing


Im using this module to return the default data template if the playerdata is nil…

im using this code to get the data of a player even if they havent played the game.

for some reason when i’m running this, it overwrites the default datatemplate which does so when u try to get the data, it returns the data as the modified table. I really don’t know how to fix this.

Help would be appreciated!

1 Like

Let me know if you know the issue!

1 Like

for some reason when i’m running this, it overwrites the default datatemplate which does so when u try to get the data, it returns the data as the modified table. I really don’t know how to fix this.

The default data template you are using is passed by reference when you return it in your GetDataForUserId function. This means that any modification to data will change the original instance of data which is why the table is being modified. You need to use table.clone() or return a new deep copy of your template table when assigning default data to a new player.

hey! Table.clone still messed up my thing

image
I didnt gift it the gamepass but i gifted a previous user the gamepass. Its still saying he owns it and from the servercode that prints both the originasl template and his data, it says he owns it. The preivous user did not own it before i purchased.

Use the option </> to post scritps.

This is the data template code

type dataType = {
	-- leaderstats
	Wins:number;
	Trophies:number;

	-- quality of life
	BlockLimit:number;

	Reports:number;
	ReportedBy:{};
	LatestReport:number?;
	Bans:number;
	
	VipBlocks: boolean;
	
	Passes:{};
	RegisteredPasses:{};
	
	Gifts:{};
	
	Settings:{};
	
	LoginStreak:number;
	LastLogin:number?;
}

export type DataTemplate = dataType

return {
	-- Leaderstats / Values
	Wins=0;
	Trophies=0;

	-- Basic Stuff
	BlockLimit=75;
	
	Reports = 0;
	ReportedBy = {};
	LatestReport = nil;
	Bans = 0;
	
	-- VIP
	VipBlocks = false;
	
	-- Gamepasses
	Passes = {};
	RegisteredPasses = {};
	
	Gifts = {};
	
	-- Settings (Default settings in the table)
	Settings = {
		"Music";
		"Nametags";
		"SFX";
		"Notifications";
	};
	
	-- Login streak
	LoginStreak = 1;
	LastLogin = nil;
	LatestStreakClaimed = 0;
}

The purchase handler that changes the table

-- Gift VIP
	[2662160435]=function(playerid,productid)
		local player = game.Players:GetPlayerByUserId(playerid)
		if not player then return Enum.ProductPurchaseDecision.NotProcessedYet end
		local data = require(game.ReplicatedStorage.Modules.Server.Manager).Datas[player]
		if not data then return Enum.ProductPurchaseDecision.NotProcessedYet end
		local gifting = player:GetAttribute("GiftingPlayer")
		if gifting == "" then return Enum.ProductPurchaseDecision.NotProcessedYet end
		local giftingData = DataStore:GetAsync(gifting)

		if not giftingData then
			giftingData = table.clone(require(game.ReplicatedStorage.Modules.Server.DataTemplate))
		end
		
		if not giftingData then return Enum.ProductPurchaseDecision.NotProcessedYet end
		if not giftingData.Passes then return Enum.ProductPurchaseDecision.NotProcessedYet end

		if table.find(giftingData.Passes, 960021336) then return Enum.ProductPurchaseDecision.NotProcessedYet end
		
		table.insert(giftingData.Passes,960021336)
		
		giftingData.Gifts["VIP"]=playerid
		
		DataStore:SetAsync(gifting, giftingData)
		
		MsgService:PublishAsync("Gift", {"VIP", playerid, gifting, 960021336}) -- [1]=AssetType, [2]=from, [3]=to, [4]=passid
		
		return Enum.ProductPurchaseDecision.PurchaseGranted
	end,

The code that returns the offline playerdata

game.ReplicatedStorage.Remotes.GetDataForUserId.OnServerInvoke = function(plr,id)
	local data = DataStore:GetAsync(id)

	if not data then
		data = table.clone(require(game.ReplicatedStorage.Modules.Server.DataTemplate))
	end

	return data
end

this is just the code in the first message but in the code form iykwim

Because you have nested tables, table.clone returns a shallow copy, meaning it will not clone the tables inside, so modifying them will also modify the tables in the template. To fix this, you just need to use a deep copy function. This is pretty easy to implement yourself with recursion, but you could also find an example on the fprum.

Here’s a function that can be used to copy everything in the table:

function deepcopy(t) {
  local nt = {}
    for i, v in pairs(t) do
      if type(v) == 'table' then
        nt[i] = deepcopy(v) --use a copy instead
      else
        nt[i] = v
      end
    end
  return nt
}

I was just going to go that way…
Put this on top of the purchase handler

local function deepClone(tbl)
    local copy = {}
    for key, value in pairs(tbl) do
        if type(value) == "table" then
            copy[key] = deepClone(value)
        else
            copy[key] = value
        end
    end
    return copy
end

Then call; giftingData = deepClone(DataTemplate)
A freash new untainted data set to work with every time.

Should work or blow up, good luck.
(make backups)