Skip to main content

AccessPlayerBase

The scripter-facing view of one player's access. Bound to every player in both realms, so anything holding a Player can ask about them without reaching for a service or knowing a registry exists.

local accessPlayer = AccessPlayerInterface:Find(player)

if accessPlayer:IsFeatureAllowed(MyFeatures.Chapters) then ... end

accessPlayer:ObserveIsFeatureAllowed(MyFeatures.Chapters):Subscribe(function(isAllowed) ... end)
accessPlayer:PromiseIsFeatureAllowed(MyFeatures.Chapters):Then(function(isAllowed) ... end)

Three shapes of the same question because callers genuinely differ: a guard wants a boolean now, a UI wants a stream, and a gate wants to wait for a real answer. They agree by construction -- all three read AccessDataService, which is still the only thing that decides anything. This class holds no rules of its own.

Boolean versus the full verdict

IsFeatureAllowed collapses unresolved to false, because a boolean has nowhere to put a third answer and failing closed is the safe half. When the difference matters -- offering a purchase, saying why somebody is refused -- use GetFeatureAllowedState and friends, which hand back the whole AccessStateUtils.AccessState.

Where replicated facts live

The server half writes what it resolved onto a JSON attribute of the player instance, and the client half reads it. Player instances replicate to every client, so one player's access state is legible to all of them -- a party UI can say who is missing a chapter without asking anyone.

That also means facts are public. Anything that must not be visible to other players does not belong in one.

Properties

REPLICATED_FACTS_ATTRIBUTE

AccessPlayerBase.REPLICATED_FACTS_ATTRIBUTE: string

The attribute carrying this player's server-resolved facts, as { [factName]: { value: boolean?, abstained: boolean? } }. One attribute rather than one per fact so a whole snapshot lands atomically instead of a UI seeing a half-updated set.

FeatureAllowedChanged

AccessPlayerBase.FeatureAllowedChanged: Signal<(
string,
boolean,
)>

Fires when a feature's verdict changes for this player, with the feature name, whether it is now allowed, and the whole state.

Covers features that take no subject -- a per-thing feature has nothing to evaluate without one, so reach those through AccessPlayerBase.ObserveIsFeatureAllowed with the subject.

REPLICATED_OVERRIDES_ATTRIBUTE

AccessPlayerBase.REPLICATED_OVERRIDES_ATTRIBUTE: string

The attribute the server's fact overrides arrive on.

Functions

new

AccessPlayerBase.new(
playerPlayer,
serviceBagServiceBag
) → AccessPlayerBase

isAccessPlayer

AccessPlayerBase.isAccessPlayer(valueany) → boolean

IsFeatureAllowed

AccessPlayerBase.IsFeatureAllowed(
featureAccessFeature,
subjectany?
) → boolean

Whether this player may use the feature, right now. Unresolved reads as false.

IsFeatureAllowedByName

AccessPlayerBase.IsFeatureAllowedByName(
featureNamestring,
subjectany?
) → boolean

GetFeatureAllowedState

AccessPlayerBase.GetFeatureAllowedState(
featureAccessFeature,
subjectany?
) → AccessState

The whole verdict, right now, for callers that must tell a refusal from a non-answer.

GetFeatureAllowedStateByName

AccessPlayerBase.GetFeatureAllowedStateByName(
featureNamestring,
subjectany?
) → AccessState

ObserveIsFeatureAllowed

AccessPlayerBase.ObserveIsFeatureAllowed(
featureAccessFeature,
subjectany?
) → Observable<boolean>

ObserveIsFeatureAllowedByName

AccessPlayerBase.ObserveIsFeatureAllowedByName(
featureNamestring,
subjectany?
) → Observable<boolean>

ObserveFeatureAllowedState

AccessPlayerBase.ObserveFeatureAllowedState(
featureAccessFeature,
subjectany?
) → Observable<AccessState>

ObserveFeatureAllowedStateByName

AccessPlayerBase.ObserveFeatureAllowedStateByName(
featureNamestring,
subjectany?
) → Observable<AccessState>

PromiseIsFeatureAllowed

AccessPlayerBase.PromiseIsFeatureAllowed(
featureAccessFeature,
subjectany?
) → Promise<boolean>

