Great module, very easy to use, and saved me quite a bit of time! However, I’d like to point out a few bugs that need to be fixed:
When a player dies, the output is flooded with errors:
To fix this, change:
if Character then -- line 52
to:
if Character and Character.PrimaryPart then -- line 52
When a player dies, the HumanoidRootPart is destroyed, but the character still exists, therefore if Character
would still return true.
Also, another thing that needs to be fixed is that you forgot to loop through and add players that already exist in the server. To fix this, add this code somewhere at the bottom of the script:
for _,player in pairs(game.Players:GetPlayers()) do
AddPlayer(player)
end
Full Code
local PetFollowModule = {}
local ModuleFunctions = {}
local ActivePets = {}
local Settings = require(script.Settings)
local LocalPlayer = game.Players.LocalPlayer
local YPoint = 0
local Addition = Settings.YDriftSpeed
local FullCircle = 2 * math.pi
local RunService = game:GetService("RunService")
function SetPetCollisions(Model)
for _, Part in pairs(Model:GetDescendants()) do
if Part:IsA("BasePart") then
Part.CanCollide = false
Part.Anchored = true
end
end
end
function getXAndZPositions(Angle, Radius)
local x = math.cos(Angle) * Radius
local z = math.sin(Angle) * Radius
return x, z
end
function ModuleFunctions:AddPet(Player, PetName)
if not PetName then PetName = Player Player = LocalPlayer end
local PetModel = Settings.PetFolder[PetName]:Clone()
PetModel.Parent = ActivePets[Player.UserId]
if Player.Character then PetModel:SetPrimaryPartCFrame(Player.Character.PrimaryPart.CFrame) end
SetPetCollisions(PetModel)
return PetModel
end
function UpdatePetPositions()
YPoint = YPoint + Addition
if YPoint > Settings.YDrift or YPoint < -1 * Settings.YDrift then Addition = -1 * Addition end
for Id, Folder in pairs(ActivePets) do
if Folder.Parent == game.Workspace then
local Player = game.Players:GetPlayerByUserId(Id)
local Character = Player.Character
if Character and Character.PrimaryPart then
local PetTable = Folder:GetChildren()
local PetTableLength = #PetTable
local Count = 0
for _, Pet in pairs(PetTable) do
Count += 1
local Angle = Count * (FullCircle / PetTableLength)
local X, Z = getXAndZPositions(Angle, Settings.Radius + (PetTableLength / 2))
local Position = (Character.PrimaryPart.CFrame * CFrame.new(X, YPoint, Z)).p
local LookAt = Character.PrimaryPart.Position
local TargetCFrame = CFrame.new(Position, LookAt)
local NewCFrame = Pet.PrimaryPart.CFrame:Lerp(TargetCFrame, Settings.Responsivness)
Pet:SetPrimaryPartCFrame(NewCFrame)
end
end
end
end
end
function ModuleFunctions:RemovePet(Player, PetId)
if not PetId then PetId = Player Player = LocalPlayer end
ActivePets[Player.UserId][PetId]:Destroy()
end
function ModuleFunctions:HidePets(Player)
ActivePets[Player.UserId].Parent = game.ReplicatedStorage
end
function ModuleFunctions:HideOthersPets()
Settings.OtherPetsVisible = false
for Id, Folder in pairs(ActivePets) do
if Id ~= LocalPlayer.UserId then
Folder.Parent = game.ReplicatedStorage
end
end
end
function ModuleFunctions:HideAllPets()
Settings.AllPetsVisible = false
for Id, Folder in pairs(ActivePets) do
Folder.Parent = game.ReplicatedStorage
end
end
function ModuleFunctions:ShowPets(Player)
ActivePets[Player.UserId].Parent = game.Workspace
end
function ModuleFunctions:ShowOthersPets()
Settings.OtherPetsVisible = true
for Id, Folder in pairs(ActivePets) do
if Id ~= LocalPlayer.UserId then
Folder.Parent = game.Workspace
end
end
end
function ModuleFunctions:ShowAllPets()
Settings.AllPetsVisible = true
for Id, Folder in pairs(ActivePets) do
Folder.Parent = game.Workspace
end
end
function AddPlayer(Player)
ActivePets[Player.UserId] = Instance.new("Folder")
if Settings.OtherPetsVisible and Settings.AllPetsVisible then
ActivePets[Player.UserId].Parent = game.Workspace
else
ActivePets[Player.UserId].Parent = game.ReplicatedStorage
end
end
for _, player in pairs(game.Players:GetPlayers()) do
AddPlayer(player)
end
game.Players.PlayerAdded:Connect(AddPlayer)
AddPlayer(game.Players.LocalPlayer)
game.Players.PlayerRemoving:Connect(function(Player)
ActivePets[Player.UserId]:Destroy()
end)
RunService:BindToRenderStep('Update', 1, UpdatePetPositions)
setmetatable(PetFollowModule, {__index = ModuleFunctions})
return PetFollowModule