Table not updating

So I’ve been working on a skin system (and it works sorta) but I want to update the table that gives the moves their properties.

For some context here is my attack and properties scripts:
Move:

function module:Move(Player, Input, ...)
	
	if not KeyTable[Player] then
		KeyTable[Player] = {}
	end
	
	local Character = Player:IsA("Model") and Player or Player.Character
	
	if not Character:FindFirstChild("Humanoid") then return end
	if Character.Humanoid.Health <= 0 then return end

	local stand = Player.Data.Ability
	local Keybinds = Movesets.ExternalKeybinds
	local Movesets = Movesets.Movesets
	
	local AbilityValue = stand.Value
	local AbilityName = Abilities[stand.Value]
	local Move = Movesets[AbilityName][Input] or Keybinds[Player.Name] and Keybinds[Player.Name][Input] or nil
	
	local backupStats = StatsFile[AbilityName][Movesets[AbilityName][Input] or Keybinds[Player.Name] and Keybinds[Player.Name][Input]]
	local SkinName = Player.Data.Skin:GetAttribute("SkinName")
	local Stats = StatsFile[SkinName or AbilityName][Move] 
	if SkinName and Stats then
		Stats = MoveUtils.DeepCopy(Stats)
		Stats.StandName = Abilities[stand.Value]
	end
	
	local move = Stats
	if move and move.Checks then
		--if not Checks.CanAttack(Player,Move,move.Checks) then return end
	end

	local cbs = Stats and Stats.callbacks or backupStats and backupStats.callbacks or {};
	local fin = cbs.finishServ or nil;	
	
	
	if Move and Stats then
		
		
		local CastMove = true
		local resourceBar = nil
		local AwakeningKey = string.format("%s_%s_%s", Player.Name, AbilityValue, Move)
		
		if Stats.Awakening and ResourceHandler.HasResourceBar(AwakeningKey) then
			local resourceBar = ResourceHandler.GetResourceBar(AwakeningKey)
			if resourceBar:GetResource() >= 1 then
				resourceBar:RemoveResource(1)
			else
				CastMove = false
			end
		end
		
		local strikeCheck, strikeType = CanAttack(Player,Input,Stats.Checks)
		
		if strikeCheck == false then
			
			if not Strikes[Player.Name] then Strikes[Player.Name] = {} end
			local strikeCount = Strikes[Player.Name] 
			table.insert(strikeCount, strikeType)

			coroutine.wrap(function()
				wait(60)
				table.remove(strikeCount, table.find(strikeCount, strikeType))
			end)()

			if #strikeCount >= 6 then
				coroutine.wrap(function()
					table.clear(strikeCount)
				end)()
			end
		end
		
		if not Stats.DoNotActivate then
			Character.Values.Active.Value = Input
		end
		
		if CastMove then
			
			if Stats.Cooldown and not Stats.AfterMove and ((Player:IsA("Player") and Player.Character == Character) or Player:IsA("Model")) then
				task.spawn(CreateCD, Player, Input, Stats.Cooldown, Stats.CooldownDelay, Stats)
			end
			
			if Moves[AbilityName] and Moves[AbilityName][Move] then
				local Stats = StatsFile[AbilityName][Move]
				local suc,fail = pcall(Moves[AbilityName][Move], {Player,Stats,Input, ...})
				if not suc then
					warn(Move, "\n", AbilityName, "\n", fail)
				end
			end
		end
		
		if Stats.Cooldown and Stats.AfterMove and ((Player:IsA("Player") and Player.Character == Character) or Player:IsA("Model")) then
			task.spawn(CreateCD, Player, Input, Stats.Cooldown, Stats.CooldownDelay, Stats)
		end
		
		if not Stats.DoNotDeactivate then
			Character.Values.Active.Value = ""
		end
			
	end
	
end

Stats:

local CS = game:GetService("CollectionService")

local rs = game:GetService("RunService")

local OutputEvent = game.ReplicatedStorage.Remotes.Output
local animation = require(game.ReplicatedStorage.ReplicatedModules.StandAnimate)
local Rem = game.ReplicatedStorage.Remotes.InputFunc

