Issue where another player can be double-tapped ability even if they were not the one who initiated the first attack

I’m encountering a strange issue in my game where, when the attacker uses an ability on a victim, the victim can also trigger the double-tap mechanic and activate a variant of the ability. This behavior is unintended and creates problems for the gameplay.

What I want to achieve is to ensure that only the attacker, who initiates the ability, can use the double-tap input to activate the variant. The victim should not be able to trigger this mechanic under any circumstances.

I need help fixing this issue to make the game mechanics function as intended.
I’m using knit.

Attack Controller ( Client )

local rp = game:GetService("ReplicatedStorage")
local Uis = game:GetService("UserInputService")

local knit = require(rp.Game.Shared.Packages.Knit)

local plr = game.Players.LocalPlayer

local AttackController = knit.CreateController {
	Name = script.Name,
	CurrentCooldowns = {},
	Connections = {},
	Skills = {
		Skill1 = 1,
		Skill2 = 2,
		Skill3 = 3,
		Skill4 = 4,
	},
	Keys = {
		[Enum.KeyCode.One] = "Skill1",
		[Enum.KeyCode.Two] = "Skill2",
		[Enum.KeyCode.Three] = "Skill3",
		[Enum.KeyCode.Four] = "Skill4",
		[Enum.KeyCode.G] = "Awaken"
	},
	Console = {
		[Enum.KeyCode.ButtonL1] = "Skill1",
		[Enum.KeyCode.ButtonL2] = "Skill2",
		[Enum.KeyCode.ButtonR1] = "Skill3",
		[Enum.KeyCode.ButtonR2] = "Skill4",
		[Enum.KeyCode.ButtonX] = "Awaken"
	},

}

function lerp(a, b, t)
	return a + (b - a) * t
end

function UIEquip(overlay, bool)
	overlay.Visible = bool
end


