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

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
