So I have a ServerScript
for a pet inside of the player’s character that handles movement, damage, and treat/sapphire giving. But when I tested my treat pile with an auto-clicker something sort of expected and another unexpected happened. Firstly, the auto-clicker was able to bypass the attack cooldown, and second, the auto-clicker was able to make the treat give the player treats and sapphires multiple times.
Here is my code for the pet: (ServerScript
)
local Players = game:GetService("Players")
local TweenService = game:GetService("TweenService")
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local EventsFolder = ReplicatedStorage:WaitForChild("Events")
local TreatEvent = EventsFolder:WaitForChild("TreatEvent")
-- Get the player and their humanoid
local player = Players:GetPlayerFromCharacter(script.Parent)
local humanoid = player.Character.Humanoid
local PlayersPets = Instance.new("Folder", game.Workspace)
PlayersPets.Name = player.Name .. "'s Pets"
-- Create the part to tween
local Pet = game.ReplicatedStorage.Pets.WhitePeacock:Clone()
Pet.Parent = PlayersPets
local part = Pet:WaitForChild("Base")
local Speed = 0.25
local Action = "Follow"
local PFA = nil -- PFA - 'Part For Action'
TreatEvent.Event:Connect(function(PlayerName, Treat)
if PlayerName == player.Name then
local leaderstats = player:FindFirstChild("leaderstats")
local Treats = leaderstats.Treats
local Saphires = leaderstats.Saphires
if Treat ~= nil and PFA == nil and Action == "Follow" then
local Nodes = Treat.Nodes:GetChildren()
local RandomNode = math.random(1, #Nodes)
PFA = Nodes[RandomNode]
Action = "Attack"
while Treat.Health.Value > 0 do
if Treat ~= nil and PFA ~= nil and Action ~= "Follow" then
wait(1)
if Treat ~= nil and PFA ~= nil and Action ~= "Follow" then
Treat.Health.Value -= Pet.Damage.Value
else
return
end
else
return
end
end
PFA = nil
Action = "Follow"
Treats.Value += Treat.Treats.Value
Saphires.Value += Treat.Saphires.Value
else
PFA = nil
Action = "Follow"
end
end
end)
-- Calculate the target position and rotation
RunService.Heartbeat:Connect(function()
if Action == "Follow" then
local targetPosition = humanoid.RootPart.Position - (humanoid.RootPart.CFrame.LookVector * 4)
local targetRotationY = humanoid.RootPart.Rotation.Y -- Extract the Y rotation value
local targetRotationX = humanoid.RootPart.Rotation.X -- Extract the Y rotation value
local targetRotationZ = humanoid.RootPart.Rotation.Z -- Extract the Y rotation value
-- Tween the part to the target position and rotation
local tweenInfo = TweenInfo.new(Speed, Enum.EasingStyle.Linear)
local tween = TweenService:Create(part, tweenInfo, {
CFrame = CFrame.new(targetPosition) * CFrame.Angles(math.rad(targetRotationX), math.rad(targetRotationY), math.rad(targetRotationZ))
})
tween:Play()
elseif Action == "Attack" then
for i, pet in ipairs(PlayersPets:GetChildren()) do
if PFA ~= nil then
local targetPosition = PFA.Position
local targetRotationY = PFA.Rotation.Y -- Extract the Y rotation value
local targetRotationX = PFA.Rotation.X -- Extract the Y rotation value
local targetRotationZ = PFA.Rotation.Z -- Extract the Y rotation value
-- Tween the part to the target position and rotation
local tweenInfo = TweenInfo.new(Speed, Enum.EasingStyle.Linear)
local tween = TweenService:Create(part, tweenInfo, {
CFrame = CFrame.new(targetPosition) * CFrame.Angles(math.rad(targetRotationX), math.rad(targetRotationY), math.rad(targetRotationZ))
})
tween:Play()
end
end
end
end)
Here are the scripts for the treat pile: (ServerScript
s)
-Handles the ClickDetector
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local EventsFolder = ReplicatedStorage:WaitForChild("Events")
local TreatEvent = EventsFolder.TreatEvent
script.Parent.ClickDetector.MouseClick:Connect(function(Player)
TreatEvent:Fire(Player.Name, script.Parent.Parent)
end)
-Handles the piles Respawn
script.Parent.Health.Changed:Connect(function()
if script.Parent.Health.Value <= 0 then
task.wait(0.5)
script.Parent.Parent = game.ReplicatedStorage
task.wait(15)
script.Parent.Health.Value = script.Parent.MaxHealth.Value
task.wait(15)
script.Parent.Parent = game.Workspace.TreetsPiles
end
end)
These ServerScripts
communicate via a BindableEvent
so if you don’t recognize the .Event
or :Fire
functions that’s why.