Error with bullets CFrame

Hello again developer forums! I’m having an issue with my bullet code displaying the error ServerScriptService.Framework - Server:74: attempt to index nil with 'CFrame' - Server - Framework - Server:74 and it is driving me crazy, I’ve done as much as my tiny brain will let me so I’m handing it over to you. I will be providing two scripts along with the place as a download file. The first is the local script that gets the viewmodel and bullet location + rotation, and then the server script which actually sets up the bullet.

Get back to me if anyone has a solution!

Local Script:

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

local humanoid = character:WaitForChild("Humanoid")

local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")

local camera = game.Workspace.CurrentCamera

local aimCF = CFrame.new()

local mouse = player:GetMouse()

local isAiming = false
local isShooting = false
local isReloading = false
local canShoot = true

local debounce = false

local currentSwayAMT = 0
local swayAMT = 0.6
local aimSwayAMT = -0.2
local swayCF = CFrame.new()
local lastCameraCF = CFrame.new()

local currentSlot = 1 -- starting slot
local lastSlot = 0
local maxSlots = 3

local fireAnim = nil

local particle
local flash
local bigFlash
local timer
local bobOffset = CFrame.new()

local inventoryOpen = false

local framework = {
	inventory = {
		"Rocket Launcher";
		"Paintball Gun";
		"Sword";
	};
	
	module = nil;
	viewmodel = nil;
	currentSlot = 1;
}

local hud = player.PlayerGui:WaitForChild("GameUI")

function deleteViewmodel()
	for i, v in pairs(camera:GetChildren()) do
		if v:IsA("Model") then
			v:Destroy()
		end
	end
end

function setInventory()
	framework.inventory[1] = "Paintball Gun"
	framework.inventory[2] = "Rocket Launcher"
	framework.inventory[3] = "Sword"
end

setInventory()

function Shoot()
	trigger()
end

function loadSlot(Item)
	local viewmodelFolder = game.ReplicatedStorage.ViewModels
	local moduleFolder = game.ReplicatedStorage:WaitForChild("Modules")

	
	isShooting = false

	deleteViewmodel()

	if moduleFolder then
		framework.module = require(moduleFolder:WaitForChild(Item))
		if viewmodelFolder:FindFirstChild(Item) then
			framework.viewmodel = viewmodelFolder:FindFirstChild(Item):Clone()
			framework.viewmodel.Parent = camera
		end
		if framework.viewmodel and framework.module and character then
			local rarity = framework.module.rarity
			-- animation
			fireAnim = Instance.new("Animation")
			fireAnim.Parent = framework.viewmodel
			fireAnim.Name = "Fire"
			fireAnim.AnimationId = framework.module.fireAnim
			fireAnim = framework.viewmodel.AnimationController.Animator:LoadAnimation(fireAnim)
			-- sound
			game.ReplicatedStorage.Events.LoadSlot:FireServer(framework.module.fireSound)
			flash = framework.viewmodel.HumanoidRootPart.Muzzel.flash
			bigFlash = framework.viewmodel.HumanoidRootPart.Muzzel.bigFlash
			hud.gun.Icon.Image = framework.module.icon
			hud.gun.Icon.ImageColor3 = hud.gun:WaitForChild(rarity).Value
		end
	end
end

local function refreshList()
	local raritys = player.PlayerGui.GunSelector.List
	local listOfWepons = player.PlayerGui.GunSelector.List.List:GetChildren()
	local frame = player.PlayerGui.GunSelector.List
	
	if inventoryOpen then
		frame.Position = UDim2.new(1, -50 ,0.5, 0)
	else
		frame.Position = UDim2.new(1.2, 0 ,0.5, 0)
	end

	for i, v in pairs(listOfWepons) do
		if v:IsA("Frame") then
			if v.Name ~= "Empty" then
				local module = require(game.ReplicatedStorage.Modules:WaitForChild(v.Name))
				v.Icon.id.Text = v.Name
				v.Icon.Image = module.icon
				v.Icon.ImageColor3 = raritys:WaitForChild(module.rarity).Value
				v.ammo.Text = module.maxAmmo
				
				if table.find(framework.inventory, v.Name) then
					v.addToInventory.Active = false
					v.addToInventory.ImageTransparency = 0.75
					v.removeFromInventory.Active = true
					v.removeFromInventory.ImageTransparency = 0
				else
					v.addToInventory.Active = true
					v.addToInventory.ImageTransparency = 0
					v.removeFromInventory.Active = false
					v.removeFromInventory.ImageTransparency = 0.5
				end
			end
		end
	end
