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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
|
package io.dico.parcels2
import io.dico.parcels2.math.Vec2i
import io.dico.parcels2.util.getPlayerName
import io.dico.parcels2.util.hasBuildAnywhere
import org.bukkit.Bukkit
import org.bukkit.entity.Player
import java.util.*
interface ParcelData {
var owner: ParcelOwner?
val added: Map<UUID, AddedStatus>
fun getAddedStatus(uuid: UUID): AddedStatus
fun setAddedStatus(uuid: UUID, status: AddedStatus): Boolean
fun isBanned(uuid: UUID): Boolean
fun isAllowed(uuid: UUID): Boolean
fun canBuild(player: Player): Boolean
var allowInteractInputs: Boolean
var allowInteractInventory: Boolean
fun isOwner(uuid: UUID): Boolean {
return owner?.uuid == uuid
}
val infoString: String
get() {
TODO()
}
}
/**
* Parcel implementation of ParcelData will update the database when changes are made.
* To change the data without updating the database, defer to the data delegate instance.
*
* This should be used for example in database query callbacks.
* However, this implementation is intentionally not thread-safe.
* Therefore, database query callbacks should schedule their updates using the bukkit scheduler.
*/
class Parcel(val world: ParcelWorld, val pos: Vec2i) : ParcelData {
val id get() = "${pos.x}:${pos.z}"
val homeLocation get() = world.generator.getHomeLocation(this)
var data: ParcelData = ParcelDataHolder(); private set
fun copyDataIgnoringDatabase(data: ParcelData) {
this.data = data
}
fun copyData(data: ParcelData) {
world.storage.setParcelData(this, data)
this.data = data
}
override val added: Map<UUID, AddedStatus> get() = data.added
override fun getAddedStatus(uuid: UUID) = data.getAddedStatus(uuid)
override fun isBanned(uuid: UUID) = data.isBanned(uuid)
override fun isAllowed(uuid: UUID) = data.isAllowed(uuid)
override fun canBuild(player: Player) = data.canBuild(player)
override var owner: ParcelOwner?
get() = data.owner
set(value) {
if (data.owner != value) {
world.storage.setParcelOwner(this, value)
data.owner = value
}
}
override fun setAddedStatus(uuid: UUID, status: AddedStatus): Boolean {
return data.setAddedStatus(uuid, status).also {
if (it) world.storage.setParcelPlayerState(this, uuid, status.asBoolean)
}
}
override var allowInteractInputs: Boolean
get() = data.allowInteractInputs
set(value) {
if (data.allowInteractInputs == value) return
world.storage.setParcelAllowsInteractInputs(this, value)
data.allowInteractInputs = value
}
override var allowInteractInventory: Boolean
get() = data.allowInteractInventory
set(value) {
if (data.allowInteractInventory == value) return
world.storage.setParcelAllowsInteractInventory(this, value)
data.allowInteractInventory = value
}
}
class ParcelDataHolder : ParcelData {
override var added = mutableMapOf<UUID, AddedStatus>()
override var owner: ParcelOwner? = null
override fun getAddedStatus(uuid: UUID): AddedStatus = added.getOrDefault(uuid, AddedStatus.DEFAULT)
override fun setAddedStatus(uuid: UUID, status: AddedStatus): Boolean = status.takeIf { it != AddedStatus.DEFAULT }
?.let { added.put(uuid, it) != it }
?: added.remove(uuid) != null
override fun isBanned(uuid: UUID) = getAddedStatus(uuid) == AddedStatus.BANNED
override fun isAllowed(uuid: UUID) = getAddedStatus(uuid) == AddedStatus.ALLOWED
override fun canBuild(player: Player) = isAllowed(player.uniqueId)
|| owner?.matches(player, allowNameMatch = false) ?: false
|| player.hasBuildAnywhere
override var allowInteractInputs = true
override var allowInteractInventory = true
}
enum class AddedStatus {
DEFAULT,
ALLOWED,
BANNED;
val asBoolean
get() = when (this) {
DEFAULT -> null
ALLOWED -> true
BANNED -> false
}
}
@Suppress("UsePropertyAccessSyntax")
class ParcelOwner(val uuid: UUID? = null,
name: String? = null) {
companion object {
fun create(uuid: UUID?, name: String?): ParcelOwner? {
return uuid?.let { ParcelOwner(uuid, name) }
?: name?.let { ParcelOwner(uuid, name) }
}
}
val name: String?
init {
uuid ?: name ?: throw IllegalArgumentException("uuid and/or name must be present")
if (name != null) this.name = name
else {
val offlinePlayer = Bukkit.getOfflinePlayer(uuid).takeIf { it.isOnline() || it.hasPlayedBefore() }
this.name = offlinePlayer?.name
}
}
val playerName get() = getPlayerName(uuid, name)
fun matches(player: Player, allowNameMatch: Boolean = false): Boolean {
return uuid?.let { it == player.uniqueId } ?: false
|| (allowNameMatch && name?.let { it == player.name } ?: false)
}
val onlinePlayer: Player? get() = uuid?.let { Bukkit.getPlayer(uuid) }
val onlinePlayerAllowingNameMatch: Player? get() = onlinePlayer ?: name?.let { Bukkit.getPlayer(name) }
@Suppress("DEPRECATION")
val offlinePlayer
get() = (uuid?.let { Bukkit.getOfflinePlayer(it) } ?: Bukkit.getOfflinePlayer(name))
?.takeIf { it.isOnline() || it.hasPlayedBefore() }
}
|