Settles once there is a real verdict, skipping unresolved. Rejects if the player leaves first.

PromiseIsFeatureAllowedByName

AccessPlayerBase.PromiseIsFeatureAllowedByName(
featureNamestring,
subjectany?
) → Promise<boolean>

PromiseFeatureAllowedState

AccessPlayerBase.PromiseFeatureAllowedState(
featureAccessFeature,
subjectany?
) → Promise<AccessState>

GetFactMetadata

AccessPlayerBase.GetFactMetadata(
factNamestring
) → any?

Why a fact reads the way it does -- the deciding layer's attribution, in whatever shape that mechanism attached. This is what a UI renders: which friends granted you access, which gamepass covered you.

Nil when the fact attached none, or when nothing decided it.

ObserveFactMetadata

AccessPlayerBase.ObserveFactMetadata(
factNamestring
) → Observable<any?>

The same attribution, live, for a UI that has to follow it.

GetReplicatedFacts

AccessPlayerBase.GetReplicatedFacts(selfAccessPlayerBase) → {[string]{
valueboolean?,
statestring
}}

What the server resolved for this player, keyed by fact name, each with its AccessReplicationState. Readable for any player, not just the local one.

ObserveReplicatedFacts

AccessPlayerBase.ObserveReplicatedFacts(selfAccessPlayerBase) → Observable<{[string]{
valueboolean?,
statestring
}}>

The same, live.

GetDebugState

AccessPlayerBase.GetDebugState(selfAccessPlayerBase) → {
featureStates{[string]any},
facts{[string]any}
}

Every feature's current verdict for this player, plus every fact underneath. What to print when somebody says they cannot get in.

