How to handle automatic skill unlocking efficiently for my game with multiple stats?

Hello, I am creating a game with multiple different stats. (Perception, dexterity, strength, etc.)

When a player reaches a certain requirement of stats for a specific skill, they will automatically unlock the skill. I have around 30 skills right now, but there will be around 200 or so in the end.

For instance, a player will unlock a skill called “Crushing Blow” at 45 strength and 15 perception.

I am wondering, what is the most lag-free way to handle this skill unlocking? Right now, I just loop through all the skills when the players stat changes, but that obviously isn’t very optimised.

If they’re values like Number values just use the changed function of the get attribute changed function for them I think. Should work

if the stats are held as intvalues in a folder, you can create an event listener for when the Value property changes, and lookup a dictionary for if they need to unlock a new skill
example:

local unlocks = {
["Strength"] = {[5]="Ability1",[10]="Ability2"}
}
for _, stat in pairs(statFolder:GetChildren()) do
    stat:GetPropertyChangedSignal("Value"):Connect(function()
        local unlockedAbility = unlocks[stat.Name][stat.Value]
        if unlockedAbility then
            -- give the new ability
        end
    end)
end

I mentioned that I already am doing that, I’m just wondering if there is a more efficient way.

this code only runs once, it does not iterate over all stats when one of them changes

Oh, I see. However, I mentioned that some skills have multiple different stat requirements.

Also, players can sometimes receive more than one stat point at a time.

in that case im not sure if there is any better way of finding out if the player unlocks any new skills, the only optimisation i can think of is only iterating over skills that the player hasnt already unlocked

Only check reqs for unobtained skills and only check the required stats instead of looping over all of them. As long as you’re doing that then there’s no quicker way to verify what skills the player needs to be awarded.

You can put a task.spawn(function() and a end) in the for loop which will start new threads for every skill, so they can update at the same time, idk if that’s as efficient as ur original core tho

Sounds like an observer for your character attributes.

All you have to do is to loop through them once, stablish a changed connection and check for their values. The other ways are the inefficient ones, from my point of view, as long as you run once, create the connections and clean them up when the player leaves, you’re already doing it the most efficient way.

There is another way though, which is a condition placed in the function/event you use to change those attributes.

-- this
local function OnPlayerAdded(player)
	
	for _, v in attributes:GetChildren() do
		local limit = attributeLimits[v.Name]
		
		if v.Value >= limit then continue end
		
		local event
		event = v.Changed:Connect(function(newValue: number)
			if newValue >= limit then
				event:Disconnect();
				event = nil
				unlockSkill()
			end
		end)
	end
	
end

Players.PlayerAdded:Connect(OnPlayerAdded)

-- or this

local function addStrength(value)
	local strength = ...
	strength += value
	
	if strenth >= limit then
		unlockStrengthSkill()
	end
end