local module = {}

local AbilityID = require(game.ReplicatedStorage.ReplicatedModules.AbilityID)
local Skins = require(game.ReplicatedStorage.ReplicatedModules.Skins)
local Converter = require(game.ReplicatedStorage.ReplicatedModules.AbilityID)
local UserInputService = require(game.ReplicatedStorage.ClientModules.InputTracker)

local junkTable = {}
local gtable = {
	["StarPlatinum"] = {};
}
local comboConverter = {
}

local function defaultCombo(Move, defaultTimer)
	return function(input, move, char)
		local plr = char or game.Players.LocalPlayer
		local char = char or plr.Character
		local Stand = AbilityID[plr.Data.Ability.Value]
		local stats = module.Stats[Stand][Move]
		if not CS:HasTag(char,"Summoned") then return end 
		if not gtable[Stand][plr.Name] then
			gtable[Stand][plr.Name] = {}
		end
		local StandValues = gtable[Stand][plr.Name]
		if not StandValues[Move] then
			StandValues[Move] = 1
		end
		if StandValues[input] then return end
		StandValues[input] = true
		local val = StandValues[Move]
		local animSpeed = stats.AnimSpeed or junkTable
		animation.playClient(Stand, ( (comboConverter[Stand] and comboConverter[Stand][input]) or input ) .. "-" .. val, nil, animSpeed[val])
		plr.Character.Values.Active.Value = "temp"
		Rem:InvokeServer(input)
		if val == stats.MaxCombo then
			StandValues[Move] = 1
		else
			StandValues[Move] += 1
		end
		coroutine.wrap(function()
			local currentval = StandValues[Move]
			wait((defaultTimer or 1.5) + stats.ComboTick)
			if currentval == StandValues[Move] then StandValues[Move] = 1 end
		end)()
		wait(stats.ComboTick)
		StandValues[input] = nil
	end
end

local function deepCopy(table)
	local newtable = {}
	for i, v in pairs(table) do
		newtable[i] = type(v) == "table" and deepCopy(v) or v
	end
	return newtable
end

