Remove named fields from field synchronizer

This commit is contained in:
DBotThePony 2023-03-06 15:10:11 +07:00
parent 3e4d6dcc11
commit f75880d5ed
Signed by: DBot
GPG Key ID: DCC23B5715498507
11 changed files with 112 additions and 249 deletions

View File

@ -62,11 +62,8 @@ class RedstoneControl(private val valueChanges: (new: Boolean, old: Boolean) ->
class SynchronizedRedstoneControl( class SynchronizedRedstoneControl(
synchronizer: FieldSynchronizer, synchronizer: FieldSynchronizer,
fieldNamePrefix: String?,
private val valueChanges: (new: Boolean, old: Boolean) -> Unit, private val valueChanges: (new: Boolean, old: Boolean) -> Unit,
) : AbstractRedstoneControl() { ) : AbstractRedstoneControl() {
constructor(synchronizer: FieldSynchronizer, valueChanges: (new: Boolean, old: Boolean) -> Unit) : this(synchronizer, "", valueChanges)
override var redstoneSetting: RedstoneSetting by synchronizer.enum(RedstoneSetting.LOW, setter = { value, access, setByRemote -> override var redstoneSetting: RedstoneSetting by synchronizer.enum(RedstoneSetting.LOW, setter = { value, access, setByRemote ->
if (access.read() == value) return@enum if (access.read() == value) return@enum
if (setByRemote) { if (setByRemote) {
@ -77,7 +74,7 @@ class SynchronizedRedstoneControl(
val state = isBlockedByRedstone val state = isBlockedByRedstone
valueChanges.invoke(state, old) valueChanges.invoke(state, old)
} }
}, name = if (fieldNamePrefix != null) "${fieldNamePrefix}_redstoneSetting" else null) })
override var redstoneSignal: Int by synchronizer.int(0, setter = { value, access, setByRemote -> override var redstoneSignal: Int by synchronizer.int(0, setter = { value, access, setByRemote ->
if (access.read() == value) return@int if (access.read() == value) return@int
@ -89,5 +86,5 @@ class SynchronizedRedstoneControl(
val state = isBlockedByRedstone val state = isBlockedByRedstone
valueChanges.invoke(state, old) valueChanges.invoke(state, old)
} }
}, name = if (fieldNamePrefix != null) "${fieldNamePrefix}_redstoneSignal" else null) })
} }

View File

@ -20,7 +20,7 @@ import ru.dbotthepony.mc.otm.registry.MBlocks
class HoloSignBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBlockEntity(MBlockEntities.HOLO_SIGN, blockPos, blockState), MenuProvider, IRedstoneControlled { class HoloSignBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBlockEntity(MBlockEntities.HOLO_SIGN, blockPos, blockState), MenuProvider, IRedstoneControlled {
override val redstoneControl = SynchronizedRedstoneControl(synchronizer) { _, _ -> setChanged() } override val redstoneControl = SynchronizedRedstoneControl(synchronizer) { _, _ -> setChanged() }
var signText by synchronizer.string("", name = "text", setter = { value, access, remote -> var signText by synchronizer.string("", setter = { value, access, remote ->
setChanged() setChanged()
access.write(value) access.write(value)
}) })

View File

@ -131,7 +131,7 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState)
}.also(::addDroppableContainer) }.also(::addDroppableContainer)
val capacitorStatus = immutableList(BatteryBankBlockEntity.CAPACITY) { val capacitorStatus = immutableList(BatteryBankBlockEntity.CAPACITY) {
synchronizer.bool(false, name = "capacitor$it") synchronizer.bool(false)
} }
init { init {

View File

@ -39,7 +39,7 @@ class BatteryBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matte
}.also(::addDroppableContainer) }.also(::addDroppableContainer)
val batteryStatus = immutableList(CAPACITY) { val batteryStatus = immutableList(CAPACITY) {
synchronizer.bool(false, name = "battery$it") synchronizer.bool(false)
} }
private val itemHandler = container.handler( private val itemHandler = container.handler(

View File

@ -121,12 +121,12 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
/** /**
* Whenever player has Exopack * Whenever player has Exopack
*/ */
var hasExoPack by publicSynchronizer.bool(name = "hasExoPack") var hasExoPack by publicSynchronizer.bool()
/** /**
* Whenever to render Exopack on player * Whenever to render Exopack on player
*/ */
var displayExoPack by publicSynchronizer.bool(true, name = "displayExoPack") var displayExoPack by publicSynchronizer.bool(true)
private val exoPackSlotModifierMap: MutableMap<UUID, Int> by synchronizer.Map( private val exoPackSlotModifierMap: MutableMap<UUID, Int> by synchronizer.Map(
keyCodec = UUIDValueCodec, keyCodec = UUIDValueCodec,
@ -135,7 +135,6 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
callback = { callback = {
this.exoPackSlotModifier.recompute() this.exoPackSlotModifier.recompute()
}, },
name = "exoPackSlotModifierMap"
) )
/** /**
@ -167,7 +166,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
_exoPackMenu = null _exoPackMenu = null
exoPackContainer = PlayerMatteryContainer(value) exoPackContainer = PlayerMatteryContainer(value)
} }
}, name = "exoPackSlotCount") })
/** /**
* Exopack container, which actually store items inside Exopack * Exopack container, which actually store items inside Exopack
@ -202,7 +201,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
access.write(value) access.write(value)
_exoPackMenu = null _exoPackMenu = null
} }
}, name = "isExoPackCraftingUpgraded") })
private var _exoPackMenu: ExoPackInventoryMenu? = null private var _exoPackMenu: ExoPackInventoryMenu? = null
set(value) { set(value) {
@ -276,7 +275,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
/** /**
* Whenever player should become an Android once transformation conditions are met (e.g. player dies or sleeps in bed) * Whenever player should become an Android once transformation conditions are met (e.g. player dies or sleeps in bed)
*/ */
var willBecomeAndroid by publicSynchronizer.bool(name = "willBecomeAndroid") var willBecomeAndroid by publicSynchronizer.bool()
/** /**
* Whenever player is an Android * Whenever player is an Android
@ -290,7 +289,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
* *
* Android-immune (de)buffs are specified in `data/overdrive_that_matters/tags/mob_effect/android_immune_effects.json` * Android-immune (de)buffs are specified in `data/overdrive_that_matters/tags/mob_effect/android_immune_effects.json`
*/ */
var isAndroid by publicSynchronizer.bool(name = "isAndroid") var isAndroid by publicSynchronizer.bool()
/** /**
* [IMatteryEnergyStorage] instance, representing Android' battery charge * [IMatteryEnergyStorage] instance, representing Android' battery charge

View File

@ -27,8 +27,8 @@ class AndroidPowerSource(
override val energyFlow: FlowDirection override val energyFlow: FlowDirection
get() = FlowDirection.INPUT get() = FlowDirection.INPUT
private var battery by synchronizer.fraction(initialCharge, name = "android battery") private var battery by synchronizer.fraction(initialCharge)
private var maxBattery by synchronizer.fraction(maxCharge, name = "android max battery") private var maxBattery by synchronizer.fraction(maxCharge)
var item by synchronizer.item(setter = setter@{ value, access, setByRemote -> var item by synchronizer.item(setter = setter@{ value, access, setByRemote ->
access.write(value) access.write(value)
@ -36,7 +36,7 @@ class AndroidPowerSource(
if (ply is ServerPlayer) { if (ply is ServerPlayer) {
AndroidBatteryTrigger.trigger(ply, value) AndroidBatteryTrigger.trigger(ply, value)
} }
}, name = "android battery item") })
override fun serializeNBT(): CompoundTag { override fun serializeNBT(): CompoundTag {
return CompoundTag().also { return CompoundTag().also {

View File

@ -1,14 +1,9 @@
package ru.dbotthepony.mc.otm.network package ru.dbotthepony.mc.otm.network
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
import it.unimi.dsi.fastutil.io.FastByteArrayInputStream
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
import it.unimi.dsi.fastutil.objects.ObjectArraySet
import it.unimi.dsi.fastutil.objects.Reference2ObjectFunction import it.unimi.dsi.fastutil.objects.Reference2ObjectFunction
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap
import it.unimi.dsi.fastutil.objects.ReferenceArraySet import it.unimi.dsi.fastutil.objects.ReferenceArraySet
import net.minecraft.nbt.NbtAccounter
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.core.* import ru.dbotthepony.mc.otm.core.*
@ -40,9 +35,6 @@ import java.lang.ref.WeakReference
import java.math.BigDecimal import java.math.BigDecimal
import java.util.* import java.util.*
import java.util.function.Supplier import java.util.function.Supplier
import kotlin.ConcurrentModificationException
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
import kotlin.properties.ReadOnlyProperty import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KMutableProperty0 import kotlin.reflect.KMutableProperty0
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
@ -66,13 +58,8 @@ sealed interface IField<V> : ReadOnlyProperty<Any?, V>, Supplier<V>, () -> V {
fun markDirty() fun markDirty()
fun markDirty(endpoint: FieldSynchronizer.Endpoint) fun markDirty(endpoint: FieldSynchronizer.Endpoint)
val value: V val value: V
val name: String
fun write(stream: DataOutputStream, endpoint: FieldSynchronizer.Endpoint) fun write(stream: DataOutputStream, endpoint: FieldSynchronizer.Endpoint)
fun read(stream: DataInputStream, payloadSize: Int) {
read(stream)
}
fun read(stream: DataInputStream) fun read(stream: DataInputStream)
override fun getValue(thisRef: Any?, property: KProperty<*>): V { override fun getValue(thisRef: Any?, property: KProperty<*>): V {
@ -128,12 +115,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
private var nextFieldID = 0 private var nextFieldID = 0
/**
* returns dummy field name
*/
fun nextFieldName() = "___field_${nextFieldID++}"
private var mappingVersion = 0
val hasObservers: Boolean get() = observers.isNotEmpty() val hasObservers: Boolean get() = observers.isNotEmpty()
val isEmpty: Boolean get() = fields.isEmpty() val isEmpty: Boolean get() = fields.isEmpty()
val isNotEmpty: Boolean get() = fields.isNotEmpty() val isNotEmpty: Boolean get() = fields.isNotEmpty()
@ -157,68 +138,68 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
hasChanges = false hasChanges = false
} }
@JvmOverloads fun byte(getter: () -> Byte, name: String? = nextFieldName()) = ComputedField(getter, ByteValueCodec, name ?: nextFieldName()) fun byte(getter: () -> Byte) = ComputedField(getter, ByteValueCodec)
@JvmOverloads fun bool(getter: () -> Boolean, name: String? = nextFieldName()) = ComputedField(getter, BooleanValueCodec, name ?: nextFieldName()) fun bool(getter: () -> Boolean) = ComputedField(getter, BooleanValueCodec)
@JvmOverloads fun short(getter: () -> Short, name: String? = nextFieldName()) = ComputedField(getter, ShortValueCodec, name ?: nextFieldName()) fun short(getter: () -> Short) = ComputedField(getter, ShortValueCodec)
@JvmOverloads fun long(getter: () -> Long, name: String? = nextFieldName()) = ComputedField(getter, VarLongValueCodec, name ?: nextFieldName()) fun long(getter: () -> Long) = ComputedField(getter, VarLongValueCodec)
@JvmOverloads fun fixedLong(getter: () -> Long, name: String? = nextFieldName()) = ComputedField(getter, LongValueCodec, name ?: nextFieldName()) fun fixedLong(getter: () -> Long) = ComputedField(getter, LongValueCodec)
@JvmOverloads fun float(getter: () -> Float, name: String? = nextFieldName()) = ComputedField(getter, FloatValueCodec, name ?: nextFieldName()) fun float(getter: () -> Float) = ComputedField(getter, FloatValueCodec)
@JvmOverloads fun double(getter: () -> Double, name: String? = nextFieldName()) = ComputedField(getter, DoubleValueCodec, name ?: nextFieldName()) fun double(getter: () -> Double) = ComputedField(getter, DoubleValueCodec)
@JvmOverloads fun uuid(getter: () -> UUID, name: String? = nextFieldName()) = ComputedField(getter, UUIDValueCodec, name ?: nextFieldName()) fun uuid(getter: () -> UUID) = ComputedField(getter, UUIDValueCodec)
@JvmOverloads fun int(getter: () -> Int, name: String? = nextFieldName()) = ComputedField(getter, VarIntValueCodec, name ?: nextFieldName()) fun int(getter: () -> Int) = ComputedField(getter, VarIntValueCodec)
@JvmOverloads fun fixedInt(getter: () -> Int, name: String? = nextFieldName()) = ComputedField(getter, IntValueCodec, name ?: nextFieldName()) fun fixedInt(getter: () -> Int) = ComputedField(getter, IntValueCodec)
@JvmOverloads fun fraction(getter: () -> Decimal, name: String? = nextFieldName()) = ComputedField(getter, ImpreciseFractionValueCodec, name ?: nextFieldName()) fun fraction(getter: () -> Decimal) = ComputedField(getter, ImpreciseFractionValueCodec)
@JvmOverloads fun bigDecimal(getter: () -> BigDecimal, name: String? = nextFieldName()) = ComputedField(getter, BigDecimalValueCodec, name ?: nextFieldName()) fun bigDecimal(getter: () -> BigDecimal) = ComputedField(getter, BigDecimalValueCodec)
@JvmOverloads fun item(getter: () -> ItemStack, name: String? = nextFieldName()) = ComputedField(getter, ItemStackValueCodec, name ?: nextFieldName()) fun item(getter: () -> ItemStack) = ComputedField(getter, ItemStackValueCodec)
@JvmOverloads fun string(getter: () -> String, name: String? = nextFieldName()) = ComputedField(getter, BinaryStringCodec, name ?: nextFieldName()) fun string(getter: () -> String) = ComputedField(getter, BinaryStringCodec)
@JvmOverloads fun byte(getter: KProperty0<Byte>, name: String? = nextFieldName()) = ComputedField(getter, ByteValueCodec, name ?: nextFieldName()) fun byte(getter: KProperty0<Byte>) = ComputedField(getter, ByteValueCodec)
@JvmOverloads fun bool(getter: KProperty0<Boolean>, name: String? = nextFieldName()) = ComputedField(getter, BooleanValueCodec, name ?: nextFieldName()) fun bool(getter: KProperty0<Boolean>) = ComputedField(getter, BooleanValueCodec)
@JvmOverloads fun short(getter: KProperty0<Short>, name: String? = nextFieldName()) = ComputedField(getter, ShortValueCodec, name ?: nextFieldName()) fun short(getter: KProperty0<Short>) = ComputedField(getter, ShortValueCodec)
@JvmOverloads fun long(getter: KProperty0<Long>, name: String? = nextFieldName()) = ComputedField(getter, VarLongValueCodec, name ?: nextFieldName()) fun long(getter: KProperty0<Long>) = ComputedField(getter, VarLongValueCodec)
@JvmOverloads fun fixedLong(getter: KProperty0<Long>, name: String? = nextFieldName()) = ComputedField(getter, LongValueCodec, name ?: nextFieldName()) fun fixedLong(getter: KProperty0<Long>) = ComputedField(getter, LongValueCodec)
@JvmOverloads fun float(getter: KProperty0<Float>, name: String? = nextFieldName()) = ComputedField(getter, FloatValueCodec, name ?: nextFieldName()) fun float(getter: KProperty0<Float>) = ComputedField(getter, FloatValueCodec)
@JvmOverloads fun double(getter: KProperty0<Double>, name: String? = nextFieldName()) = ComputedField(getter, DoubleValueCodec, name ?: nextFieldName()) fun double(getter: KProperty0<Double>) = ComputedField(getter, DoubleValueCodec)
@JvmOverloads fun uuid(getter: KProperty0<UUID>, name: String? = nextFieldName()) = ComputedField(getter, UUIDValueCodec, name ?: nextFieldName()) fun uuid(getter: KProperty0<UUID>) = ComputedField(getter, UUIDValueCodec)
@JvmOverloads fun int(getter: KProperty0<Int>, name: String? = nextFieldName()) = ComputedField(getter, VarIntValueCodec, name ?: nextFieldName()) fun int(getter: KProperty0<Int>) = ComputedField(getter, VarIntValueCodec)
@JvmOverloads fun fixedInt(getter: KProperty0<Int>, name: String? = nextFieldName()) = ComputedField(getter, IntValueCodec, name ?: nextFieldName()) fun fixedInt(getter: KProperty0<Int>) = ComputedField(getter, IntValueCodec)
@JvmOverloads fun fraction(getter: KProperty0<Decimal>, name: String? = nextFieldName()) = ComputedField(getter, ImpreciseFractionValueCodec, name ?: nextFieldName()) fun fraction(getter: KProperty0<Decimal>) = ComputedField(getter, ImpreciseFractionValueCodec)
@JvmOverloads fun bigDecimal(getter: KProperty0<BigDecimal>, name: String? = nextFieldName()) = ComputedField(getter, BigDecimalValueCodec, name ?: nextFieldName()) fun bigDecimal(getter: KProperty0<BigDecimal>) = ComputedField(getter, BigDecimalValueCodec)
@JvmOverloads fun item(getter: KProperty0<ItemStack>, name: String? = nextFieldName()) = ComputedField(getter, ItemStackValueCodec, name ?: nextFieldName()) fun item(getter: KProperty0<ItemStack>) = ComputedField(getter, ItemStackValueCodec)
@JvmOverloads fun string(getter: KProperty0<String>, name: String? = nextFieldName()) = ComputedField(getter, BinaryStringCodec, name ?: nextFieldName()) fun string(getter: KProperty0<String>) = ComputedField(getter, BinaryStringCodec)
@JvmOverloads fun byte(getter: Supplier<Byte>, name: String? = nextFieldName()) = ComputedField(getter::get, ByteValueCodec, name ?: nextFieldName()) fun byte(getter: Supplier<Byte>) = ComputedField(getter::get, ByteValueCodec)
@JvmOverloads fun bool(getter: Supplier<Boolean>, name: String? = nextFieldName()) = ComputedField(getter::get, BooleanValueCodec, name ?: nextFieldName()) fun bool(getter: Supplier<Boolean>) = ComputedField(getter::get, BooleanValueCodec)
@JvmOverloads fun short(getter: Supplier<Short>, name: String? = nextFieldName()) = ComputedField(getter::get, ShortValueCodec, name ?: nextFieldName()) fun short(getter: Supplier<Short>) = ComputedField(getter::get, ShortValueCodec)
@JvmOverloads fun long(getter: Supplier<Long>, name: String? = nextFieldName()) = ComputedField(getter::get, VarLongValueCodec, name ?: nextFieldName()) fun long(getter: Supplier<Long>) = ComputedField(getter::get, VarLongValueCodec)
@JvmOverloads fun fixedLong(getter: Supplier<Long>, name: String? = nextFieldName()) = ComputedField(getter::get, LongValueCodec, name ?: nextFieldName()) fun fixedLong(getter: Supplier<Long>) = ComputedField(getter::get, LongValueCodec)
@JvmOverloads fun float(getter: Supplier<Float>, name: String? = nextFieldName()) = ComputedField(getter::get, FloatValueCodec, name ?: nextFieldName()) fun float(getter: Supplier<Float>) = ComputedField(getter::get, FloatValueCodec)
@JvmOverloads fun double(getter: Supplier<Double>, name: String? = nextFieldName()) = ComputedField(getter::get, DoubleValueCodec, name ?: nextFieldName()) fun double(getter: Supplier<Double>) = ComputedField(getter::get, DoubleValueCodec)
@JvmOverloads fun uuid(getter: Supplier<UUID>, name: String? = nextFieldName()) = ComputedField(getter::get, UUIDValueCodec, name ?: nextFieldName()) fun uuid(getter: Supplier<UUID>) = ComputedField(getter::get, UUIDValueCodec)
@JvmOverloads fun int(getter: Supplier<Int>, name: String? = nextFieldName()) = ComputedField(getter::get, VarIntValueCodec, name ?: nextFieldName()) fun int(getter: Supplier<Int>) = ComputedField(getter::get, VarIntValueCodec)
@JvmOverloads fun fixedInt(getter: Supplier<Int>, name: String? = nextFieldName()) = ComputedField(getter::get, IntValueCodec, name ?: nextFieldName()) fun fixedInt(getter: Supplier<Int>) = ComputedField(getter::get, IntValueCodec)
@JvmOverloads fun fraction(getter: Supplier<Decimal>, name: String? = nextFieldName()) = ComputedField(getter::get, ImpreciseFractionValueCodec, name ?: nextFieldName()) fun fraction(getter: Supplier<Decimal>) = ComputedField(getter::get, ImpreciseFractionValueCodec)
@JvmOverloads fun bigDecimal(getter: Supplier<BigDecimal>, name: String? = nextFieldName()) = ComputedField(getter::get, BigDecimalValueCodec, name ?: nextFieldName()) fun bigDecimal(getter: Supplier<BigDecimal>) = ComputedField(getter::get, BigDecimalValueCodec)
@JvmOverloads fun item(getter: Supplier<ItemStack>, name: String? = nextFieldName()) = ComputedField(getter::get, ItemStackValueCodec, name ?: nextFieldName()) fun item(getter: Supplier<ItemStack>) = ComputedField(getter::get, ItemStackValueCodec)
@JvmOverloads fun string(getter: Supplier<String>, name: String? = nextFieldName()) = ComputedField(getter::get, BinaryStringCodec, name ?: nextFieldName()) fun string(getter: Supplier<String>) = ComputedField(getter::get, BinaryStringCodec)
@JvmOverloads fun <T : Enum<T>> enum(type: Class<T>, getter: () -> T, name: String? = nextFieldName()) = ComputedField(getter, EnumValueCodec.of(type), name ?: nextFieldName()) fun <T : Enum<T>> enum(type: Class<T>, getter: () -> T) = ComputedField(getter, EnumValueCodec.of(type))
inline fun <reified T : Enum<T>> enum(noinline getter: () -> T, name: String? = nextFieldName()) = ComputedField(getter, EnumValueCodec.of(T::class.java), name ?: nextFieldName()) inline fun <reified T : Enum<T>> enum(noinline getter: () -> T) = ComputedField(getter, EnumValueCodec.of(T::class.java))
@JvmOverloads fun <T : Enum<T>> enum(type: Class<T>, getter: KProperty0<T>, name: String? = nextFieldName()) = ComputedField(getter, EnumValueCodec.of(type), name ?: nextFieldName()) fun <T : Enum<T>> enum(type: Class<T>, getter: KProperty0<T>) = ComputedField(getter, EnumValueCodec.of(type))
inline fun <reified T : Enum<T>> enum(getter: KProperty0<T>, name: String? = nextFieldName()) = ComputedField(getter, EnumValueCodec.of(T::class.java), name ?: nextFieldName()) inline fun <reified T : Enum<T>> enum(getter: KProperty0<T>) = ComputedField(getter, EnumValueCodec.of(T::class.java))
@JvmOverloads fun <T : Enum<T>> enum(type: Class<T>, getter: Supplier<T>, name: String? = nextFieldName()) = ComputedField(getter::get, EnumValueCodec.of(type), name ?: nextFieldName()) fun <T : Enum<T>> enum(type: Class<T>, getter: Supplier<T>) = ComputedField(getter::get, EnumValueCodec.of(type))
inline fun <reified T : Enum<T>> enum(getter: Supplier<T>, name: String? = nextFieldName()) = ComputedField(getter::get, EnumValueCodec.of(T::class.java), name ?: nextFieldName()) inline fun <reified T : Enum<T>> enum(getter: Supplier<T>) = ComputedField(getter::get, EnumValueCodec.of(T::class.java))
@JvmOverloads @JvmOverloads
fun byte( fun byte(
value: Byte = 0, value: Byte = 0,
getter: FieldGetter<Byte>? = null, getter: FieldGetter<Byte>? = null,
setter: FieldSetter<Byte>? = null, setter: FieldSetter<Byte>? = null,
name: String? = nextFieldName(),
): Field<Byte> { ): Field<Byte> {
return Field(value, ByteValueCodec, getter, setter, name = name ?: nextFieldName()) return Field(value, ByteValueCodec, getter, setter)
} }
@JvmOverloads @JvmOverloads
@ -226,9 +207,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: Boolean = false, value: Boolean = false,
getter: FieldGetter<Boolean>? = null, getter: FieldGetter<Boolean>? = null,
setter: FieldSetter<Boolean>? = null, setter: FieldSetter<Boolean>? = null,
name: String? = nextFieldName(),
): Field<Boolean> { ): Field<Boolean> {
return Field(value, BooleanValueCodec, getter, setter, name = name ?: nextFieldName()) return Field(value, BooleanValueCodec, getter, setter)
} }
@JvmOverloads @JvmOverloads
@ -236,9 +217,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: Short = 0, value: Short = 0,
getter: FieldGetter<Short>? = null, getter: FieldGetter<Short>? = null,
setter: FieldSetter<Short>? = null, setter: FieldSetter<Short>? = null,
name: String? = nextFieldName(),
): Field<Short> { ): Field<Short> {
return Field(value, ShortValueCodec, getter, setter, name = name ?: nextFieldName()) return Field(value, ShortValueCodec, getter, setter)
} }
@JvmOverloads @JvmOverloads
@ -246,9 +227,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: Long = 0L, value: Long = 0L,
getter: FieldGetter<Long>? = null, getter: FieldGetter<Long>? = null,
setter: FieldSetter<Long>? = null, setter: FieldSetter<Long>? = null,
name: String? = nextFieldName(),
): Field<Long> { ): Field<Long> {
return Field(value, VarLongValueCodec, getter, setter, name = name ?: nextFieldName()) return Field(value, VarLongValueCodec, getter, setter)
} }
@JvmOverloads @JvmOverloads
@ -256,9 +237,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: Long = 0L, value: Long = 0L,
getter: FieldGetter<Long>? = null, getter: FieldGetter<Long>? = null,
setter: FieldSetter<Long>? = null, setter: FieldSetter<Long>? = null,
name: String? = nextFieldName(),
): Field<Long> { ): Field<Long> {
return Field(value, LongValueCodec, getter, setter, name = name ?: nextFieldName()) return Field(value, LongValueCodec, getter, setter)
} }
@JvmOverloads @JvmOverloads
@ -266,9 +247,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: Float = 0f, value: Float = 0f,
getter: FieldGetter<Float>? = null, getter: FieldGetter<Float>? = null,
setter: FieldSetter<Float>? = null, setter: FieldSetter<Float>? = null,
name: String? = nextFieldName(),
): Field<Float> { ): Field<Float> {
return Field(value, FloatValueCodec, getter, setter, name = name ?: nextFieldName()) return Field(value, FloatValueCodec, getter, setter)
} }
@JvmOverloads @JvmOverloads
@ -276,9 +257,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: Double = 0.0, value: Double = 0.0,
getter: FieldGetter<Double>? = null, getter: FieldGetter<Double>? = null,
setter: FieldSetter<Double>? = null, setter: FieldSetter<Double>? = null,
name: String? = nextFieldName(),
): Field<Double> { ): Field<Double> {
return Field(value, DoubleValueCodec, getter, setter, name = name ?: nextFieldName()) return Field(value, DoubleValueCodec, getter, setter)
} }
@JvmOverloads @JvmOverloads
@ -286,9 +267,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: UUID = UUID(0L, 0L), value: UUID = UUID(0L, 0L),
getter: FieldGetter<UUID>? = null, getter: FieldGetter<UUID>? = null,
setter: FieldSetter<UUID>? = null, setter: FieldSetter<UUID>? = null,
name: String? = nextFieldName(),
): Field<UUID> { ): Field<UUID> {
return Field(value, UUIDValueCodec, getter, setter, name = name ?: nextFieldName()) return Field(value, UUIDValueCodec, getter, setter)
} }
@JvmOverloads @JvmOverloads
@ -296,9 +277,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: Int = 0, value: Int = 0,
getter: FieldGetter<Int>? = null, getter: FieldGetter<Int>? = null,
setter: FieldSetter<Int>? = null, setter: FieldSetter<Int>? = null,
name: String? = nextFieldName(),
): Field<Int> { ): Field<Int> {
return Field(value, VarIntValueCodec, getter, setter, name = name ?: nextFieldName()) return Field(value, VarIntValueCodec, getter, setter)
} }
@JvmOverloads @JvmOverloads
@ -306,9 +287,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: String = "", value: String = "",
getter: FieldGetter<String>? = null, getter: FieldGetter<String>? = null,
setter: FieldSetter<String>? = null, setter: FieldSetter<String>? = null,
name: String? = nextFieldName(),
): Field<String> { ): Field<String> {
return Field(value, BinaryStringCodec, getter, setter, name = name ?: nextFieldName()) return Field(value, BinaryStringCodec, getter, setter)
} }
@JvmOverloads @JvmOverloads
@ -316,9 +297,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: Int = 0, value: Int = 0,
getter: FieldGetter<Int>? = null, getter: FieldGetter<Int>? = null,
setter: FieldSetter<Int>? = null, setter: FieldSetter<Int>? = null,
name: String? = nextFieldName(),
): Field<Int> { ): Field<Int> {
return Field(value, IntValueCodec, getter, setter, name = name ?: nextFieldName()) return Field(value, IntValueCodec, getter, setter)
} }
@JvmOverloads @JvmOverloads
@ -326,9 +307,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: Decimal = Decimal.ZERO, value: Decimal = Decimal.ZERO,
getter: FieldGetter<Decimal>? = null, getter: FieldGetter<Decimal>? = null,
setter: FieldSetter<Decimal>? = null, setter: FieldSetter<Decimal>? = null,
name: String? = nextFieldName(),
): Field<Decimal> { ): Field<Decimal> {
return Field(value, ImpreciseFractionValueCodec, getter, setter, name = name ?: nextFieldName()) return Field(value, ImpreciseFractionValueCodec, getter, setter)
} }
@JvmOverloads @JvmOverloads
@ -336,9 +317,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: BigDecimal = BigDecimal.ZERO, value: BigDecimal = BigDecimal.ZERO,
getter: FieldGetter<BigDecimal>? = null, getter: FieldGetter<BigDecimal>? = null,
setter: FieldSetter<BigDecimal>? = null, setter: FieldSetter<BigDecimal>? = null,
name: String? = nextFieldName(),
): Field<BigDecimal> { ): Field<BigDecimal> {
return Field(value, BigDecimalValueCodec, getter, setter, name = name ?: nextFieldName()) return Field(value, BigDecimalValueCodec, getter, setter)
} }
@JvmOverloads @JvmOverloads
@ -347,9 +328,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: T = type.enumConstants[0], value: T = type.enumConstants[0],
getter: FieldGetter<T>? = null, getter: FieldGetter<T>? = null,
setter: FieldSetter<T>? = null, setter: FieldSetter<T>? = null,
name: String? = nextFieldName(),
): Field<T> { ): Field<T> {
return Field(value, EnumValueCodec.of(type), getter, setter, name = name ?: nextFieldName()) return Field(value, EnumValueCodec.of(type), getter, setter)
} }
@JvmOverloads @JvmOverloads
@ -357,9 +338,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: T, value: T,
getter: FieldGetter<T>? = null, getter: FieldGetter<T>? = null,
setter: FieldSetter<T>? = null, setter: FieldSetter<T>? = null,
name: String? = nextFieldName(),
): Field<T> { ): Field<T> {
return Field(value, EnumValueCodec.of(value::class.java), getter, setter, name = name ?: nextFieldName()) return Field(value, EnumValueCodec.of(value::class.java), getter, setter)
} }
@JvmOverloads @JvmOverloads
@ -368,17 +349,14 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
getter: FieldGetter<ItemStack>? = null, getter: FieldGetter<ItemStack>? = null,
setter: FieldSetter<ItemStack>? = null, setter: FieldSetter<ItemStack>? = null,
observe: Boolean = true, observe: Boolean = true,
name: String? = nextFieldName(),
): Field<ItemStack> { ): Field<ItemStack> {
return Field(value, ItemStackValueCodec, getter, setter, isObserver = observe, name = name ?: nextFieldName()) return Field(value, ItemStackValueCodec, getter, setter, isObserver = observe)
} }
@JvmOverloads
fun item( fun item(
delegate: KMutableProperty0<ItemStack>, delegate: KMutableProperty0<ItemStack>,
name: String? = nextFieldName(),
): ObservedField<ItemStack> { ): ObservedField<ItemStack> {
return ObservedField(delegate, ItemStackValueCodec, name = name ?: nextFieldName()) return ObservedField(delegate, ItemStackValueCodec)
} }
@JvmOverloads @JvmOverloads
@ -388,7 +366,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
callback: ((changes: Collection<MapChangeset<K, V>>) -> Unit)? = null, callback: ((changes: Collection<MapChangeset<K, V>>) -> Unit)? = null,
backingMap: MutableMap<K, V> = HashMap(), backingMap: MutableMap<K, V> = HashMap(),
observingBackingMap: MutableMap<K, V>? = null, observingBackingMap: MutableMap<K, V>? = null,
name: String? = nextFieldName(),
): Map<K, V> { ): Map<K, V> {
return Map( return Map(
keyCodec = keyCodec, keyCodec = keyCodec,
@ -396,7 +373,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
callback = callback, callback = callback,
backingMap = backingMap, backingMap = backingMap,
observingBackingMap = observingBackingMap, observingBackingMap = observingBackingMap,
name = name ?: nextFieldName(),
) )
} }
@ -516,36 +492,11 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
} }
val stream = FastByteArrayOutputStream() val stream = FastByteArrayOutputStream()
val dataStream = DataOutputStream(stream)
if (mappingVersion != this@FieldSynchronizer.mappingVersion) {
stream.write(1)
for (field in fields) {
check(field.id > 0) { "This should never happen: $field maps to invalid ID: ${field.id}!" }
stream.writeVarIntLE(field.id)
val bytes = field.name.toByteArray(Charsets.UTF_8)
stream.writeVarIntLE(bytes.size)
stream.write(bytes)
}
stream.writeVarIntLE(0)
mappingVersion = this@FieldSynchronizer.mappingVersion
} else {
stream.write(0)
}
for (field in dirtyFields) { for (field in dirtyFields) {
val id = field.id stream.writeVarIntLE(field.id)
check(id > 0) { "This should never happen: $field maps to invalid ID: $id!" }
stream.writeVarIntLE(id)
val innerStream = FastByteArrayOutputStream()
val dataStream = DataOutputStream(innerStream)
field.write(dataStream, this) field.write(dataStream, this)
stream.writeVarIntLE(innerStream.length)
stream.write(innerStream.array, 0, innerStream.length)
} }
dirtyFields.clear() dirtyFields.clear()
@ -570,15 +521,11 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
} }
@Suppress("LeakingThis") @Suppress("LeakingThis")
abstract inner class AbstractField<V>( abstract inner class AbstractField<V> : IField<V> {
final override val name: String = nextFieldName(), val id: Int = fields.size + 1
) : IField<V> {
var id: Int = fields.size + 1
init { init {
check(!fields.any { it.name == name }) { "Duplicate field name $name" }
fields.add(this) fields.add(this)
mappingVersion++
} }
} }
@ -591,8 +538,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
private val getter: FieldGetter<V>? = null, private val getter: FieldGetter<V>? = null,
private val setter: FieldSetter<V>? = null, private val setter: FieldSetter<V>? = null,
isObserver: Boolean = false, isObserver: Boolean = false,
name: String = nextFieldName(), ) : AbstractField<V>(), IMutableField<V> {
) : AbstractField<V>(name), IMutableField<V> {
private var remote: V = codec.copy(field) private var remote: V = codec.copy(field)
init { init {
@ -691,9 +637,8 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
inner class ComputedField<V>( inner class ComputedField<V>(
private val getter: () -> V, private val getter: () -> V,
private val codec: IStreamCodec<V>, private val codec: IStreamCodec<V>,
name: String = nextFieldName(),
private val observer: (new: V) -> Unit = {} private val observer: (new: V) -> Unit = {}
) : AbstractField<V>(name), IField<V> { ) : AbstractField<V>(), IField<V> {
private var remote: V? = null private var remote: V? = null
private var clientValue: V? = null private var clientValue: V? = null
private var isDirty = false private var isDirty = false
@ -750,14 +695,14 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
get() = getter.invoke() get() = getter.invoke()
set(value) { setter.invoke(value) } set(value) { setter.invoke(value) }
constructor(field: KMutableProperty0<V>, codec: IStreamCodec<V>, name: String = nextFieldName()) : super(name) { constructor(field: KMutableProperty0<V>, codec: IStreamCodec<V>) : super() {
this.codec = codec this.codec = codec
getter = field::get getter = field::get
setter = field::set setter = field::set
remote = codec.copy(value) remote = codec.copy(value)
} }
constructor(getter: () -> V, setter: (V) -> Unit, codec: IStreamCodec<V>, name: String = nextFieldName()) : super(name) { constructor(getter: () -> V, setter: (V) -> Unit, codec: IStreamCodec<V>) : super() {
this.codec = codec this.codec = codec
this.getter = getter this.getter = getter
this.setter = setter this.setter = setter
@ -806,8 +751,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
private val backingMap: MutableMap<K, V>, private val backingMap: MutableMap<K, V>,
private val observingBackingMap: MutableMap<K, V>? = null, private val observingBackingMap: MutableMap<K, V>? = null,
private val callback: ((changes: Collection<MapChangeset<K, V>>) -> Unit)? = null, private val callback: ((changes: Collection<MapChangeset<K, V>>) -> Unit)? = null,
name: String = nextFieldName(), ) : AbstractField<MutableMap<K, V>>(), IField<MutableMap<K, V>> {
) : AbstractField<MutableMap<K, V>>(name), IField<MutableMap<K, V>> {
private var isDirty = false private var isDirty = false
private var sentAllValues = false private var sentAllValues = false
private var isRemote = false private var isRemote = false
@ -1116,63 +1060,15 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
return values return values
} }
private val idToField = Int2ObjectOpenHashMap<IField<*>>() fun read(stream: InputStream): Int {
private val missingFields = ObjectArraySet<String>() var fieldId = stream.readVarIntLE()
private val missingFieldsMap = Int2ObjectArrayMap<String>()
fun read(stream: InputStream, sizeLimit: NbtAccounter = NbtAccounter(1L shl 21 /* 2 MiB */)): Int {
if (stream.read() > 0) {
idToField.clear()
missingFieldsMap.clear()
var fieldId = stream.readVarIntLE(sizeLimit)
while (fieldId != 0) {
val size = stream.readVarIntLE(sizeLimit)
val nameBytes = ByteArray(size)
stream.read(nameBytes)
val name = String(nameBytes, Charsets.UTF_8)
val findField = fields.firstOrNull { it.name == name }
if (findField == null) {
if (missingFields.add(name)) {
LOGGER.error("Unable to find field $name in $this, expect issues!")
}
missingFieldsMap[fieldId] = name
} else {
idToField[fieldId] = findField
findField.id = fieldId
}
fieldId = stream.readVarIntLE(sizeLimit)
}
}
if (idToField.isEmpty()) {
throw IllegalStateException("Can't read anything, field ID mapping is empty!")
}
var fieldId = stream.readVarIntLE(sizeLimit)
var i = 0 var i = 0
val dataStream = DataInputStream(stream)
while (fieldId != 0) { while (fieldId != 0) {
val field = idToField[fieldId] val field = fields.getOrNull(fieldId - 1) ?: throw IllegalArgumentException("Unknown field ID ${fieldId - 1}")
val payloadSize = stream.readVarIntLE(sizeLimit) field.read(dataStream)
fieldId = stream.readVarIntLE()
if (field == null) {
LOGGER.error("Unable to read field $fieldId (${missingFieldsMap[fieldId]}) because we don't know anything about it! Skipping $payloadSize bytes", IllegalStateException("Unknown field $fieldId"))
sizeLimit.accountBytes(payloadSize.toLong())
stream.skipNBytes(payloadSize.toLong())
continue
}
sizeLimit.accountBytes(payloadSize.toLong())
val bytes = ByteArray(payloadSize)
stream.read(bytes)
field.read(DataInputStream(FastByteArrayInputStream(bytes)), payloadSize)
fieldId = stream.readVarIntLE(sizeLimit)
i++ i++
} }
@ -1183,6 +1079,5 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
private val ClearBacklogEntry = { stream: DataOutputStream -> stream.write(MapAction.CLEAR.ordinal + 1) } private val ClearBacklogEntry = { stream: DataOutputStream -> stream.write(MapAction.CLEAR.ordinal + 1) }
private val MapActionList = MapAction.values() private val MapActionList = MapAction.values()
private val ClearMapChangeset = MapChangeset(MapAction.CLEAR, null, null) private val ClearMapChangeset = MapChangeset(MapAction.CLEAR, null, null)
private val LOGGER = LogManager.getLogger()
} }
} }

View File

@ -511,7 +511,7 @@ object HideExosuitPacket : MatteryPacket {
} }
object MatteryPlayerNetworkChannel : MatteryNetworkChannel( object MatteryPlayerNetworkChannel : MatteryNetworkChannel(
version = "1", version = "2",
name = "player" name = "player"
) { ) {
fun register() { fun register() {

View File

@ -5,7 +5,7 @@ import ru.dbotthepony.mc.otm.item.weapon.WeaponFireInputPacket
import ru.dbotthepony.mc.otm.item.weapon.WeaponScopePacket import ru.dbotthepony.mc.otm.item.weapon.WeaponScopePacket
object WeaponNetworkChannel : MatteryNetworkChannel( object WeaponNetworkChannel : MatteryNetworkChannel(
version = "1", version = "2",
name = "weapon" name = "weapon"
) { ) {
fun register() { fun register() {

View File

@ -93,7 +93,7 @@ class BlockEntitySyncPacket(val position: BlockPos, val buffer: ByteArray, val v
} }
object WorldNetworkChannel : MatteryNetworkChannel( object WorldNetworkChannel : MatteryNetworkChannel(
version = "3", version = "4",
name = "world" name = "world"
) { ) {
fun register() { fun register() {

View File

@ -131,32 +131,4 @@ object FieldSynchronizerTests {
assertEquals(fieldsa[i].value, fieldsb[i].value) assertEquals(fieldsa[i].value, fieldsb[i].value)
} }
} }
@Test
@DisplayName("Field Synchronizer field order definition mismatch")
fun orderMismatch() {
val a = FieldSynchronizer()
val b = FieldSynchronizer()
val fieldsa = ArrayList<IMutableField<Int>>()
val fieldsb = ArrayList<IMutableField<Int>>()
for (i in 0 .. 900) {
fieldsa.add(a.int(name = "int$i"))
}
for (i in 900 downTo 0) {
fieldsb.add(0, b.int(name = "int$i"))
}
for (i in 0 .. 900) {
fieldsa[i].value = i
}
b.read(a.collectNetworkPayload()!!.let { ByteArrayInputStream(it.array, 0, it.length) })
for (i in 0 .. 900) {
assertEquals(fieldsa[i].value, fieldsb[i].value)
}
}
} }