From 48a156cd9a4d16d2cd439babfd534dd277c6a043 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 18 Mar 2023 07:49:58 +0700 Subject: [PATCH] Reimplement variable length int field synchronizers, mark Supplier interface as deprecated --- .../mc/otm/network/FieldSynchronizer.kt | 363 +++++++++++------- 1 file changed, 217 insertions(+), 146 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/FieldSynchronizer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/FieldSynchronizer.kt index f161c5fe4..4fee277fc 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/FieldSynchronizer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/FieldSynchronizer.kt @@ -23,7 +23,9 @@ import ru.dbotthepony.mc.otm.core.util.ItemStackValueCodec import ru.dbotthepony.mc.otm.core.util.ShortValueCodec import ru.dbotthepony.mc.otm.core.util.UUIDValueCodec import ru.dbotthepony.mc.otm.core.util.readVarIntLE +import ru.dbotthepony.mc.otm.core.util.readVarLongLE import ru.dbotthepony.mc.otm.core.util.writeVarIntLE +import ru.dbotthepony.mc.otm.core.util.writeVarLongLE import ru.dbotthepony.mc.otm.secondTime import java.io.DataInputStream import java.io.DataOutputStream @@ -218,6 +220,11 @@ sealed interface IFloatField : IField, FloatSupplier { override val value: Float get() = float + @Deprecated("Use type specific Supplier interface") + override fun get(): Float { + return float + } + override fun getAsFloat(): Float { return float } @@ -236,6 +243,11 @@ sealed interface IDoubleField : IField, DoubleSupplier { val double: Double val property: IDoubleProperty + @Deprecated("Use type specific Supplier interface") + override fun get(): Double { + return double + } + override val value: Double get() = double @@ -257,6 +269,11 @@ sealed interface IIntField : IField, IntSupplier { val int: Int val property: IIntProperty + @Deprecated("Use type specific Supplier interface") + override fun get(): Int { + return int + } + override val value: Int get() = int @@ -278,6 +295,11 @@ sealed interface ILongField : IField, LongSupplier { val long: Long val property: ILongProperty + @Deprecated("Use type specific Supplier interface") + override fun get(): Long { + return long + } + override val value: Long get() = long @@ -299,6 +321,11 @@ sealed interface IBooleanField : IField, BooleanSupplier { val boolean: Boolean val property: IBooleanProperty + @Deprecated("Use type specific Supplier interface") + override fun get(): Boolean { + return boolean + } + override val value: Boolean get() = boolean @@ -332,9 +359,9 @@ interface IMutableFloatProperty : IFloatProperty { operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Float) } -sealed interface IMutableFloatField : IMutableField, FloatConsumer { - var float: Float - val property: IMutableFloatProperty +sealed interface IMutableFloatField : IMutableField, IFloatField, FloatConsumer { + override var float: Float + override val property: IMutableFloatProperty @Deprecated("Use type specific property", replaceWith = ReplaceWith("this.float")) override var value: Float @@ -360,9 +387,9 @@ interface IMutableDoubleProperty : IDoubleProperty { operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Double) } -sealed interface IMutableDoubleField : IMutableField, DoubleConsumer { - var double: Double - val property: IMutableDoubleProperty +sealed interface IMutableDoubleField : IMutableField, IDoubleField, DoubleConsumer { + override var double: Double + override val property: IMutableDoubleProperty @Deprecated("Use type specific property", replaceWith = ReplaceWith("this.double")) override var value: Double @@ -388,9 +415,9 @@ interface IMutableIntProperty : IIntProperty { operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) } -sealed interface IMutableIntField : IMutableField, IntConsumer { - var int: Int - val property: IMutableIntProperty +sealed interface IMutableIntField : IMutableField, IIntField, IntConsumer { + override var int: Int + override val property: IMutableIntProperty @Deprecated("Use type specific property", replaceWith = ReplaceWith("this.int")) override var value: Int @@ -416,9 +443,9 @@ interface IMutableLongProperty : ILongProperty { operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Long) } -sealed interface IMutableLongField : IMutableField, LongConsumer { - var long: Long - val property: IMutableLongProperty +sealed interface IMutableLongField : IMutableField, ILongField, LongConsumer { + override var long: Long + override val property: IMutableLongProperty @Deprecated("Use type specific property", replaceWith = ReplaceWith("this.long")) override var value: Long @@ -444,9 +471,9 @@ interface IMutableBooleanProperty : IBooleanProperty { operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Boolean) } -sealed interface IMutableBooleanField : IMutableField, BooleanConsumer { - var boolean: Boolean - val property: IMutableBooleanProperty +sealed interface IMutableBooleanField : IMutableField, IBooleanField, BooleanConsumer { + override var boolean: Boolean + override val property: IMutableBooleanProperty @Deprecated("Use type specific property", replaceWith = ReplaceWith("this.boolean")) override var value: Boolean @@ -541,12 +568,12 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa fun bool(getter: BooleanSupplier) = ComputedBooleanField(getter) fun short(getter: () -> Short) = ComputedField(getter, ShortValueCodec) fun long(getter: LongSupplier) = ComputedLongField(getter) - fun fixedLong(getter: LongSupplier) = ComputedLongField(getter) + fun fixedLong(getter: LongSupplier) = ComputedFixedLongField(getter) fun float(getter: FloatSupplier) = ComputedFloatField(getter) fun double(getter: DoubleSupplier) = ComputedDoubleField(getter) fun uuid(getter: () -> UUID) = ComputedField(getter, UUIDValueCodec) fun int(getter: IntSupplier) = ComputedIntField(getter) - fun fixedInt(getter: IntSupplier) = ComputedIntField(getter) + fun fixedInt(getter: IntSupplier) = ComputedFixedIntField(getter) fun fraction(getter: () -> Decimal) = ComputedField(getter, DecimalValueCodec) fun bigDecimal(getter: () -> BigDecimal) = ComputedField(getter, BigDecimalValueCodec) fun item(getter: () -> ItemStack) = ComputedField(getter, ItemStackValueCodec) @@ -556,12 +583,12 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa fun bool(getter: KProperty0) = ComputedBooleanField(getter::get) fun short(getter: KProperty0) = ComputedField(getter, ShortValueCodec) fun long(getter: KProperty0) = ComputedLongField(getter::get) - fun fixedLong(getter: KProperty0) = ComputedLongField(getter::get) + fun fixedLong(getter: KProperty0) = ComputedFixedLongField(getter::get) fun float(getter: KProperty0) = ComputedFloatField(getter::get) fun double(getter: KProperty0) = ComputedDoubleField(getter::get) fun uuid(getter: KProperty0) = ComputedField(getter, UUIDValueCodec) fun int(getter: KProperty0) = ComputedIntField(getter::get) - fun fixedInt(getter: KProperty0) = ComputedIntField(getter::get) + fun fixedInt(getter: KProperty0) = ComputedFixedIntField(getter::get) fun fraction(getter: KProperty0) = ComputedField(getter, DecimalValueCodec) fun bigDecimal(getter: KProperty0) = ComputedField(getter, BigDecimalValueCodec) fun item(getter: KProperty0) = ComputedField(getter, ItemStackValueCodec) @@ -571,12 +598,12 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa fun bool(getter: Supplier) = ComputedBooleanField(getter::get) fun short(getter: Supplier) = ComputedField(getter::get, ShortValueCodec) fun long(getter: Supplier) = ComputedLongField(getter::get) - fun fixedLong(getter: Supplier) = ComputedLongField(getter::get) + fun fixedLong(getter: Supplier) = ComputedFixedLongField(getter::get) fun float(getter: Supplier) = ComputedFloatField(getter::get) fun double(getter: Supplier) = ComputedDoubleField(getter::get) fun uuid(getter: Supplier) = ComputedField(getter::get, UUIDValueCodec) fun int(getter: Supplier) = ComputedIntField(getter::get) - fun fixedInt(getter: Supplier) = ComputedIntField(getter::get) + fun fixedInt(getter: Supplier) = ComputedFixedIntField(getter::get) fun fraction(getter: Supplier) = ComputedField(getter::get, DecimalValueCodec) fun bigDecimal(getter: Supplier) = ComputedField(getter::get, BigDecimalValueCodec) fun item(getter: Supplier) = ComputedField(getter::get, ItemStackValueCodec) @@ -632,8 +659,8 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa value: Long = 0L, getter: LongFieldGetter? = null, setter: LongFieldSetter? = null, - ): LongField { - return LongField(value, getter, setter) + ): FixedLongField { + return FixedLongField(value, getter, setter) } @JvmOverloads @@ -686,8 +713,8 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa value: Int = 0, getter: IntFieldGetter? = null, setter: IntFieldSetter? = null, - ): IntField { - return IntField(value, getter, setter) + ): FixedIntField { + return FixedIntField(value, getter, setter) } @JvmOverloads @@ -1046,12 +1073,25 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa } } + abstract inner class PrimitiveField() : AbstractField() { + protected var isDirty = false + + override fun observe(): Boolean { + check(!isRemoved) { "Field was removed" } + return isDirty + } + + override fun markDirty() { + check(!isRemoved) { "Field was removed" } + notifyEndpoints(this) + isDirty = true + } + } + /** * Type specific field, storing primitive [Float] directly */ - inner class FloatField(private var field: Float, private val getter: FloatFieldGetter? = null, private val setter: FloatFieldSetter? = null) : AbstractField(), IMutableFloatField { - private var isDirty = false - + inner class FloatField(private var field: Float, private val getter: FloatFieldGetter? = null, private val setter: FloatFieldSetter? = null) : PrimitiveField(), IMutableFloatField { override val property = object : IMutableFloatProperty { override fun getValue(thisRef: Any?, property: KProperty<*>): Float { return this@FloatField.float @@ -1077,11 +1117,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa } } - override fun observe(): Boolean { - check(!isRemoved) { "Field was removed" } - return isDirty - } - override var float: Float get() { return getter?.invoke(access) ?: this.field @@ -1091,10 +1126,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa if (setter != null) { setter.invoke(value, access, false) - return - } - - if (value != this.field) { + } else if (value != this.field) { if (!isDirty) { notifyEndpoints(this) isDirty = true @@ -1104,12 +1136,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa } } - override fun markDirty() { - check(!isRemoved) { "Field was removed" } - notifyEndpoints(this) - isDirty = true - } - override fun write(stream: DataOutputStream, endpoint: Endpoint) { check(!isRemoved) { "Field was removed" } stream.writeFloat(this.field) @@ -1132,9 +1158,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa /** * Type specific field, storing primitive [Double] directly */ - inner class DoubleField(private var field: Double, private val getter: DoubleFieldGetter? = null, private val setter: DoubleFieldSetter? = null) : AbstractField(), IMutableDoubleField { - private var isDirty = false - + inner class DoubleField(private var field: Double, private val getter: DoubleFieldGetter? = null, private val setter: DoubleFieldSetter? = null) : PrimitiveField(), IMutableDoubleField { override val property = object : IMutableDoubleProperty { override fun getValue(thisRef: Any?, property: KProperty<*>): Double { return this@DoubleField.double @@ -1160,11 +1184,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa } } - override fun observe(): Boolean { - check(!isRemoved) { "Field was removed" } - return isDirty - } - override var double: Double get() { return getter?.invoke(access) ?: this.field @@ -1174,10 +1193,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa if (setter != null) { setter.invoke(value, access, false) - return - } - - if (value != this.field) { + } else if (value != this.field) { if (!isDirty) { notifyEndpoints(this) isDirty = true @@ -1187,12 +1203,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa } } - override fun markDirty() { - check(!isRemoved) { "Field was removed" } - notifyEndpoints(this) - isDirty = true - } - override fun write(stream: DataOutputStream, endpoint: Endpoint) { check(!isRemoved) { "Field was removed" } stream.writeDouble(this.field) @@ -1212,43 +1222,33 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa } } - /** - * Type specific field, storing primitive [Int] directly - */ - inner class IntField(private var field: Int, private val getter: IntFieldGetter? = null, private val setter: IntFieldSetter? = null) : AbstractField(), IMutableIntField { - private var isDirty = false - - override val property = object : IMutableIntProperty { + abstract inner class AbstractIntField(protected var field: Int, private val getter: IntFieldGetter? = null, protected val setter: IntFieldSetter? = null) : PrimitiveField(), IMutableIntField { + final override val property = object : IMutableIntProperty { override fun getValue(thisRef: Any?, property: KProperty<*>): Int { - return this@IntField.int + return this@AbstractIntField.int } override fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) { - this@IntField.int = value + this@AbstractIntField.int = value } } - private val access = object : IntFieldAccess { + protected val access = object : IntFieldAccess { override fun readInt(): Int { - return this@IntField.field + return this@AbstractIntField.field } override fun write(value: Int) { - if (!isDirty && value != this@IntField.field) { - notifyEndpoints(this@IntField) + if (!isDirty && value != this@AbstractIntField.field) { + notifyEndpoints(this@AbstractIntField) isDirty = true } - this@IntField.field = value + this@AbstractIntField.field = value } } - override fun observe(): Boolean { - check(!isRemoved) { "Field was removed" } - return isDirty - } - - override var int: Int + final override var int: Int get() { return getter?.invoke(access) ?: this.field } @@ -1257,10 +1257,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa if (setter != null) { setter.invoke(value, access, false) - return - } - - if (value != this.field) { + } else if (value != this.field) { if (!isDirty) { notifyEndpoints(this) isDirty = true @@ -1269,13 +1266,35 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa this.field = value } } + } - override fun markDirty() { + /** + * Type specific field, storing primitive [Int] directly, and networking it as variable length integer + */ + inner class IntField(field: Int, getter: IntFieldGetter? = null, setter: IntFieldSetter? = null) : AbstractIntField(field, getter, setter) { + override fun write(stream: DataOutputStream, endpoint: Endpoint) { check(!isRemoved) { "Field was removed" } - notifyEndpoints(this) - isDirty = true + stream.writeVarIntLE(this.field) + isDirty = false } + override fun read(stream: DataInputStream) { + check(!isRemoved) { "Field was removed" } + val value = stream.readVarIntLE() + val setter = this.setter + + if (setter != null) { + setter.invoke(value, access, true) + } else { + this.field = value + } + } + } + + /** + * Type specific field, storing primitive [Int] directly, and networking it as 4 octets + */ + inner class FixedIntField(field: Int, getter: IntFieldGetter? = null, setter: IntFieldSetter? = null) : AbstractIntField(field, getter, setter) { override fun write(stream: DataOutputStream, endpoint: Endpoint) { check(!isRemoved) { "Field was removed" } stream.writeInt(this.field) @@ -1298,40 +1317,33 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa /** * Type specific field, storing primitive [Long] directly */ - inner class LongField(private var field: Long, private val getter: LongFieldGetter? = null, private val setter: LongFieldSetter? = null) : AbstractField(), IMutableLongField { - private var isDirty = false - - override val property = object : IMutableLongProperty { + abstract inner class AbstractLongField(protected var field: Long, private val getter: LongFieldGetter? = null, protected val setter: LongFieldSetter? = null) : PrimitiveField(), IMutableLongField { + final override val property = object : IMutableLongProperty { override fun getValue(thisRef: Any?, property: KProperty<*>): Long { - return this@LongField.long + return this@AbstractLongField.long } override fun setValue(thisRef: Any?, property: KProperty<*>, value: Long) { - this@LongField.long = value + this@AbstractLongField.long = value } } - private val access = object : LongFieldAccess { + protected val access = object : LongFieldAccess { override fun readLong(): Long { - return this@LongField.field + return this@AbstractLongField.field } override fun write(value: Long) { - if (!isDirty && value != this@LongField.field) { - notifyEndpoints(this@LongField) + if (!isDirty && value != this@AbstractLongField.field) { + notifyEndpoints(this@AbstractLongField) isDirty = true } - this@LongField.field = value + this@AbstractLongField.field = value } } - override fun observe(): Boolean { - check(!isRemoved) { "Field was removed" } - return isDirty - } - - override var long: Long + final override var long: Long get() { return getter?.invoke(access) ?: this.field } @@ -1340,10 +1352,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa if (setter != null) { setter.invoke(value, access, false) - return - } - - if (value != this.field) { + } else if (value != this.field) { if (!isDirty) { notifyEndpoints(this) isDirty = true @@ -1352,13 +1361,35 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa this.field = value } } + } - override fun markDirty() { + /** + * Type specific field, storing primitive [Long] directly, and networking it as variable length integer + */ + inner class LongField(field: Long, getter: LongFieldGetter? = null, setter: LongFieldSetter? = null) : AbstractLongField(field, getter, setter) { + override fun write(stream: DataOutputStream, endpoint: Endpoint) { check(!isRemoved) { "Field was removed" } - notifyEndpoints(this) - isDirty = true + stream.writeVarLongLE(this.field) + isDirty = false } + override fun read(stream: DataInputStream) { + check(!isRemoved) { "Field was removed" } + val value = stream.readVarLongLE() + val setter = this.setter + + if (setter != null) { + setter.invoke(value, access, true) + } else { + this.field = value + } + } + } + + /** + * Type specific field, storing primitive [Long] directly, and networking it as 8 octets + */ + inner class FixedLongField(field: Long, getter: LongFieldGetter? = null, setter: LongFieldSetter? = null) : AbstractLongField(field, getter, setter) { override fun write(stream: DataOutputStream, endpoint: Endpoint) { check(!isRemoved) { "Field was removed" } stream.writeLong(this.field) @@ -1381,9 +1412,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa /** * Type specific field, storing primitive [Boolean] directly */ - inner class BooleanField(private var field: Boolean, private val getter: BooleanFieldGetter? = null, private val setter: BooleanFieldSetter? = null) : AbstractField(), IMutableBooleanField { - private var isDirty = false - + inner class BooleanField(private var field: Boolean, private val getter: BooleanFieldGetter? = null, private val setter: BooleanFieldSetter? = null) : PrimitiveField(), IMutableBooleanField { override val property = object : IMutableBooleanProperty { override fun getValue(thisRef: Any?, property: KProperty<*>): Boolean { return this@BooleanField.boolean @@ -1409,11 +1438,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa } } - override fun observe(): Boolean { - check(!isRemoved) { "Field was removed" } - return isDirty - } - override var boolean: Boolean get() { return getter?.invoke(access) ?: this.field @@ -1423,10 +1447,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa if (setter != null) { setter.invoke(value, access, false) - return - } - - if (value != this.field) { + } else if (value != this.field) { if (!isDirty) { notifyEndpoints(this) isDirty = true @@ -1436,12 +1457,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa } } - override fun markDirty() { - check(!isRemoved) { "Field was removed" } - notifyEndpoints(this) - isDirty = true - } - override fun write(stream: DataOutputStream, endpoint: Endpoint) { check(!isRemoved) { "Field was removed" } stream.writeBoolean(this.field) @@ -1653,14 +1668,14 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa * * This class has concrete implementation for [Int] primitive */ - inner class ComputedIntField(private val getter: IntSupplier, private val observer: IntConsumer = IntConsumer {}) : AbstractField(), IIntField { + abstract inner class AbstractComputedIntField(protected val getter: IntSupplier, protected val observer: IntConsumer = IntConsumer {}) : AbstractField(), IIntField { private var remote: Int = 0 private var isRemoteSet = false - private var clientValue: Int = 0 - private var isClientValue = false - private var isDirty = false + protected var clientValue: Int = 0 + protected var isClientValue = false + protected var isDirty = false - override val property = object : IIntProperty { + final override val property = object : IIntProperty { override fun getValue(thisRef: Any?, property: KProperty<*>): Int { return int } @@ -1670,7 +1685,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa observers.add(this) } - override fun observe(): Boolean { + final override fun observe(): Boolean { check(!isRemoved) { "Field was removed" } val value = getter.asInt @@ -1685,13 +1700,13 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa return isDirty } - override fun markDirty() { + final override fun markDirty() { check(!isRemoved) { "Field was removed" } notifyEndpoints(this) isDirty = true } - override val int: Int + final override val int: Int get() { if (isClientValue) { return clientValue @@ -1699,7 +1714,35 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa return getter.asInt } } + } + /** + * Networked value with backing getter which is constantly polled + * + * This class has concrete implementation for [Int] primitive, networking it as variable length integer + */ + inner class ComputedIntField(getter: IntSupplier, observer: IntConsumer = IntConsumer {}) : AbstractComputedIntField(getter, observer) { + override fun write(stream: DataOutputStream, endpoint: Endpoint) { + check(!isRemoved) { "Field was removed" } + stream.writeVarIntLE(getter.asInt) + isDirty = false + } + + override fun read(stream: DataInputStream) { + check(!isRemoved) { "Field was removed" } + val newValue = stream.readVarIntLE() + clientValue = newValue + isClientValue = true + observer.accept(newValue) + } + } + + /** + * Networked value with backing getter which is constantly polled + * + * This class has concrete implementation for [Int] primitive, networking it as 4 octets + */ + inner class ComputedFixedIntField(getter: IntSupplier, observer: IntConsumer = IntConsumer {}) : AbstractComputedIntField(getter, observer) { override fun write(stream: DataOutputStream, endpoint: Endpoint) { check(!isRemoved) { "Field was removed" } stream.writeInt(getter.asInt) @@ -1720,14 +1763,14 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa * * This class has concrete implementation for [Long] primitive */ - inner class ComputedLongField(private val getter: LongSupplier, private val observer: LongConsumer = LongConsumer {}) : AbstractField(), ILongField { + abstract inner class AbstractComputedLongField(protected val getter: LongSupplier, protected val observer: LongConsumer = LongConsumer {}) : AbstractField(), ILongField { private var remote: Long = 0L private var isRemoteSet = false - private var clientValue: Long = 0L - private var isClientValue = false - private var isDirty = false + protected var clientValue: Long = 0L + protected var isClientValue = false + protected var isDirty = false - override val property = object : ILongProperty { + final override val property = object : ILongProperty { override fun getValue(thisRef: Any?, property: KProperty<*>): Long { return long } @@ -1737,7 +1780,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa observers.add(this) } - override fun observe(): Boolean { + final override fun observe(): Boolean { check(!isRemoved) { "Field was removed" } val value = getter.asLong @@ -1752,13 +1795,13 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa return isDirty } - override fun markDirty() { + final override fun markDirty() { check(!isRemoved) { "Field was removed" } notifyEndpoints(this) isDirty = true } - override val long: Long + final override val long: Long get() { if (isClientValue) { return clientValue @@ -1766,7 +1809,35 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa return getter.asLong } } + } + /** + * Networked value with backing getter which is constantly polled + * + * This class has concrete implementation for [Long] primitive, networking it as variable length integer + */ + inner class ComputedLongField(getter: LongSupplier, observer: LongConsumer = LongConsumer {}) : AbstractComputedLongField(getter, observer) { + override fun write(stream: DataOutputStream, endpoint: Endpoint) { + check(!isRemoved) { "Field was removed" } + stream.writeVarLongLE(getter.asLong) + isDirty = false + } + + override fun read(stream: DataInputStream) { + check(!isRemoved) { "Field was removed" } + val newValue = stream.readVarLongLE() + clientValue = newValue + isClientValue = true + observer.accept(newValue) + } + } + + /** + * Networked value with backing getter which is constantly polled + * + * This class has concrete implementation for [Long] primitive, networking it as 8 octets + */ + inner class ComputedFixedLongField(getter: LongSupplier, observer: LongConsumer = LongConsumer {}) : AbstractComputedLongField(getter, observer) { override fun write(stream: DataOutputStream, endpoint: Endpoint) { check(!isRemoved) { "Field was removed" } stream.writeLong(getter.asLong)