module.Stats = {
	["StarPlatinum"] = {
		["Summon"] = {
			Checks = {CheckSummoned = false,CheckActive = true};
			LeaveParts = {"StandHumanoidRootPart","invis"};
			FadeIn = 0.3;
			Cooldown = 1.5;
			AuraColour = ColorSequence.new{
				ColorSequenceKeypoint.new(0, Color3.fromRGB(123, 83, 193)),
				ColorSequenceKeypoint.new(1, Color3.fromRGB(139, 67, 227))
			},
		    CooldownDelay = 0;
			callbacks = {
				client = function(p, c, stand)
					if not CS:HasTag(c,"Summoned") then
						local anim = animation.playClient("StarPlatinum","StandIdle",Enum.AnimationPriority.Idle)
					else
						animation.stopClient("StarPlatinum","StandIdle")
					end
				end,
			}
		};
		["Barrage"] = {
			Checks = {CheckSummoned = true,CheckActive = true};
			Length = 4.022;
			Damage = 1;
			Hitbox = {Type = "Magnitude";
				RelativePart = "Stand.StandHumanoidRootPart",
				Size = 4.5;
				Offset = CFrame.new(0,0,-4.5)				
			},
			Knockback = {5,0.05};
		    Cooldown = 10;
			Stun = 0.6;
			AfterMove = true;
			callbacks = {
				client = function(p, c, stand)
					local Animation = animation.playClient("StarPlatinum","Barrage",Enum.AnimationPriority.Action,nil,c:FindFirstChildWhichIsA("Humanoid"),true)
					Animation:AdjustSpeed(3)
					local T = tick()
					repeat
						wait(0.025)
					until tick() - T > 4.022 or not UserInputService:IsKeyDown(Enum.KeyCode.E)  or not p or not p.Parent or p.Character.Humanoid:GetState() == Enum.HumanoidStateType.Dead
					Animation:Stop()
				end,
			}
		};
		["ChargePunch"] = {
			Checks = {CheckSummoned = true,CheckActive = true};
			Cooldown = 15;
			Knockback = {50,0.3,Vector3.new(0,35,0)};
			Hitbox = {Type = "Magnitude";
				RelativePart = "Stand.StandHumanoidRootPart";
				Size = 4;
				Offset = CFrame.new(0,0,-4.5)
			};
			Damage = 20,
			callbacks = {
				client = function(p, c, stand)
					if CS:HasTag(c,"Summoned") then
						animation.playClient("StarPlatinum","StrongPunch",Enum.AnimationPriority.Action2,nil,c:FindFirstChildWhichIsA("Humanoid"),true)
					end
				end,
			}
		};
		["Pose"] = {
			Checks = {CheckSummoned = true,CheckActive = true};
			Cooldown = 2;
			callbacks = {
				client = function(p, c, stand)
					if CS:HasTag(c,"Posing") then
						animation.stopClient("StarPlatinum","Pose")
						local CD = Instance.new("BinaryStringValue")
						CD.Name = "P"
						CD.Parent = p.Cooldowns
						local CDCount
						repeat
							wait(0.025)
							CDCount = 0
							for i,v in pairs(p.Cooldowns:GetChildren()) do
								if v.Name == "P" then
									CDCount = CDCount + 1
								end
							end
						until CDCount == 2
						CD:Destroy()
					else
						local Anim = animation.playClient("StarPlatinum","PoseTransition",Enum.AnimationPriority.Action2,nil,c:FindFirstChildWhichIsA("Humanoid"),true)
						Anim.Stopped:Wait()
						animation.playClient("StarPlatinum","Pose",Enum.AnimationPriority.Action3,nil,c:FindFirstChildWhichIsA("Humanoid"),true)
						local CD = Instance.new("BinaryStringValue")
						CD.Name = "P"
						CD.Parent = p.Cooldowns
						local CDCount
						repeat
							wait(0.025)
							CDCount = 0
							for i,v in pairs(p.Cooldowns:GetChildren()) do
								if v.Name == "P" then
									CDCount = CDCount + 1
								end
							end
						until CDCount == 2
						CD:Destroy()
					end
				end,
			}
		};
		["TeleportKnife"] = {
			Checks = {CheckSummoned = true,CheckActive = true};
			Cooldown = 8;
			CustomInvoke = function(input,_,c)
				local p = c or game.Players.LocalPlayer
				local c = c or p.Character
				if c.Cooldowns:FindFirstChild("TeleportKnife") then return end
				if CS:HasTag(c,"Summoned") then
					local Animation = p:IsA("Player") and animation.playClient("StarPlatinum","KnifeThrow") or animation.playClient("StarPlatinum","KnifeThrow",nil,nil,c:FindFirstChildWhichIsA("Humanoid"),true)
					Animation:Play()
				end
			end,
		};
		["Ground Slam"] = {
			Checks = {CheckSummoned = true};
			Cooldown = 100;
			AuraColour = ColorSequence.new{
				ColorSequenceKeypoint.new(0, Color3.fromRGB(229, 121, 43)),
				ColorSequenceKeypoint.new(1, Color3.fromRGB(214, 167, 71))
			},	
			AwakenTime = 50,
			Awakening = true
		};
		["Timestop"] = {
			Checks = {CheckSummoned = true,CheckActive = true};
			Cooldown = 50;
			callbacks = {
				client = function(p, c, stand)
					
				end,
			}
		};
		["Beatdown"] = {
		
		};
		["Star Finger"] = {
			Checks = {CheckSummoned = true};
			Cooldown = 9;
			callbacks = {
				client = function(p, c, stand)
					
				end,
			}
		};
		["Drink"] = {
			
		};
		["Quote"] = {
			Cooldown = 2,
			Quotes = {
				{"Yare yare daze..",
					"rbxassetid://5332928074",
					5,
					3},	
				{"I told you I'd fight, and I'm a man of my word.",
					"rbxassetid://7259089971",
					{
					},
					2, 2},
				{"You really ticked me off..",
					"rbxassetid://5572232666",
					{
					},
					5, 2},
				{"",
					"rbxassetid://5572233210",
					{
					},
					5, 2},
			}
		};
		["LMB Combo"] = {
			Checks = {CheckSummoned = true,CheckActive = true},
			Cooldown = 0.2;
			Stun = 0.75;
			Knockback = {5,0.05};
			Hitbox = {
				Type = "Magnitude";
				RelativePart = "Stand.StandHumanoidRootPart";
				Size = 4;
				Offset = CFrame.new(0, 0, -5)
			};
			Damage = 8;
			MaxCombo = 4;
			ComboTick = 0.3;
			AnimSpeed = {
				[4] = 2;
			};
			CustomInvoke = defaultCombo("LMB Combo",0.75);
		}
	};
	["TheWorld"] = {
		["Summon"] = {
			Checks = {CheckSummoned = false,CheckActive = true};
			LeaveParts = {"StandHumanoidRootPart"};
			FadeIn = 0.3;
			Cooldown = 1.5;
			AuraColour = ColorSequence.new{
				ColorSequenceKeypoint.new(0, Color3.fromRGB(193, 138, 50)),
				ColorSequenceKeypoint.new(1, Color3.fromRGB(227, 186, 115))
			},
			CooldownDelay = 0;
			callbacks = {
				client = function(p, c, stand)
					if not CS:HasTag(c,"Summoned") then
						local anim = animation.playClient("TheWorld","StandIdle",Enum.AnimationPriority.Idle)
					else
						animation.stopClient("TheWorld","StandIdle")
					end
				end,
			}	
		},
		["Quote"] = {
			Cooldown = 2,
			Quotes = {
				{"THIS IS TRULY THE GREATEST HIGH!!",
					"rbxassetid://616582888",
					7,
					3},	
				{"*very menacing laugh*",
					"rbxassetid://2553928874",
					5,
					3},	
				{"If this were a game of chess between us, this would easily class as checkmate.",
					"rbxassetid://616594208",
					5,
					3},
			}
		}
	}
}

