Creating a door that whitelists teams

Hi guys,
Not sure if this is the appropriate forum to post on.

I’m currently trying to make a door that only allows players of certain teams to pass through.

I was thinking of doing this via a table that stores the teams that are whitelisted to pass through. This is handled via a GUI that allows the player to select certain teams to be whitelisted and added to said table.

However, I can’t seem to find any way to actually add a table to an instance as its own property.

Would I have to make a class (OOP) specifically for this type of door? Otherwise, how could I go about this?

Thanks, guys

1 Like

No, you can use functional code. OOP is just a style of coding and isn’t required. If you wanted a table of players in a team, then you can make that.

2 Likes

Use CollectionService (hereafter “TagService”, because that’s what it should have been called) and a TagService plugin to set a common tag on all doors that need this functionality, then use TagService:GetTagged and TagService:GetInstanceAddedSignal to call a setup function on all doors that exist at the start and that get added during gameplay. Here’s some code I adapted to what I think your situation is:

local Players = game:GetService("Players")
local TagS = game:GetService("CollectionService")

local ReplicatedStorage = game.ReplicatedStorage
local Libraries = ReplicatedStorage.Libraries
local Remotes = ReplicatedStorage.Remotes
local ServerStorage = game.ServerStorage
local Locals = ServerStorage.Locals --BindableEvents and BindableFunctions for inter-serverscript comms. Or use a ModuleScript and return an interface, up to you.

local Signal = require(Libraries.GoodSignal) --I love GoodSignal <3
local Trove = require(Libraries.Trove) --Actually, probably use a different state cleaning lib there are quite a few out there

local DOOR_TAG = "Door"

local DoorCreated = Signal.new()
local DoorRemoving = Signal.new()
local modelDoors = setmetatable({}, {__mode="k"}) --Don't prevent GC'ing models just for referencing door objects (the tables created in setupDoor)
local playerTroves = setmetatable({}, {__mode="kv"}) --Don't prevent GC'ing players or troves (might not be necessary as Player instances get Destroy'ed when they leave)

local function map(t, mapper) --Put in a functional programming / table util library, or find an existing one
    local result = table.create(#t)
    local i = 1
    for _, v in t do
        result[i] = mapper(v)
        i += 1
    end
    return result
end

local function filter(t, pred) --Put in a functional programming / table util lib, or find an existing one
    local result = {}
    local i = 1
    for _, v in t do
        if pred(v) then
            result[i] = v
            i += 1
        end
    end
    return result
end

local function setupDoor(model: Model)
    --If you wanted to use OOP style, you'd call it newDoor and use metatables to enable dynamic dispatch for methods,
    --  i.e. Door:SerializeForRemoteEvent()
    local door = {
        Model = model,
        Owner = nil,
        AllowedTeams = {},
    }
    modelDoors[model] = door
    DoorCreated:Fire(door)
    return door
end

local function cleanupDoor(door)
    --Depends on your game's requirements.
    DoorRemoving:Fire(door)
    modelDoors[door.Model] = nil --Not necessary for GC, but necessary to prevent e.g. GetDoorFromModel from returning this door (can't expect GC to run immediately)
end

map(TagS:GetTagged(DOOR_TAG), setupDoor)
TagS:GetInstanceAddedSignaL(DOOR_TAG):Connect(setupDoor)
TagS:GetInstanceRemovedSignal(DOOR_TAG):Connect(cleanupDoor)

local function updateTeamCollisionGroups()
    --Create a collision group per team, and ensure all players on each team have their character's
    --  and the teams' doors' collision groups set accordingly.
end

local function updateDoorCollisionGroups(door)
    --Set the door's collision group according to it's owner's team.
end

local function serializeDoorForRemoteEvent(door, forOwner)
    return table.clone(door) --Manually populate a new table if the door object contains secrets that the owner or other players shouldn't know about
end

Players.PlayerAdded:Connect(function(player)
    local T = Trove.new() --Gets cleaned on this player removing
    playerTroves[player] = T --Gets GC'ed eventually because playerTroves is weak

    ServerStorage.AwaitPlayerReady:Invoke(player)

    T:Add(DoorCreated:Connect(function(door)
        local serialized = serializeDoorForRemoteEvent(door, door.Owner == player)
        Remotes.ToClient.OnDoorCreated:Fire(player, serialized)
    end))

    T:Add(DoorRemoving:Connect(function(door)
        local serialized = serializeDoorForRemoteEvent(door, door.Owner == player)
        Remotes.ToClient.OnDoorRemoving:Fire(player, serialized)
    end))

    T:Add(Players.PlayerRemoving:Connect(function(removingPlayer)
        if removingPlayer ~= player then return end
        T:Clean()
    end))
end)

--Note: Only EVER have RemoteFunctions in ToServer, never in ToClient!!! Or use a client/server comms/replication library
Remotes.ToServer.RequestAllDoors.OnInvoke = function(player) 
    return map(modelDoors, function(door)
        return serializeDoorForRemoteEvent(door, door.Owner == player)
    end)
end

Remotes.ToServer.RequestOwnedDoors.OnInvoke = function(player: Player, owner: Player?)
    assert(typeof(owner)=="Instance" and owner:IsA("Player")) --Or find a type checking library and ensure the correct types are passed
    owner = owner or player

    return map(
        filter(
            modelDoors, 
            function(door) return door.Owner == owner end
        ),
        function(door) return serializeDoorForRemoteEvent(door, door.Owner == player) end
    )
end

Locals.GetDoorFromModel.OnInvoke = function(instance)
    return modelDoors[instance]
end
1 Like

Thanks @ThanksRoBama, I’ll definitely give this a look. Right now I’ve just stuck with a simple system without whitelisting, but i’ll be sure to use your response when I get around to making it

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.