From 006b9992fa9022e84f7ed35e1df429aabe05e364 Mon Sep 17 00:00:00 2001 From: Curtis Woodard Date: Tue, 12 Nov 2019 19:43:44 -0700 Subject: [PATCH 1/9] Added `AttributeDelegate` to `game.model.attr` This allows you to delegate a `Pawn` extension property to an `AttributeKey` for easy get/set. This is meant to reduce or potentially remove the possibility of bugs related to repeating code. --- .../game/model/attr/AttributeDelegate.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 game/src/main/kotlin/gg/rsmod/game/model/attr/AttributeDelegate.kt diff --git a/game/src/main/kotlin/gg/rsmod/game/model/attr/AttributeDelegate.kt b/game/src/main/kotlin/gg/rsmod/game/model/attr/AttributeDelegate.kt new file mode 100644 index 0000000000..294cc08a97 --- /dev/null +++ b/game/src/main/kotlin/gg/rsmod/game/model/attr/AttributeDelegate.kt @@ -0,0 +1,22 @@ +package gg.rsmod.game.model.attr + +import gg.rsmod.game.model.entity.Pawn +import kotlin.reflect.KProperty + +/** + * A delegate class meant for delegating [Pawn] extension properties to. + * + * @property [attributeKey] The [AttributeKey] being delegated to + * + * @property [defaultValue] The default value when [getValue] is called but [Pawn.attr] fails to return a [T] + */ +class AttributeDelegate(val attributeKey: AttributeKey, private val defaultValue: T) { + constructor(persistenceKey: String? = null, resetOnDeath: Boolean = false, defaultValue: T): this( + attributeKey = AttributeKey(persistenceKey, resetOnDeath), + defaultValue = defaultValue + ) + + operator fun getValue(pawn: Pawn, prop: KProperty<*>): T = pawn.attr[attributeKey] ?: defaultValue + + operator fun setValue(pawn: Pawn, prop: KProperty<*>, newValue: T) { pawn.attr[attributeKey] = newValue } +} From c6f2425598d85aec1219c10a4f2f9e8f46b13a7f Mon Sep 17 00:00:00 2001 From: Curtis Woodard Date: Tue, 12 Nov 2019 19:45:33 -0700 Subject: [PATCH 2/9] You can now directly delegate to an `AttributeKey` This may be a problem if you worry about getting something that isn't a `T`, but you can set a default value (thus delegating to an `AttributeDelegate` instead) using the invoke operator `()`. Example: `val Pawn.isSmart by IS_SMART_ATTRIBUTE(defaultValue = true)` --- .../kotlin/gg/rsmod/game/model/attr/AttributeKey.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/game/src/main/kotlin/gg/rsmod/game/model/attr/AttributeKey.kt b/game/src/main/kotlin/gg/rsmod/game/model/attr/AttributeKey.kt index 6ebd4c1322..59b3497263 100644 --- a/game/src/main/kotlin/gg/rsmod/game/model/attr/AttributeKey.kt +++ b/game/src/main/kotlin/gg/rsmod/game/model/attr/AttributeKey.kt @@ -1,11 +1,15 @@ package gg.rsmod.game.model.attr import com.google.common.base.MoreObjects +import gg.rsmod.game.model.entity.Pawn +import kotlin.reflect.KProperty /** * An [AttributeKey] is a flexible key that can be used to represent any type of * value. * + * Can also be used as a delegate for a [Pawn] extension property + * * @param T * The type of the value that this attribute will store. * @@ -26,6 +30,15 @@ import com.google.common.base.MoreObjects */ class AttributeKey(val persistenceKey: String? = null, val resetOnDeath: Boolean = false) { + operator fun getValue(ref: Pawn, prop: KProperty<*>): T = ref.attr[this] as T + + operator fun setValue(ref: Pawn, prop: KProperty<*>, value: T) { ref.attr[this] = value } + + /** + * For when you want to delegate to this key but also want a default value just in case. + */ + operator fun invoke(defaultValue: T) = AttributeDelegate(this, defaultValue) + override fun toString(): String = MoreObjects.toStringHelper(this).add("persistenceKey", persistenceKey).add("resetOnDeath", resetOnDeath).toString() override fun equals(other: Any?): Boolean { From 304bc29d954a052be654623c07067eae5ada9641 Mon Sep 17 00:00:00 2001 From: Curtis Woodard Date: Tue, 12 Nov 2019 20:15:33 -0700 Subject: [PATCH 3/9] Added `VarpDelegate` to `game.model.varp.delegate` `VarpDelegate` allows you to delegate a `Player` extension property to this to allow for easy getting and setting as well as intermediate translating if needed --- .../game/model/varp/delegate/VarpDelegate.kt | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 game/src/main/kotlin/gg/rsmod/game/model/varp/delegate/VarpDelegate.kt diff --git a/game/src/main/kotlin/gg/rsmod/game/model/varp/delegate/VarpDelegate.kt b/game/src/main/kotlin/gg/rsmod/game/model/varp/delegate/VarpDelegate.kt new file mode 100644 index 0000000000..72a62c27fc --- /dev/null +++ b/game/src/main/kotlin/gg/rsmod/game/model/varp/delegate/VarpDelegate.kt @@ -0,0 +1,36 @@ +package gg.rsmod.game.model.varp.delegate + +import gg.rsmod.game.model.entity.Player +import kotlin.reflect.KProperty + +/** + * Allows you to delegate a [Player] extension property to have quick simple and easy access to a varp + * + * @property [varpId] The id of the varp you are writing to and reading from + */ +abstract class VarpDelegate(val varpId: Int) { + + /** + * Translates your input to [Int] to write to the varp + * + * @param [inValue] The value you are translating to [Int] + */ + abstract fun translateIn(inValue: T): Int + + /** + * Translates the varp [Int] to output type [T] + * + * @param [outValue] The value getting translated to [Int] + */ + abstract fun translateOut(outValue: Int): T + + operator fun getValue(player: Player, property: KProperty<*>): T = translateOut(getVarp(player, varpId)) + + operator fun setValue(player: Player, property: KProperty<*>, value: T) = setVarp(player, varpId, translateIn(value)) + + companion object { + fun getVarp(player: Player, varpId: Int): Int = player.varps.getState(varpId) + + fun setVarp(player: Player, varpId: Int, value: Int) = player.varps.setState(varpId, value) + } +} From ff491fe7d79d476b0d5b5f70315bbc5a3ba0efe3 Mon Sep 17 00:00:00 2001 From: Curtis Woodard Date: Tue, 12 Nov 2019 20:21:07 -0700 Subject: [PATCH 4/9] Added a sample `VarpDelegate` implementation `IntVarp` An example usage of `IntVarp`: `var Player.questPoints by IntVarp(101) // 101 is the varp for Quest Points` Now you can `Player.questPoints += 25` or `Player.questPoints = -200` --- .../gg/rsmod/game/model/varp/delegate/impl/IntVarp.kt | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 game/src/main/kotlin/gg/rsmod/game/model/varp/delegate/impl/IntVarp.kt diff --git a/game/src/main/kotlin/gg/rsmod/game/model/varp/delegate/impl/IntVarp.kt b/game/src/main/kotlin/gg/rsmod/game/model/varp/delegate/impl/IntVarp.kt new file mode 100644 index 0000000000..0bdad399c4 --- /dev/null +++ b/game/src/main/kotlin/gg/rsmod/game/model/varp/delegate/impl/IntVarp.kt @@ -0,0 +1,8 @@ +package gg.rsmod.game.model.varp.delegate.impl + +import gg.rsmod.game.model.varp.delegate.VarpDelegate + +class IntVarp(varpId: Int): VarpDelegate(varpId) { + override fun translateIn(inValue: Int): Int = inValue + override fun translateOut(outValue: Int): Int = outValue +} From 144588d004a96925c3f8dafc51ac7a5fe298f9a4 Mon Sep 17 00:00:00 2001 From: Curtis Woodard Date: Tue, 12 Nov 2019 20:50:26 -0700 Subject: [PATCH 5/9] Added `VarbitDelegate` to `game.model.varbit.delegate` `VarbitDelegate` allows you to easily get and set the value of a varbit and have intermediate translations if necessary --- .../model/varbit/delegate/VarbitDelegate.kt | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 game/src/main/kotlin/gg/rsmod/game/model/varbit/delegate/VarbitDelegate.kt diff --git a/game/src/main/kotlin/gg/rsmod/game/model/varbit/delegate/VarbitDelegate.kt b/game/src/main/kotlin/gg/rsmod/game/model/varbit/delegate/VarbitDelegate.kt new file mode 100644 index 0000000000..67b5002e5f --- /dev/null +++ b/game/src/main/kotlin/gg/rsmod/game/model/varbit/delegate/VarbitDelegate.kt @@ -0,0 +1,66 @@ +package gg.rsmod.game.model.varbit.delegate + +import gg.rsmod.game.fs.def.VarbitDef +import gg.rsmod.game.model.entity.Player +import kotlin.reflect.KProperty + +/** + * Allows you to delegate a [Player] extension property to have quick simple and easy access to a varbit + * + * @property [varbitId] The id of the varbit you are writing to and reading from + */ +abstract class VarbitDelegate(val varbitId: Int) { + + private var _varbitDef: VarbitDef? = null + + /** @property [varbitDef] The [VarbitDef] used in [getVarbit] and [setVarbit] */ + val varbitDef: VarbitDef + get() = _varbitDef ?: throw Exception("Varbit Def $varbitId not found") + + /** + * Translates your input to [Int] to write to the varbit + * + * @param [inValue] The value you are translating to [Int] + * + * @return [Int] + */ + abstract fun translateIn(inValue: T): Int + + /** + * Translates the varbit [Int] to the output type [T] + * + * @param [outValue] The value you are translating to [T] + * + * @return [T] + */ + abstract fun translateOut(outValue: Int): T + + operator fun getValue(player: Player, property: KProperty<*>): T { + ensureVarbitDef(player) + return translateOut(getVarbit(player)) + } + + operator fun setValue(player: Player, property: KProperty<*>, value: T) { + ensureVarbitDef(player) + setVarbit(player, translateIn(value)) + } + + private fun getVarbit(player: Player): Int { + ensureVarbitDef(player) + return player.varps.getBit(varbitId, varbitDef.startBit, varbitDef.endBit) + } + + private fun setVarbit(player: Player, value: Int) { + ensureVarbitDef(player) + player.varps.setBit(varbitDef.varp, varbitDef.startBit, varbitDef.endBit, value) + } + + /** + * Ensures that [varbitDef] is set + */ + private fun ensureVarbitDef(player: Player) { + if (_varbitDef == null) { + _varbitDef = player.world.definitions.get(VarbitDef::class.java, varbitId) + } + } +} From 48dc43bd8092e46c2e6c9a0367f8bf1a4244c273 Mon Sep 17 00:00:00 2001 From: Curtis Woodard Date: Tue, 12 Nov 2019 20:52:45 -0700 Subject: [PATCH 6/9] Added `IntVarbit` a sample implementation of `VarbitDelegate` Example usage: `val Player.slayerPoints by IntVarbit(4068) // 4068 is the varbit id for slayer points` --- .../gg/rsmod/game/model/varbit/delegate/impl/IntVarbit.kt | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 game/src/main/kotlin/gg/rsmod/game/model/varbit/delegate/impl/IntVarbit.kt diff --git a/game/src/main/kotlin/gg/rsmod/game/model/varbit/delegate/impl/IntVarbit.kt b/game/src/main/kotlin/gg/rsmod/game/model/varbit/delegate/impl/IntVarbit.kt new file mode 100644 index 0000000000..109b19ae07 --- /dev/null +++ b/game/src/main/kotlin/gg/rsmod/game/model/varbit/delegate/impl/IntVarbit.kt @@ -0,0 +1,8 @@ +package gg.rsmod.game.model.varbit.delegate.impl + +import gg.rsmod.game.model.varbit.delegate.VarbitDelegate + +class IntVarbit(varbitId: Int): VarbitDelegate(varbitId) { + override fun translateIn(inValue: Int): Int = inValue + override fun translateOut(outValue: Int): Int = outValue +} From cbeae60835e64964ebe0ac1fdb878cc7960b2ad2 Mon Sep 17 00:00:00 2001 From: Curtis Woodard Date: Tue, 12 Nov 2019 20:53:45 -0700 Subject: [PATCH 7/9] Added `BoolVarbit` a sample implementation of `VarbitDelegate` Example usage: `val Player.gargoyleSlayer by BoolVarbit(4027) // 4027 is the varbit id for Gargoyle Slayer unlock` --- .../rsmod/game/model/varbit/delegate/impl/BoolVarbit.kt | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 game/src/main/kotlin/gg/rsmod/game/model/varbit/delegate/impl/BoolVarbit.kt diff --git a/game/src/main/kotlin/gg/rsmod/game/model/varbit/delegate/impl/BoolVarbit.kt b/game/src/main/kotlin/gg/rsmod/game/model/varbit/delegate/impl/BoolVarbit.kt new file mode 100644 index 0000000000..6d705d8255 --- /dev/null +++ b/game/src/main/kotlin/gg/rsmod/game/model/varbit/delegate/impl/BoolVarbit.kt @@ -0,0 +1,8 @@ +package gg.rsmod.game.model.varbit.delegate.impl + +import gg.rsmod.game.model.varbit.delegate.VarbitDelegate + +class BoolVarbit(varbitId: Int): VarbitDelegate(varbitId) { + override fun translateIn(inValue: Boolean): Int = if (inValue) 1 else 0 + override fun translateOut(outValue: Int): Boolean = outValue != 0 +} From 4de6b21ff37dbfec6c07468988e771909dbc56b3 Mon Sep 17 00:00:00 2001 From: Curtis Woodard Date: Tue, 12 Nov 2019 22:48:27 -0700 Subject: [PATCH 8/9] Fixed not being able to get the value of the varp. Small oversight and mis-type --- .../gg/rsmod/game/model/varbit/delegate/VarbitDelegate.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/game/src/main/kotlin/gg/rsmod/game/model/varbit/delegate/VarbitDelegate.kt b/game/src/main/kotlin/gg/rsmod/game/model/varbit/delegate/VarbitDelegate.kt index 67b5002e5f..ecd2fa9533 100644 --- a/game/src/main/kotlin/gg/rsmod/game/model/varbit/delegate/VarbitDelegate.kt +++ b/game/src/main/kotlin/gg/rsmod/game/model/varbit/delegate/VarbitDelegate.kt @@ -47,7 +47,7 @@ abstract class VarbitDelegate(val varbitId: Int) { private fun getVarbit(player: Player): Int { ensureVarbitDef(player) - return player.varps.getBit(varbitId, varbitDef.startBit, varbitDef.endBit) + return player.varps.getBit(varbitDef.varp, varbitDef.startBit, varbitDef.endBit) } private fun setVarbit(player: Player, value: Int) { From 521fd509d3bb71ac59cb277e99cbf673e2982245 Mon Sep 17 00:00:00 2001 From: Curtis Woodard Date: Tue, 12 Nov 2019 23:49:10 -0700 Subject: [PATCH 9/9] Author attribution in documentation --- .../main/kotlin/gg/rsmod/game/model/attr/AttributeDelegate.kt | 2 ++ .../gg/rsmod/game/model/varbit/delegate/VarbitDelegate.kt | 2 ++ .../kotlin/gg/rsmod/game/model/varp/delegate/VarpDelegate.kt | 2 ++ 3 files changed, 6 insertions(+) diff --git a/game/src/main/kotlin/gg/rsmod/game/model/attr/AttributeDelegate.kt b/game/src/main/kotlin/gg/rsmod/game/model/attr/AttributeDelegate.kt index 294cc08a97..9c9e20e7be 100644 --- a/game/src/main/kotlin/gg/rsmod/game/model/attr/AttributeDelegate.kt +++ b/game/src/main/kotlin/gg/rsmod/game/model/attr/AttributeDelegate.kt @@ -9,6 +9,8 @@ import kotlin.reflect.KProperty * @property [attributeKey] The [AttributeKey] being delegated to * * @property [defaultValue] The default value when [getValue] is called but [Pawn.attr] fails to return a [T] + * + * @author Curtis Woodard */ class AttributeDelegate(val attributeKey: AttributeKey, private val defaultValue: T) { constructor(persistenceKey: String? = null, resetOnDeath: Boolean = false, defaultValue: T): this( diff --git a/game/src/main/kotlin/gg/rsmod/game/model/varbit/delegate/VarbitDelegate.kt b/game/src/main/kotlin/gg/rsmod/game/model/varbit/delegate/VarbitDelegate.kt index ecd2fa9533..a9e00826a4 100644 --- a/game/src/main/kotlin/gg/rsmod/game/model/varbit/delegate/VarbitDelegate.kt +++ b/game/src/main/kotlin/gg/rsmod/game/model/varbit/delegate/VarbitDelegate.kt @@ -8,6 +8,8 @@ import kotlin.reflect.KProperty * Allows you to delegate a [Player] extension property to have quick simple and easy access to a varbit * * @property [varbitId] The id of the varbit you are writing to and reading from + * + * @author Curtis Woodard */ abstract class VarbitDelegate(val varbitId: Int) { diff --git a/game/src/main/kotlin/gg/rsmod/game/model/varp/delegate/VarpDelegate.kt b/game/src/main/kotlin/gg/rsmod/game/model/varp/delegate/VarpDelegate.kt index 72a62c27fc..5641c773e5 100644 --- a/game/src/main/kotlin/gg/rsmod/game/model/varp/delegate/VarpDelegate.kt +++ b/game/src/main/kotlin/gg/rsmod/game/model/varp/delegate/VarpDelegate.kt @@ -7,6 +7,8 @@ import kotlin.reflect.KProperty * Allows you to delegate a [Player] extension property to have quick simple and easy access to a varp * * @property [varpId] The id of the varp you are writing to and reading from + * + * @author Curtis Woodard */ abstract class VarpDelegate(val varpId: Int) {