JSON Becomes Unsorted When Using JSONDecode

I’m currently making an in-game changelog, however I’ve stumbled upon a problem that I can’t seem to figure out. I have my changelog in JSON format posted here on Pastebin and I request the raw from the once a player requests it. From there, I decode it with JSONDecode and forward it to the client. The client then sorts through it and creates the changelog. The problem is that it becomes out of order somewhere and I’m not sure why.

It ends up looking like this:

This is how I format each version:

"Version [Number]":
    {"Additions":
        ["Text"],
    "Fixes":
        ["Text"],
    "Changes":
        ["Text"]}
Client Script
function SetupCL()
	for i,v in pairs(ChangelogHolder:GetChildren()) do -- ChangelogHolder is a Frame where I store all of the TextLabels
		if v.Name ~= "UIListLayout" and v.Name ~= "Loading" then -- Get rid of the old changelog
			v:Destroy()
		end
	end
	local LoadingText = ChangelogHolder:FindFirstChild("Loading") -- Show updating message
	if LoadingText then
		LoadingText.Visible = true
	end
	local Data = RequestChangelogRF:InvokeServer() -- Request for changelog
	if Data == "Issue" then -- Let the client know that a server error occured
		local Clone = DefaultClItems:WaitForChild("Version"):Clone() -- A pre-customized TextLabel
		Clone.Parent = ChangelogHolder
		Clone.Text = "An error occured while getting the Changelog D:"
	else
		local Success, Err = pcall(function()
			local num = 1
			for i,v in pairs(Data) do
				num = num + 1
				local VClone = DefaultClItems:WaitForChild("Version"):Clone() -- Setup Version Name TextLabel
				VClone.Text = i
				VClone.LayoutOrder = num
				VClone.Parent = ChangelogHolder
				num = num + 1
				local LClone = DefaultClItems:WaitForChild("Line"):Clone() -- The line that goes underneith the name
				LClone.LayoutOrder = num
				LClone.Parent = ChangelogHolder
				for ii,vv in pairs(v["Additions"]) do -- Add the additions
					if vv ~= "None" then
						num = num + 1
						local Clone = DefaultClItems:WaitForChild("Change"):Clone()
						Clone.Text = "+ "..vv
						Clone.LayoutOrder = num
						Clone.Parent = ChangelogHolder
					end
				end
				for ii,vv in pairs(v["Fixes"]) do -- Add the fixes
					if vv ~= "None" then
						num = num + 1
						local Clone = DefaultClItems:WaitForChild("Change"):Clone()
						Clone.Text = "· "..vv
						Clone.LayoutOrder = num
						Clone.Parent = ChangelogHolder
					end
				end
				for ii,vv in pairs(v["Changes"]) do -- Add the changes
					if vv ~= "None" then
						num = num + 1
						local Clone = DefaultClItems:WaitForChild("Change"):Clone()
						Clone.Text = "- "..vv
						Clone.LayoutOrder = num
						Clone.Parent = ChangelogHolder
					end
				end
			end
			local size = 0 -- Calculate the size for the ScrollingFrame
			for i,v in pairs(ChangelogHolder:GetChildren()) do
				if v.Name == "Change" or v.Name == "Line" or v.Name == "Version" then
					size = size + v.Size.Y.Offset
				end
			end
			ChangelogHolder.CanvasSize = UDim2.new(0, 0, 0, size)
		end)
		if not Success then -- Let the client know an error occured
			local Clone = DefaultClItems:WaitForChild("Version"):Clone()
			Clone.Parent = ChangelogHolder
			Clone.Text = "An error occured while getting the Changelog D:"
		end
	end
	local LoadingText = ChangelogHolder:FindFirstChild("Loading") -- Hide the refreshing Text
	if LoadingText then
		LoadingText.Visible = false
	end
end
Server Script
local ClDebounce = false -- Debounce to prevent spamming
RequestChangelogRemoteF.OnServerInvoke = function(player)
	if ClDebounce == false then 
		ClDebounce = true
		local Success, Err = pcall(function()
			local ClJSON = HTTPService:GetAsync(ChangelogURL, false) -- Fetch JSON changelog
			local Changeloged = HTTPService:JSONDecode(ClJSON)
			for i,v in pairs(Changeloged) do
			Changelog = Changeloged -- Set the changelog variable so it can be returned to players when the debounce is true
		end)
		if not Success then
			GAEvents:Error(player, 5, "Changelog Error: ".. tostring(Err))
			return "Issue" -- Let the client know an error occured
		end
		spawn(function()
			wait(60)
			ClDebounce = false
		end)
	end
	return Changelog
end

This is because you are storing a dictionary, which has no defined order in reality. You should drop down your Version property into the actual JSON update entry and instead have an ordered array holding all your versions.

3 Likes

So like this and then add on the “Version” in front of the number on the client?

"1020":
    {"Additions":
        ["Text"],
    "Fixes":
        ["Text"],
    "Changes":
        ["Text"]}

More like this:

[
  {
    "Version": "1022",
    "Additions": ["None"],
    "Fixes": ["Reworked the entire Xbox GUI navigation system", "Internal Fixes"],
    "Changes": ["None"]
  },
  {
    "Version":"1021",
    "Additions": ...
]

The big picture being that each version info is ordered in the top-level array [ ... ].

2 Likes

Ok, thanks. I won’t be able to try this until later tomorrow

Edit: It works, thanks! :smiley: I decided to simplify it too since I no longer think I need all the sections for additions, fixes, and changes.