All proximity prompts somehow refer to the different objects, despite not being it

My objects that have proximity prompts in them somehow all refer to the same object (WallFirstAidCase) when they’re next to it, WallFirstAidCase is unironically the only consistent object

i have ZERO clue as to why this is happening and i am extremely confused
some objects seem to be able to refer to themselves, but the crate can’t do it at all and always refers to ‘WallFirstAidCase’

All of the proximity prompts are parented to the proper objects, and the objects are all anchored and welded as needed.




again; ZERO clue why this is happening

local pPromptService = game:GetService("ProximityPromptService")
local cService = game:GetService("CollectionService")
local rStorage = game:GetService("ReplicatedStorage")
local players = game:GetService("Players")

-- Player variables;
local player = players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local mouse = player:GetMouse()
local camera = workspace.CurrentCamera

-- Path to events;
local eventsFolder = rStorage:WaitForChild("Events")
local bindableEvents = eventsFolder:WaitForChild("Bindable")

-- Events;
local notification = bindableEvents:WaitForChild("Notification")

-- Path to modules;
local playerScripts = player.PlayerScripts
local settingScripts = playerScripts:WaitForChild('Settings')
local modulesFolder = rStorage:WaitForChild("Modules")
local functionalityModules = modulesFolder:WaitForChild("FunctionalityModules")
local weaponModules = modulesFolder:WaitForChild("WeaponModules")

-- Modules;
local openableStats = require(functionalityModules:WaitForChild("OpenableStats"))
local weaponStats = require(weaponModules:WaitForChild("WeaponStats"))
local playerSettings = require(settingScripts:WaitForChild("UserSettingsModule"))
local visuals = require(script:WaitForChild("Visuals"))

-- Path to elements to clone;
local guiElements = rStorage:WaitForChild("GUIElements")
local gameplayGuiElements = guiElements:WaitForChild("Gameplay")

-- Elements to clone;
local promptToClone = gameplayGuiElements:WaitForChild("Prompt")

-- Values;
local checkInterval = 0.05
local distance = 20
local useKey = playerSettings['Keybinds']['Use']

-- Parameters;
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {character}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude

-- Helper functions;
local function IsPlayerCloseEnough(promptedPart: BasePart)
	local root = character.PrimaryPart
	local prompt = promptedPart:FindFirstChildOfClass('ProximityPrompt')

	local distance = (promptedPart.Position - root.Position).Magnitude
	if distance > prompt.MaxActivationDistance then
		print(`Player is too far from prompt, max distance is {prompt.MaxActivationDistance}, actual distance is {distance}`)
		return false
	else
		return true
	end
end

local function ClearPrompts()
	if not script.Parent:FindFirstChildOfClass('BillboardGui') then return end
	local promptsCleared = 0
	
	for _, potentialPrompt: BillboardGui in script.Parent:GetChildren() do
		if potentialPrompt:IsA('BillboardGui') then
			potentialPrompt:Destroy()
			promptsCleared += 1
		end
	end
	
	for _, taggedInstance in cService:GetTagged('objectHighlight') do
		taggedInstance:Destroy()
	end
	
	print(`All prompts successfully cleared! There was {promptsCleared} prompt/s.`)
end

local function RaycastFromCharacter()
	local origin = character.PrimaryPart.Position
	local direction = (mouse.Hit.Position - origin).Unit
	local raycast = workspace:Raycast(origin, (direction * distance), raycastParams)
	
	if raycast then
		return raycast
	end
	
	--print('No hit detected, skipping.')
	ClearPrompts()
	return nil
end

-- Main functions;
local function SetupPrompt(hitInstance: BasePart, promptInstance: ProximityPrompt)
	promptInstance.KeyboardKeyCode = useKey
	
	local fullObject = hitInstance:FindFirstAncestorOfClass('Model') or hitInstance:FindFirstAncestorOfClass('Tool')
	local prompt = promptToClone:Clone()
	local objectData = weaponStats[fullObject.Name] or openableStats[fullObject.Name]
	
	if script.Parent:FindFirstChildOfClass('BillboardGui') then return end
	
	prompt.Parent = script.Parent
	prompt.Adornee = hitInstance
	prompt.Name = `{fullObject.Name}Prompt`
	--prompt.ExtentsOffset = Vector3.new(0, -3, 0)
	
	visuals.SetObjectAndActionText(prompt, objectData, useKey)
	visuals.ToggleStatVisibility(objectData, prompt, useKey)
	visuals.HighlightObject(fullObject)
	visuals.ChangeBorderColor(objectData.tier or 'NaN', prompt)
	
	task.spawn(function()
		while prompt.Enabled do
			local raycast = RaycastFromCharacter()
			if not raycast then
				prompt.Enabled = false
				break
			end
			
			if not raycast.Instance:FindFirstChildOfClass('ProximityPrompt') then
				prompt.Enabled = false
				break
			end
			
			prompt.Enabled = IsPlayerCloseEnough(hitInstance)
			task.wait(checkInterval)
		end
		
		ClearPrompts()
	end)
end

local function ScanForPrompts()
	while task.wait(checkInterval) do
		if character.Parent ~= workspace.InGame then
			--print(`Character's not in-game, skipping`)
			continue
		end
		
		if player.CameraMode == Enum.CameraMode.Classic then
			--print(`Player's camera mode is classic, skipping`)
			ClearPrompts()
			continue 
		end
		
		local raycast = RaycastFromCharacter()
		if not raycast then continue end
		
		local hitInstance: BasePart = raycast.Instance
		local prompt = hitInstance:FindFirstChildOfClass('ProximityPrompt')
		
		if not prompt then
			--print('No proximity prompt found, skipping')
			continue
		end
		if not IsPlayerCloseEnough(hitInstance) then continue end		
		if prompt.Style == Enum.ProximityPromptStyle.Default then
			print(`Default prompt style, skipping {prompt.Parent.Parent.Name}`)
			continue
		end
		
		SetupPrompt(hitInstance, prompt)
	end
end

local function OnPromptTriggered(promptTriggered: ProximityPrompt, playerWhoTriggered: Player)
	if playerWhoTriggered ~= player then return end
	
	local object = promptTriggered:FindFirstAncestorOfClass('Model') or promptTriggered:FindFirstAncestorOfClass('Tool')
	local objectData = openableStats[object.Name]
	print(objectData)
	print(object.Name)
	if not objectData then return end
	
	local openTime = objectData.openTime
	if openTime == 0 then return end	
	notification:Fire('interaction', 'Opening', openTime)
end

local function OnRespawned(newChar: Model)
	character = newChar
	raycastParams.FilterDescendantsInstances = {character}
end

-- Runtime;
task.spawn(ScanForPrompts)
pPromptService.PromptTriggered:Connect(OnPromptTriggered)
player.CharacterAdded:Connect(OnRespawned)
1 Like

Have you tried debugging with prints to see what object gets returned when the raycast fires?

2 Likes

it’s ok i found a workaround (or a solution i guess)

the proximity prompts have to be disabled and only enabled whenever the raycast actually hits their part instance, that way the incorrect prompts can never trigger

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.