Hello. I’m making an ice bullet of sorts that is created and shot by a module script run by a server script. The script works fine but the bullet ends up in the wrong position for the client who fired it and correctly on the server.
Ex:
this is what the server-side sees (this is what it should look like)
This is what the client sees
When the icicles are shot, a ray is casted consistently, and when the ray hits something that’s close enough to the icicle, the icicles position goes to the rays hit position.
here’s the code:
Code
--[[ Services ]]--
local ServerStorage = game:GetService("ServerStorage")
local RunService = game:GetService("RunService")
--[[ Variables ]]--
local projectilesFolder = workspace.Projectiles
local particlesFolder = workspace.Particles
local iceFolder = ServerStorage.Spells.Ice
local icicle = iceFolder:WaitForChild("Icicle")
local icicleExplosion = iceFolder:WaitForChild("IceExplosin")
--[[ Custom Variables ]]--
local SPEED_OF_ICEICLE = 100
local LIFETIME = 5
local DAMAGE = 10
--[[ Functions ]]--
local function shootIce(hmnRP)
local ORIGIN_POINT = (hmnRP.CFrame * CFrame.new(0, 0, -3)).Position
local TARGET = (hmnRP.CFrame * CFrame.new(0, 0, 7)).Position
local velocity = (ORIGIN_POINT - TARGET).unit * SPEED_OF_ICEICLE
local clonedIcicle = icicle:Clone()
clonedIcicle:SetPrimaryPartCFrame(CFrame.new(ORIGIN_POINT) * (hmnRP.CFrame - hmnRP.Position))
local originalRotation = hmnRP.CFrame - hmnRP.Position
clonedIcicle.Parent = projectilesFolder
local bulletPos, bulletVelocity = ORIGIN_POINT, velocity
local startTime = DateTime.now().UnixTimestamp
while DateTime.now().UnixTimestamp - startTime < LIFETIME do
local dt = RunService.Heartbeat:Wait()
local bulletRay = Ray.new(bulletPos, bulletVelocity)
local hit, position = workspace:FindPartOnRayWithIgnoreList(bulletRay, projectilesFolder:GetDescendants())
if hit and (position - bulletPos).magnitude < 2 then --Doesn't position in the wall
print(position)
clonedIcicle:SetPrimaryPartCFrame(CFrame.new(position) * originalRotation)
local hmn = hit.Parent:FindFirstChild("Humanoid")
if hmn then
if not hit:IsDescendantOf(hmnRP.Parent) then --Doesn't always hit hmn
local clonedExplosin = icicleExplosion:Clone()
clonedExplosin.Parent = particlesFolder
clonedExplosin.Position = position
hmn:TakeDamage(DAMAGE)
clonedIcicle:Destroy()
wait(.2)
clonedExplosin.IceExplosin.Rate = 0
wait(4)
clonedExplosin:Destroy()
return
end
elseif hit:IsA("BasePart") and not hmn then
clonedIcicle.PrimaryPart.Anchored = true
clonedIcicle.PrimaryPart.CanCollide = false
clonedIcicle.PrimaryPart.ForceFieldGlow:Destroy()
wait(.5)
clonedIcicle.PrimaryPart.ParticleEmitter.Rate = 0
clonedIcicle.PrimaryPart.Transparency = .7
wait(30)
break
end
end
bulletPos = bulletPos + bulletVelocity * dt
if not clonedIcicle then break end
clonedIcicle:SetPrimaryPartCFrame(CFrame.new(bulletPos) * originalRotation)
end
clonedIcicle:Destroy()
end
return shootIce
The code is in a module script ran by a server script that receives a remote event from the client.
The icicles physics are calculated by the script, not by server physics.
I’m not totally sure how it functions, but I’m assuming that you send a remote event/function event between the client and the server.
Try having the server create a part representing the server’s raycast (using the position the ray hit’s in order to get the midpoint with the starting position and then angling the part with CFrame in order for it to point from the start to the endpoint), and then do the same on the client with a different color. You may see some or no difference.
It’ll be helpful for testing things.
Another thing to note is that not everything replicates between the server and the client, though I believe you already knew that. It may be that the character is moving and therefore not exactly in the same place as the server (due to ping). Doesn’t entirely explain the parallax even while studio testing, but you can always simulate a heavy load internet by increasing replicating time somewhere in the studio settings.
I do send a remote event that tells the server to create the bullet and shoot it on the server. I didn’t, or don’t know how to do that second part, but I did print out the position from the server and checked if the client’s side matched up, and it didn’t.
I actually didn’t know this. I tried doing the heavy load internet thing but I didn’t see much difference with where the icicle hit the wall.
Hm, everything is the same between both? You might just need to leave it on the server, and just let the workspace replicate rather than have the server and the client do it both.
The server naturally replicates to the client. Due to FilteringEnabled anything done on the client doesn’t replicate to the server. That’s what I meant by having two different visualizing scripts for the raycasts.
So like, fire the module script on the client and the server except the server wouldn’t replicate it back to the client? How do I play it on the server without making double for the person who fired it. I’m really confused.
I figure out what the problem was but I can’t make sense of it. I noticed that when the bullet landed it looked like it bounced off the wall for a split sec for the client and only the client. I assume the part was being placed in the right place but because the part wasn’t anchored till after it checked if the ray hit a humanoid, it had a split sec to act on the servers physics, bounced glitched out the wall, then was anchored. All I had to do was move the line where is set the parts position after the part was anchored. Honestly surprised I found this. But anyways thank you for the help!