I’m noticing that as more States are added my structure will look more and more cluttered. It’s not difficult to read but I’d like the code to be more condensed.
My idea is to place the states under States.Activations and checking if the state is valid through States.Transitions (Example below). I can see this idea has it’s downsides too, any recommendations?
Example
local Sprint = require(script.Sprint)
local Block = require(script.Block)
local LightAttack = require(script.LightAttack)
local States = {
	Activations = {
		ActivateState = function(StateMachine, State, Activation, ...)
			StateMachine:TransitionState(State, Activation)
		end,
		LightAttack = function(StateMachine, Character, ...)
			LightAttack:Light(StateMachine, Character)
		end,
		EndCombat = function(StateMachine, Character)
			Character.Humanoid.WalkSpeed = Character:GetAttribute("BaseWalkSpeed")
			StateMachine:ChangeState("Idle")
		end,
		Sprint = function(StateMachine, Character, InputState)
			if InputState then
				Sprint:Enable(StateMachine, Character)
			end
		end,
		EndSprint = function(StateMachine, Character,  InputState)
			if not InputState then
				Sprint:Disable(StateMachine, Character)
				StateMachine:ChangeState("Idle")
			end
		end,
  },
},
How it works Currently: StateMachine checks if the state is valid through States.Transitions and finds the function to run through States.Activations[State][Function].
local Sprint = require(script.Sprint)
local Block = require(script.Block)
local LightAttack = require(script.LightAttack)
local States = {
	Activations = {
		Idle = {
			ASprint = function(StateMachine, ...)
				StateMachine:TransitionState("Sprinting", "Sprint", ...)
			end,
			ALightAttack = function(StateMachine, ...)
				StateMachine:TransitionState("Attacking", "LightAttack", ...)
			end,
			ABlock = function(StateMachine, ...)
				StateMachine:TransitionState("Blocking", "Block", ...)
			end,
		},
		Sprinting = {
			Sprint = function(StateMachine, Character, InputState)
				if InputState then
					Sprint:Enable(StateMachine, Character)
				end
			end,
			EndSprint = function(StateMachine, Character,  InputState)
				if not InputState then
					Sprint:Disable(StateMachine, Character)
					StateMachine:ChangeState("Idle")
				end
			end,
			ALightAttack = function(StateMachine, ...)
				Sprint:Disable(StateMachine, ...)
				StateMachine:TransitionState("Attacking", "LightAttack", ...)
			end,
			ABlock = function(StateMachine, ...)
				Sprint:Disable(StateMachine, ...)
				StateMachine:TransitionState("Blocking", "Block", ...)
			end,
		},	
		Attacking = {
			LightAttack = function(StateMachine, Character, ...)
				LightAttack:Light(StateMachine, Character)
			end,
			EndCombat = function(StateMachine, Character)
				Character.Humanoid.WalkSpeed = Character:GetAttribute("BaseWalkSpeed")
				StateMachine:ChangeState("Idle")
			end,
		},
		Blocking = {
			Block = function(StateMachine, Character, ...)
				Block:Enable(StateMachine, Character)
			end,
			EndBlock = function(StateMachine, Character, ...)
				Block:Disable(StateMachine, Character)
			end,
			EndSprint = function(StateMachine, Character, ...)
				Sprint:Disable(StateMachine, Character)
			end,
		},
		Stunned = {
			Stun = function(StateMachine, Character)
				
			end,
			EndStun = function(StateMachine, Character)
				
			end,
		},
	} 
}
States.Transitions = {
	Idle = {
		ASprint = true,
		ALightAttack = true,
		ABlock = true,
		TakeDamage = true,
	},
	Sprinting = {
		ALightAttack = true,
		ABlock = true,
		EndSprint = true,
		TakeDamage = true,
	},	
	Attacking = {
		EndCombat = true,
		TakeDamage = true,
	},
	Blocking =  {
		EndBlock = true,
		TakeDamage = true,
	},
}