Comparing old folder with new folder


#1

I am trying to create a function which compares a players data folder with the main data folder which is given to new players. If I add a new number value to the main data folder such as “Gold” I want it to be able to carry over to the player’s data folder next time they join as their saved data folder will not have this new value.

For example:
image
Say this is the original folder and I wanted to add a new value named “Hunger”

Like so:
image

How would I make it so the players who have their data saved without the “Hunger” value could have it added to their folder the next time they joined.

I couldn’t really get my head around this and got a bit confused.

Sorry if this is worded badly.


#2

Are the data folders made from datastores?


#3

Yes.


#4

From what I recall, you can just add the value to the array/default data and it’ll do the work for you. Just to be sure, would you mind showing the structure of your default data?


#5

I think I understand what you’re going for here. I use table deep merging for this without ValueBase or Folder instances. I store the schema version of the data table as a key, and compare it to the version of the schema template.

If the schema version of loaded data is higher, the merge is an “overwriter” / authoritative, meaning that if a key does not exist in the merge target (the schema template copy), it is added anyway. The same principles apply here. This will protect you from players joining older servers with newer data.

Then, you simply save all data indiscrimantly.

Good that you’re handling this. Many developers don’t, and I suspect it’s a major source of data loss.


#6

I’m not quite sure how to do this, is there any tutorials? I was thinking of comparing the two folders descendants and checking for differences but I could not think of a way to do so.


#8

Is there no way to compare the descendants of two folders?


#9

Maybe I’m misunderstanding what you’re trying to do. What do you mean by that? Compare them to see if two tables are equal?


#10

Sorry, I mean folders. I want to be able to compare the descendants of two folders and check for differences.


#11

If you want to tell if two folders are “equal”, it’d be something like this:

local function is_folders_equal(first, second)
    local first_children = first:GetChildren()

    for index = 1, #first_children do
        local child = first_children[index]
        local child_in_second = second:FindFirstChild(child.Name)

        if child_in_second == nil then
            return false
        end

        if child_in_second.ClassName ~= child.ClassName then
            return false
        end

        if child:IsA("ValueBase") then
            if child.Value ~= child_in_second.Value then
                return false
            end
        elseif child:IsA("Folder") then
            if is_folders_equal(child, child_in_second) == false then
                return false
            end
        end
    end

    return true
end

I’ll delete my last reply since it seems irrelevant to what you’re asking.


#12

How would I go about making it so it updates the outdated folder and adds the new values?


#13

I tried doing this however both “Current” and “Original” eventually became nil

Current is the Players loaded data folder and original is the folder which is given to new players with no data.
I want it to be able to detect if there is new values and add them to the players fodler if so,

function compare(Original, Current)
	for _, Object in pairs(Original:GetChildren()) do
		if Current:FindFirstChild(Object.Name) == nil then
			Object:Clone().Parent = Current
		else
			compare(Original[Object.Name], Current[Object.Name])
		end
	end
end

#14

Not quite sure i understand what your asking, but I use this function to match two tables upon join without erasing any saved data. You can probably modify this to work with your folder structure or use it as is to compare the servers current saved data structure with the players saved data.

--Adds any missing indexes to loaded data.
local function halfMatch(TableToMatch,LoadedData) --Table To Match, Loaded Data
	LoadedData=LoadedData or {}
	for i,v in pairs (TableToMatch) do
		if (type(v)=="table") then
			LoadedData[i]=halfMatch(v,LoadedData[i])
		elseif (LoadedData[i]==nil) then
			LoadedData[i]=v
		end
	end
	return LoadedData
end

#15

Something like this is what you’d want, but this is a very awkward way to implement player data management:

local value_classes = {
    bool = "BoolValue",
    number = "NumberValue",
    string = "StringValue",
}

local function add_data_to_folder(data, folder)
    for key, value in pairs(data) do
        if type(value) == "table" then
            local new_folder = Instance.new("Folder")
            new_folder.Name = key
            add_data_to_folder(value, new_folder)
        else
            local new_class = value_classes[type(value)]
            local new_value = Instance.new(new_class)
            new_value.Name = key
            new_value.Parent = folder
        end
    end
end

#16

It turns out my code was actually fine from the beginning, it was breaking because I had one of the folders named as “Name”. Class members have a higher priority then children.

Thank you everyone for helping.