Which method better?

local character = player.Character
	local isStunned = StunChecker(character)
	wait()
	if isStunned then return end
	local combo = character:GetAttribute("Combo")
	local humanoid = character:FindFirstChild("Humanoid")
	if humanoid then
		local rootpart = humanoid.RootPart
		local trail = AllAnimations.Parent.VFX.Trail:Clone()
		trail.Parent = character[punchAttacks[combo]]
		trail.CFrame = character[punchAttacks[combo]].CFrame
		trail.Motor6D.Part0 = character[punchAttacks[combo]]
		trail.Motor6D.Part1 = trail
		game.Debris:AddItem(trail, 0.5)
		local animator = humanoid:FindFirstChild("Animator")
		local animation = animator:LoadAnimation(AllAnimations["Punch"..combo])
		animation:Play()
		character:SetAttribute("Attacking", true)
		local velocity = rootpart.CFrame.LookVector*4
		local knck_time = 0.1
		local stunvalue = 1.8
		if combo ~= 4 then
			character:SetAttribute("Combo", combo+1)
		elseif combo == 4 then
			character:SetAttribute("Combo", 1)
			stunvalue = 2.5
			knck_time = 0.3
			velocity = rootpart.CFrame.LookVector*50
		end
		task.wait(0.18)
		Hitboxes.CreateModule(character, {
			CFrame = rootpart.CFrame + (rootpart.CFrame.lookVector * 5),
			Size = Vector3.new(5, 5, 5),
			TakeDamage = 3,
			Stun = stunvalue,
			Knockback = knck_time,
			Velocity = velocity,
			isVisualerAttack = true,
		})
		
		animation.Ended:Wait()
		if combo == 4 then
			wait(1.7)
		end
		character:SetAttribute("Attacking", false)
	end

This is player part. Activates when player is trying to M1.

local module = {}

local StunAttributes = {Stun = true, Ragdolled = true, Attacking = true, Blocking = true}
local AllAnimations = game.ReplicatedStorage.Container.Combat.Animations
local Hitboxes = require(game.ReplicatedStorage.Modules.CombatSystem.Hitbox)

local function StunChecker(character)
	local attributes = character:GetAttributes()
	for i, v in attributes do
		if StunAttributes[i] == true then
			if v == true then
				return true
			end
		end
	end
end

function module:NPC_Attack(character, punchAttacks)
	local isStunned = StunChecker(character)
	wait()
	if isStunned then return end
	local combo = character:GetAttribute("Combo")
	local humanoid = character:FindFirstChild("Humanoid")
	if humanoid then
		local rootpart = humanoid.RootPart
		local trail = AllAnimations.Parent.VFX.Trail:Clone()
		trail.Parent = character[punchAttacks[combo]]
		trail.CFrame = character[punchAttacks[combo]].CFrame
		trail.Motor6D.Part0 = character[punchAttacks[combo]]
		trail.Motor6D.Part1 = trail
		game.Debris:AddItem(trail, 0.5)
		local animator = humanoid:FindFirstChild("Animator")
		local animation = animator:LoadAnimation(AllAnimations["Punch"..combo])
		animation:Play()
		character:SetAttribute("Attacking", true)
		local velocity = rootpart.CFrame.LookVector*4
		local knck_time = 0.1
		local stunvalue = 1.8
		if combo ~= 4 then
			character:SetAttribute("Combo", combo+1)
		elseif combo == 4 then
			character:SetAttribute("Combo", 1)
			stunvalue = 2.5
			knck_time = 0.3
			velocity = rootpart.CFrame.LookVector*50
		end
		task.wait(0.18)
		Hitboxes.CreateModule(character, {
			CFrame = rootpart.CFrame + (rootpart.CFrame.lookVector * 5),
			Size = Vector3.new(5, 5, 5),
			TakeDamage = 3,
			Stun = stunvalue,
			Knockback = knck_time,
			Velocity = velocity
		})

		animation.Ended:Wait()
		if combo == 4 then
			wait(1.7)
		end
		character:SetAttribute("Attacking", false)
	end
end

return module

This is NPC combat. which is almost the same with first one (it’s should have no difference, the “isVisualerAttack” is didn’t count.)

Maybe, i need to use 1 Module script to make this combat being always similar? is it optimizated, or i should update the NPC script myself?

does it run on a server script or local script

both running on server (player script running from Client to Server, npc: Character.Script (while true do *modulescript*:NPCAttack() task.wait() end)