end

player.PlayerGui:WaitForChild("GunSelector"):WaitForChild("List"):WaitForChild("Refresh").MouseButton1Click:Connect(function()
	print("click")
	refreshList()
end)

player.PlayerGui:WaitForChild("GunSelector"):WaitForChild("List"):WaitForChild("inventoryButton").MouseButton1Click:Connect(function()
	if inventoryOpen then
		inventoryOpen = false
	else
		inventoryOpen = true
	end
	refreshList()
end)

RunService.RenderStepped:Connect(function()
	local rot = camera.CFrame:ToObjectSpace(lastCameraCF)
	local X, Y, Z = rot:ToOrientation()
	swayCF = swayCF:Lerp(CFrame.Angles(math.sin(X) * currentSwayAMT, math.sin(Y) * currentSwayAMT, 0), .1)
	lastCameraCF = camera.CFrame

	if framework.viewmodel and framework.module then
		hud.gun.Icon.id.Text = framework.inventory[framework.currentSlot]
		hud.ammo.amount.Text = framework.module.ammo .. "/" .. framework.module.maxAmmo
	end

	if humanoid then
		local movementOffset = CFrame.new()

		if framework.viewmodel ~= nil and framework.module ~= nil then
			if humanoid.MoveDirection.Magnitude > 0 and humanoid:GetState() ~= Enum.HumanoidStateType.Freefall then
				if isReloading == true then
					bobOffset = bobOffset:Lerp(CFrame.new(math.cos(tick() * 4) * .05, -humanoid.CameraOffset.Y/1, 0) * CFrame.Angles(0, math.sin(tick() * -4) * -.05, math.cos(tick() * -4) * .05), .005)
				else
					if isAiming == true then
						bobOffset = bobOffset:Lerp(CFrame.new(math.cos(tick() * 4) * .05, -humanoid.CameraOffset.Y/3, 0) * CFrame.Angles(0, math.sin(tick() * -4) * -.05, math.cos(tick() * -4) * .05), .005)
					else
						bobOffset = bobOffset:Lerp(CFrame.new(math.cos(tick() * 4) * .05, -humanoid.CameraOffset.Y/3, 0) * CFrame.Angles(0, math.sin(tick() * -4) * -.05, math.cos(tick() * -4) * .05), humanoid.WalkSpeed/45)
					end
				end
			end
		else
			bobOffset = bobOffset:Lerp(CFrame.new(0, -humanoid.CameraOffset.Y/3, 0), .1)
		end

	end

	for i, v in pairs(camera:GetChildren()) do
		if v:IsA("Model") then
			v.PrimaryPart.CFrame = (camera.CFrame * swayCF * aimCF * bobOffset)
			--updateCameraShake()
		end
	end

	if isAiming and framework.viewmodel ~= nil and framework.module.canAim then
		local offset = framework.viewmodel.AimCamera.CFrame:ToObjectSpace(framework.viewmodel.PrimaryPart.CFrame)
		aimCF = aimCF:Lerp(offset, framework.module.aimSmooth)
		currentSwayAMT = aimSwayAMT
	else
		local offset = CFrame.new()
		aimCF = aimCF:Lerp(offset, .2)
		currentSwayAMT = swayAMT
	end
	
	-- HUD
	if hud and moduleFolder == moduleFolder then
		if framework.module.ammo < framework.module.maxAmmo/4 then
			hud.ammo.Icon.ImageColor3 = Color3.fromRGB(255, 0, 0) 
		else
			hud.ammo.Icon.ImageColor3 = Color3.new(1, 1, 1)
		end

		if isReloading == true then
			hud.ammo.Icon.reload.Visible = true
			hud.ammo.Icon.ImageTransparency = 0.75
		else
			hud.ammo.Icon.reload.Visible = false
			hud.ammo.Icon.ImageTransparency = 0
		end
	end
end)

