I have noticed before that there are not many party systems open to the public. So, I decided to make a party system that is object oriented. You are going to need a bit of lua knowledge to understand how to use this module, but I will give a few examples.
A few things to note:
- I do not have that many error checks, you can add them yourself if you wish to.
- When adding a member to the party, you are going to have to have a check for if it’s invite only or not, I do not check when calling addMember()
- It also creates physical information in a folder named “PhysicalParties” in ReplicatedStorage as you can see in the screenshot below. There are attributes that are apart of the Player. “Leader”, “CanKick”, and “CanInvite”
- This works best when combined with remotes obviously so you can tell who called the functions and such obviously. I created a basic remote example for sending and accepting invites. You would also probably want to add something to it like adding a GUI that when you accept an invite, the remote to join your current invite fires. You could attach the GUI popup part to onInviteSent
Model:
OOP Party System - Roblox
I am very open to suggestions of stuff to add, or how to improve it. Please feel free to give me feedback
local Party = {}
Party.__index = Party
local Players = game:GetService("Players")
local Parties = {};
local PhysicalParty
local defaultMaxMembers = 4
local inviteCooldown = 20
local PartyRemote = script:WaitForChild("Party")
--[[
local PartyModule = require(game.ReplicatedStorage.PartySystem.Parties) -->> Referring to this module
PartyModule:getParty(Player) -->> Requires a player argument. Will return the player's current party (even if they are not the leader), if they are in one.
PartyModule:onInviteSent(function(Invite, PartyLeader, invitedPlayer)
-- MUST BE USED BEFORE ANY PARTIES ARE CREATED
-->> Invite is the physical invite stored in PhysicalParty.Invites
-->> PartyLeader is the player instance of the party leader of which party the player was invited to
-->> invitedPlayer is the player instance of the player who was invited
print(Invite)
print(PartyLeader)
print(invitedPlayer)
end)
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
local Party = Party.new(Leader) -->> Requires a player argument. Player argument will become the leader.
Party:disband()
Party:transferOwnership(Player) -->> Requires a Player argument
Party:invitePlayer(Player) -->> Requires a Player argument
Party:addMember(Player) -->> Requires a Player argument
Party:removeMember(Player) -->> Requires a Player argument
Party:blacklistPlayer(Player) -->> Requires a Player argument
Party:unblacklistPlayer(Player) -->> Requires a Player argument
Party:setMaxMembers(MaxMembers) -->> Requires a number argument. The default max members is 4, and can be change in the module
Party:setPermission(Member, Permission, Bool) -->> Requires a player argument, string argument, and bool argument.
Party:toggleInviteOnly(Toggle) -->> Requires a bool argument.
Party:getMembers() -->> Returns an array of all the current party members
Party:isMember(Player) -->> Requires a Player argument. Returns a bool (true/false)
Party:isLeader(Player) -->> Requires a Player argument. Returns a bool (true/false)
Party:isInviteOnly() -->> Returns a bool (true/false)
Party:hasPermission(Player, Permission) -->> Requires a Player argument and a string for the permission. Returns a bool (true/false)
Party:teleportMembers(123456789, {ReservedServerCode = "CodeHere", JobId = "1234567890abc", ShouldReserveServer = true}) -->> Requires a PlaceId. Anything inside the table is optional.
]]--
local function createNewInstance(InstanceType, Parent, Name, Value)
local newInstance
local Success, err = pcall(function()
newInstance = Instance.new(InstanceType)
newInstance.Parent = Parent
newInstance.Name = Name
if Value then
newInstance.Value = Value
end
return newInstance
end)
if not Success then
warn("Error creating instance: " ..err)
else
return newInstance
end
end
--// Party module functions \\--
-->> Return what party a player is in, if any
function Party:getParty(Player: Player)
if Parties[Player] then
return Parties[Player]
end
for PartyLeader,Party in pairs (Parties) do
for i,Member in pairs (Party.Members) do
if Member == Player then
return Party
end
end
end
return "NoParty"
end
--// Party object function --\\
-->> Create a new party
function Party.new(Leader: Player)
if Parties[Leader] then
warn(("%s is already a party leader!"):format(Leader.Name))
return Parties[Leader]
end
setmetatable({}, Party)
Party.Leader = Leader;
Party.MaxMembers = defaultMaxMembers;
Party.CurrentMemberCount = 0;
Party.InviteOnly = false;
Party.Members = {};
Party.Invites = {};
Party.Blacklist = {};
PhysicalParty = script.Parent.PhysicalParties.PartyTemplate:Clone()
Party:addMember(Leader)
PhysicalParty.Name = Leader.Name
PhysicalParty.Parent = script.Parent.PhysicalParties
PhysicalParty.Members[Leader.Name]:SetAttribute("Leader", true)
PhysicalParty.Members[Leader.Name]:SetAttribute("CanKick", true)
PhysicalParty.Members[Leader.Name]:SetAttribute("CanInvite", true)
Parties[Leader] = Party
print(Parties)
return Party
end
-->> Disband a party/delete a party
function Party:disband()
if not Parties[self.Leader] then
warn("Party does not exist!")
return
end
Parties[self.Leader] = nil
PhysicalParty:Destroy()
end
-->> Transfer party ownership to another party member
function Party:transferOwnership(Member: Player)
if not table.find(self.Members, Member) then
print(("%s not in the party."):format(Member.Name))
return "NotInParty"
elseif self.Leader == Member then
warn("Cannot transfer ownership to current leader.")
return
end
PhysicalParty.Name = Member.Name
PhysicalParty.Members[self.Leader.Name]:SetAttribute("Leader", false)
PhysicalParty.Members[Member.Name]:SetAttribute("Leader", true)
self.Leader = Member
end
-->> Invites a player to the party
function Party:invitePlayer(Player: Player)
if self.Invites[Player] then
warn(("%s already has an invite. Wait before sending another."):format(Player.Name))
return
end
if self.Members[Player] then
warn(("%s is already a party member."):format(Player.Name))
return
end
self.Invites[Player] = self
createNewInstance("ObjectValue", PhysicalParty.Invites, Player.Name, Player)
spawn(function()
task.wait(inviteCooldown)
self.Invites[Player] = nil
if PhysicalParty.Invites:FindFirstChild(Player.Name) then
PhysicalParty.Invites[Player.Name]:Destroy()
end
end)
end
-->> Adds a member to the party
function Party:addMember(Member: Player)
if self.CurrentMemberCount + 1 > self.MaxMembers then
warn(("[%s:%s] Cannot add %s to party. Too many members!"):format(Member.Name, self.CurrentMemberCount, self.MaxMembers))
return
elseif table.find(self.Members, Member) then
warn(("%s is already in the party."):format(Member.Name))
return
elseif table.find(self.Blacklist, Member) then
warn(("%s is blacklisted from the party!"):format(Member.Name))
return
end
table.insert(self.Members, Member)
self.CurrentMemberCount += 1
local newPhysicalMember = createNewInstance("ObjectValue", PhysicalParty.Members, Member.Name, Member)
newPhysicalMember:SetAttribute("Leader", false)
newPhysicalMember:SetAttribute("CanKick", false)
newPhysicalMember:SetAttribute("CanInvite", false)
end
-->> Removes a member from the party
function Party:removeMember(Member: Player)
if not table.find(self.Members, Member) then
warn(("%s not in the party."):format(Member.Name))
return
elseif self.Leader == Member then
warn("You cannot kick the leader from the party.")
return
end
table.remove(self.Members, table.find(self.Members, Member))
PhysicalParty.Members[Member.Name]:Destroy()
end
-->> Blacklist a player from a party
function Party:blacklistPlayer(Player: Player)
if table.find(self.Blacklist, Player) then
warn(("%s is already blacklisted."):format(Player.Name))
return
elseif self.Leader == Player then
warn("The party leader cannot be blacklisted.")
return
end
table.insert(self.Blacklist, Player)
local newPhysicalBlacklist = createNewInstance("ObjectValue", PhysicalParty.Blacklist, Player.Name, Player)
if self:isMember(Player) then
self:removeMember(Player)
end
end
-->> Unblacklist a player from a party
function Party:unblacklistPlayer(Player: Player)
if not table.find(self.Blacklist, Player) then
warn(("%s is not blacklisted from the party"):format(Player.Name))
return
end
table.remove(self.Blacklist, table.find(self.Blacklist, Player))
if PhysicalParty.Blacklist:FindFirstChild(Player.Name) then
PhysicalParty.Blacklist[Player.Name]:Destroy()
end
end
-->> Set the number of members allowed in a party
function Party:setMaxMembers(MaxMembers: number)
self.MaxMembers = MaxMembers
end
-->> Set a player's permission
function Party:setPermission(Member, Permission, Toggle)
if not table.find(self.Members, Member) then
warn(("%s is not in the party"):format(Member.Name))
return
elseif self.Leader == Member then
warn("Cannot set leaders permissions.")
return
elseif Permission == "Leader" then
warn(("You cannot set the %s permission. Use transferOwnership instead."):format("Leader"))
return
end
PhysicalParty.Members[Member.Name]:SetAttribute(Permission, Toggle)
end
function Party:toggleInviteOnly(Toggle: boolean)
if Toggle == true then
self.InviteOnly = true
PhysicalParty.InviteOnly.Value = true
elseif Toggle == false then
self.InviteOnly = false
PhysicalParty.InviteOnly.Value = false
end
end
-->> Return the members of a party
function Party:getMembers()
return self.Members
end
-->> Return if a player is a member of a party
function Party:isMember(Player: Player)
if not PhysicalParty.Members:FindFirstChild(Player.Name) then
warn(Player.Name.. " is not a member of the party.")
return
end
if table.find(self.Members, Player) then
return true
end
return false
end
function Party:isLeader(Player: Player)
if not PhysicalParty.Members:FindFirstChild(Player.Name) then
warn(Player.Name.. " is not a member of the party.")
return
end
if PhysicalParty.Members[Player.Name]:GetAttribute("Leader") == true then
return true
end
return false
end
-->> Return if a party is invite only
function Party:isInviteOnly()
if self.InviteOnly then
return true
end
return false
end
-->> Check if player has a permission for a party
function Party:hasPermission(Member, Permission: string)
if not PhysicalParty.Members[Member.Name]:GetAttribute(Permission) then
print(("'%s' is an invalid permission."):format(Permission))
return
end
if PhysicalParty.Members[Member.Name]:GetAttribute(Permission) == true then
return true
end
return false
end
function Party:teleportMembers(PlaceId, OptionalData)
local TeleportOptions = Instance.new("TeleportOptions")
if OptionalData.ReservedServerCode then
TeleportOptions.ReservedServerAccessCode = OptionalData.ReservedServerCode
end
if OptionalData.JobId then
TeleportOptions.ServerInstanceId = OptionalData.JobId
end
if OptionalData.ShouldReserveServer then
OptionalData.ShouldReserveServer = OptionalData.ShouldReserveServer
end
game:GetService("TeleportService"):TeleportAsync(PlaceId, self.Members, TeleportOptions)
end
function Party:onInviteSent(Callback)
script.Parent.PhysicalParties.ChildAdded:Connect(function(newParty)
local Tries
local PartyLeader
local invitedPlayer
newParty.Invites.ChildAdded:Connect(function(newInvite)
Tries = 0
repeat
task.wait(.25)
Tries += 1
until newInvite.Value ~= nil or Tries >= 3
if Tries >= 3 then
warn("An error has occured while attempting to run a callback when an invite was sent.")
return
end
if newInvite.Parent.Parent ~= nil then
if not game.Players:FindFirstChild(newInvite.Parent.Parent.Name) then
print(newInvite.Parent.Parent.Name)
warn("An error has occured!")
return
end
PartyLeader = game.Players:FindFirstChild(newInvite.Parent.Parent.Name)
invitedPlayer = game.Players:FindFirstChild(newInvite.Name)
end
Callback(newInvite, PartyLeader, invitedPlayer)
end)
end)
end
--// Handle remote
local function getPlayerParty(Player)
for i,Party in pairs (script.Parent.PhysicalParties:GetChildren()) do
if Party.Members:FindFirstChild(Player.Name) then
return Party.Members:FindFirstChild(Player.Name)
end
end
return false
end
local function playerHasInvite(Player)
for i,Party in pairs (script.Parent.PhysicalParties:GetChildren()) do
for i,Invite in pairs (Party.Invites:GetChildren()) do
if Invite.Name == Player.Name then
local PartyOwner = Players[Party.Name]
return Parties[PartyOwner]
end
end
end
return false
end
local function removePlayerInvites(Player)
for i,Party in pairs (script.Parent.PhysicalParties:GetChildren()) do
for i,Invite in pairs (Party.Invites:GetChildren()) do
if Invite.Name == Player.Name then
Invite:Destroy()
end
end
end
for i,Party in pairs (Parties) do
if Party.Invites[Player] then
Party.Invites[Player] = nil
end
end
end
local function handleRemoteRequest(Player, Request, Data)
if Request == "InvitePlayer" then
if getPlayerParty(Player) and getPlayerParty(Player):GetAttribute("CanInvite") == true then
Party:invitePlayer(Data.InvitedPlayer)
end
elseif Request == "AcceptInvite" then
if playerHasInvite(Player) then
playerHasInvite(Player):addMember(Player)
removePlayerInvites(Player)
end
end
end
PartyRemote.OnServerEvent:Connect(handleRemoteRequest)
return Party
PartyModule Example usages:
local PartyModule = require(game.ReplicatedStorage.Parties) -->> Referring to this module
PartyModule:getParty(Player) -->> Requires a player argument. Will return the player's current party (even if they are not the leader), if they are in one.
PartyModule:onInviteSent(function(Invite, PartyLeader, invitedPlayer)
-- MUST BE USED BFORE ANY PARTIES ARE CREATED
-->> Invite is the physical invite stored in PhysicalParty.Invites
-->> PartyLeader is the player instance of the party leader of which party the player was invited to
-->> invitedPlayer is the player instance of the player who was invited
print(Invite)
print(PartyLeader)
print(invitedPlayer)
end)
--------------------------------------------------------------------------------------------------
local newParty = PartyModule.new(game.Players:WaitForChild("bellaouzo")) -->> Requires a player argument. Player argument will become the leader.
newParty:disband()
newParty:transferOwnership(game.Players:WaitForChild("bellaouzo")) -->> Requires a Player argument
newParty:invitePlayer(Player) -->> Requires a Player argument
newParty:addMember(game.Players:WaitForChild("bellaouzo")) -->> Requires a Player argument
newParty:removeMember(game.Players:WaitForChild("bellaouzo")) -->> Requires a Player argument
newParty:blacklistPlayer(game.Players:WaitForChild("bellaouzo")) -->> Requires a Player argument
newParty:unblacklistPlayer(game.Players:WaitForChild("bellaouzo")) -->> Requires a Player argument
newParty:setMaxMembers(6) -->> Requires a number argument. The default max members is 4, and can be change in the module
newParty:setPermission(game.Players:WaitForChild("bellaouzo"), "CanKick", true) -->> Requires a player argument, string argument and bool argument.
newParty:toggleInviteOnly(true) -->> Requires a bool argument.
newParty:getMembers() -->> Returns an array of all the current party members
newParty:isMember(game.Players:WaitForChild("bellaouzo")) -->> Requires a Player argument
newParty:isInviteOnly() -->> Returns a bool (true or false)
newParty:hasPermission(game.Players:WaitForChild("bellaouzo"), "CanKick") -->> Requires a Player argument and a string for the permission.
newParty:teleportMembers(123456789, {ReservedServerCode = "CodeHere", JobId = "1234567890abc", ShouldReserveServer = true}) -->> Requires a PlaceId. Anything inside the table is optional.
--[[
Permissions:
Leader
CanKick
CanInvite
--]]
(Local Script Example) Remote Examples Usages:
local PartyRemote = PartyModule.Party
PartyRemote:FireServer("InvitePlayer", {InvitedPlayer = game.Players:WaitForChild("Player2")}) -->> Would send an invite to Player2 if the person who called the remote can send invites
PartyRemote:FireServer("AcceptInvite") -->> Would accept a party invite if the person who called the remote has a pending invite