Class GuildRules
- Namespace
- FishMMO.Server.Implementation.World.SceneServer
- Assembly
- FishMMO.Server.dll
The guild permission rules, as pure functions of a resolved standing.
public static class GuildRules
- Inheritance
-
GuildRules
- Inherited Members
Remarks
Every server-side guild permission decision is one of these. They were originally inline in the async handlers, which meant the only way to exercise them was to stand up a database, a network connection and a scene server — so in practice they were not exercised at all, and a permission model nobody can test is a permission model nobody can trust.
Pulled out here they take a GuildAuthority and some plain values, touch nothing else, and are called by exactly one place each. The handler keeps the IO; this keeps the policy.
Methods
CanChangeMemberRank(GuildAuthority, byte, byte)
May the actor move a member from one rank to another?
public static GuildActionResult CanChangeMemberRank(GuildAuthority actor, byte currentRankOrder, byte newRankOrder)
Parameters
actorGuildAuthorityThe actor's standing.
currentRankOrderbyteThe member's present ladder position.
newRankOrderbyteThe requested ladder position.
Returns
- GuildActionResult
The decision.
Remarks
Four rules. The destination must exist; neither the top seat may be entered nor left through this path (that is a leadership transfer, which demotes the outgoing holder in the same breath); the actor must outrank the member's CURRENT rank; and the actor must outrank the DESTINATION.
The last is the one that is easy to omit and is a direct escalation: without it an officer able to promote could move somebody — or a second character of their own — into a rank above their own, and be outranked by a seat they created.
CanCreateRank(GuildAuthority, byte, GuildPermissions)
May the actor insert a rank at the given position with the given permissions?
public static GuildActionResult CanCreateRank(GuildAuthority actor, byte rankOrder, GuildPermissions proposed)
Parameters
actorGuildAuthorityThe actor's standing.
rankOrderbyteThe position the new rank would take.
proposedGuildPermissionsThe requested mask.
Returns
- GuildActionResult
The decision.
Remarks
The position is an insertion point, not a free slot. Everything already at
or above rankOrder moves up one rung — see
IGuildRankService.InsertAsync. It has to work that way: a guild is seeded with
three contiguous ranks and the actor may only create below their own seat, so a leader
at order 3 has orders 1 and 2 to choose from and both are already taken. Requiring a
free position meant no guild could ever add a rank.
Which is why the actor's OWN order is allowed here, where CanEditRank(GuildAuthority, byte, GuildPermissions) refuses it. The two are not the same act. Editing your own row is the shortest path from "may edit ranks" to "may do anything": you add the bits you want to the seat you already occupy. Inserting at your own order adds a rank BELOW you and moves your row up with the rest of the ladder — it cannot change your own permissions, and every seniority comparison in the guild is preserved because every rank at or above the point moves by the same one. Refusing it would mean the most useful placement, a new tier directly under the person creating it, was the one placement nobody could ask for.
Headroom is NOT checked here. Whether the top of the ladder can move up one is a fact about rows this struct does not necessarily hold in full, and the service settles it inside the same transaction that performs the shift.
CanDeleteRank(GuildAuthority, byte)
May the actor remove a rank?
public static GuildActionResult CanDeleteRank(GuildAuthority actor, byte rankOrder)
Parameters
actorGuildAuthorityThe actor's standing.
rankOrderbyteThe rank to remove.
Returns
- GuildActionResult
The decision.
Remarks
Whether the rank still has MEMBERS is not decided here — that is a race the database settles in the same statement as the delete. What is decided here is whether the guild would still work afterwards.
CanEditRank(GuildAuthority, byte, GuildPermissions)
May the actor change a rank's name and permissions?
public static GuildActionResult CanEditRank(GuildAuthority actor, byte rankOrder, GuildPermissions proposed)
Parameters
actorGuildAuthorityThe actor's standing.
rankOrderbyteThe rank being edited.
proposedGuildPermissionsThe mask the rank would end up with.
Returns
- GuildActionResult
The decision.
Remarks
The grant check compares only the bits being ADDED against the actor's own mask. A rank that already holds a permission the actor lacks keeps it: removing it is not an escalation, and refusing the whole edit over it would make such a rank uneditable forever by anyone below the person who granted it.
The actor's own row may be RENAMED, never re-permissioned. Seniority is strict for any change to a mask, because editing the seat you occupy is the shortest path from "may edit ranks" to "may do anything". A rename carries no such path — the mask is compared bit for bit and must be identical — and without the exception the guild's top rank could never be called anything but what it was seeded as, since nobody outranks the leader.
CanKick(GuildAuthority, byte)
May the actor remove the member holding the given rank?
public static GuildActionResult CanKick(GuildAuthority actor, byte targetRankOrder)
Parameters
actorGuildAuthorityThe actor's standing.
targetRankOrderbyteThe target's ladder position.
Returns
- GuildActionResult
The decision.
CanTransferLeadership(GuildAuthority)
May the actor hand the guild's top seat to somebody else?
public static GuildActionResult CanTransferLeadership(GuildAuthority actor)
Parameters
actorGuildAuthorityThe actor's standing.
Returns
- GuildActionResult
The decision.
Remarks
Stricter than the permission alone: the actor must also currently OCCUPY the top seat.
A rank editor could grant TransferLeadership to a subordinate rank, and giving
away the leader's own seat is not something a subordinate should be able to do.
CanUse(GuildAuthority, GuildPermissions)
May the actor perform an action gated by a single permission and nothing else?
public static GuildActionResult CanUse(GuildAuthority actor, GuildPermissions permission)
Parameters
actorGuildAuthorityThe actor's standing.
permissionGuildPermissionsThe permission required.
Returns
- GuildActionResult
The decision.
Remarks
Covers invite, disband, the two text edits, the two note edits, recruitment editing and the application queue — every action whose only question is "do you hold the bit".
WouldOrphanRankAdministration(IReadOnlyList<GuildRankData>, byte, GuildPermissions)
Would this change leave no rank able to administer ranks?
public static bool WouldOrphanRankAdministration(IReadOnlyList<GuildRankData> ladder, byte rankOrder, GuildPermissions newPermissions)
Parameters
ladderIReadOnlyList<GuildRankData>The guild's rank rows.
rankOrderbyteThe rank being changed or removed.
newPermissionsGuildPermissionsThe mask that rank would end up with.
Returns
- bool
True when the change must be refused.
Remarks
The soft-lock guard. A guild whose only rank holding EditRanks gives it up can
never get it back — editing ranks is the permission that would be needed — and cannot
promote anybody into a rank that has it, because there is no such rank. The guild is
then frozen in whatever shape it was in, permanently, with no in-game recovery.
Only EditRanks is protected this way. It is the one permission whose absence
prevents its own restoration; a guild that loses every Invite can still edit a
rank to grant it back.