-
Notifications
You must be signed in to change notification settings - Fork 1
USERS PERMISSIONS
Pixels has two unrelated concepts called groups. Social groups are player communities. Permission groups are operator controlled authorization roles. This page covers permission groups and the exact algorithm used to decide one dotted capability.
The internal/realm/group realm implements Habbo style social groups. They have a name, badge, owner, members, administrators, a home room, furniture rights, and a forum. Joining one is player facing social behavior.
internal/permission implements hotel wide authorization. Its groups resemble roles such as member, moderator, and admin. They have a numeric weight, optional inheritance, node grants, a client security level projection, and an optional room effect. Players never browse or join these roles through the Habbo group interface.
| Concept | Social group | Permission group |
|---|---|---|
| Owner | internal/realm/group |
internal/permission |
| Purpose | Community identity and collaboration | Server authorization and staff capabilities |
| Typical names | Fan club, builders, event team | Member, moderator, admin |
| Membership | Managed through social group flows | Managed through protected permission administration |
| Badge and forum | Yes | No |
| Dotted capability nodes | No | Yes |
| Numeric weight | No | Yes |
A player may belong to many groups of either kind. Membership in a social group never grants a permission node unless a separate feature explicitly consults that social group.
A node names one concrete capability:
room.doorbell.answer.any
crafting.altar.manage.any
moderation.guide.duty
plugin.hello-plugin.hello.use
Segments use lowercase ASCII letters, digits, underscores, or hyphens. Dots express a namespace, not an automatic inheritance tree. A stored wildcard creates prefix coverage only when * is the final complete segment.
| Stored grant | Query | Matches | Specificity |
|---|---|---|---|
* |
room.doorbell.answer.any |
Yes | 0 |
room.* |
room.doorbell.answer.any |
Yes | 1 |
room.doorbell.* |
room.doorbell.answer.any |
Yes | 2 |
room.doorbell.answer.any |
room.doorbell.answer.any |
Yes | 4 |
room.doorbell.* |
room.doorbell |
No | Not applicable |
room.*.answer |
Any query | No | Invalid syntax |
Specificity is the number of fixed segments. Exact nodes therefore beat broader wildcards inside the same resolution scope.
Realms register concrete nodes in code at startup. This produces a catalog with the declaring package, optional Nitro perk name, and plugin descriptions. Persistence may store wildcards, but checks always ask for a concrete registered capability.
| Node | Capability |
|---|---|
admin.alert |
Send a direct player alert with :alert
|
admin.halert |
Broadcast a hotel alert with :halert
|
admin.about |
Read private build and plugin metadata with :about
|
admin.trace |
Capture the issuing player's packet traffic with :trace
|
admin.effect |
Select or clear the issuing player's owned avatar effect with :effect
|
PIXELS_EFFECT_ALLOW_UNPERMITTED_CLEAR=true provides one narrow exception: a player without admin.effect may execute :effect 0 to clear their own active effect. It never permits selecting a nonzero effect.
Both permission groups and individual players may store a node with allowed=true or allowed=false. A false grant is an explicit deny. Removing a grant is different from denying it: removal lets the resolver continue to another source, while a deny is a decision.
The complete order is:
- Resolve direct player grants.
- If any direct grant matches, use the most specific direct match and stop.
- Load the player's active permission groups by descending weight, then ascending group id for equal weights.
- Resolve the first group whose inheritance chain contains any matching grant.
- Ignore every lower weight group after that first group decision.
- Deny when no source contains a matching grant.
This makes a direct player override absolute. A direct room.* = false wins even if an admin group grants * = true. It also means a high weight group with a matching deny wins over all lower weight groups.
Each permission group may have one parent. The resolver walks the selected group, then its parent, then the next parent until the chain ends. It detects cycles and rejects a broken chain.
Candidates inside that chain are compared in this order:
- More fixed node segments win.
- When specificity ties, the grant nearest the selected child group wins.
- When specificity and inheritance depth both tie, deny wins.
Specificity comes before inheritance distance. For example, a parent exact grant beats a child wildcard because the exact node describes the requested capability more precisely. A child exact deny beats a parent exact allow because both have the same specificity and the child is nearer.
Assume a player belongs to moderator at weight 50 and member at weight 0. moderator inherits from member.
| Grants | Query | Result | Reason |
|---|---|---|---|
Moderator has room.* = true
|
room.doorbell.answer.any |
Allow | First matching group and prefix wildcard |
Moderator has room.* = false, member has exact allow |
room.doorbell.answer.any |
Deny | Moderator already produced a decision, so member membership is not considered |
Moderator child has room.* = false, inherited member has exact allow |
room.doorbell.answer.any |
Allow | Both are in one inheritance chain and the parent exact grant is more specific |
| Moderator child has exact deny, inherited member has exact allow | room.doorbell.answer.any |
Deny | Same specificity, nearer child wins |
Direct player exact allow, admin group has * = false
|
Same exact node | Allow | Direct player decisions are resolved before groups |
| No matching direct or group grant | Any concrete node | Deny | Permissions are closed by default |
Weight determines which membership is considered first and which group is exposed as the player's primary permission group. It is not added together, and lower groups do not contribute after a higher group has made a matching decision.
The primary group is simply the active membership with greatest weight. Pixels uses it for client security projection and synthetic group effects. Authorization still follows the complete node algorithm, so being primary does not imply every capability.
The development seeds make demo an admin at weight 100, alice a moderator at weight 50, and bob plus carol members at weight 0. Every created player receives the default member membership atomically.
A registered node may map to a Nitro perk name. EffectivePerks resolves every mapped node and sends only allowed perks through USER_PERKS. The client view is therefore derived from the server permission engine rather than maintained as a second authorization list.
Permission records use a local cache for hot checks and Redis for shared cache fragments. Mutations invalidate the affected player, membership, group, and node fragments. Online players receive refreshed permissions and perks after the database commit. The warmed local resolution path is designed to remain allocation free.
The protected permission routes expose the registered catalog, permission groups, memberships, direct player grants, effective nodes, and individual checks. GET /docs in development documents the exact request bodies and responses.
The API key authenticates the HTTP caller to the private API boundary. Permission nodes then authorize the acting player for domain operations. These are separate checks: possession of X-API-Key should not be treated as an unlimited staff rank inside gameplay workflows.
Pixels
Getting Started
Architecture
Architecture Internals
Authentication
Users
Navigator
Inventory
Furniture
Rooms
Decoration
Games
Plugins
- PLUGINS-OVERVIEW
- PLUGINS-CREATING
- PLUGINS-LISTENERS
- PLUGINS-EVENTS-REALMS
- PLUGINS-EVENTS-ECONOMY-ROOMS
- PLUGINS-EVENTS-MODERATION-TRADES
- PLUGINS-EVENTS-COMMERCE-WORLD
- PLUGINS-EVENT-FURNITURE-MOVE
- PLUGINS-EVENT-FURNITURE-PICKUP
- PLUGINS-EVENT-ROOM-CREATE
- PLUGINS-EVENT-MARKETPLACE-LIST
- PLUGINS-EVENT-MARKETPLACE-BUY
- PLUGINS-EVENT-PLAYER-PROFILE-UPDATE
- PLUGINS-EVENT-BOT-SPEECH
- PLUGINS-EVENT-GROUP-MEMBERSHIP-CHANGE
- PLUGINS-EVENT-MESSENGER-FRIEND-REQUEST
- PLUGINS-EVENT-MESSENGER-FRIEND-ACCEPT
- PLUGINS-EVENT-CRAFTING-CRAFT
- PLUGINS-WIRED
- WIRED
- PLUGINS-COMMANDS
- PLUGINS-SDK
- PLUGINS-DEPLOYMENT