summaryrefslogtreecommitdiff
path: root/src/main/kotlin/io/dico/parcels2/Privileges.kt
blob: 1aad3f6b57e06d76c5509818cfd0bc4a27da3e2a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package io.dico.parcels2

import io.dico.parcels2.Privilege.*
import org.bukkit.OfflinePlayer

enum class Privilege(
    val number: Int,
    val transient: Boolean = false
) {
    BANNED(1),
    DEFAULT(2),
    CAN_BUILD(3),
    CAN_MANAGE(4),

    OWNER(-1, transient = true),
    ADMIN(-1, transient = true);

    fun isDistanceGrEq(other: Privilege): Boolean =
        when { // used for example when disallowBuild is called and CAN_MANAGE is the privilege.
            other > DEFAULT -> this >= other
            other == DEFAULT -> this == other
            else -> this <= other
        }

    fun requireNonTransient(): Privilege {
        if (transient) {
            throw IllegalArgumentException("Transient privilege $this is invalid")
        }
        return this
    }

    /*
    fun canEnter() = this >= BANNED
    fun canBuild() = this >= CAN_BUILD
    fun canManage() = this >= CAN_MANAGE
    */

    companion object {
        fun getByNumber(id: Int) =
            when (id) {
                1 -> BANNED
                2 -> DEFAULT
                3 -> CAN_BUILD
                4 -> CAN_MANAGE
                else -> null
            }
    }
}

typealias PrivilegeKey = PlayerProfile.Real
typealias MutablePrivilegeMap = MutableMap<PrivilegeKey, Privilege>
typealias PrivilegeMap = Map<PrivilegeKey, Privilege>

@Suppress("FunctionName")
fun MutablePrivilegeMap(): MutablePrivilegeMap = hashMapOf()

/**
 * Privileges object never returns a transient privilege.
 */
interface Privileges {
    val map: PrivilegeMap
    var privilegeOfStar: Privilege

    fun privilege(key: PrivilegeKey): Privilege
    fun privilege(player: OfflinePlayer) = privilege(player.privilegeKey)
    fun setPrivilege(key: PrivilegeKey, privilege: Privilege): Boolean
    fun setPrivilege(player: OfflinePlayer, privilege: Privilege) = setPrivilege(player.privilegeKey, privilege)
    fun changePrivilege(key: PrivilegeKey, expect: Privilege, update: Privilege): Boolean =
        privilege(key).isDistanceGrEq(expect) && setPrivilege(key, update)

    fun hasPrivilegeToManage(key: PrivilegeKey) = privilege(key) >= CAN_MANAGE
    fun allowManage(key: PrivilegeKey) = setPrivilege(key, CAN_MANAGE)
    fun disallowManage(key: PrivilegeKey) = changePrivilege(key, CAN_MANAGE, CAN_BUILD)

    fun hasPrivilegeToBuild(key: PrivilegeKey) = privilege(key) >= CAN_BUILD
    fun allowBuild(key: PrivilegeKey) = setPrivilege(key, CAN_BUILD)
    fun disallowBuild(key: PrivilegeKey) = changePrivilege(key, CAN_BUILD, DEFAULT)

    fun isBanned(key: PrivilegeKey) = privilege(key) == BANNED
    fun ban(key: PrivilegeKey) = setPrivilege(key, BANNED)
    fun unban(key: PrivilegeKey) = changePrivilege(key, BANNED, DEFAULT)

    /* OfflinePlayer overloads */

    fun hasPrivilegeToManage(player: OfflinePlayer) = hasPrivilegeToManage(player.privilegeKey)
    fun allowManage(player: OfflinePlayer) = allowManage(player.privilegeKey)
    fun disallowManage(player: OfflinePlayer) = disallowManage(player.privilegeKey)

    fun hasPrivilegeToBuild(player: OfflinePlayer) = hasPrivilegeToBuild(player.privilegeKey)
    fun allowBuild(player: OfflinePlayer) = allowBuild(player.privilegeKey)
    fun disallowBuild(player: OfflinePlayer) = disallowBuild(player.privilegeKey)

    fun isBanned(player: OfflinePlayer) = isBanned(player.privilegeKey)
    fun ban(player: OfflinePlayer) = ban(player.privilegeKey)
    fun unban(player: OfflinePlayer) = unban(player.privilegeKey)
}

val OfflinePlayer.privilegeKey: PrivilegeKey
    inline get() = PlayerProfile.nameless(this)

open class PrivilegesHolder(override var map: MutablePrivilegeMap = MutablePrivilegeMap()) : Privileges {
    override var privilegeOfStar: Privilege = DEFAULT
        set(value) = run { field = value.requireNonTransient() }

    override fun privilege(key: PrivilegeKey): Privilege = map.getOrDefault(key, privilegeOfStar)

    override fun setPrivilege(key: PrivilegeKey, privilege: Privilege): Boolean {
        privilege.requireNonTransient()

        if (key.isStar) {
            if (privilegeOfStar == privilege) return false
            privilegeOfStar = privilege
            return true
        }

        return if (privilege == DEFAULT) map.remove(key) != null
        else map.put(key, privilege) != privilege
    }
}

interface GlobalPrivileges : Privileges {
    val owner: PlayerProfile
}

interface GlobalPrivilegesManager {
    operator fun get(owner: PlayerProfile): GlobalPrivileges
    operator fun get(owner: OfflinePlayer): GlobalPrivileges = get(owner.privilegeKey)
}