Show raw api
{
    "functions": [
        {
            "name": "new",
            "desc": "",
            "params": [
                {
                    "name": "player",
                    "desc": "",
                    "lua_type": "Player"
                },
                {
                    "name": "serviceBag",
                    "desc": "",
                    "lua_type": "ServiceBag"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "AccessPlayerBase"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 88,
                "path": "src/access/src/Shared/Binders/AccessPlayerBase.lua"
            }
        },
        {
            "name": "isAccessPlayer",
            "desc": "",
            "params": [
                {
                    "name": "value",
                    "desc": "",
                    "lua_type": "any"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "boolean"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 118,
                "path": "src/access/src/Shared/Binders/AccessPlayerBase.lua"
            }
        },
        {
            "name": "IsFeatureAllowed",
            "desc": "Whether this player may use the feature, right now. Unresolved reads as false.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "AccessPlayerBase"
                },
                {
                    "name": "feature",
                    "desc": "",
                    "lua_type": "AccessFeature"
                },
                {
                    "name": "subject",
                    "desc": "",
                    "lua_type": "any?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "boolean"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 129,
                "path": "src/access/src/Shared/Binders/AccessPlayerBase.lua"
            }
        },
        {
            "name": "IsFeatureAllowedByName",
            "desc": "",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "AccessPlayerBase"
                },
                {
                    "name": "featureName",
                    "desc": "",
                    "lua_type": "string"
                },
                {
                    "name": "subject",
                    "desc": "",
                    "lua_type": "any?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "boolean"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 142,
                "path": "src/access/src/Shared/Binders/AccessPlayerBase.lua"
            }
        },
        {
            "name": "GetFeatureAllowedState",
            "desc": "The whole verdict, right now, for callers that must tell a refusal from a non-answer.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "AccessPlayerBase"
                },
                {
                    "name": "feature",
                    "desc": "",
                    "lua_type": "AccessFeature"
                },
                {
                    "name": "subject",
                    "desc": "",
                    "lua_type": "any?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "AccessState"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 153,
                "path": "src/access/src/Shared/Binders/AccessPlayerBase.lua"
            }
        },
        {
            "name": "GetFeatureAllowedStateByName",
            "desc": "",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "AccessPlayerBase"
                },
                {
                    "name": "featureName",
                    "desc": "",
                    "lua_type": "string"
                },
                {
                    "name": "subject",
                    "desc": "",
                    "lua_type": "any?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "AccessState"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 175,
                "path": "src/access/src/Shared/Binders/AccessPlayerBase.lua"
            }
        },
        {
            "name": "ObserveIsFeatureAllowed",
            "desc": "",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "AccessPlayerBase"
                },
                {
                    "name": "feature",
                    "desc": "",
                    "lua_type": "AccessFeature"
                },
                {
                    "name": "subject",
                    "desc": "",
                    "lua_type": "any?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Observable<boolean>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 189,
                "path": "src/access/src/Shared/Binders/AccessPlayerBase.lua"
            }
        },
        {
            "name": "ObserveIsFeatureAllowedByName",
            "desc": "",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "AccessPlayerBase"
                },
                {
                    "name": "featureName",
                    "desc": "",
                    "lua_type": "string"
                },
                {
                    "name": "subject",
                    "desc": "",
                    "lua_type": "any?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Observable<boolean>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 202,
                "path": "src/access/src/Shared/Binders/AccessPlayerBase.lua"
            }
        },
        {
            "name": "ObserveFeatureAllowedState",
            "desc": "",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "AccessPlayerBase"
                },
                {
                    "name": "feature",
                    "desc": "",
                    "lua_type": "AccessFeature"
                },
                {
                    "name": "subject",
                    "desc": "",
                    "lua_type": "any?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Observable<AccessState>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 215,
                "path": "src/access/src/Shared/Binders/AccessPlayerBase.lua"
            }
        },
        {
            "name": "ObserveFeatureAllowedStateByName",
            "desc": "",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "AccessPlayerBase"
                },
                {
                    "name": "featureName",
                    "desc": "",
                    "lua_type": "string"
                },
                {
                    "name": "subject",
                    "desc": "",
                    "lua_type": "any?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Observable<AccessState>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 228,
                "path": "src/access/src/Shared/Binders/AccessPlayerBase.lua"
            }
        },
        {
            "name": "PromiseIsFeatureAllowed",
            "desc": "Settles once there is a real verdict, skipping unresolved. Rejects if the player leaves first.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "AccessPlayerBase"
                },
                {
                    "name": "feature",
                    "desc": "",
                    "lua_type": "AccessFeature"
                },
                {
                    "name": "subject",
                    "desc": "",
                    "lua_type": "any?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise<boolean>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 243,
                "path": "src/access/src/Shared/Binders/AccessPlayerBase.lua"
            }
        },
        {
            "name": "PromiseIsFeatureAllowedByName",
            "desc": "",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "AccessPlayerBase"
                },
                {
                    "name": "featureName",
                    "desc": "",
                    "lua_type": "string"
                },
                {
                    "name": "subject",
                    "desc": "",
                    "lua_type": "any?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise<boolean>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 258,
                "path": "src/access/src/Shared/Binders/AccessPlayerBase.lua"
            }
        },
        {
            "name": "PromiseFeatureAllowedState",
            "desc": "",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "AccessPlayerBase"
                },
                {
                    "name": "feature",
                    "desc": "",
                    "lua_type": "AccessFeature"
                },
                {
                    "name": "subject",
                    "desc": "",
                    "lua_type": "any?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise<AccessState>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 271,
                "path": "src/access/src/Shared/Binders/AccessPlayerBase.lua"
            }
        },
        {
            "name": "GetFactMetadata",
            "desc": "Why a fact reads the way it does -- the deciding layer's attribution, in whatever shape that mechanism\nattached. This is what a UI renders: which friends granted you access, which gamepass covered you.\n\nNil when the fact attached none, or when nothing decided it.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "AccessPlayerBase"
                },
                {
                    "name": "factName",
                    "desc": "",
                    "lua_type": "string"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "any?"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 288,
                "path": "src/access/src/Shared/Binders/AccessPlayerBase.lua"
            }
        },
        {
            "name": "ObserveFactMetadata",
            "desc": "The same attribution, live, for a UI that has to follow it.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "AccessPlayerBase"
                },
                {
                    "name": "factName",
                    "desc": "",
                    "lua_type": "string"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Observable<any?>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 300,
                "path": "src/access/src/Shared/Binders/AccessPlayerBase.lua"
            }
        },
        {
            "name": "GetReplicatedFacts",
            "desc": "What the server resolved for this player, keyed by fact name, each with its\n[AccessReplicationState]. Readable for **any** player, not just the local one.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "AccessPlayerBase"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "{ [string]: { value: boolean?, state: string } }"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 314,
                "path": "src/access/src/Shared/Binders/AccessPlayerBase.lua"
            }
        },
        {
            "name": "ObserveReplicatedFacts",
            "desc": "The same, live.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "AccessPlayerBase"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Observable<{ [string]: { value: boolean?, state: string } }>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 332,
                "path": "src/access/src/Shared/Binders/AccessPlayerBase.lua"
            }
        },
        {
            "name": "GetDebugState",
            "desc": "Every feature's current verdict for this player, plus every fact underneath. What to print when\nsomebody says they cannot get in.",
            "params": [
                {
                    "name": "self",
                    "desc": "",
                    "lua_type": "AccessPlayerBase"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "{ featureStates: { [string]: any }, facts: { [string]: any } }"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 346,
                "path": "src/access/src/Shared/Binders/AccessPlayerBase.lua"
            }
        }
    ],
    "properties": [
        {
            "name": "REPLICATED_FACTS_ATTRIBUTE",
            "desc": "The attribute carrying this player's server-resolved facts, as\n`{ [factName]: { value: boolean?, abstained: boolean? } }`. One attribute rather than one per fact so\na whole snapshot lands atomically instead of a UI seeing a half-updated set.",
            "lua_type": "string",
            "source": {
                "line": 62,
                "path": "src/access/src/Shared/Binders/AccessPlayerBase.lua"
            }
        },
        {
            "name": "FeatureAllowedChanged",
            "desc": "Fires when a feature's verdict changes for this player, with the feature name, whether it is now\nallowed, and the whole state.\n\nCovers features that take no subject -- a per-thing feature has nothing to evaluate without one, so\nreach those through [AccessPlayerBase.ObserveIsFeatureAllowed] with the subject.\n\n\t",
            "lua_type": "Signal<(string, boolean, AccessState)>",
            "source": {
                "line": 107,
                "path": "src/access/src/Shared/Binders/AccessPlayerBase.lua"
            }
        },
        {
            "name": "REPLICATED_OVERRIDES_ATTRIBUTE",
            "desc": "The attribute the server's fact overrides arrive on.",
            "lua_type": "string",
            "source": {
                "line": 408,
                "path": "src/access/src/Shared/Binders/AccessPlayerBase.lua"
            }
        }
    ],
    "types": [],
    "name": "AccessPlayerBase",
    "desc": "The scripter-facing view of one player's access. Bound to every player in both realms, so anything\nholding a `Player` can ask about them without reaching for a service or knowing a registry exists.\n\n```lua\nlocal accessPlayer = AccessPlayerInterface:Find(player)\n\nif accessPlayer:IsFeatureAllowed(MyFeatures.Chapters) then ... end\n\naccessPlayer:ObserveIsFeatureAllowed(MyFeatures.Chapters):Subscribe(function(isAllowed) ... end)\naccessPlayer:PromiseIsFeatureAllowed(MyFeatures.Chapters):Then(function(isAllowed) ... end)\n```\n\nThree shapes of the same question because callers genuinely differ: a guard wants a boolean now, a UI\nwants a stream, and a gate wants to wait for a real answer. They agree by construction -- all three\nread [AccessDataService], which is still the only thing that decides anything. This class holds no\nrules of its own.\n\n## Boolean versus the full verdict\n\n`IsFeatureAllowed` collapses unresolved to **false**, because a boolean has nowhere to put a third\nanswer and failing closed is the safe half. When the difference matters -- offering a purchase, saying\n*why* somebody is refused -- use `GetFeatureAllowedState` and friends, which hand back the whole\n[AccessStateUtils.AccessState].\n\n## Where replicated facts live\n\nThe server half writes what it resolved onto a JSON attribute of the player instance, and the client\nhalf reads it. Player instances replicate to *every* client, so one player's access state is legible\nto all of them -- a party UI can say who is missing a chapter without asking anyone.\n\nThat also means facts are **public**. Anything that must not be visible to other players does not\nbelong in one.",
    "source": {
        "line": 38,
        "path": "src/access/src/Shared/Binders/AccessPlayerBase.lua"
    }
}