I’m trying to make a mechanic that allows you to repair generators in my game, when you press mousebutton1 you start fixing it and when you release it, you stop fixing it.
I have it set up on a local script to trigger a proximityprompt when you press mousebutton1
The only problem I have with this is when the player repairs the generator it fires a loop (which is inside of a coroutine) that increases the progress of the generator every .5 seconds and for some reason if you spam it, progress is faster and faster.
The Main Script
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local GeneratorManager = require(script:WaitForChild("GeneratorManager"))
local AnimationSetup = require(script:WaitForChild("AnimationSetup"))
local animations = require(script:WaitForChild("GeneratorManager"):WaitForChild("Animations"))
local PositionReplication = ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("CharacterReplication"):WaitForChild("PositionReplication")
local PlayerMouseInputEndedEvent = ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("PlayerReplication"):WaitForChild("PlayerMouseInputEnded")
local animationsToPreload = {
animations.generatorRepair
}
AnimationSetup.PreloadAnimations(animationsToPreload)
local function GetClosestSide(plr, parts)
local closestPart
local playerPosition
PositionReplication:FireClient(plr)
local connection
connection = PositionReplication.OnServerEvent:Connect(function(sender, pos)
if sender == plr then
playerPosition = pos
connection:Disconnect()
end
end)
while not playerPosition do
task.wait()
end
for _, part in pairs(parts) do
local distance = (part.Position - playerPosition).Magnitude
if not closestPart or distance < (closestPart.Position - playerPosition).Magnitude then
closestPart = part
end
end
return closestPart
end
for _, prompt in pairs(game.Workspace:GetDescendants()) do
if prompt:IsA("ProximityPrompt") and prompt:GetAttribute("Generator") == true then
local GeneratorConfig = GeneratorManager.ConfigureGenerator(prompt)
prompt.Triggered:Connect(function(plr)
if GeneratorConfig.generatorCompleted then return end
local char = plr.Character or plr.CharacterAdded:Wait()
local humRoot = char:WaitForChild("HumanoidRootPart")
local closestSide = GetClosestSide(plr, GeneratorConfig.OpenPos)
GeneratorConfig:FixGeneratorStart(plr, closestSide)
end)
PlayerMouseInputEndedEvent.OnServerEvent:Connect(function(plr)
GeneratorConfig:FixGeneratorEnd(plr)
end)
end
end
The Module Script
local GeneratorManager = {}
GeneratorManager.__index = GeneratorManager
local animations = require(script.Animations)
local localManagement = require(game.ServerStorage:WaitForChild("Optimization"):WaitForChild("LocalManagement"))
local characterManager = require(game.ServerStorage:WaitForChild("CharacterManager"))
local ProgressBarEvent = game.ReplicatedStorage:WaitForChild("RemoteEvents"):WaitForChild("GuiEvents"):WaitForChild("SignalProgressBar")
local lockinfo = {0.3, Enum.EasingStyle.Sine}
function GeneratorManager.ConfigureGenerator(prompt)
local promptConfig = {}
promptConfig.progress = 0
promptConfig.generatorCompleted = false
promptConfig.playersFixing = {}
promptConfig.activeCoroutines = {}
promptConfig.debounceTable = {}
promptConfig.prompt = prompt
promptConfig.generator = prompt.Parent.Parent
promptConfig.OpenPos = {
prompt.Parent.Parent.FixPos1,
prompt.Parent.Parent.FixPos2,
prompt.Parent.Parent.FixPos3,
prompt.Parent.Parent.FixPos4,
}
setmetatable(promptConfig, GeneratorManager)
return promptConfig
end
function GeneratorManager:FixGeneratorStart(plr, closestSide)
if self.debounceTable[plr] and tick() - self.debounceTable[plr] < 0.3 then return end
self.debounceTable[plr] = tick()
if self.activeCoroutines[plr] then return end
table.insert(self.playersFixing, plr)
ProgressBarEvent:FireClient(plr, self.progress / 100, true)
local char = plr.Character or plr.CharacterAdded:Wait()
local plrHumRoot = char:WaitForChild("HumanoidRootPart")
local hum = char:WaitForChild("Humanoid")
local plrAnimator = hum:WaitForChild("Animator")
plrHumRoot.Anchored = true
characterManager:SetPlayerTurn(plr, false)
localManagement:PlayAnimation(plr, animations.generatorRepair.AnimationId, plrAnimator)
localManagement:SetModelCollision(plr, self.generator, true)
localManagement.Tween(plrHumRoot, lockinfo, {CFrame = closestSide.CFrame})
local cor = coroutine.create(function()
local LastTick = tick()
while true do
task.wait()
if not table.find(self.playersFixing, plr) then break end
if tick() - LastTick > 0.5 then
LastTick = tick()
self.progress += 1
ProgressBarEvent:FireClient(plr, self.progress / 100, true)
end
end
end)
self.activeCoroutines[plr] = cor
coroutine.resume(cor)
end
function GeneratorManager:FixGeneratorEnd(plr)
if not table.find(self.playersFixing, plr) then return end
local index = table.find(self.playersFixing, plr)
table.remove(self.playersFixing, index)
ProgressBarEvent:FireClient(plr, self.progress / 100, false)
local char = plr.Character or plr.CharacterAdded:Wait()
local plrHumRoot = char:WaitForChild("HumanoidRootPart")
local hum = char:WaitForChild("Humanoid")
local plrAnimator = hum:WaitForChild("Animator")
plrHumRoot.Anchored = false
characterManager:SetPlayerTurn(plr, true)
localManagement:StopAnimation(plr, animations.generatorRepair.AnimationId, plrAnimator, nil, nil, true)
local cor = self.activeCoroutines[plr]
if cor then
coroutine.close(cor)
self.activeCoroutines[plr] = nil
end
self.debounceTable[plr] = nil
end
return GeneratorManager