Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Utility Delegates #179

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions game/src/main/kotlin/gg/rsmod/game/model/attr/AttributeDelegate.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
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]
*
* @author Curtis Woodard <[email protected]>
*/
class AttributeDelegate<T>(val attributeKey: AttributeKey<T>, private val defaultValue: T) {
constructor(persistenceKey: String? = null, resetOnDeath: Boolean = false, defaultValue: T): this(
attributeKey = AttributeKey<T>(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 }
}
13 changes: 13 additions & 0 deletions game/src/main/kotlin/gg/rsmod/game/model/attr/AttributeKey.kt
Original file line number Diff line number Diff line change
@@ -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.
*
Expand All @@ -26,6 +30,15 @@ import com.google.common.base.MoreObjects
*/
class AttributeKey<T>(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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
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
*
* @author Curtis Woodard <[email protected]>
*/
abstract class VarbitDelegate<T>(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(varbitDef.varp, 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)
}
}
}
Original file line number Diff line number Diff line change
@@ -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<Boolean>(varbitId) {
override fun translateIn(inValue: Boolean): Int = if (inValue) 1 else 0
override fun translateOut(outValue: Int): Boolean = outValue != 0
}
Original file line number Diff line number Diff line change
@@ -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<Int>(varbitId) {
override fun translateIn(inValue: Int): Int = inValue
override fun translateOut(outValue: Int): Int = outValue
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
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
*
* @author Curtis Woodard <[email protected]>
*/
abstract class VarpDelegate<T>(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)
}
}
Original file line number Diff line number Diff line change
@@ -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<Int>(varpId) {
override fun translateIn(inValue: Int): Int = inValue
override fun translateOut(outValue: Int): Int = outValue
}