Replace this:
if model and model:IsA("Model") then
print(model.Name)
end
Replace this:
if model and model:IsA("Model") then
print(model.Name)
end
I would recommend doing this on the client, not the server. That way, you can use the camera (which is more “precise” than the head). If you’re in shift lock switch or first person, using the head can cause problems because the head won’t face where you are actually looking, which means you might think that the player is looking at something when they actually aren’t. (this problem doesn’t exist with the camera)
Then, if the player is looking at something, you can fire a RemoteEvent to tell the server to act on this. If you’re concerned about security, then you can validate if the player was actually looking at the object on the server.
If it’s in view with the camera, it’s always in view with the head, but if it’s in view with the head, then it’s not always in view with the camera. That means that if the client tells you it’s in view with the camera, you can validate it on the server using the head.
Here’s what you would do on the client:
-- localscript in StarterPlayerScripts
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TestingRemote = ReplicatedStorage.TestingRemote
local RunService = game:GetService("RunService")
local priority = Enum.RenderPriority.Camera.Value
local Player = game:GetService("Players").LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local camera = workspace.CurrentCamera
local position = -- the position you want to check if its looking at
local options = RaycastParams.new()
options.FilterType = Enum.RaycastFilterType.Blacklist
options.IgnoreWater = true
RunService:BindToRenderStep("Check", priority, function()
local _, onScreen = camera:WorldToViewportPoint(position)
if onScreen then
-- direction check passed, now raycast
options.FilterDescendantsInstances = { Character }
local cameraPos = camera.CFrame.Position
local result = workspace:Raycast(
cameraPos,
position - cameraPos,
options
)
if result and result.Instance then
-- it's visible on the client, send it to the server
TestingRemote:FireServer(position)
end
end
end)
Player.CharacterAdded:Connect(function(character)
Character = character
end)
And then here’s what you would use on the server to validate it:
-- server script in ServerScriptService
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TestingRemote = ReplicatedStorage.TestingRemote
TestingRemote.OnServerEvent:Connect(function(player, lookAt)
--[[
client told us that they're looking at it with their camera,
and passed the Vector3 of what they looked at. We have
to validate it.
]]
local character = player.Character
local direction = (lookAt - character.Head.Position).Unit
local lookVector = character.Head.CFrame.LookVector
if direction:Dot(lookVector) > 0.5 then
--// they were looking at it, proceed
end
end)
The server uses dot product to validate it, and the client uses WorldToViewportPoint and workspace:Raycast() to see if it is on screen. Then, the server can take action if it gets validated. Otherwise, there is a chance the client may have been exploiting, but we still aren’t sure so we can’t take any action on it.
For more information about Dot product, see @okeanskiy’s video here: https://www.youtube.com/watch?v=BUwAcW_18Ws
For more information about Camera:WorldToViewportPoint(), see the developer article here:
https://developer.roblox.com/en-us/api-reference/function/Camera/WorldToViewportPoint
You can use his if you want, but the thing I posted doesn’t work with his.