It would have helped to have commented your code and pointed out where specifically your error was. It was fairly painful to count out your lines to find the source of error.
I feel that it’d be more worth your time to address all the potential or actual code problems that you’re having or that can be improved upon rather than going at the error specifically, since there’s a lot to be looked at in your code.
Client:
-
Try keeping your variables and constants together for better readability. You should also aim to use consistent conventions. Unless, well, you don’t care. Here’s what I typically use:
- This in reference to all your variables being lowercase except for ReplicatedStorage, SpellChatted and VALID_DURATION.
-
Might be more helpful to send variables through remotes in the order that you check them in.
-
SpellChatted, orientation, mouse.Hit
-
First, you check if a spell was chatted. If it was, then you use the orientation of the Handle to determine a start point. Finally, you construct a Ray to mouse.Hit.
-
You may also want to consider not adding a debounce if a spell wasn’t chatted for the sake of UX design. Might hurt the experience to chant a spell but not be able to use it.
-
Server:
-
You broke convention using RepStorage over ReplicatedStorage! What happened!?
-
Everything from indexing the StarterPack’s Wand to the IsWandEquipped function is pointless overhead. Get rid of it. Keep the function but change how it works to something less intensive.1
-
For a receiving remote, don’t use CharacterAdded.Wait. Check if a character exists; if it doesn’t reject the request. Don’t stall the thread until the character exists.
-
MAIN SOURCE OF YOUR ERROR: Your code assumes that FindPartOnRay returns a non-nil part. When you use that method, it can return a nil value. Thus, when your code proceeds and doesn’t check if part is non-nil, it attempts to index Parent. Parent is not a valid member of nil.3
- Even if the part does exist, Parent can be nil too. Parts with nil parents are typically not going to be in the Workspace or detectable, but just keep that in mind.
-
For some reason, you’re casting two rays? Get rid of the bottom one, you don’t use its arguments anyway and one them variable shadows a parameter sent to the function avadakedavra.2
-
Do NOT use the parent argument of Instance.new. Set your properties first and then set the Parent.4
-
A note that I’m just addressing your code work, but typically what I’d recommend here is that you pass this beam creation work to the client to render.
-
You can also get rid of unnecessary property setting.
-
[1]:
local function isWandEquipped(character)
local tool = character:FindFirstChildWhichIsA("Tool")
if tool and tool.Name == "Wand" then
return true
end
return false
end
-- The function below is also acceptable:
local function isWandEquipped(character)
local tool = character:FindFirstChildWhichIsA("Tool")
return tool and tool.Name == "Wand"
end
[2]:
local part, position = workspace:FindPartOnRay(ray, plr.Character, false, true)
[3]:
if part and part.Parent then
local humanoid = part.Parent:FindFirstChildWhichIsA("Humanoid")
if not humanoid and part.Parent.Parent then
humanoid = part.Parent.Parent:FindFirstChildWhichIsA("Humanoid")
end
end
[4]:
-- It'd be better to create a function that makes and returns the beam.
local beam = Instance.new("Part")
beam.BrickColor = BrickColor.new("Really red")
beam.Material = Enum.Material.Neon
beam.Transparency = 0.5
beam.Anchored = true
beam.CanCollide = false
beam.Orientation = orientation
beam.Size = Vector3.new(1, 1, 1)
-- Got rid of distance calculation, you don't ever use distance
-- @ below, CFrame.p is deprecated in favour of CFrame.Position
beam.CFrame = CFrame.new(plr.Character.Head.CFrame.Position - position)
beam.Parent = workspace