local moveStats = module.Stats

local function getStats(ability)
	return moveStats[ability]
end

local function loadCode(module)
	local standCode = require(module)
	for i,v in pairs(standCode) do
		--print(i,v)
		moveStats[i] = v
	end
	standCode.GetStats = getStats
end
local function iterate(folder)
	for i,v in ipairs(folder:GetChildren()) do
		if v:IsA("ModuleScript") then
			local suc, fail = pcall(loadCode, v)
			if not suc then warn(fail, v) end
		elseif v:IsA("Folder") then
			iterate(v)
		end
	end
end

iterate(script)

for i,v in pairs(moveStats) do
	if not gtable[i] then
		gtable[i] = {}
	end
end

for stand, moves in pairs(moveStats) do
	for i, v in pairs(moves) do
		v.MoveName = i
		v.StandName = stand
		if i == "Quote" then
			v.DoNotActivate = true
			v.DoNotDeactivate = true
		end
	end
end	

local function recurseCopyTable(table1, table2)
	for key, value in pairs(table2) do
		if type(value) == "table" then
			recurseCopyTable(table1[key], value)
		else
			table1[key] = value
		end
	end
end

local function modifyStats(stats, newStats)
	for move, value in pairs(newStats) do
		if not stats[move] then
			warn(move, "not found, creating new stats for it")
			stats[move] = deepCopy(value)
		else
			if value.EraseKey then 
				stats[move] = nil
				continue
			elseif value.ShallowCopy then
				stats[move] = deepCopy(value)
				continue
			end
			for key, val in pairs(value) do
				if type(val) == "table" then
					recurseCopyTable(stats[move][key], val)
				else
					stats[move][key] = val
				end
			end
		end
	end
	return stats
end