function AttackController:Setup()
	for i,v in pairs(self.Connections) do
		v:Disconnect()
	end
	local plrgui = plr.PlayerGui
	local backpack = plr.Backpack

	local Main = plrgui:WaitForChild("Main")
	local AwakeningFrame = Main:WaitForChild("AwakeningFrame")
	local energyBar = AwakeningFrame.ProgressBar.MainBar.Bar
	local Hotbar = Main:WaitForChild("Hotbar")
	local Grid = Hotbar:WaitForChild("Grid")

	local Info = require(rp.Info).Characters[plr:GetAttribute("Character")]

	local function Writethistextforme(label, text)
		task.spawn(function()
			for i = 1, #text do
				label.Text = string.sub(text, 1, i)
				task.wait(.05)
			end
		end)
	end

	plr.AttributeChanged:Connect(function()
		energyBar:TweenSize(UDim2.new(plr:GetAttribute("Ultimate")/100,0,1,0), Enum.EasingDirection.Out, Enum.EasingStyle.Sine, .2, true)
		energyBar.ImageColor3 = Info.Color
	end)

	if plr.CharacterAppearanceLoaded and plr:HasAppearanceLoaded() then
		if plr:GetAttributeChangedSignal("Character") then
			Writethistextforme(AwakeningFrame.AwakeningName, Info.UltimateName)
		end
	end

	Writethistextforme(AwakeningFrame.AwakeningName, Info.UltimateName)
	Writethistextforme(AwakeningFrame.AwakeningName.AwakeningName, Info.UltimateName)

	energyBar:TweenSize(UDim2.new(plr:GetAttribute("Ultimate")/100,0,1,0), Enum.EasingDirection.Out, Enum.EasingStyle.Sine, .2, true)
	energyBar.ImageColor3 = Info.Color

	for _, v in Grid:GetChildren() do
		if v:IsA("ImageButton") then
			v:Destroy()
		end
	end

	local function AddSlot(num, infos)
		local Slot = script.SlotFrame:Clone()
		Slot.ToolName.Text = infos.Name
		Slot.LayoutOrder = num
		Slot.Number.Text = tostring(num)
		Slot.Name = "Skill"..tostring(num)
		Slot.Parent = Grid
		if infos.twiceInfo then
			Slot.Reuse.Visible = true
			Slot.Reuse.Reuse.Visible = true
		else
			Slot.Reuse.Visible = false
			Slot.Reuse.Reuse.Visible = false
		end
	end

	for i,v in pairs(Info.Base) do
		local slotnum = self.Skills[i]
		if slotnum then
			AddSlot(slotnum, v)
		end
	end

	local Uis = game:GetService("UserInputService")
	local plr = game.Players.LocalPlayer

	self.Connections[#self.Connections + 1] = Uis.InputBegan:Connect(function(input, proc)
		if proc then return end

		self.KeyPressTimes = self.KeyPressTimes or {}

		local keycode = input.KeyCode
		local skill = self.Keys[keycode] or self.Console[keycode]
		local autoActivate = plr.Data.Settings["Auto Equip"].Value

		if skill and Info.Base[skill] then
			if not autoActivate then
				if self.SelectedSkill == skill and self.Equipped then
					local hotbar = plr.PlayerGui.Main.Hotbar.Grid
					local lastKeyButton = hotbar:FindFirstChild(self.SelectedSkill)

					if lastKeyButton then
						local overlay = lastKeyButton:FindFirstChild("Overlay")
						if overlay then
							overlay.Visible = false
							self.Equipped = false
							plr.Character:SetAttribute("CheckActivated", nil)
						end
					end
					return
				end

				if self.LastKey then
					local hotbar = plr.PlayerGui.Main.Hotbar.Grid
					local lastKeyButton = hotbar:FindFirstChild(self.LastKey)

					if lastKeyButton then
						local overlay = lastKeyButton:FindFirstChild("Overlay")
						if overlay then
							overlay.Visible = false
							plr.Character:SetAttribute("CheckActivated", nil)
						end
					end
				end

				self.SelectedSkill = skill
				self.LastKey = skill

				local hotbar = plr.PlayerGui.Main.Hotbar.Grid
				local selectedSkillButton = hotbar:FindFirstChild(self.SelectedSkill)

				if selectedSkillButton then
					local overlay = selectedSkillButton:FindFirstChild("Overlay")
					if overlay then
						overlay.Visible = true
						self.Equipped = true
						plr.Character:SetAttribute("CheckActivated", true)
					end
				end
			else
				self.SelectedSkill = skill
				self.Equipped = false

				local hotbar = plr.PlayerGui.Main.Hotbar.Grid
				local lastKeyButton = hotbar:FindFirstChild(self.SelectedSkill)

				self.KeyPressTimes[keycode] = self.KeyPressTimes[keycode] or 0
				local currentTime = tick()

				if Info and Info.Base[self.SelectedSkill]["twiceInfo"] and knit.Player.Character then
					local character = knit.Player.Character
					if character:IsDescendantOf(workspace.Mobs) then
						local isDoubleTap = (currentTime - self.KeyPressTimes[keycode] <= Info.Base[self.SelectedSkill]["twiceInfo"]["interval"])
						self.KeyPressTimes[keycode] = currentTime

						if isDoubleTap then
							knit.GetService("AttackService").Attack:Fire(self.SelectedSkill, nil, isDoubleTap)
							return
						end
					end
				end

				knit.GetService("AttackService").Attack:Fire(self.SelectedSkill, nil)


				if lastKeyButton then
					local overlay = lastKeyButton:FindFirstChild("Overlay")
					if overlay then
						overlay.Visible = false
						self.Equipped = false
						plr.Character:SetAttribute("CheckActivated", nil)
					end
				end

			end
		end

		if Uis:IsMouseButtonPressed(Enum.UserInputType.MouseButton1) and self.SelectedSkill then
			if self.Equipped then
				self.KeyPressTimes[keycode] = self.KeyPressTimes[keycode] or 0
				local currentTime = tick()

				if Info.Base[self.SelectedSkill]["twiceInfo"] then
					local isDoubleTap = (currentTime - self.KeyPressTimes[keycode] <= Info.Base[self.SelectedSkill]["twiceInfo"]["interval"])
					self.KeyPressTimes[keycode] = currentTime

					if isDoubleTap then
						knit.GetService("AttackService").Attack:Fire(self.SelectedSkill, nil, isDoubleTap)
						return
					end
				end		

				knit.GetService("AttackService").Attack:Fire(self.SelectedSkill)
			end
		end

		if skill == "Awaken" and plr:GetAttribute("Ultimate") >= plr:GetAttribute("MaxUltimate") then
			knit.GetService("AttackService").Awaken:Fire()

			-- Function to update awakened or base skills
			local function updateAwakenedSkills()
				if plr:GetAttribute("IsUltimate") then
					for _, v in Grid:GetChildren() do
						if v:IsA("ImageButton") then
							v:Destroy()
						end
					end

					for i, v in pairs(Info.Awakened) do
						local slotnum = self.Skills[i]
						if slotnum then
							AddSlot(slotnum, v)
						end
					end
				else
					for _, v in Grid:GetChildren() do
						if v:IsA("ImageButton") then
							v:Destroy()
						end
					end

					for i, v in pairs(Info.Base) do
						local slotnum = self.Skills[i]
						if slotnum then
							AddSlot(slotnum, v)
						end
					end
				end
			end

			-- Reset Ultimate attributes
			plr:SetAttribute("Ultimate", 0)
			plr:SetAttribute("MaxUltimate", 100)

			-- Connect to the AttributeChanged event to monitor IsUltimate changes
			plr:GetAttributeChangedSignal("IsUltimate"):Connect(function()
				updateAwakenedSkills()
			end)

			-- Initial skill update
			updateAwakenedSkills()

			print("yes awaken")

			-- Update energy bar
			local energyBar = AwakeningFrame.ProgressBar.MainBar.Bar
			energyBar.ImageColor3 = Info.Color
			energyBar:TweenSize(
				UDim2.new(plr:GetAttribute("Ultimate") / 100, 0, 1, 0),
				Enum.EasingDirection.Out,
				Enum.EasingStyle.Sine,
				0.2,
				true
			)
		end
	end)