local function updateWeapon(slot)
	if isReloading == true then
		isReloading = false
		canShoot = true
	end
	if isReloading == false then
		framework.currentSlot = slot
		loadSlot(framework.inventory[currentSlot])
	end
	refreshList()
end

updateWeapon(1)


-- SLOT CHANGING
local function changeSlot(howMuch)
	currentSlot += howMuch
	if currentSlot > maxSlots then
		currentSlot = 1
	elseif currentSlot < 1 then
		currentSlot = maxSlots
	end
	updateWeapon(currentSlot)
end

local function setSlot(whatSlot)
	if framework.currentSlot ~= whatSlot then
		currentSlot = whatSlot
	end
	updateWeapon(currentSlot)
end

local function reload()
	if isReloading == false and framework.module.maxAmmo ~= 0 and framework.module.ammo ~= framework.module.maxAmmo then
		canShoot = false
		isReloading = true
		
		wait(framework.module.reloadTime)
		
		if isReloading == true then
			framework.module.ammo = framework.module.maxAmmo
		end
		canShoot = true
		isReloading = false
		
	end
end

-- SHOOTING --
local function fireWeapon()
	if isReloading == true and framework.module.ammo ~= 0 then
		isReloading = false
		canShoot = true
	end
	if character and framework.viewmodel and framework.module and framework.module.ammo ~= 0 and debounce == false and isReloading == false	and canShoot == true and framework.module.maxAmmo ~= 0 then
		game.ReplicatedStorage.Events.Shoot:FireServer(framework.viewmodel.Muzzle.Position, mouse.Hit.p)
		fireAnim:Play()
		character.Torso.FireSound:Play()
		framework.module.ammo -= 1
		debounce = true

		wait(framework.module.fireRate)

		debounce = false
	elseif character and framework.viewmodel and framework.module and debounce == false and framework.module.maxAmmo == 0 then
		game.ReplicatedStorage.Events.Shoot:FireServer(framework.viewmodel.Muzzle.Position, mouse.Hit.p)
		fireAnim:Play()
		character.Torso.FireSound:Play()
		debounce = true

		wait(framework.module.fireRate)

		debounce = false
	end
end

local function trigger()
	if isReloading == true and canShoot == false and framework.module.ammo ~= 0 then
		isReloading = false
		canShoot = true
	end
	
	if framework.module.fireMode == "Semi" then
		fireWeapon()
	end

	if framework.module.fireMode == "Full Auto" then
		isShooting = true
	end
end

local oldCamCF = CFrame.new()

function updateCameraShake()
	local newCamCF = framework.viewmodel.FakeCamera.CFrame:ToObjectSpace(framework.viewmodel.PrimaryPart.CFrame)
	camera.CFrame = camera.CFrame * newCamCF:ToObjectSpace(oldCamCF)
	oldCamCF = newCamCF
end


-- INPUTS -- 

--UserInputService.MouseIconEnabled = false

