Hello! I’ve been working on a “magic projectile” over the last week and I had finally finished up until I tested it on a multiplayer server. Somehow, my client-made projectile is being replicated to all players. I.e., while having 3 players in a server, one playing activating their “magic attack” creates 3 projectiles viewable for every player.
My code is set up as:
Client calls remote event from the local script in their tool > server receives remote event via server script in the tool > server script fires the event back to all clients > local script in PlayerStarterScripts receives the event and the projectile is created there.
I have attempted to change the part’s parent location and the location from which it’s cloned but neither has helped.
Here is the code working properly with 1 player:
https://gyazo.com/eecacff4e41e9cd55aa446d5bda24c86
Here is the code not working properly with 2 players:
https://gyazo.com/6637ebe6f09a7aa3107d79b8dbdf31de
This is the local script that fires when the player activates the tool:
Summary
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RemoteEvents = ReplicatedStorage:WaitForChild("RemoteEvents")
local FireballEvent = RemoteEvents:WaitForChild("FireballEvent")
local player = game:GetService("Players").LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local HumanoidRootPart = character:WaitForChild("HumanoidRootPart")
local holdingClick = false
local mouse = player:GetMouse()
mouse.TargetFilter = workspace:WaitForChild("CharacterStorage")
local Tool = script.Parent
local Particle1 = Tool:WaitForChild("Hitbox"):WaitForChild("Particle1")
local Particle2 = Tool:WaitForChild("Hitbox"):WaitForChild("Particle2")
local equipped = false
local timer = 0
local maxChargeTime = 2
local charged
local maxDistance = 250
-- Reset script values for next attack
local function resetValues()
holdingClick = false
charged = false
Particle1.Enabled = false
Particle2.Enabled = false
Particle1.Rate = 30
timer = 0
end
-- Tool equip and unequip events
Tool.Equipped:Connect(function()
equipped = true
end)
Tool.Unequipped:Connect(function()
equipped = false
resetValues()
end)
-- Mouse press events
mouse.Button1Down:Connect(function()
if equipped == true then
holdingClick = true
Particle1.Enabled = true
Particle2.Enabled = true
while holdingClick do
timer += 1
task.wait(1)
if timer >= maxChargeTime then
Particle1.Rate = 80
end
end
end
end)
mouse.Button1Up:Connect(function()
if equipped == true then
holdingClick = false
if timer >= maxChargeTime then
charged = true
end
-- Check to see if the target is in range and isnt the skybox
if mouse.Target ~= nil and (HumanoidRootPart.Position - mouse.hit.Position).Magnitude <= maxDistance then
FireballEvent:FireServer(mouse.Hit.Position, charged, Tool)
end
resetValues()
end
end)
This is the server script that receives the remote event call:
Summary
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RemoteEvents = ReplicatedStorage:WaitForChild("RemoteEvents")
local FireballEvent = RemoteEvents:WaitForChild("FireballEvent")
local onCooldown = false
local cooldown = 1
-- Recieve event from local script, then fire back to all clients
FireballEvent.OnServerEvent:Connect(function(player, mousePosition, charged, Tool)
local Humanoid = player.Character:WaitForChild("Humanoid")
-- Make sure the player isnt dead while firing
if Humanoid.Health > 0 and Humanoid:GetState() ~= Enum.HumanoidStateType.Dead and onCooldown == false then
FireballEvent:FireAllClients(player, mousePosition, charged, Tool)
onCooldown = true
task.wait(cooldown)
onCooldown = false
end
end)
This is the local script that receives the remote event back from the server:
Summary
local Workspace = game:GetService("Workspace")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RemoteEvents = ReplicatedStorage:WaitForChild("RemoteEvents")
local FireballEvent = RemoteEvents:WaitForChild("FireballEvent")
local DamageHumanoidEvent = RemoteEvents:WaitForChild("DamageHumanoidEvent")
local ProjectileStorage = workspace:WaitForChild("CharacterStorage"):WaitForChild("ProjectileStorage")
local Fireball = script:WaitForChild("Fireball")
local explosionRadius = Vector3.new(12,12,12)
local chargedExplosionRadius = Vector3.new(18,18,18)
local damage = 15
local chargedDamage = 30
local travelSpeed = 60
local TweenService = game:GetService("TweenService")
local tweenLength = 0.8
-- Bezier curve functions
local function lerp(p0, p1, t)
return p0*(1-t) + p1*t
end
local function quad(p0, p1, p2, t)
local l1 = lerp(p0, p1, t)
local l2 = lerp(p1, p2, t)
local quad = lerp(l1, l2, t)
return quad
end
-- Create a projectile when the server sends out the event to all clients
FireballEvent.OnClientEvent:Connect(function(player, mousePosition, charged, Tool)
print("MOOSE!!!!")
local clone = Fireball:Clone()
clone.Parent = ProjectileStorage
clone.CFrame = Tool:WaitForChild("Hitbox").CFrame
if charged then
clone.Size = clone.Size * 2
end
clone:WaitForChild("Fire"):Play()
-- Start bezier curve path
local randomX = math.random(-12, 12)
local start = Tool.Hitbox.Position
local finish = mousePosition
local middle = (finish + start)/2 + Vector3.new(randomX, 30, 0)
for i = 1, travelSpeed do
local t = i/travelSpeed
local updated = quad(start,middle,finish,t)
clone.Position = updated
task.wait(0.01)
end
-- Disable projectile particles
for i, effect in pairs(clone:WaitForChild("Attachment"):GetChildren()) do
effect.Enabled = false
end
-- Create tween
local info = TweenInfo.new(tweenLength, Enum.EasingStyle.Linear, Enum.EasingDirection.In, 0, false, 0)
local goal = {}
goal.Transparency = 1
if charged then
goal.Size = chargedExplosionRadius
else
goal.Size = explosionRadius
end
local tween = TweenService:Create(clone, info, goal)
tween:Play()
local foundCharacters = {}
local timer = tick()
repeat
task.wait()
-- Get parts in region
local foundParts = Workspace:GetPartsInPart(clone)
-- Add characters to table and damage players
for i, part in pairs(foundParts) do
local Humanoid = part.Parent:FindFirstChildWhichIsA("Humanoid")
if Humanoid and not table.find(foundCharacters, part.Parent) and part.Parent ~= player.Character then
table.insert(foundCharacters, part.Parent)
if charged then
DamageHumanoidEvent:FireServer(Humanoid, chargedDamage)
else
DamageHumanoidEvent:FireServer(Humanoid, damage)
end
end
end
until (tick() - timer >= tweenLength)
table.clear(foundCharacters)
clone:Destroy()
end)
Any thoughts or ideas would help. Additionally, I’ve run into the issue of humanoids being damaged multiple times because each client fires off the “damage humanoid remote event” under the last local script. Anything would be super appreciated, thank you!