end



function AttackController:KnitStart()
	knit.GetService("CooldownService").Event:Connect(function(player, skill, duration)
		local Hotbar = player.PlayerGui:WaitForChild("Main"):WaitForChild("Hotbar"):WaitForChild("Grid")

		for i,v in pairs(Hotbar:GetChildren()) do
			if v and v.Parent and v.Name == skill then-- wat
				local cd = script.SlotFrame.Cooldown:Clone()
				cd.Parent = v
				cd.Visible = true

				game:GetService("TweenService"):Create(cd, TweenInfo.new(duration, Enum.EasingStyle.Linear, Enum.EasingDirection.Out), {
					Size = UDim2.new(1,0,0,0)
				}):Play()

				task.delay(duration, function()
				end)

				table.insert(self.CurrentCooldowns, cd)
			end
		end
	end)

	knit.GetService("CooldownService").CooldownsCleared:Connect(function(plr, attack)
		local Hotbar = knit.Player.PlayerGui:WaitForChild("Main"):WaitForChild("Hotbar"):WaitForChild("Grid")
		for _, v in pairs(Hotbar:GetChildren()) do
			if v:IsA("ImageButton") then
				local cooldownInstance = v:FindFirstChild("Cooldown")
				if cooldownInstance then
					cooldownInstance:Destroy()
				end
			end
		end
	end)

	knit.GetService("CooldownService").specificCD:Connect(function(plr, attack)
		local Hotbar = knit.Player.PlayerGui:WaitForChild("Main"):WaitForChild("Hotbar"):WaitForChild("Grid")

		local attackButton = Hotbar:FindFirstChild(attack)
		if attackButton and attackButton:IsA("ImageButton") then
			local cooldownInstance = attackButton:FindFirstChild("Cooldown")
			if cooldownInstance then
				cooldownInstance:Destroy()
			end
		end
	end)

	
	plr.CharacterAdded:Connect(function()
		self:Setup()
	end)

	if plr.Character then
		self:Setup()
	end
end

return AttackController

Attack Service ( Server )

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerScriptService = game:GetService("ServerScriptService")
local Knit = require(ReplicatedStorage.Game.Shared.Packages.Knit)
local Info = require(ReplicatedStorage.Info)

local Skills = {}