for stand, skins in pairs(Skins.Funcs.GetSkins()) do
	local DefaultAbility = Converter[tonumber(stand)]
	for id, name in pairs(skins) do
		if moveStats[name] and moveStats[name] ~= moveStats[DefaultAbility] then
			local stats = deepCopy(moveStats[DefaultAbility])
			if rs:IsStudio() then
				warn(name, "stats found, copying and overwriting", DefaultAbility, "stats")
			end
			modifyStats(stats, moveStats[name])
			moveStats[name] = stats
		else
			moveStats[name] = moveStats[DefaultAbility]
		end
	end
end

local function indexHandler(ParentTable)
	return function(t,k)
		if k == "ParentTable" then
			return ParentTable
		end
	end
end

for stand, moves in pairs(moveStats) do
	for i, v in pairs(moves) do
		setmetatable(v, {
			__index = indexHandler(moves)
		})
	end
end


setmetatable(moveStats, {
	__index = function(t, k)
		warn(k, " stats not found")
	end;
})

return module

Skin Stats:

local CS = game:GetService("CollectionService")
local UserInputService = game:GetService("UserInputService")
local OutputEvent = game.ReplicatedStorage.Remotes.Output
local animation = require(game.ReplicatedStorage.ReplicatedModules.StandAnimate)

local Rem = game.ReplicatedStorage.Remotes.InputFunc

local module = {}

local AbilityID = require(game.ReplicatedStorage.ReplicatedModules.AbilityID)
local junkTable = {}
local gtable = {
	["StarPlatinum"] = {};
}

local comboConverter = {}

local function defaultCombo(Move, defaultTimer)
	return function(input, move, char)
		local plr = char or game.Players.LocalPlayer
		local char = char or plr.Character
		local Stand = AbilityID[plr.Data.Ability.Value]
		local stats = module.Stats[Stand][Move]
		if not CS:HasTag(char,"Summoned") then return end 
		if not gtable[Stand][plr.Name] then
			gtable[Stand][plr.Name] = {}
		end
		local StandValues = gtable[Stand][plr.Name]
		if not StandValues[Move] then
			StandValues[Move] = 1
		end
		if StandValues[input] then return end
		StandValues[input] = true
		local val = StandValues[Move]
		local animSpeed = stats.AnimSpeed or junkTable
		animation.playClient(Stand, ( (comboConverter[Stand] and comboConverter[Stand][input]) or input ) .. "-" .. val, nil, animSpeed[val])
		plr.Character.Values.Active.Value = "temp"
		Rem:InvokeServer(input)
		if val == stats.MaxCombo then
			StandValues[Move] = 1
		else
			StandValues[Move] += 1
		end
		coroutine.wrap(function()
			local currentval = StandValues[Move]
			wait((defaultTimer or 1.5) + stats.ComboTick)
			if currentval == StandValues[Move] then StandValues[Move] = 1 end
		end)()
		wait(stats.ComboTick)
		StandValues[input] = nil
	end
end

module.Stats = {
	["OVA"] = {
		["Summon"] = {
			AuraColour = ColorSequence.new{
				ColorSequenceKeypoint.new(0, Color3.fromRGB(221, 111, 33)),
				ColorSequenceKeypoint.new(1, Color3.fromRGB(227, 135, 29))
			};
		}
	}
}

local moveStats = module.Stats

for i,v in pairs(module) do
	if not gtable[i] then
		gtable[i] = {}
	end
end

local function loadCode(newModule)
	local standCode = require(newModule)
	for i,v in pairs(standCode) do
		--print(i,v)
		module[i] = v
	end
end

for i,v in ipairs(script:GetChildren()) do
	--	print(v)
	local suc, fail = pcall(loadCode, v)
	if not suc then warn(fail, v) end
end

return module


The problem is that when I equip the skin the old stats are used and not the new ones after I use deepCopy.

Also, this is my first DevForum post so if there is something wrong please tell me what to change.

Sometimes the table isn’t copied or moved over correctly. Try using table.clone and see if that fixes the issue.

Just tried it and it doesn’t work.