local function v(v)if not v then return end if not v:IsA("\066\097\115\101\080\097\114\116")then return end local s=v:GetAttribute("\073\110\116\101\114\097\099\116\097\098\108\101")if not s then return end local C=interactables:FindFirstChild(v.Name)if not C then return end local S=(v.Position-hrp.Position).magnitude if S>MAX_INTERACTION_DIST+math.max(v.Size.X,v.Size.Y,v.Size.Z)/2 then return end return C end local function s(v)if v~=ply then v:Kick(_G.EXPLOITER_KICK_MESSAGE)return false end return true end local function C()if downedVal.Value then return end if holdingInputVal.Value and mouseHoverObjectVal.Value then local s=v(mouseHoverObjectVal.Value)local C=false local S=nil if s then local v=require(s)if v and(v.serverChecks and typeof(v.serverChecks)=="\102\117\110\099\116\105\111\110")then C=v.serverChecks(mouseHoverObjectVal.Value)S=v.serverChecks else C=true end end if C then local v=CIH.determineInteraction(ply,mouseHoverObjectVal.Value)local s=true local C=nil while v and s do C,s=CIH.interact(ply,mouseHoverObjectVal.Value)if s then v=CIH.determineInteraction(ply,mouseHoverObjectVal.Value)end end if S and not S(mouseHoverObjectVal.Value)then deleteInteractionUIEvent:FireClient(ply,mouseHoverObjectVal.Value)end end end end local function S(v,S)if not s(v)then return end if downedVal.Value then return end if S~=nil and typeof(S)=="\098\111\111\108\101\097\110"then holdingInputVal.Value=S else holdingInputVal.Value=false end C()end local F=nil local function O(S,Z)if not s(S)then return end if downedVal.Value then return end if F then F:Disconnect()end mouseHoverObjectVal.Value=nil local N=v(Z)if N then mouseHoverObjectVal.Value=Z if F then F:Disconnect()end F=Z.Changed:Connect(function()if F then F:Disconnect()end mouseHoverObjectVal.Value=nil O(S,Z)end)end C()end local function Z(v)if v then O(ply,nil)mouseHoverObjectVal.Value=nil holdingInputVal.Value=false end end
--

local function isAValidNearbyInteractable(targetObj)
	if not targetObj then return end
	if not targetObj:IsA("BasePart") then return end
	local interactable = targetObj:GetAttribute("Interactable")
	if not interactable then return end
	local module = interactables:FindFirstChild(targetObj.Name)
	if not module then return end
	local dist = (targetObj.Position - hrp.Position).magnitude	
	if dist > MAX_INTERACTION_DIST + math.max(targetObj.Size.X, targetObj.Size.Y, targetObj.Size.Z) / 2 then return end

	return module
end

local function samePlayer(rPly)
	if rPly ~= ply then rPly:Kick(_G.EXPLOITER_KICK_MESSAGE) return false end
	return true
end

local function interact()
	if downedVal.Value then return end 
	
	if holdingInputVal.Value and mouseHoverObjectVal.Value then		
		local interactableModule = isAValidNearbyInteractable(mouseHoverObjectVal.Value)	
		local success = false
		local serverChecksFunc = nil
		if interactableModule then
			local mod = require(interactableModule)	
			if mod and mod.serverChecks and typeof(mod.serverChecks) == "function" then
				success = mod.serverChecks(mouseHoverObjectVal.Value)
				serverChecksFunc = mod.serverChecks
			else
				success = true
			end
		end
		
		if success then
				
			local interactionSuccessful = CIH.determineInteraction(ply, mouseHoverObjectVal.Value)	
			local shouldKeepHolding = true
			local interacted = nil

			while interactionSuccessful and shouldKeepHolding do
				interacted, shouldKeepHolding = CIH.interact(ply, mouseHoverObjectVal.Value)
				if shouldKeepHolding then
					interactionSuccessful = CIH.determineInteraction(ply, mouseHoverObjectVal.Value)	
				end
			end
			
			if serverChecksFunc and not serverChecksFunc(mouseHoverObjectVal.Value) then
				deleteInteractionUIEvent:FireClient(ply, mouseHoverObjectVal.Value)
			end
		end
	end
end

local function onUpdateInputHoldEvent(rPly, inputState)
	if not samePlayer(rPly) then return end
	if downedVal.Value then return end
	
	if inputState ~= nil and typeof(inputState) == "boolean" then
		holdingInputVal.Value = inputState
	else
		holdingInputVal.Value = false
	end	
	
	interact()
end

local globalObjChangedConn = nil

local function onUpdateHoverObjectEvent(rPly, newObj)
	if not samePlayer(rPly) then return end
	if downedVal.Value then return end
	
	if globalObjChangedConn then globalObjChangedConn:Disconnect() end
	mouseHoverObjectVal.Value = nil
	
	local interactableModule = isAValidNearbyInteractable(newObj)	
	
	if interactableModule then
		mouseHoverObjectVal.Value = newObj
		
		if globalObjChangedConn then globalObjChangedConn:Disconnect() end
		globalObjChangedConn = newObj.Changed:Connect(function()
			if globalObjChangedConn then globalObjChangedConn:Disconnect() end
			mouseHoverObjectVal.Value = nil
			onUpdateHoverObjectEvent(rPly, newObj)
		end)
	end
	
	interact()
end

local function onDown(val)
	if val then
		onUpdateHoverObjectEvent(ply, nil)
		mouseHoverObjectVal.Value = nil
		holdingInputVal.Value = false
	end
end
