Trying to fix Server Owned rockets exploding early for clients

For my game there’s going to be turrets that shoot rockets at the player. I want them to explode right on impact on the players screens.

The rockets are server owned using :SetNetworkOwner(nil) and im trying to fix them exploding early for the clients, and rockets exploding if it hits the player on the server and not on client due to lag.

Examples:
Exploding early


Player lag

Been looking for a solution for a couple days. Ive tried sending the rockets position to all clients every heartbeat. Ive also tried making the client check if a rocket has hit them, then fires the server, but tab glitching makes the rocket not explode.

There is one module script thats spawns the rocket part, and one ServerScript that is a child of the rocket part that moves it and explodes. Both scripts are just edited versions of the free rocket launcher model. I want it to work and look kinda good for other players aswell.

ModuleScript:

--edited version of the roblox rocketlauncher free model to work shoot anywhere

--CONSTANTS--

local GRAVITY_ACCELERATION = workspace.Gravity

local ROCKET_SPEED = 60 -- Speed of the projectile
local ROCKET_PART_SIZE = Vector3.new(1, 1, 4) --brickbattle rocket size is 1, 1, 4
local ROCKET_BRICKCOLOR = BrickColor.new("Bright blue")

local TRAIL_LIFETIME = 0.1
local TRAIL_TEXTURE = "rbxassetid://18299926535"

--VARIABLES--

local Players = game:GetService("Players")
local CollectionService = game:GetService("CollectionService")
local SoundService = game:GetService("SoundService")

local RocketScript = script:FindFirstChild("Rocket")
local SwooshSound = SoundService.Sounds.Swoosh
local BoomSound = SoundService.Sounds.Boom

--rocket instance, cloned when rocket is fired
local Rocket = Instance.new("Part") do
	Rocket.Name = "Rocket"
	Rocket.Size = ROCKET_PART_SIZE
	Rocket.BrickColor = ROCKET_BRICKCOLOR
	Rocket.TopSurface = Enum.SurfaceType.Studs
	Rocket.BottomSurface = Enum.SurfaceType.Studs
	Rocket.LeftSurface = Enum.SurfaceType.Studs
	Rocket.RightSurface = Enum.SurfaceType.Studs
	Rocket.FrontSurface = Enum.SurfaceType.Studs
	Rocket.BackSurface = Enum.SurfaceType.Studs
	Rocket.CanCollide = false
	
	--attachments for trail
	local attachment0 = Instance.new("Attachment")
	attachment0.Name = "attachment0"
	attachment0.Position = Vector3.new(0.4, 0.4, 2)
	attachment0.Parent = Rocket
	
	local attachment1 = Instance.new("Attachment")
	attachment1.Name = "attachment1"
	attachment1.Position = Vector3.new(-0.4, -0.4, 2)
	attachment1.Parent = Rocket
	
	local trail = Instance.new("Trail")
	trail.Attachment0 = attachment0
	trail.Attachment1 = attachment1
	trail.Lifetime = TRAIL_LIFETIME
	trail.Texture = TRAIL_TEXTURE
	trail.FaceCamera = true
	trail.LightEmission = 1
	trail.Transparency = NumberSequence.new(0, 1)
	trail.Parent = Rocket
	
	--attachment for vectorforce
	local attachment2 = Instance.new("Attachment")
	attachment2.Name = "attachment2"
	attachment2.Parent = Rocket
	
	-- Add a force to counteract gravity
	local vectorForce = Instance.new("VectorForce")
	vectorForce.Name = "Antigravity"
	vectorForce.Attachment0 = attachment2
	vectorForce.Force = Vector3.new(0, Rocket:GetMass() * GRAVITY_ACCELERATION, 0)
	vectorForce.RelativeTo = Enum.ActuatorRelativeTo.World
	vectorForce.Parent = Rocket
	
	--fades out when spawned
	local highlight = Instance.new("Highlight")
	highlight.DepthMode = Enum.HighlightDepthMode.Occluded
	highlight.FillTransparency = 0.1
	highlight.FillColor = Color3.fromRGB(255, 255, 255)
	highlight.OutlineTransparency = 1
	highlight.Parent = Rocket

	local swooshSoundClone = SwooshSound:Clone()
	swooshSoundClone.Parent = Rocket

	local boomSoundClone = BoomSound:Clone()
	boomSoundClone.PlayOnRemove = true
	boomSoundClone.Parent = Rocket

	local rocketScriptClone = RocketScript:Clone()
	rocketScriptClone.Disabled = false
	rocketScriptClone.Parent = Rocket
	
	CollectionService:AddTag(Rocket, "Rocket")
end

--MODULE

local LaunchRocket = {}

function LaunchRocket.Launch(target: Vector3, shooter:Part) --target = vector3 where rocket faces, shooter = where rocket spawns
	local rocketClone = Rocket:Clone()

	-- position and launch
	local spawnPosition = (shooter.Position)
	rocketClone.CFrame = CFrame.new(spawnPosition, target) --NOTE: This must be done before assigning Parent
	rocketClone.Velocity = rocketClone.CFrame.lookVector * ROCKET_SPEED --NOTE: This should be done before assigning Parent
	rocketClone.Parent = workspace.TempParts
	rocketClone:SetNetworkOwner(nil)
end

return LaunchRocket

RocketScript:

-----------------
--| Constants |--
-----------------

local BLAST_RADIUS = 6 -- Blast radius of the explosion
local BLAST_DAMAGE = 30 -- Amount of damage done to players
local BLAST_PRESSURE = 250000 -- Amount of force applied to parts

local ROCKET_REMOVE_TIME = 10

-----------------
--| Variables |--
-----------------

local TweenService = game:GetService("TweenService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Debris = game:GetService("Debris")

local Remote = ReplicatedStorage.Remote
local RocketSyncEvent = Remote.FireAllClients.RocketSyncEvent

local Rocket: Part = script.Parent

local SwooshSound = Rocket:FindFirstChild("Swoosh")

-----------------
--| Functions |--
-----------------

local modelsHit = {}

local function touched()
	local explosion = Instance.new("Explosion")
	explosion.Position = Rocket.Position
	explosion.DestroyJointRadiusPercent = 0
	explosion.BlastPressure = BLAST_PRESSURE
	explosion.BlastRadius = BLAST_RADIUS
	explosion.Parent = workspace.TempEffects
	
	Rocket:Destroy()

	explosion.Hit:Connect(function(part, distance) --i took this from the roblox explosion docs
		local parentModel = part.Parent
		if parentModel then
			-- check to see if this model has already been hit
			if modelsHit[parentModel] then
				return
			end
			-- log this model as hit
			modelsHit[parentModel] = true

			-- look for a humanoid
			local humanoid:Humanoid = parentModel:FindFirstChild("Humanoid")
			if humanoid then
				humanoid:TakeDamage(BLAST_DAMAGE)

				local IsRagdoll = humanoid.Parent:FindFirstChild("IsRagdoll")
				if IsRagdoll then
					IsRagdoll.Value = true
				end
			end
		end
	end)
end

--other

local highlight = Rocket:FindFirstChild("Highlight")
TweenService:Create(highlight, TweenInfo.new(1.5), {FillTransparency = 1}):Play()

Debris:AddItem(Rocket, ROCKET_REMOVE_TIME)

SwooshSound:Play()
Rocket.Touched:Connect(touched)

Im using CompletedLoop’s Perect R6 Ragdoll modules so thats why theres ragdoll stuff in the code.

1 Like