UserInputService.InputBegan:Connect(function(input)
	if input.KeyCode == Enum.KeyCode.One then
		setSlot(1)
	end
	
	if input.KeyCode == Enum.KeyCode.Two then
		setSlot(2)
	end
	
	if input.KeyCode == Enum.KeyCode.Three then
		setSlot(3)
	end
	
	if input.UserInputType == Enum.UserInputType.Gamepad1 then
		if input.KeyCode == Enum.KeyCode.ButtonL1 then
			changeSlot(1)
		end
	end
	
	if input.UserInputType == Enum.UserInputType.Gamepad1 then
		if input.KeyCode == Enum.KeyCode.ButtonR1 then
			changeSlot(-1)
		end
	end
	
	if input.UserInputType == Enum.UserInputType.MouseButton3 then
		print("middleButton")
	end
	
	if input.UserInputType == Enum.UserInputType.MouseButton2 then
		isAiming = true
	end
	
	if input.UserInputType == Enum.UserInputType.MouseButton1 then
		if character and framework.viewmodel and framework.module then
			trigger()
		end
	end
	
	if input.UserInputType == Enum.UserInputType.Gamepad1 then
		if input.KeyCode == Enum.KeyCode.ButtonL2 then
			isAiming = true
		end
	end
	
	if input.UserInputType == Enum.UserInputType.Gamepad1 then
		if input.KeyCode == Enum.KeyCode.ButtonR2 then
			trigger()
		end
	end
	
	-- RELOAD
	if input.KeyCode == Enum.KeyCode.R then
		reload()
	end
	
	if input.UserInputType == Enum.UserInputType.Gamepad1 then
		if input.KeyCode == Enum.KeyCode.ButtonX then
			reload()
		end
	end
end)

UserInputService.InputEnded:Connect(function(input)
	if input.UserInputType == Enum.UserInputType.MouseButton2 then
		isAiming = false
	end
	
	if input.UserInputType == Enum.UserInputType.Gamepad1 then
		if input.KeyCode == Enum.KeyCode.ButtonL2 then
			isAiming = false
		end
	end
	
	if input.UserInputType == Enum.UserInputType.MouseButton1 then
		isShooting = false
	end
	
	if input.UserInputType == Enum.UserInputType.Gamepad1 then
		if input.KeyCode == Enum.KeyCode.ButtonR2 then
			isShooting = false
		end
	end
end)

mouse.WheelForward:Connect(function()
	changeSlot(1)
end)

mouse.WheelBackward:Connect(function()
	changeSlot(-1)
end)

game.ReplicatedStorage.Events.PlayerAdded.OnClientEvent:Connect(function(ply, char)
	
	player = game.Players.LocalPlayer
	
	character = player.Character
	
	humanoid = character:WaitForChild("Humanoid")
	
	setInventory()
	
	framework.module.ammo = framework.module.maxAmmo

	framework.module = nil
	framework.viewmodel = nil
	framework.currentSlot = 1
	

	loadSlot(framework.inventory[currentSlot])

	humanoid.Died:Connect(function()
		
		deleteViewmodel()
		
		local isAiming = false
		local isShooting = false
		local isReloading = false
		local canShoot = true

		local debounce = false

		local currentSwayAMT = 0
		local swayAMT = 0.6
		local aimSwayAMT = -0.2
		local swayCF = CFrame.new()
		local lastCameraCF = CFrame.new()

		local currentSlot = 1 -- starting slot
		local lastSlot = 0
		local maxSlots = 3

		local fireAnim = nil

		local particle
		local flash
		local bigFlash
		local timer
		local bobOffset = CFrame.new()
	end)
end)  

game.ReplicatedStorage.Events.HitEvent.OnClientEvent:Connect(function(ply)
	game.SoundService.SoundEffects.Damage:Play()
end)

while wait() do
	if isShooting and framework.module.ammo > 0 and isReloading ~= true and canShoot == true then
		framework.module.ammo -= 1
		fireAnim:Play()
		game.ReplicatedStorage.Events.Shoot:FireServer(framework.viewmodel.Muzzle.Position, mouse.Hit.Position)
		mouse.Button1Up:Connect(function()
			isShooting = false
		end)
		wait(framework.module.fireRate)
	end
end

Server Script:

-- Bullet Pool
local bulletPool = {}
local maxBullets = 150
local bulletTemplate = game.ReplicatedStorage.BulletMesh.Bullet