for _, module in pairs(ServerScriptService.Main.Skills:GetDescendants()) do
	if module:IsA("ModuleScript") then
		Skills[module.Parent.Name .. module.Name] = require(module)
	end
end

local AttackService = Knit.CreateService {
	Name = script.Name,
	Client = {
		Attack = Knit.CreateSignal(),
		Awaken = Knit.CreateSignal(),
	},
}

local doubleTapped = {}

local function executeSkill(skill, char, skillType, isDoubleTapped)
	if skill and typeof(skill[skillType]) == "function" then
		task.spawn(function()
			skill[skillType](skill, char, skillType, isDoubleTapped)
		end)
		return true
	end
	return false
end

function AttackService:KnitStart()
	self.Client.Awaken:Connect(function(player)
		if Knit.ActionCheck(player.Character, {}, false) then
			return
		end

		local char = player.Character
		if not char then return end

		player:SetAttribute("IsUltimate", true)
		Knit.GetService("CooldownService"):RemoveCooldowns(char)

		local awakeningSkill = Skills["Awakening" .. "Awaken"]
		if awakeningSkill then
			if executeSkill(awakeningSkill, char, "Fired", false) then
				print("Awakening skill triggered")
			end
		end
	end)

	self.Client.Attack:Connect(function(player, skill, skillType, IsDoubleTap)
		local char = player.Character or player.CharacterAdded:Wait()
		if not char or not player:HasAppearanceLoaded() then
			warn("Character not ready or appearance not loaded")
			return
		end

		local characterKey = player:GetAttribute("Character")
		if not characterKey then
			warn("Player character attribute is missing")
			return
		end

		local baseSkill = Skills[characterKey .. tostring(skill)]
		local ultimateSkill = Skills["Awakening" .. tostring(skill)]


		if baseSkill and not player:GetAttribute("IsUltimate") then
			local skillInfo = Info.Characters[characterKey] and Info.Characters[characterKey].Base[skill]
			if skillInfo and skillInfo["Active"] then
				executeSkill(baseSkill, char, "Fired", IsDoubleTap)
			end
		end

		if ultimateSkill and player:GetAttribute("IsUltimate") then
			local awakenedInfo = Info.Characters[characterKey] and Info.Characters[characterKey].Awakened[skill]
			if awakenedInfo and awakenedInfo["Active"] then
				executeSkill(ultimateSkill, char, "Fired", IsDoubleTap)
			end
			print("Ultimate skill triggered")
		end
	end)
end

return AttackService

It might be long so here the double tap logic

else
				self.SelectedSkill = skill
				self.Equipped = false

				local hotbar = plr.PlayerGui.Main.Hotbar.Grid
				local lastKeyButton = hotbar:FindFirstChild(self.SelectedSkill)

				self.KeyPressTimes[keycode] = self.KeyPressTimes[keycode] or 0
				local currentTime = tick()

				if Info and Info.Base[self.SelectedSkill]["twiceInfo"] and knit.Player.Character then
					local character = knit.Player.Character
					if character:IsDescendantOf(workspace.Mobs) then
						local isDoubleTap = (currentTime - self.KeyPressTimes[keycode] <= Info.Base[self.SelectedSkill]["twiceInfo"]["interval"])
						self.KeyPressTimes[keycode] = currentTime

						if isDoubleTap then
							knit.GetService("AttackService").Attack:Fire(self.SelectedSkill, nil, isDoubleTap)
							return
						end
					end
				end

				knit.GetService("AttackService").Attack:Fire(self.SelectedSkill, nil)


				if lastKeyButton then
					local overlay = lastKeyButton:FindFirstChild("Overlay")
					if overlay then
						overlay.Visible = false
						self.Equipped = false
						plr.Character:SetAttribute("CheckActivated", nil)
					end
				end

			end
		end

As shown in the video, I’m attacking another player, and when I switch to my alternate account, it seems like the victim (the one being attacked) can still double-tap to trigger the ability. This behavior should not be happening. I want to ensure that only the attacker (the one who initiated the attack) can double-tap to activate the ability, and the victim should not be able to trigger it.

Can you help me fix this?

My head hurts after tryna find a solution for this.

Oh! In the attack service, I send the double-tap input to the skill module so it can detect when a double-tap occurs.