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(
synchronizer: FieldSynchronizer,
fieldNamePrefix: String?,
private val valueChanges: (new: Boolean, old: Boolean) -> Unit,
) : 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 ->
if (access.read() == value) return@enum
if (setByRemote) {
@ -77,7 +74,7 @@ class SynchronizedRedstoneControl(
val state = isBlockedByRedstone
valueChanges.invoke(state, old)
}
}, name = if (fieldNamePrefix != null) "${fieldNamePrefix}_redstoneSetting" else null)
})
override var redstoneSignal: Int by synchronizer.int(0, setter = { value, access, setByRemote ->
if (access.read() == value) return@int
@ -89,5 +86,5 @@ class SynchronizedRedstoneControl(
val state = isBlockedByRedstone
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 {
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()
access.write(value)
})

View File

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

View File

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

View File

@ -121,12 +121,12 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
/**
* Whenever player has Exopack
*/
var hasExoPack by publicSynchronizer.bool(name = "hasExoPack")
var hasExoPack by publicSynchronizer.bool()
/**
* 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(
keyCodec = UUIDValueCodec,
@ -135,7 +135,6 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
callback = {
this.exoPackSlotModifier.recompute()
},
name = "exoPackSlotModifierMap"
)
/**
@ -167,7 +166,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
_exoPackMenu = null
exoPackContainer = PlayerMatteryContainer(value)
}
}, name = "exoPackSlotCount")
})
/**
* Exopack container, which actually store items inside Exopack
@ -202,7 +201,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
access.write(value)
_exoPackMenu = null
}
}, name = "isExoPackCraftingUpgraded")
})
private var _exoPackMenu: ExoPackInventoryMenu? = null
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)
*/
var willBecomeAndroid by publicSynchronizer.bool(name = "willBecomeAndroid")
var willBecomeAndroid by publicSynchronizer.bool()
/**
* 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`
*/
var isAndroid by publicSynchronizer.bool(name = "isAndroid")
var isAndroid by publicSynchronizer.bool()
/**
* [IMatteryEnergyStorage] instance, representing Android' battery charge

View File

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

View File

@ -1,14 +1,9 @@
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.objects.ObjectArraySet
import it.unimi.dsi.fastutil.objects.Reference2ObjectFunction
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap
import it.unimi.dsi.fastutil.objects.ReferenceArraySet
import net.minecraft.nbt.NbtAccounter
import net.minecraft.world.item.ItemStack
import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.core.*
@ -40,9 +35,6 @@ import java.lang.ref.WeakReference
import java.math.BigDecimal
import java.util.*
import java.util.function.Supplier
import kotlin.ConcurrentModificationException
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KMutableProperty0
import kotlin.reflect.KProperty
@ -66,13 +58,8 @@ sealed interface IField<V> : ReadOnlyProperty<Any?, V>, Supplier<V>, () -> V {
fun markDirty()
fun markDirty(endpoint: FieldSynchronizer.Endpoint)
val value: V
val name: String
fun write(stream: DataOutputStream, endpoint: FieldSynchronizer.Endpoint)
fun read(stream: DataInputStream, payloadSize: Int) {
read(stream)
}
fun read(stream: DataInputStream)
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
/**
* returns dummy field name
*/
fun nextFieldName() = "___field_${nextFieldID++}"
private var mappingVersion = 0
val hasObservers: Boolean get() = observers.isNotEmpty()
val isEmpty: Boolean get() = fields.isEmpty()
val isNotEmpty: Boolean get() = fields.isNotEmpty()
@ -157,68 +138,68 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
hasChanges = false
}
@JvmOverloads fun byte(getter: () -> Byte, name: String? = nextFieldName()) = ComputedField(getter, ByteValueCodec, name ?: nextFieldName())
@JvmOverloads fun bool(getter: () -> Boolean, name: String? = nextFieldName()) = ComputedField(getter, BooleanValueCodec, name ?: nextFieldName())
@JvmOverloads fun short(getter: () -> Short, name: String? = nextFieldName()) = ComputedField(getter, ShortValueCodec, name ?: nextFieldName())
@JvmOverloads fun long(getter: () -> Long, name: String? = nextFieldName()) = ComputedField(getter, VarLongValueCodec, name ?: nextFieldName())
@JvmOverloads fun fixedLong(getter: () -> Long, name: String? = nextFieldName()) = ComputedField(getter, LongValueCodec, name ?: nextFieldName())
@JvmOverloads fun float(getter: () -> Float, name: String? = nextFieldName()) = ComputedField(getter, FloatValueCodec, name ?: nextFieldName())
@JvmOverloads fun double(getter: () -> Double, name: String? = nextFieldName()) = ComputedField(getter, DoubleValueCodec, name ?: nextFieldName())
@JvmOverloads fun uuid(getter: () -> UUID, name: String? = nextFieldName()) = ComputedField(getter, UUIDValueCodec, name ?: nextFieldName())
@JvmOverloads fun int(getter: () -> Int, name: String? = nextFieldName()) = ComputedField(getter, VarIntValueCodec, name ?: nextFieldName())
@JvmOverloads fun fixedInt(getter: () -> Int, name: String? = nextFieldName()) = ComputedField(getter, IntValueCodec, name ?: nextFieldName())
@JvmOverloads fun fraction(getter: () -> Decimal, name: String? = nextFieldName()) = ComputedField(getter, ImpreciseFractionValueCodec, name ?: nextFieldName())
@JvmOverloads fun bigDecimal(getter: () -> BigDecimal, name: String? = nextFieldName()) = ComputedField(getter, BigDecimalValueCodec, name ?: nextFieldName())
@JvmOverloads fun item(getter: () -> ItemStack, name: String? = nextFieldName()) = ComputedField(getter, ItemStackValueCodec, name ?: nextFieldName())
@JvmOverloads fun string(getter: () -> String, name: String? = nextFieldName()) = ComputedField(getter, BinaryStringCodec, name ?: nextFieldName())
fun byte(getter: () -> Byte) = ComputedField(getter, ByteValueCodec)
fun bool(getter: () -> Boolean) = ComputedField(getter, BooleanValueCodec)
fun short(getter: () -> Short) = ComputedField(getter, ShortValueCodec)
fun long(getter: () -> Long) = ComputedField(getter, VarLongValueCodec)
fun fixedLong(getter: () -> Long) = ComputedField(getter, LongValueCodec)
fun float(getter: () -> Float) = ComputedField(getter, FloatValueCodec)
fun double(getter: () -> Double) = ComputedField(getter, DoubleValueCodec)
fun uuid(getter: () -> UUID) = ComputedField(getter, UUIDValueCodec)
fun int(getter: () -> Int) = ComputedField(getter, VarIntValueCodec)
fun fixedInt(getter: () -> Int) = ComputedField(getter, IntValueCodec)
fun fraction(getter: () -> Decimal) = ComputedField(getter, ImpreciseFractionValueCodec)
fun bigDecimal(getter: () -> BigDecimal) = ComputedField(getter, BigDecimalValueCodec)
fun item(getter: () -> ItemStack) = ComputedField(getter, ItemStackValueCodec)
fun string(getter: () -> String) = ComputedField(getter, BinaryStringCodec)
@JvmOverloads fun byte(getter: KProperty0<Byte>, name: String? = nextFieldName()) = ComputedField(getter, ByteValueCodec, name ?: nextFieldName())
@JvmOverloads fun bool(getter: KProperty0<Boolean>, name: String? = nextFieldName()) = ComputedField(getter, BooleanValueCodec, name ?: nextFieldName())
@JvmOverloads fun short(getter: KProperty0<Short>, name: String? = nextFieldName()) = ComputedField(getter, ShortValueCodec, name ?: nextFieldName())
@JvmOverloads fun long(getter: KProperty0<Long>, name: String? = nextFieldName()) = ComputedField(getter, VarLongValueCodec, name ?: nextFieldName())
@JvmOverloads fun fixedLong(getter: KProperty0<Long>, name: String? = nextFieldName()) = ComputedField(getter, LongValueCodec, name ?: nextFieldName())
@JvmOverloads fun float(getter: KProperty0<Float>, name: String? = nextFieldName()) = ComputedField(getter, FloatValueCodec, name ?: nextFieldName())
@JvmOverloads fun double(getter: KProperty0<Double>, name: String? = nextFieldName()) = ComputedField(getter, DoubleValueCodec, name ?: nextFieldName())
@JvmOverloads fun uuid(getter: KProperty0<UUID>, name: String? = nextFieldName()) = ComputedField(getter, UUIDValueCodec, name ?: nextFieldName())
@JvmOverloads fun int(getter: KProperty0<Int>, name: String? = nextFieldName()) = ComputedField(getter, VarIntValueCodec, name ?: nextFieldName())
@JvmOverloads fun fixedInt(getter: KProperty0<Int>, name: String? = nextFieldName()) = ComputedField(getter, IntValueCodec, name ?: nextFieldName())
@JvmOverloads fun fraction(getter: KProperty0<Decimal>, name: String? = nextFieldName()) = ComputedField(getter, ImpreciseFractionValueCodec, name ?: nextFieldName())
@JvmOverloads fun bigDecimal(getter: KProperty0<BigDecimal>, name: String? = nextFieldName()) = ComputedField(getter, BigDecimalValueCodec, name ?: nextFieldName())
@JvmOverloads fun item(getter: KProperty0<ItemStack>, name: String? = nextFieldName()) = ComputedField(getter, ItemStackValueCodec, name ?: nextFieldName())
@JvmOverloads fun string(getter: KProperty0<String>, name: String? = nextFieldName()) = ComputedField(getter, BinaryStringCodec, name ?: nextFieldName())
fun byte(getter: KProperty0<Byte>) = ComputedField(getter, ByteValueCodec)
fun bool(getter: KProperty0<Boolean>) = ComputedField(getter, BooleanValueCodec)
fun short(getter: KProperty0<Short>) = ComputedField(getter, ShortValueCodec)
fun long(getter: KProperty0<Long>) = ComputedField(getter, VarLongValueCodec)
fun fixedLong(getter: KProperty0<Long>) = ComputedField(getter, LongValueCodec)
fun float(getter: KProperty0<Float>) = ComputedField(getter, FloatValueCodec)
fun double(getter: KProperty0<Double>) = ComputedField(getter, DoubleValueCodec)
fun uuid(getter: KProperty0<UUID>) = ComputedField(getter, UUIDValueCodec)
fun int(getter: KProperty0<Int>) = ComputedField(getter, VarIntValueCodec)
fun fixedInt(getter: KProperty0<Int>) = ComputedField(getter, IntValueCodec)
fun fraction(getter: KProperty0<Decimal>) = ComputedField(getter, ImpreciseFractionValueCodec)
fun bigDecimal(getter: KProperty0<BigDecimal>) = ComputedField(getter, BigDecimalValueCodec)
fun item(getter: KProperty0<ItemStack>) = ComputedField(getter, ItemStackValueCodec)
fun string(getter: KProperty0<String>) = ComputedField(getter, BinaryStringCodec)
@JvmOverloads fun byte(getter: Supplier<Byte>, name: String? = nextFieldName()) = ComputedField(getter::get, ByteValueCodec, name ?: nextFieldName())
@JvmOverloads fun bool(getter: Supplier<Boolean>, name: String? = nextFieldName()) = ComputedField(getter::get, BooleanValueCodec, name ?: nextFieldName())
@JvmOverloads fun short(getter: Supplier<Short>, name: String? = nextFieldName()) = ComputedField(getter::get, ShortValueCodec, name ?: nextFieldName())
@JvmOverloads fun long(getter: Supplier<Long>, name: String? = nextFieldName()) = ComputedField(getter::get, VarLongValueCodec, name ?: nextFieldName())
@JvmOverloads fun fixedLong(getter: Supplier<Long>, name: String? = nextFieldName()) = ComputedField(getter::get, LongValueCodec, name ?: nextFieldName())
@JvmOverloads fun float(getter: Supplier<Float>, name: String? = nextFieldName()) = ComputedField(getter::get, FloatValueCodec, name ?: nextFieldName())
@JvmOverloads fun double(getter: Supplier<Double>, name: String? = nextFieldName()) = ComputedField(getter::get, DoubleValueCodec, name ?: nextFieldName())
@JvmOverloads fun uuid(getter: Supplier<UUID>, name: String? = nextFieldName()) = ComputedField(getter::get, UUIDValueCodec, name ?: nextFieldName())
@JvmOverloads fun int(getter: Supplier<Int>, name: String? = nextFieldName()) = ComputedField(getter::get, VarIntValueCodec, name ?: nextFieldName())
@JvmOverloads fun fixedInt(getter: Supplier<Int>, name: String? = nextFieldName()) = ComputedField(getter::get, IntValueCodec, name ?: nextFieldName())
@JvmOverloads fun fraction(getter: Supplier<Decimal>, name: String? = nextFieldName()) = ComputedField(getter::get, ImpreciseFractionValueCodec, name ?: nextFieldName())
@JvmOverloads fun bigDecimal(getter: Supplier<BigDecimal>, name: String? = nextFieldName()) = ComputedField(getter::get, BigDecimalValueCodec, name ?: nextFieldName())
@JvmOverloads fun item(getter: Supplier<ItemStack>, name: String? = nextFieldName()) = ComputedField(getter::get, ItemStackValueCodec, name ?: nextFieldName())
@JvmOverloads fun string(getter: Supplier<String>, name: String? = nextFieldName()) = ComputedField(getter::get, BinaryStringCodec, name ?: nextFieldName())
fun byte(getter: Supplier<Byte>) = ComputedField(getter::get, ByteValueCodec)
fun bool(getter: Supplier<Boolean>) = ComputedField(getter::get, BooleanValueCodec)
fun short(getter: Supplier<Short>) = ComputedField(getter::get, ShortValueCodec)
fun long(getter: Supplier<Long>) = ComputedField(getter::get, VarLongValueCodec)
fun fixedLong(getter: Supplier<Long>) = ComputedField(getter::get, LongValueCodec)
fun float(getter: Supplier<Float>) = ComputedField(getter::get, FloatValueCodec)
fun double(getter: Supplier<Double>) = ComputedField(getter::get, DoubleValueCodec)
fun uuid(getter: Supplier<UUID>) = ComputedField(getter::get, UUIDValueCodec)
fun int(getter: Supplier<Int>) = ComputedField(getter::get, VarIntValueCodec)
fun fixedInt(getter: Supplier<Int>) = ComputedField(getter::get, IntValueCodec)
fun fraction(getter: Supplier<Decimal>) = ComputedField(getter::get, ImpreciseFractionValueCodec)
fun bigDecimal(getter: Supplier<BigDecimal>) = ComputedField(getter::get, BigDecimalValueCodec)
fun item(getter: Supplier<ItemStack>) = ComputedField(getter::get, ItemStackValueCodec)
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())
inline fun <reified T : Enum<T>> enum(noinline getter: () -> T, name: String? = nextFieldName()) = ComputedField(getter, EnumValueCodec.of(T::class.java), 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) = 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())
inline fun <reified T : Enum<T>> enum(getter: KProperty0<T>, name: String? = nextFieldName()) = ComputedField(getter, EnumValueCodec.of(T::class.java), 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>) = 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())
inline fun <reified T : Enum<T>> enum(getter: Supplier<T>, name: String? = nextFieldName()) = ComputedField(getter::get, EnumValueCodec.of(T::class.java), 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>) = ComputedField(getter::get, EnumValueCodec.of(T::class.java))
@JvmOverloads
fun byte(
value: Byte = 0,
getter: FieldGetter<Byte>? = null,
setter: FieldSetter<Byte>? = null,
name: String? = nextFieldName(),
): Field<Byte> {
return Field(value, ByteValueCodec, getter, setter, name = name ?: nextFieldName())
return Field(value, ByteValueCodec, getter, setter)
}
@JvmOverloads
@ -226,9 +207,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: Boolean = false,
getter: FieldGetter<Boolean>? = null,
setter: FieldSetter<Boolean>? = null,
name: String? = nextFieldName(),
): Field<Boolean> {
return Field(value, BooleanValueCodec, getter, setter, name = name ?: nextFieldName())
return Field(value, BooleanValueCodec, getter, setter)
}
@JvmOverloads
@ -236,9 +217,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: Short = 0,
getter: FieldGetter<Short>? = null,
setter: FieldSetter<Short>? = null,
name: String? = nextFieldName(),
): Field<Short> {
return Field(value, ShortValueCodec, getter, setter, name = name ?: nextFieldName())
return Field(value, ShortValueCodec, getter, setter)
}
@JvmOverloads
@ -246,9 +227,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: Long = 0L,
getter: FieldGetter<Long>? = null,
setter: FieldSetter<Long>? = null,
name: String? = nextFieldName(),
): Field<Long> {
return Field(value, VarLongValueCodec, getter, setter, name = name ?: nextFieldName())
return Field(value, VarLongValueCodec, getter, setter)
}
@JvmOverloads
@ -256,9 +237,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: Long = 0L,
getter: FieldGetter<Long>? = null,
setter: FieldSetter<Long>? = null,
name: String? = nextFieldName(),
): Field<Long> {
return Field(value, LongValueCodec, getter, setter, name = name ?: nextFieldName())
return Field(value, LongValueCodec, getter, setter)
}
@JvmOverloads
@ -266,9 +247,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: Float = 0f,
getter: FieldGetter<Float>? = null,
setter: FieldSetter<Float>? = null,
name: String? = nextFieldName(),
): Field<Float> {
return Field(value, FloatValueCodec, getter, setter, name = name ?: nextFieldName())
return Field(value, FloatValueCodec, getter, setter)
}
@JvmOverloads
@ -276,9 +257,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: Double = 0.0,
getter: FieldGetter<Double>? = null,
setter: FieldSetter<Double>? = null,
name: String? = nextFieldName(),
): Field<Double> {
return Field(value, DoubleValueCodec, getter, setter, name = name ?: nextFieldName())
return Field(value, DoubleValueCodec, getter, setter)
}
@JvmOverloads
@ -286,9 +267,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: UUID = UUID(0L, 0L),
getter: FieldGetter<UUID>? = null,
setter: FieldSetter<UUID>? = null,
name: String? = nextFieldName(),
): Field<UUID> {
return Field(value, UUIDValueCodec, getter, setter, name = name ?: nextFieldName())
return Field(value, UUIDValueCodec, getter, setter)
}
@JvmOverloads
@ -296,9 +277,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: Int = 0,
getter: FieldGetter<Int>? = null,
setter: FieldSetter<Int>? = null,
name: String? = nextFieldName(),
): Field<Int> {
return Field(value, VarIntValueCodec, getter, setter, name = name ?: nextFieldName())
return Field(value, VarIntValueCodec, getter, setter)
}
@JvmOverloads
@ -306,9 +287,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: String = "",
getter: FieldGetter<String>? = null,
setter: FieldSetter<String>? = null,
name: String? = nextFieldName(),
): Field<String> {
return Field(value, BinaryStringCodec, getter, setter, name = name ?: nextFieldName())
return Field(value, BinaryStringCodec, getter, setter)
}
@JvmOverloads
@ -316,9 +297,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: Int = 0,
getter: FieldGetter<Int>? = null,
setter: FieldSetter<Int>? = null,
name: String? = nextFieldName(),
): Field<Int> {
return Field(value, IntValueCodec, getter, setter, name = name ?: nextFieldName())
return Field(value, IntValueCodec, getter, setter)
}
@JvmOverloads
@ -326,9 +307,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: Decimal = Decimal.ZERO,
getter: FieldGetter<Decimal>? = null,
setter: FieldSetter<Decimal>? = null,
name: String? = nextFieldName(),
): Field<Decimal> {
return Field(value, ImpreciseFractionValueCodec, getter, setter, name = name ?: nextFieldName())
return Field(value, ImpreciseFractionValueCodec, getter, setter)
}
@JvmOverloads
@ -336,9 +317,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: BigDecimal = BigDecimal.ZERO,
getter: FieldGetter<BigDecimal>? = null,
setter: FieldSetter<BigDecimal>? = null,
name: String? = nextFieldName(),
): Field<BigDecimal> {
return Field(value, BigDecimalValueCodec, getter, setter, name = name ?: nextFieldName())
return Field(value, BigDecimalValueCodec, getter, setter)
}
@JvmOverloads
@ -347,9 +328,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: T = type.enumConstants[0],
getter: FieldGetter<T>? = null,
setter: FieldSetter<T>? = null,
name: String? = nextFieldName(),
): Field<T> {
return Field(value, EnumValueCodec.of(type), getter, setter, name = name ?: nextFieldName())
return Field(value, EnumValueCodec.of(type), getter, setter)
}
@JvmOverloads
@ -357,9 +338,9 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
value: T,
getter: FieldGetter<T>? = null,
setter: FieldSetter<T>? = null,
name: String? = nextFieldName(),
): 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
@ -368,17 +349,14 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
getter: FieldGetter<ItemStack>? = null,
setter: FieldSetter<ItemStack>? = null,
observe: Boolean = true,
name: String? = nextFieldName(),
): Field<ItemStack> {
return Field(value, ItemStackValueCodec, getter, setter, isObserver = observe, name = name ?: nextFieldName())
return Field(value, ItemStackValueCodec, getter, setter, isObserver = observe)
}
@JvmOverloads
fun item(
delegate: KMutableProperty0<ItemStack>,
name: String? = nextFieldName(),
): ObservedField<ItemStack> {
return ObservedField(delegate, ItemStackValueCodec, name = name ?: nextFieldName())
return ObservedField(delegate, ItemStackValueCodec)
}
@JvmOverloads
@ -388,7 +366,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
callback: ((changes: Collection<MapChangeset<K, V>>) -> Unit)? = null,
backingMap: MutableMap<K, V> = HashMap(),
observingBackingMap: MutableMap<K, V>? = null,
name: String? = nextFieldName(),
): Map<K, V> {
return Map(
keyCodec = keyCodec,
@ -396,7 +373,6 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
callback = callback,
backingMap = backingMap,
observingBackingMap = observingBackingMap,
name = name ?: nextFieldName(),
)
}
@ -516,36 +492,11 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
}
val stream = FastByteArrayOutputStream()
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)
}
val dataStream = DataOutputStream(stream)
for (field in dirtyFields) {
val id = 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)
stream.writeVarIntLE(field.id)
field.write(dataStream, this)
stream.writeVarIntLE(innerStream.length)
stream.write(innerStream.array, 0, innerStream.length)
}
dirtyFields.clear()
@ -570,15 +521,11 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
}
@Suppress("LeakingThis")
abstract inner class AbstractField<V>(
final override val name: String = nextFieldName(),
) : IField<V> {
var id: Int = fields.size + 1
abstract inner class AbstractField<V> : IField<V> {
val id: Int = fields.size + 1
init {
check(!fields.any { it.name == name }) { "Duplicate field name $name" }
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 setter: FieldSetter<V>? = null,
isObserver: Boolean = false,
name: String = nextFieldName(),
) : AbstractField<V>(name), IMutableField<V> {
) : AbstractField<V>(), IMutableField<V> {
private var remote: V = codec.copy(field)
init {
@ -691,9 +637,8 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
inner class ComputedField<V>(
private val getter: () -> V,
private val codec: IStreamCodec<V>,
name: String = nextFieldName(),
private val observer: (new: V) -> Unit = {}
) : AbstractField<V>(name), IField<V> {
) : AbstractField<V>(), IField<V> {
private var remote: V? = null
private var clientValue: V? = null
private var isDirty = false
@ -750,14 +695,14 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
get() = getter.invoke()
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
getter = field::get
setter = field::set
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.getter = getter
this.setter = setter
@ -806,8 +751,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
private val backingMap: MutableMap<K, V>,
private val observingBackingMap: MutableMap<K, V>? = null,
private val callback: ((changes: Collection<MapChangeset<K, V>>) -> Unit)? = null,
name: String = nextFieldName(),
) : AbstractField<MutableMap<K, V>>(name), IField<MutableMap<K, V>> {
) : AbstractField<MutableMap<K, V>>(), IField<MutableMap<K, V>> {
private var isDirty = false
private var sentAllValues = false
private var isRemote = false
@ -1116,63 +1060,15 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
return values
}
private val idToField = Int2ObjectOpenHashMap<IField<*>>()
private val missingFields = ObjectArraySet<String>()
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)
fun read(stream: InputStream): Int {
var fieldId = stream.readVarIntLE()
var i = 0
val dataStream = DataInputStream(stream)
while (fieldId != 0) {
val field = idToField[fieldId]
val payloadSize = stream.readVarIntLE(sizeLimit)
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)
val field = fields.getOrNull(fieldId - 1) ?: throw IllegalArgumentException("Unknown field ID ${fieldId - 1}")
field.read(dataStream)
fieldId = stream.readVarIntLE()
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 MapActionList = MapAction.values()
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(
version = "1",
version = "2",
name = "player"
) {
fun register() {

View File

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

View File

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

View File

@ -131,32 +131,4 @@ object FieldSynchronizerTests {
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)
}
}
}