I’ve been trying to utilize view models for my game, but the position of the attachment where the bullet should come from is different from the position of the view model’s weapon.
How would I make it more accurate without it looking weird for the client and server side of the players?
--Events and parts of the gan
local MouseEvent = script.Parent:WaitForChild("MouseEvent")
local tool = script.Parent
local FastCast = require(tool.FastCastRedux)
local caster = FastCast.new()
local bulletsFolder = game.Workspace:WaitForChild("bulletsFolder")
local debris = game:GetService("Debris")
local KeyEvent = script.Parent:WaitForChild("KeyEvent")
--sound management
local Sounds = script.Parent:WaitForChild("Handle")
local gunshotsfx = Sounds:WaitForChild("M1911 Gun Sound")
gunshotsfx.RollOffMode = Enum.RollOffMode.Linear
gunshotsfx.RollOffMinDistance = 30
gunshotsfx.RollOffMaxDistance = 100
gunshotsfx.Volume = 0.5
local reloadsfx = Sounds:WaitForChild("Pistol Reload Sound")
reloadsfx.EmitterSize = 3
reloadsfx.RollOffMode = Enum.RollOffMode.Linear
reloadsfx.RollOffMinDistance = 10
reloadsfx.RollOffMaxDistance = 20
reloadsfx.Volume = 0.5
--These are the stats of the gun
local stats = tool.Stats
local damage = stats.Damage.Value
local bulletspeed = stats.Velocity.Value
local headshotMultiplier = stats.Headshot_Multiplier.Value
local reserve = stats.Reserve
local mag = stats.Mag
local magSize = stats.Mag_size.Value
local rTime = stats.Reload_time.Value
local isReloading = stats.Is_Reloading.Value
local Pierce = stats.Pierce.Value
FastCast.VisualizeCasts = false
--Cosmetic Bullets
local bulletTemplate = Instance.new("Part")
bulletTemplate.Anchored = true
bulletTemplate.Parent = bulletsFolder
bulletTemplate.CanCollide = false
bulletTemplate.Size = Vector3.new(0.1,0.1,2)
bulletTemplate.Material = Enum.Material.Neon
bulletTemplate.TopSurface = Enum.SurfaceType.Smooth
bulletTemplate.CanQuery = false
local castParams = RaycastParams.new()
castParams.FilterType = Enum.RaycastFilterType.Exclude
castParams.IgnoreWater = true
castParams.RespectCanCollide = true
local castBehavior = FastCast.newBehavior()
castBehavior.RaycastParams = castParams
castBehavior.AutoIgnoreContainer = false
castBehavior.CosmeticBulletContainer = bulletsFolder
castBehavior.CosmeticBulletTemplate = bulletTemplate
tool.Equipped:Connect(function()
castParams.FilterDescendantsInstances = {tool.Parent}
local firepoint = tool.Handle.FirePoint
firepoint.WorldCFrame = tool.Bolt.CFrame
castBehavior.CanPierceFunction = CanRayPierce
end)
function OnLengthChanged(cast, lastpoint, direction, length, velocity, bullet)
if bullet then
local bulletLength = bullet.Size.Z/2
local offset = CFrame.new(0,0, -(length - bulletLength))
bullet.CFrame = CFrame.lookAt(lastpoint, lastpoint+direction):ToWorldSpace(offset)
end
end
function reload()
if mag.Value ~= magSize and isReloading == false then
isReloading = true
reloadsfx:Play()
wait(rTime)
if reserve.Value > 0 and isReloading == true then
local sub_ammo = magSize - mag.Value
if reserve.Value - sub_ammo > 0 then
mag.Value += sub_ammo
reserve.Value -= sub_ammo
else
mag.Value += reserve.Value
reserve.Value = 0
end
isReloading = false
end
end
end
function shoot(player, mousehit)
local origin = tool.Handle.FirePoint.WorldPosition
local direction = (mousehit - origin).unit
if mag.Value > 0 and isReloading == false then
gunshotsfx:Play()
caster:Fire(origin, direction, bulletspeed, castBehavior)
mag.Value -= 1
else
if isReloading == false then
reload()
end
end
end
function CanRayPierce (cast, result, segmentVelocity)
local hits = cast.UserData.Hits
if (hits == nil) then
cast.UserData.Hits = 1
else
cast.UserData.Hits += 1
end
if (cast.UserData.Hits == Pierce) then
return false
end
local hit = result.Instance
castBehavior.CanPierceFunction = CanRayPierce
local character = hit:FindFirstAncestorWhichIsA("Model")
if character and character:FindFirstChild("Humanoid") then
if character.Humanoid.Health > 0 then
if hit.Name == "Head" or hit.Name == "head" then
character.Humanoid:TakeDamage(damage * headshotMultiplier/cast.UserData.Hits)
else
character.Humanoid:TakeDamage(damage/cast.UserData.Hits)
end
end
end
return true
end
function onRayHit(cast, result, velocity, bullet)
local hit = result.Instance
local character = hit:FindFirstAncestorWhichIsA("Model")
if character and character:FindFirstChild("Humanoid") then
if character.Humanoid.Health > 0 then
if hit.Name == "Head" or hit.Name == "head" then
character.Humanoid:TakeDamage(damage * headshotMultiplier)
else
character.Humanoid:TakeDamage(damage)
end
end
end
end
MouseEvent.OnServerEvent:Connect(shoot)
caster.RayHit:Connect(onRayHit)
KeyEvent.OnServerEvent:Connect(reload)
caster.LengthChanged:Connect(OnLengthChanged)
Sorry if its a bit messy, I’ve been trying to figure out fast cast while making this. I’ve been thinking of creating a “fake cast” on the client, but I think that would be a bit too resource intensive, not to mention that the server side’s can look different ;-;
Not really, fast cast is already pretty performant and the method you mentioned is the one used widely. If you create bullets on the server then it could cause massive delays for players with just above 100 ping.
And, you should send the origin on the bullet to the server via the remote event you are using if you don’t want to use the “fake cast” system. This does mean that exploiters could potentially break the system but you can just add checks on the server. For example, seeing how far the origin of the tool (on the server) is from that the client sent.
-- client sends us this: origin = tool.Handle.FirePoint.WorldPosition
function shoot(player, origin, mousehit)
local direction = (mousehit - origin).unit
if mag.Value > 0 and isReloading == false then
gunshotsfx:Play()
caster:Fire(origin, direction, bulletspeed, castBehavior)
mag.Value -= 1
else
if isReloading == false then
reload()
end
end
end
How can I make the server bullet invisible for the client without it affecting any of the server bullets from other players? I know localtransparency modifier exists, so I tried using Child added, but it also affects bullets that aren’t from the client. Does the fast cast api have anything I can use for that?