I’ve modified the script to be modular, so if you change the names at the top to whatever your gun’s name and the names of the remote events, it will work. I’ve also cleaned up some code to help you out:
local UserInputService = game:GetService("UserInputService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local LogService = game:GetService("LogService")
local RunService = game:GetService("RunService")
local GUN_EVENT_NAME = "MP5SD RE"
local GUN_NAME = "MP5SD"
local FireEvent = ReplicatedStorage[GUN_EVENT_NAME]:WaitForChild(GUN_NAME .. "Fire")
local FireLastEvent = ReplicatedStorage[GUN_EVENT_NAME]:WaitForChild(GUN_NAME .. "FireLast")
local ReloadNotEmptyEvent = ReplicatedStorage[GUN_EVENT_NAME]:WaitForChild("Reload" .. GUN_NAME .. "NotEmpty")
local ReloadEmptyEvent = ReplicatedStorage[GUN_EVENT_NAME]:WaitForChild("Reload" .. GUN_NAME .. "Empty")
local player = Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local connections = {}
local function setupViewModel()
-- Destroy existing viewmodel if it exists
if workspace.CurrentCamera:FindFirstChild("ViewModelMP5SD") then
workspace.CurrentCamera.ViewModelMP5SD:Destroy()
end
-- Get the camera
local camera = workspace.CurrentCamera
-- Clone the viewmodel from ReplicatedStorage
local viewmodel = ReplicatedStorage:WaitForChild("ViewModelMP5SD"):Clone()
viewmodel.Parent = workspace.CurrentCamera
-- Get the Animator
local animator = viewmodel:WaitForChild("Humanoid"):WaitForChild("Animator")
-- Load the animations
local Ranimation = Instance.new("Animation")
Ranimation.AnimationId = "rbxassetid://121937746273937" -- Replace with your animation ID
local RanimationTrack = animator:LoadAnimation(Ranimation)
RanimationTrack.Priority = Enum.AnimationPriority.Action2
local REanimation = Instance.new("Animation")
REanimation.AnimationId = "rbxassetid://75766370456110" -- Replace with your animation ID
local REanimationTrack = animator:LoadAnimation(REanimation)
REanimationTrack.Priority = Enum.AnimationPriority.Action4
local REEmptyAnimation = Instance.new("Animation")
REEmptyAnimation.AnimationId = "rbxassetid://111792193575216" -- Replace with your animation ID for empty reload
local REEmptyAnimationTrack = animator:LoadAnimation(REEmptyAnimation)
REEmptyAnimationTrack.Priority = Enum.AnimationPriority.Action4
local RanimationL = Instance.new("Animation")
RanimationL.AnimationId = "rbxassetid://118944095797406" -- Replace with your animation ID for last shot
local RanimationLTrack = animator:LoadAnimation(RanimationL)
local WalkAnimation = Instance.new("Animation")
WalkAnimation.AnimationId = "rbxassetid://88135397333059" -- Replace with your animation ID
local WalkAnimationTrack = animator:LoadAnimation(WalkAnimation)
WalkAnimationTrack.Looped = true
-- Function to stop all playing animations
local function stopAllAnimations()
for _, track in ipairs(animator:GetPlayingAnimationTracks()) do
track:Stop()
end
end
-- Recoil for camera animation
local function moveCameraUp()
local currentCFrame = camera.CFrame
local newCFrame = currentCFrame * CFrame.Angles(math.rad(0.8), 0, 0)
camera.CFrame = newCFrame
end
-- Function to play the animations
local function RecoilAnimation()
stopAllAnimations()
RanimationTrack:Play()
end
local function ReloadAnimation()
stopAllAnimations()
REanimationTrack.Priority = Enum.AnimationPriority.Action4
REanimationTrack:Play()
end
local function ReloadEmptyAnimation()
stopAllAnimations()
REEmptyAnimationTrack:Play()
end
local function LastShotAnimation()
stopAllAnimations()
RanimationLTrack:Play()
end
-- Lock position at the end of the last shot animation
RanimationLTrack.Stopped:Connect(function()
local lastFrameCFrame = viewmodel.PrimaryPart.CFrame -- Assuming PrimaryPart is set
viewmodel:SetPrimaryPartCFrame(lastFrameCFrame)
end)
FireEvent.OnClientEvent:Connect(function()
moveCameraUp()
RecoilAnimation()
end)
FireLastEvent.OnClientEvent:Connect(function()
moveCameraUp()
LastShotAnimation()
end)
ReloadNotEmptyEvent.OnClientEvent:Connect(function()
ReloadAnimation()
end)
ReloadEmptyEvent.OnClientEvent:Connect(function()
ReloadEmptyAnimation()
end)
-- Function to handle walking animation
local function updateWalkingAnimation()
if character.Humanoid.MoveDirection.Magnitude > 0 then
if not WalkAnimationTrack.IsPlaying then
WalkAnimationTrack:Play()
end
else
if WalkAnimationTrack.IsPlaying then
WalkAnimationTrack:Stop()
end
end
end
-- Connect the walking animation update to the RenderStepped event
local runConnection = RunService.RenderStepped:Connect(updateWalkingAnimation)
local FireConnection = FireEvent.OnClientEvent:Connect(function() -- IMPORTANT PART
moveCameraUp()
RecoilAnimation()
end)
local FireLastConnection = FireLastEvent.OnClientEvent:Connect(function() -- IMPORTANT PART
moveCameraUp()
LastShotAnimation()
end)
local ReloadNotEmptyConnection = ReloadNotEmptyEvent.OnClientEvent:Connect(function() -- IMPORTANT PART
ReloadAnimation()
end)
local ReloadDEmptyConnection = ReloadEmptyEvent.OnClientEvent:Connect(function() -- IMPORTANT PART
ReloadEmptyAnimation()
end)
table.insert(connections, runConnection)
table.insert(connections, FireConnection)
table.insert(connections, FireLastConnection)
table.insert(connections, ReloadNotEmptyConnection)
table.insert(connections, ReloadDEmptyConnection)
end
local tool = player.Backpack:WaitForChild(GUN_NAME)
tool.Unequipped:Connect(function()
for _, connection in connections do
-- We verify that the connection isn't nil or already disconnected
if connection then
connection:Disconnect()
end
end
-- Clean the table's memory pointers
connections = {}
end)
local function onToolEquipped(toolEquipped)
if toolEquipped.Name == GUN_NAME then
setupViewModel()
end
end
-- Connect the tool equipped event
player.Character.ChildAdded:Connect(function(child)
if child:IsA("Tool") then
onToolEquipped(child)
end
end)
-- Handle tool replacement
player.Character.ChildRemoved:Connect(function(child)
if child:IsA("Tool") and child.Name == GUN_NAME then
setupViewModel()
end
end)
Okay, so now we’ll do some troubleshooting after the changes we’ve made.
Add a print statement inside the onToolEquipped function.
Add a print statement inside the tool.Unequipped function.
Add a print statement at the end of setupAnimations function.
We’re basically adding these prints to trace how far the script goes, and we’re isolating the location of the issue. If it doesn’t print all 3, then there’s a problem before the suspected print.
I see, then it seems like something outside of the script was changed. Are the RemoteEvent names still the same? This is to ensure that the events are being fired when you click or reload.
What I like to do is have a table called connections.
Every connection I make will be stored inside the table.
Once I’m done with it, just loop through all of the connections and disconnect.
I also sometimes use Trove by Sleitnik that does it for me when I need more complex systems that need cleanup.
What changes have you made after we talked about re-using the code for the M4A1? I would revert back to the version that’s in the solution if it’s still not working. If the solution version isn’t working, then it’s most likely something that was changed outside of the script.
Ah okay, these types of bugs where it would intermittently stop working because of something missing is called Race Conditions. When a script sometimes works, it’s usually caused by a race condition. I’m assuming that the root of the problem is related to the reference of the script’s tool.
Can you send a screenshot of where your script is, and where you keep your tools? I suspect that something is wrong with the referencing in the script, but there could be other things as well. I’ll try to help you as much as possible.
nothing in the output (for some reason it works now but i suspect it to stop working later) and waitforchild is used like once in the refrencing of the tool in the backpack thats how u use it ig
I see, well I’m scanning through the animation script and there doesn’t seem to be anything out of place. Is there some other LocalScript that handles the shooting and reloading? The script that handles your UserInputService stuff?
Here’s what I have for your animation script:
local UserInputService = game:GetService("UserInputService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local LogService = game:GetService("LogService")
local RunService = game:GetService("RunService")
local GUN_EVENT_NAME = "MP5SD RE"
local GUN_NAME = "MP5SD"
local FireEvent = ReplicatedStorage[GUN_EVENT_NAME]:WaitForChild(GUN_NAME .. "Fire")
local FireLastEvent = ReplicatedStorage[GUN_EVENT_NAME]:WaitForChild(GUN_NAME .. "FireLast")
local ReloadNotEmptyEvent = ReplicatedStorage[GUN_EVENT_NAME]:WaitForChild("Reload" .. GUN_NAME .. "NotEmpty")
local ReloadEmptyEvent = ReplicatedStorage[GUN_EVENT_NAME]:WaitForChild("Reload" .. GUN_NAME .. "Empty")
local player = Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local connections = {}
local function setupViewModel()
-- Destroy existing viewmodel if it exists
if workspace.CurrentCamera:FindFirstChild("ViewModelMP5SD") then
workspace.CurrentCamera.ViewModelMP5SD:Destroy()
end
-- Get the camera
local camera = workspace.CurrentCamera
-- Clone the viewmodel from ReplicatedStorage
local viewmodel = ReplicatedStorage:WaitForChild("ViewModelMP5SD"):Clone()
viewmodel.Parent = workspace.CurrentCamera
-- Get the Animator
local animator = viewmodel:WaitForChild("Humanoid"):WaitForChild("Animator")
-- Load the animations
local Ranimation = Instance.new("Animation")
Ranimation.AnimationId = "rbxassetid://121937746273937" -- Replace with your animation ID
local RanimationTrack = animator:LoadAnimation(Ranimation)
RanimationTrack.Priority = Enum.AnimationPriority.Action2
local REanimation = Instance.new("Animation")
REanimation.AnimationId = "rbxassetid://75766370456110" -- Replace with your animation ID
local REanimationTrack = animator:LoadAnimation(REanimation)
REanimationTrack.Priority = Enum.AnimationPriority.Action4
local REEmptyAnimation = Instance.new("Animation")
REEmptyAnimation.AnimationId = "rbxassetid://111792193575216" -- Replace with your animation ID for empty reload
local REEmptyAnimationTrack = animator:LoadAnimation(REEmptyAnimation)
REEmptyAnimationTrack.Priority = Enum.AnimationPriority.Action4
local RanimationL = Instance.new("Animation")
RanimationL.AnimationId = "rbxassetid://118944095797406" -- Replace with your animation ID for last shot
local RanimationLTrack = animator:LoadAnimation(RanimationL)
local WalkAnimation = Instance.new("Animation")
WalkAnimation.AnimationId = "rbxassetid://88135397333059" -- Replace with your animation ID
local WalkAnimationTrack = animator:LoadAnimation(WalkAnimation)
WalkAnimationTrack.Looped = true
-- Function to stop all playing animations
local function stopAllAnimations()
for _, track in ipairs(animator:GetPlayingAnimationTracks()) do
track:Stop()
end
end
-- Recoil for camera animation
local function moveCameraUp()
local currentCFrame = camera.CFrame
local newCFrame = currentCFrame * CFrame.Angles(math.rad(0.8), 0, 0)
camera.CFrame = newCFrame
end
-- Function to play the animations
local function RecoilAnimation()
stopAllAnimations()
RanimationTrack:Play()
end
local function ReloadAnimation()
stopAllAnimations()
REanimationTrack.Priority = Enum.AnimationPriority.Action4
REanimationTrack:Play()
end
local function ReloadEmptyAnimation()
stopAllAnimations()
REEmptyAnimationTrack:Play()
end
local function LastShotAnimation()
stopAllAnimations()
RanimationLTrack:Play()
end
-- Lock position at the end of the last shot animation
RanimationLTrack.Stopped:Connect(function()
local lastFrameCFrame = viewmodel.PrimaryPart.CFrame -- Assuming PrimaryPart is set
viewmodel:SetPrimaryPartCFrame(lastFrameCFrame)
end)
FireEvent.OnClientEvent:Connect(function()
moveCameraUp()
RecoilAnimation()
end)
FireLastEvent.OnClientEvent:Connect(function()
moveCameraUp()
LastShotAnimation()
end)
ReloadNotEmptyEvent.OnClientEvent:Connect(function()
ReloadAnimation()
end)
ReloadEmptyEvent.OnClientEvent:Connect(function()
ReloadEmptyAnimation()
end)
-- Function to handle walking animation
local function updateWalkingAnimation()
if character.Humanoid.MoveDirection.Magnitude > 0 then
if not WalkAnimationTrack.IsPlaying then
WalkAnimationTrack:Play()
end
else
if WalkAnimationTrack.IsPlaying then
WalkAnimationTrack:Stop()
end
end
end
-- Connect the walking animation update to the RenderStepped event
local runConnection = RunService.RenderStepped:Connect(updateWalkingAnimation)
local FireConnection = FireEvent.OnClientEvent:Connect(function() -- IMPORTANT PART
moveCameraUp()
RecoilAnimation()
end)
local FireLastConnection = FireLastEvent.OnClientEvent:Connect(function() -- IMPORTANT PART
moveCameraUp()
LastShotAnimation()
end)
local ReloadNotEmptyConnection = ReloadNotEmptyEvent.OnClientEvent:Connect(function() -- IMPORTANT PART
ReloadAnimation()
end)
local ReloadDEmptyConnection = ReloadEmptyEvent.OnClientEvent:Connect(function() -- IMPORTANT PART
ReloadEmptyAnimation()
end)
table.insert(connections, runConnection)
table.insert(connections, FireConnection)
table.insert(connections, FireLastConnection)
table.insert(connections, ReloadNotEmptyConnection)
table.insert(connections, ReloadDEmptyConnection)
end
local tool = player.Backpack:WaitForChild(GUN_NAME)
tool.Unequipped:Connect(function()
for _, connection in connections do
-- We verify that the connection isn't nil or already disconnected
if connection then
connection:Disconnect()
end
end
-- Clean the table's memory pointers
connections = {}
end)
local function onToolEquipped(toolEquipped)
if toolEquipped.Name == GUN_NAME then
setupViewModel()
end
end
-- Connect the tool equipped event
player.Character.ChildAdded:Connect(function(child)
if child:IsA("Tool") then
onToolEquipped(child)
end
end)
-- Handle tool replacement
player.Character.ChildRemoved:Connect(function(child)
if child:IsA("Tool") and child.Name == GUN_NAME then
setupViewModel()
end
end)