Client Side Effects Help

  1. What do you want to achieve?
    Im trying to make client to server to client replication projectile effects for my game, I’ve made the scripts simpler than what I have, to show the basic idea and problem
  2. What is the issue?
    How would I replicate the part if the player didn’t hit anything. Also the part only replicates when it hits something and not when the player fires the projectile so theres a lot of latency. I’ve tried to move the remote fireserver but I had problems with the remote replicating multiple times because it’s a spatial query in a loop.

the latency
https://gyazo.com/f99760a27549cdc8766e836dd961dd3d
when you hit nothing
https://gyazo.com/71bb6e5b8ef08b44bf42899db2b84949

the module script

local module = {}


function module.Projectile(character)
	
	local remote = game.ReplicatedStorage.Events.RemoteEvent
	local torso = character.HumanoidRootPart
	local projectile = game.ReplicatedStorage.Part:Clone()
	local hit = false
	
	local linearvelocity = Instance.new("LinearVelocity")
	
	local linearattachment = Instance.new("Attachment")
	
	linearvelocity.MaxForce = 25000
	linearvelocity.Attachment0 = linearattachment
	linearvelocity.VectorVelocity = torso.CFrame.LookVector * 50
	linearvelocity.Parent = linearattachment
	linearattachment.Parent = projectile
	
	projectile.Position = torso.Position + torso.CFrame.LookVector * 5
	projectile.Parent = workspace
	
	local overlap = OverlapParams.new()
	overlap.FilterDescendantsInstances = {character, projectile}
	overlap.FilterType = Enum.RaycastFilterType.Exclude
	
	local heart = game:GetService("RunService").Heartbeat:Connect(function()
		
		local hitbox = workspace:GetPartsInPart(projectile)
		
		for i,v in pairs(hitbox) do
			if hit then return end
			hit = true
			
			remote:FireServer(v.Position, projectile.Name, torso.Position)
		end
	end)
	
	task.wait(1)
	heart:Disconnect()
end

return module

the local script

local uips = game:GetService("UserInputService")
local module = require(game.ReplicatedStorage.ModuleScript)

local remote = game.ReplicatedStorage.Events.RemoteEvent

local tween = game:GetService("TweenService")

uips.InputBegan:Connect(function(input)
	if input.KeyCode == Enum.KeyCode.F then
		module.Projectile(character)
	end
end)

remote.OnClientEvent:Connect(function(hitposition, attackname, origin)
	
	local attack = game.ReplicatedStorage[attackname]:Clone()
	
	attack.Position = origin
	attack.Anchored = true
	attack.Parent = workspace
	
	tween:Create(attack, TweenInfo.new(), {Position = hitposition}):Play()
end)

the server script

local remote = game.ReplicatedStorage.Events.RemoteEvent
local players = game:GetService("Players")

remote.OnServerEvent:Connect(function(player, hitposition, attackname, origin)
	
	
	for i,v in pairs(players:GetPlayers()) do
		if v ~= player then
			-- different player
			
			remote:FireClient(v, hitposition, attackname, origin)
		end
	end
	
	
	
end)

Well, I mean, what are you waiting to replicate the projectile for? When the client starts their projectile, just send the information for replicating it to the other clients immediately.

I tried this and it works, but when I have a effect that has a explosion when it hits something I’m not sure how I would replicate that with the spatial query hits

It’s only sending when there’s a hit because the remote is triggered inside a for loop. If the table is empty, the loop doesn’t run, so the remote isn’t fired.

You can’t do much to reduce latency itself, but you can interpolate the projectile’s position by passing along its spawn time and calculating where it should be based on that

I got it working but, when I moved the remote event outside the remote would fire multiple times because it was in a heartbeat function, I just made the players give it a linearvelocity instead of tweening it or calculating it.

here’s the code if anyone wants it. I hope this edifies, God bless.

the module script

local module = {}


function module.Projectile(character)

	local remote = game.ReplicatedStorage.Events.RemoteEvent
	local torso = character.HumanoidRootPart
	local projectile = game.ReplicatedStorage.Part:Clone()
	local hit = false

	local linearvelocity = Instance.new("LinearVelocity")

	local linearattachment = Instance.new("Attachment")

	linearvelocity.MaxForce = 25000
	linearvelocity.Attachment0 = linearattachment
	linearvelocity.VectorVelocity = torso.CFrame.LookVector * 50
	linearvelocity.Parent = linearattachment
	linearattachment.Parent = projectile

	projectile.Position = torso.Position + torso.CFrame.LookVector * 5
	projectile.Parent = workspace

	local overlap = OverlapParams.new()
	overlap.FilterDescendantsInstances = {character, projectile}
	overlap.FilterType = Enum.RaycastFilterType.Exclude
	
	remote:FireServer(projectile.Name, torso)

	local heart = game:GetService("RunService").Heartbeat:Connect(function()

		local hitbox = workspace:GetPartsInPart(projectile)

		for i,v in pairs(hitbox) do
			if hit then return end
			hit = true
			
			projectile:Destroy()
			
		end
	end)

	task.wait(1)
	heart:Disconnect()
end

return module

the local script

local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()

local uips = game:GetService("UserInputService")
local module = require(game.ReplicatedStorage.ModuleScript)

local remote = game.ReplicatedStorage.Events.RemoteEvent

local tween = game:GetService("TweenService")

uips.InputBegan:Connect(function(input)
	if input.KeyCode == Enum.KeyCode.F then
		module.Projectile(character)
	end
end)

remote.OnClientEvent:Connect(function(attackname, origin)

	local projectile = game.ReplicatedStorage[attackname]:Clone()

	local linearvelocity = Instance.new("LinearVelocity")

	local linearattachment = Instance.new("Attachment")

	linearvelocity.MaxForce = 25000
	linearvelocity.Attachment0 = linearattachment
	linearvelocity.VectorVelocity = origin.CFrame.LookVector * 50
	linearvelocity.Parent = linearattachment
	linearattachment.Parent = projectile
	
	projectile.Position = origin.Position + origin.CFrame.LookVector * 5
	projectile.Parent = workspace
	
	projectile.Touched:Connect(function(hit)
		projectile:Destroy()
	end)
end)

the server script

local remote = game.ReplicatedStorage.Events.RemoteEvent
local players = game:GetService("Players")

remote.OnServerEvent:Connect(function(player, attackname, origin)


	for i,v in pairs(players:GetPlayers()) do
		if v ~= player then
			-- different player

			remote:FireClient(v, attackname, origin)
		end
	end



end)

one more thing, how would I do damage when the spatial query in the module hits something, do I use another remote to fire to the server for damage?

I tried doing this and it works alright where I pass the hitbox if its a player in the module script and in the server script I do damage and return, is this a good way to do this or is there a better way?

module

	local heart = game:GetService("RunService").Heartbeat:Connect(function()

		local hitbox = workspace:GetPartsInPart(projectile)

		for i,v in pairs(hitbox) do
			if not v.Parent:FindFirstChild("Humanoid") then return end
			if hit then return end
			hit = true

			projectile:Destroy()
			remote:FireServer(projectile.Name, torso, v.Parent)

		end
	end)

server script

local remote = game.ReplicatedStorage.Events.RemoteEvent
local players = game:GetService("Players")

remote.OnServerEvent:Connect(function(player, attackname, origin, hitplayer)
	
	if hitplayer then
		hitplayer.Humanoid:TakeDamage(10)
		return
	end


	for i,v in pairs(players:GetPlayers()) do
		if v ~= player then
			-- different player

			remote:FireClient(v, attackname, origin)
		end
	end



end)