bindables library for kotlin inspired by the osu!framework bindable system
Bindables are objects that hold a value and provide following listeners:
Bindable<T>
- value change
BindableList<T>
- value added to list
- value removed from list
- value set by index in list
- list updated
BindableMap<K, V>
- value set
- value removed
- map updated
repositories {
maven {
name = "devOS"
url = uri("https://mvn.devos.one/releases")
}
}
dependencies {
implementation("cz.lukynka:kotlin-bindables:2.0")
}
There are different types of bindables, each with their own events
val playerHealth = Bindable<Int>(5)
// Register a listener
playerHealth.valueChanged {
println("Player health changed from ${it.oldValue} to ${it.newValue}!")
}
// Set the value
playerHealth.value = 20
val x = Bindable<Int>(1)
val y = Bindable<Int>(2)
x.bindTo(y)
assertEquals(x.value, y.value) // bindTo() immediately sets x's value to y's
y.value = 10
assertEquals(10, x.value) // The value set to y above is propagated to x
x.value = 5
assertEquals(5, y.value) // Same as above - dual-way communication
You may also use:
val x = Bindable<Int>(1)
val y = x.getBoundCopy()
// or
val x = Bindable<Int>(1)
val y = Bindable<Int>(2).withBindTo(x)
Note that a Bindable cannot be bound to self or another bindable that is bound to the first bindable. Neither can you bind again when the bindable is already bound. You will need to call bindable.unbind()
first.
val playersOnline = BindableList<String>()
// called when item gets added
playersOnline.itemAdded {
println("Player ${it.item} has joined!")
}
// called when item gets removed
playersOnline.itemRemoved {
println("Player ${it.item} has left!")
}
// called when item at index is set
playersOnline.itemChanged {
println("object at index ${it.index} has been changed to ${it.item}!")
}
playersOnline.add("AsoDesu_")
playersOnline.add("LukynkaCZE")
playersOnline.remove("AsoDesu_")
playersOnline.setIndex(1, "KinichAjaw")
val uuidToPlayerName = BindableMap<UUID, String>()
// Is both called from BindableMap.set and BindableMap.add
uuidToPlayerName.itemSet {
println("Player with uuid ${it.key} (${it.value}) has joined!")
}
// called when item is removed
uuidToPlayerName.itemRemoved {
println("Player with uuid ${it.key} (${it.value}) has left!")
}
// called when the map is updated
uuidToPlayerName.mapUpdated {
println("The player list has been updated!")
}
uuidToPlayerName[UUID.fromString("aeb19a9c-a64a-4255-bb42-e74f05f9d30f")] = "AsoDesu_"
uuidToPlayerName[UUID.fromString("0c9151e4-7083-418d-a29c-bbc58f7c741b")] = "LukynkaCZE"
uuidToPlayerName.remove(UUID.fromString("aeb19a9c-a64a-4255-bb42-e74f05f9d30f"))
uuidToPlayerName.set(UUID.fromString("0c9151e4-7083-418d-a29c-bbc58f7c741b"), "KinichAjaw")
All event functions provide you back with a listener that you can then unregister at a later time:
val playerHealth = Bindable<Int>(5)
val playerHealthChangeListener = playerHealth.valueChanged {
println("Player health changed from ${it.oldValue} to ${it.newValue}!")
}
playerHealth.value = 20
// later in your program
playerHealth.unregister(playerHealthChangeListener)
You can also dispose a bindable using the dispose
method, this will remove all listeners from it and unbind it
val playerHealth = Bindable<Int>(5)
val playerHealthChangeListener = playerHealth.valueChanged {
println("Player health changed from ${it.oldValue} to ${it.newValue}!")
}
playerHealth.value = 20
//later in your program
playerHealth.dispose()
The Bindable dispatcher system is a local event-bus type system that sends notifications of a specified type (T).
val dispatcher = BindableDispatcher<Int>()
dispatcher.subscribe { int -> // subscribe
println("dispatcher notification: $int")
}
dispatcher.dispatch(69) // dispatch
Like any other bindable, you can call dispose
which will unsubscribe all subscribed listeners
In more complicated scenarios, you can create a BindablePool
class which will keep track of all your bindables:
val bindablePool = BindablePool()
val playerHealth = pool.provideBindable<Double>(20.0)
val playerFood = pool.provideBindable<Double>(20.0)
val playerStamina = pool.provideBindable<Double>(20.0)
val metadata: pool.provideBindableMap<EntityMetadataType, EntityMetadata>()
playerHealth.valueChanged {
player.sendPacket(UpdateHealthPacket(it.newValue))
}
playerFood.valueChanged {
player.sendPacket(UpdateFoodPacket(it.newValue))
}
playerStamina.valueChanged {
player.sendPacket(UpdateStaminaPacket(it.newValue))
}
metadata.mapUpdated {
sendMetadataPacketToViewers()
sendSelfMetadataIfPlayer()
}
// later in your program (when player leaves the server for example)
bindablePool.dispose() // remove all listeners registered
You can also manually unregister bindable from a pool:
bindablePool.unregister(playerStamina)
On all the types, you can also use .triggerUpdate()
to call the listeners without actually causing any update to the value(s)
Both BindableList
and BindableMap
have .addIfNotPresent(value)
and .removeIfPresent(value)
functions
All the bindable types provide .setSilently(value)
which will set the value of the bindable without calling any of the listeners