I’m trying to think of an efficient way to create a family system. My current layout would be:
Player1 invites Player2 to join their family
If Player2 accepts, then they join Player1’s family (this would create a folder under a Families folder like so)
Families
Player1
Player2
And anybody else who gets invited to join Player1’s family would be added on like so
Families
Player1
Player2
Player3
So Player1 would be like the ‘owner’ of the family. So if they left the game, the family would be destroyed.
I’m not a huge fan of this though, but I can’t think of an efficient way to store the families. I don’t just want to do it as a numerical thing
Families
Family1
Player1
Player2
Family2
Player3
But I feel that may be the only way to do it? That’d then beg the question of what happens if you don’t want people in your family anymore, you’d have to leave the whole family, instead of just kicking one member out
Why not? The one you’re least comfortable with is really the better option here and it seems like it completely covers your use case and issues as well. The only problem is you aren’t comfortable with it and it’s not apparent why.
If you want to go with option two, again not sure why you don’t want a numerical system, but you can instead just name the folder differently like “Player’s Family”. You could then allow them to change the family name and thus the folder, or don’t, doesn’t really matter. Clearing out the family is as simple as providing an option to bulk kick instead of kick individually - you don’t need to think very hard about that one.
I think the third option, creating a family class that has the owner determined by seniority, is the best way to do it. It seems pretty easy to organize through an OOP framework. As a bonus, it gives you more freedom to do other things with it later, such as if you want to have co-ownership.
Reason why I was fearful of doing the second option was like so:
If Player1 creates the family, and then the folder is stored as
Families
Player1 Family
Player1
Player2
Then what happens if Player1 leaves? Ye I can remove them from the family folder, but the folder would still be named as the Player1’s family. Player2 wouldn’t have access to control it, so it’d make sense to just completely destroy the folder when Player1 leaves. But I feel that can be a problem if you had like 5 players all in a family, then the owner leaves and now none of them are in a family and would have to go about making another one
I’ve already kinda started a setup using OOP based structure, like so
--[[
// NinjoOnline \\
Family
--]]
local Family = {}
Family.__index = Family
local ReplicatedStorage = game:GetService('ReplicatedStorage')
local Families = ReplicatedStorage:WaitForChild('Families')
-- Create / destroy the family folder (owner)
local function CreateFamilyFolder(owner)
local FamilyFolder = Families:FindFirstChild(owner.Name)
if FamilyFolder then return end
FamilyFolder = Instance.new('Folder')
FamilyFolder.Name = owner.Name
FamilyFolder.Parent = Families
end
local function DestroyFamilyFolder(owner)
local FamilyFolder = Families:FindFirstChild(owner.Name)
if not FamilyFolder then return end
FamilyFolder:Destroy()
end
-- Add / remove family members
local function AddMemberFolder(familyData)
for _, member in pairs(familyData.Members) do
if member ~= familyData.Owner then
local FamilyFolder = Families:FindFirstChild(familyData.Owner.Name)
if not FamilyFolder then return end
if not FamilyFolder:FindFirstChild(member.Name) then
local NewMember = Instance.new('StringValue')
NewMember.Name = member.Name
NewMember.Value = 'Member'
NewMember.Parent = FamilyFolder
end
end
end
end
local function RemoveMemberFolder(owner, member)
local FamilyFolder = Families:FindFirstChild(owner.Name)
if not FamilyFolder then return end
local MemberFolder = FamilyFolder:FindFirstChild(member.Name)
if not MemberFolder then return end
MemberFolder:Destroy()
if #FamilyFolder:GetChildren() == 0 then
-- Family has no members, destroy the folder
DestroyFamilyFolder(owner)
end
end
-- Add family member
function Family:AddMember(member)
table.insert(self.Members, member)
AddMemberFolder(self)
end
-- Remove famiyl member
function Family:RemoveMember(member)
if member == self.Owner then
DestroyFamilyFolder(self.Owner)
else
RemoveMemberFolder(self.Owner, member)
end
-- Remove member from family
local MemberIndex = table.find(self.Members, member)
if MemberIndex then
table.remove(self.Members, MemberIndex)
end
if #self.Members <= 1 then
-- Only the owner is a member, remove family
self = nil
end
end
-- New family constructor
function Family.new(owner)
local NewFamily = {}
setmetatable(NewFamily, Family)
NewFamily.Owner = owner
NewFamily.Members = {owner}
CreateFamilyFolder(owner)
return NewFamily
end
return Family
So is the problem succession then? There are many ways you can work around this, up to adding metadata to the folder (a separate folder with informational values) or handle that in your code by determining the order of who joined the family and thus who should be passed control if the owner happens to leave it. Seems like mostly trivial stuff with a bit of work to do.
Is there any easy way to then check what family a player is in, other than having to do a for loop within a for loop?
for _, familyFolder in pairs(Families:GetChildren()) do
for _, player in pairs(familyFolder:GetChildren()) do
if player.Name == LocalPlayer.Name then
print(player.Name .. " is in " .. familyFolder.Name)
end
end
end
I don’t know OOP, but here’s a simple function that does what you’re looking for. You can convert it to OOP if needed. By the looks of it, you just need to use GetDescendants().
function GetFamily(Player) -- "Player" is the player instance
for i,v in pairs(Families:GetDescendants()) do -- Assuming "Families" is defined
if v.Name == Player.Name and v:IsA('StringValue') then -- Checking to make sure the object found is the correct type of object
print(v.Name..' is in '..v.Parent.Name..'\'s Family') -- I'm assuming the parent of the Value is the owner of the Family's name.
end
end
end
Meta should also be controlling this. You need outside values that should be set to identify what family a player belongs to, which you can then reference in other code. For example, an ObjectValue can point directly to the family folder so you can access it by value.
local familyFolder = PlayerDataLocation.Family.Value
Or you can also use a StringValue to identify the family. This is probably less appropriate an option if you include renaming since you’d also have to update these values if the family name changes. There’d be more manual management involved than using a direct reference.
local familyName = PlayerDataLocation.Family.Value
local familyFolder = Families:FindFirstChild(familyName)
My personal preference would be using CollectionService to tag people. No folders or anything, other than for metadata that I might want to include. Even successors and owners can be managed through tags, though you’ll still need to loop - which would be fairly negligible. For this though, you would have to track the name of the family and probably have players assign an unchanging name upon creation.
for _, familyMember in ipairs(CollectionService:GetTagged("Epic Family")) do
local isOwner = CollectionService:HasTag(familyMember, "Owner")
local isSuccessor = CollectionService:HasTag(familyMember, "Successor")
end
These are all good problems you need to design your systems around. Keeping a storage of player session data somewhere and tracking their family in an actual script or ValueObject will get rid of the need of having to looping over the families. Including meta in your folder will help you identify information better so you can work with families.
On a separate wing, you can reduce that for loop assuming a player can only be part of a single family. This is a really ugly trick making lots of assumptions though and I don’t recommend it at all.
-- First check if a player belongs to any family
local membership = Families:FindFirstChild(player.Name, true)
-- Identify the family by finding an ancestor folder if membership exists
local family = membership and membership:FindFirstAncestorOfClass("Folder")
-- Membership exists as does the family: proceed
if membership and family then
local familyName = family.Name
end