Okay so here’s the situation:
I have a module script that handles most functions for my game. For a while, only NPCs had guns and thus they were the only ones who could shoot but now we are adding the option for players to get guns too. I am aware that to prevent the infamous “hopping” that the bullet does when switching network ownership automatically, I have to manually set the network ownership to the client of the person who fired it.
However, our game has multiple maps and each map is seen by the server but it is moved to replicated storage on all of the clients when they join the game. This is to reduce lag from rendering while having the server-side NPCs being able to interact with the map they are in.
The problem:
When I set the network ownership of the bullet to the server, everything works fine and it detects when the bullet is hit.
However, when the bullet is set to the network ownership of the client, it only detects when it hits things that aren’t touched by the client. This means that the bullets only register a hit when it hits terrain, other NPCs, and other players.
When a player spawns at a map, it is cloned locally from ReplicatedStorage and put into a folder in Workspace. The bullets do not register hits when they hit objects in these folders but they do register them when the network ownership is the server.
I don’t think that my code is the issue but here it is anyway:
function module.shoot(gun, targetLocation, team, dmg, firer) --team 0 = light, 1 = dark
local bolt = game.ReplicatedStorage.BlasterBolt:Clone()
local teamInd = Instance.new("NumberValue")
if not dmg == nil then
bolt.Damage.Value = dmg
end
teamInd.Parent = bolt
if team == 0 then
teamInd.Name = "LightSide"
bolt.Trail.Color = lightColor
bolt.Particles.Color = lightColor
bolt.OutterMesh.BrickColor = BrickColor.new("Lapis")
elseif team == 1 then
teamInd.Name = "DarkSide"
bolt.Trail.Color = darkColor
bolt.Particles.Color = darkColor
bolt.OutterMesh.BrickColor = BrickColor.new("Really red")
end
local sound = Instance.new("Sound", gun)
if firer and firer.Name == "Separatist Tank" then
sound.SoundId = "rbxassetid://314322896"
else
sound.SoundId = "rbxassetid://387095243"
end
sound.MaxDistance = 750
sound.Parent = gun
sound.Volume = 1.5
if gun.Parent.Name == "B2" then
sound.PlaybackSpeed = 1.25
elseif gun.Parent.Name == "Chaingun" then
sound.PlaybackSpeed = 0.75
end
if game.Players:GetPlayerFromCharacter(firer) then
local playerHit = game.Players:GetPlayerFromCharacter(firer)
bolt.BulletScript.Shooter.Value = playerHit
else
bolt.BulletScript.Shooter.Value = firer
end
sound:Play()
bolt.BodyVelocity.Velocity = CFrame.new(gun.Position, targetLocation).LookVector*250
bolt.Parent = workspace
bolt.CFrame = gun.CFrame
bolt.CFrame = CFrame.new(gun.Position, targetLocation)
local startPos = gun.Position
if game.Players:GetPlayerFromCharacter(firer) then
local playerHit = game.Players:GetPlayerFromCharacter(firer)
--bolt:SetNetworkOwner(playerHit)
else
bolt:SetNetworkOwner(nil)
end
bolt.Touched:Connect(function(hit)
if bolt.Dud.Value == false and hit.Transparency ~= 1 and hit.Parent.ClassName ~= "Accessory"
and hit.Name ~= "BlasterBolt" and not hit.Parent:FindFirstChild("Cosmetic") and not
hit:IsDescendantOf(firer) then
--print("Bullet hit "..hit.Name)
local lookVector = CFrame.new(startPos, targetLocation).LookVector*4000
local ray = Ray.new(startPos, lookVector)
local usedPositions = {}
local usedParts = {}
local usedNormals = {}
local usedMaterials = {}
local lastPosition = nil
local lastPart = nil
local lastNormal = nil
local lastMaterial = nil
repeat
local ignoreList = {firer}
for i = 1, #usedParts do
table.insert(ignoreList, usedParts[i])
end
lastPart, lastPosition, lastNormal, lastMaterial =
workspace:FindPartOnRayWithIgnoreList(ray, ignoreList)
table.insert(usedParts, lastPart)
table.insert(usedPositions, lastPosition)
table.insert(usedNormals, lastNormal)
table.insert(usedMaterials, lastMaterial)
until lastPart == nil
for i = 1, #usedParts do
if game.Players:GetPlayerFromCharacter(firer) then
--print(usedParts[i].Name)
end
if usedParts[i] == hit then
--print(firer.Name .." impacted " .. usedParts[i].Name)
bolt.Dud.Value = true
bulletImpact(usedParts[i], bolt, usedPositions[i], usedNormals[i], usedMaterials[i], firer)
end
end
end
end)
module.debris(bolt,5)
end
Edit: here’s a video of the issue. The ship interior is made up of local parts and the big square in the middle is never affected by the client. As you can see, the bullets make their bullet holes/marks in the part that isn’t altered by the client but the hits don’t register at all with the client parts of the ship.
Contrast this with this next video where the network owner of the bullets is set to the server. Notice how it registers the hits this time.