function setTransparency(trans, model)
	for i, v in pairs(model:GetChildren()) do
		if v:IsA("Mesh") then
			v.Transparency = trans
		end
	end
end

for i = 1, maxBullets do
	local Mbullet = bulletTemplate:Clone()
	Mbullet.Name = "PooledBullet"
	Mbullet.Parent = game.Workspace
	Mbullet:SetAttribute("Avalible", true)
	Mbullet.PrimaryPart.CFrame = CFrame.new(0,0,0)
	Mbullet:SetAttribute("Visible", false)
	setTransparency(1, Mbullet)
	table.insert(bulletPool, Mbullet)
end

local function GetBullet()
	for _, bullet in ipairs(bulletPool) do
		if bullet:GetAttribute("Avalible") then
			bullet:SetAttribute("Avalible", false)
			bullet:SetAttribute("Visible", true)
			setTransparency(0, bullet)
			return bullet
		end
	end
	warn("No avalible bullets")
	return nil
end

local function ReturnBullet(rBullet)
	if rBullet:GetAttribute("Avalible") then return end
	rBullet:SetAttribute("Avalible", true)
	rBullet:SetAttribute("Visible", false)
	rBullet.PrimaryPart.CFrame = CFrame.new(0,0,0)
	rBullet.PrimaryPart.LinearVelocity.VectorVelocity = Vector3.zero
	setTransparency(1, rBullet)
end

game.ReplicatedStorage.Events.LoadSlot.OnServerEvent:Connect(function(player, Sound)
	if player.Character	then
		for i, v in pairs(player.Character.Torso:GetChildren()) do
			if v.Name == "FireSound" then
				v:Destroy()
			end
		end
		
		local fireSound = Sound:Clone()
		fireSound.Parent = player.Character.Torso
	end
end)



game.ReplicatedStorage.Events.Shoot.OnServerEvent:Connect(function(player, MuzzelPos, MousePos)
	if player.Character then
		local sound = player.Character.Torso.FireSound
		if sound then
			sound:Play()
		end
		
		local bullet = GetBullet()
		if bullet then
			bullet.Name = "Bullet"
			bullet.Parent = game.Workspace
			print(CFrame.new(MuzzelPos, MousePos))
			bullet.PrimaryPart.CFrame = CFrame.new(MuzzelPos, MousePos)
			

			local linearVelocity = bullet.PrimaryPart.LinearVelocity
			local attachment = bullet.PrimaryPart.Attachment
			-- Configure LinearVelocity
			linearVelocity.VectorVelocity = bullet.PrimaryPart.CFrame.LookVector * 400
			linearVelocity.MaxForce = math.huge
			--bullet.PrimaryPart.CFrame = CFrame.new(bullet.PrimaryPart.Position, bullet.PrimaryPart.Position + bullet.PrimaryPart.CFrame.LookVector)
			--bullet.RootPart.AlignOrientation.CFrame = bullet.PrimaryPart.CFrame
			bullet.RootPart.Trail.Enabled = true
			
			bullet.PrimaryPart.Touched:Connect(function(hit)
				bullet.RootPart.Trail.Enabled = false
				--ReturnBullet(bullet)
				if hit.Parent:FindFirstChild("Humanoid") then
					hit.Parent:FindFirstChild("Humanoid"):TakeDamage(10)
					game.ReplicatedStorage.Events.HitEvent:FireClient(player, player.Character)
				end
			end)
		end
	end
end)

game.Players.PlayerAdded:Connect(function(fplayer)
	fplayer.CharacterAdded:Connect(function(fcharacter)
		game.ReplicatedStorage.Events.PlayerAdded:FireClient(fplayer, fcharacter)
	end)
end)

And lastly, the download file:
Framework Testing Untitled Games Development.rbxl (346.3 KB)

1 Like

It’s your bullet pooling. It allows the existence of bullets for like 2 seconds and then the bullets disappear in the workspace after the gun is first shot because the bullet pool causes all bullets to become nil.

2 Likes

Watch this video so you see what’s causing the problem

1 Like