Use synchronizers for research/features fields

This commit is contained in:
DBotThePony 2022-09-17 15:14:18 +07:00
parent 97457ab027
commit 4acb362916
Signed by: DBot
GPG Key ID: DCC23B5715498507
5 changed files with 51 additions and 70 deletions

View File

@ -1,31 +1,25 @@
package ru.dbotthepony.mc.otm.android package ru.dbotthepony.mc.otm.android
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraftforge.common.util.INBTSerializable import net.minecraftforge.common.util.INBTSerializable
import net.minecraftforge.event.entity.living.LivingHurtEvent import net.minecraftforge.event.entity.living.LivingHurtEvent
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.core.readNbt
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.set import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.core.writeNbt import ru.dbotthepony.mc.otm.network.FieldSynchronizer
import java.io.DataInputStream
import java.io.InputStream import java.io.InputStream
import java.io.OutputStream
abstract class AndroidFeature(val type: AndroidFeatureType<*>, val android: MatteryPlayerCapability) : INBTSerializable<CompoundTag> { abstract class AndroidFeature(val type: AndroidFeatureType<*>, val android: MatteryPlayerCapability) : INBTSerializable<CompoundTag> {
val entity get() = android.ply val entity get() = android.ply
val synchronizer = FieldSynchronizer()
/** open var level by synchronizer.int(setter = setter@{ value, field, setByRemote ->
* Whenever there are changes to network if (value != field.read()) {
*/ field.write(value)
var isDirty = false applyModifiers()
open var level = 0
set(value) {
if (value != field) {
field = value
applyModifiers()
}
} }
})
open fun tickClient() {} open fun tickClient() {}
open fun tickServer() {} open fun tickServer() {}
@ -33,19 +27,21 @@ abstract class AndroidFeature(val type: AndroidFeatureType<*>, val android: Matt
/** /**
* Called when it is required to network everything again * Called when it is required to network everything again
*/ */
open fun invalidateNetwork() {} open fun invalidateNetwork() {
synchronizer.invalidate()
}
open fun applyModifiers() {} open fun applyModifiers() {}
open fun removeModifiers() {} open fun removeModifiers() {}
open fun onHurt(event: LivingHurtEvent) {} open fun onHurt(event: LivingHurtEvent) {}
open fun writeNetwork(stream: OutputStream) { open fun collectNetworkPayload(): FastByteArrayOutputStream? {
stream.writeNbt(serializeNBT()) return synchronizer.collectNetworkPayload()
} }
open fun readNetwork(stream: InputStream) { open fun applyNetworkPayload(stream: InputStream) {
deserializeNBT(stream.readNbt()) synchronizer.applyNetworkPayload(DataInputStream(stream))
} }
override fun serializeNBT(): CompoundTag { override fun serializeNBT(): CompoundTag {

View File

@ -1,5 +1,6 @@
package ru.dbotthepony.mc.otm.android package ru.dbotthepony.mc.otm.android
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
import net.minecraft.ChatFormatting import net.minecraft.ChatFormatting
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
@ -7,26 +8,23 @@ import net.minecraft.world.item.ItemStack
import net.minecraftforge.common.util.INBTSerializable import net.minecraftforge.common.util.INBTSerializable
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.client.render.SkinElement import ru.dbotthepony.mc.otm.client.render.SkinElement
import ru.dbotthepony.mc.otm.core.readNbt
import ru.dbotthepony.mc.otm.container.set
import ru.dbotthepony.mc.otm.core.set import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.core.writeNbt import ru.dbotthepony.mc.otm.network.FieldSynchronizer
import java.io.DataInputStream
import java.io.InputStream import java.io.InputStream
import java.io.OutputStream
abstract class AndroidResearch(val type: AndroidResearchType<*>, val capability: MatteryPlayerCapability) : INBTSerializable<CompoundTag> { abstract class AndroidResearch(val type: AndroidResearchType<*>, val capability: MatteryPlayerCapability) : INBTSerializable<CompoundTag> {
var isResearched = false val synchronizer = FieldSynchronizer()
protected set
/** var isResearched by synchronizer.bool()
* Whenever there are changes to network protected set
*/
var isDirty = false
/** /**
* Called when it is required to network everything again * Called when it is required to network everything again
*/ */
abstract fun invalidateNetwork() open fun invalidateNetwork() {
synchronizer.invalidate()
}
fun unResearch() { fun unResearch() {
if (!isResearched) { if (!isResearched) {
@ -35,7 +33,6 @@ abstract class AndroidResearch(val type: AndroidResearchType<*>, val capability:
onUnResearch() onUnResearch()
isResearched = false isResearched = false
isDirty = true
} }
abstract fun onUnResearch() abstract fun onUnResearch()
@ -57,12 +54,12 @@ abstract class AndroidResearch(val type: AndroidResearchType<*>, val capability:
*/ */
abstract fun refund(simulate: Boolean): Boolean abstract fun refund(simulate: Boolean): Boolean
open fun writeNetwork(buff: OutputStream) { open fun collectNetworkPayload(): FastByteArrayOutputStream? {
buff.writeNbt(serializeNBT()) return synchronizer.collectNetworkPayload()
} }
open fun readNetwork(buff: InputStream) { open fun applyNetworkPayload(stream: InputStream) {
deserializeNBT(buff.readNbt()) synchronizer.applyNetworkPayload(DataInputStream(stream))
} }
open val canResearch: Boolean get() { open val canResearch: Boolean get() {
@ -146,12 +143,10 @@ abstract class AndroidResearch(val type: AndroidResearchType<*>, val capability:
if (force) { if (force) {
onResearched() onResearched()
isResearched = true isResearched = true
isDirty = true
return true return true
} else if (consumeResearchCost(false)) { } else if (consumeResearchCost(false)) {
onResearched() onResearched()
isResearched = true isResearched = true
isDirty = true
return true return true
} }

View File

@ -193,10 +193,6 @@ class AndroidResearchBuilder(
return object : AndroidResearchType<AndroidResearch>(factory@{ it, capability -> return object : AndroidResearchType<AndroidResearch>(factory@{ it, capability ->
return@factory object : AndroidResearch(it, capability) { return@factory object : AndroidResearch(it, capability) {
override fun invalidateNetwork() {
// NO-OP
}
override fun onUnResearch() { override fun onUnResearch() {
for (feature in features) { for (feature in features) {
val level = oldResearchLevel[feature.feature] val level = oldResearchLevel[feature.feature]

View File

@ -30,7 +30,6 @@ import net.minecraftforge.event.TickEvent
import net.minecraftforge.event.TickEvent.PlayerTickEvent import net.minecraftforge.event.TickEvent.PlayerTickEvent
import net.minecraftforge.event.entity.living.LivingDeathEvent import net.minecraftforge.event.entity.living.LivingDeathEvent
import net.minecraftforge.event.entity.living.LivingDropsEvent import net.minecraftforge.event.entity.living.LivingDropsEvent
import net.minecraftforge.event.entity.living.LivingEvent
import net.minecraftforge.event.entity.living.LivingHurtEvent import net.minecraftforge.event.entity.living.LivingHurtEvent
import net.minecraftforge.event.entity.living.LivingSpawnEvent import net.minecraftforge.event.entity.living.LivingSpawnEvent
import net.minecraftforge.event.entity.player.EntityItemPickupEvent import net.minecraftforge.event.entity.player.EntityItemPickupEvent
@ -279,7 +278,12 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
} }
if (ply is ServerPlayer) { if (ply is ServerPlayer) {
sendNetwork(AndroidFeatureSyncPacket(feature)) feature.invalidateNetwork()
val payload = feature.collectNetworkPayload()
if (payload != null) {
sendNetwork(AndroidFeatureSyncPacket(feature.type, payload, null))
}
} }
return true return true
@ -299,7 +303,12 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
} }
if (ply is ServerPlayer) { if (ply is ServerPlayer) {
sendNetwork(AndroidFeatureSyncPacket(factory)) factory.invalidateNetwork()
val payload = factory.collectNetworkPayload()
if (payload != null) {
sendNetwork(AndroidFeatureSyncPacket(feature, payload, null))
}
} }
return factory return factory
@ -582,12 +591,10 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
synchronizer.invalidate() synchronizer.invalidate()
for (instance in research.values) { for (instance in research.values) {
instance.isDirty = true
instance.invalidateNetwork() instance.invalidateNetwork()
} }
for (feature in features.values) { for (feature in features.values) {
feature.isDirty = true
feature.invalidateNetwork() feature.invalidateNetwork()
} }
} }
@ -609,16 +616,18 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
} }
for (instance in research.values) { for (instance in research.values) {
if (instance.isDirty) { val researchPayload = instance.collectNetworkPayload()
instance.isDirty = false
sendNetwork(AndroidResearchSyncPacket(instance)) if (researchPayload != null) {
sendNetwork(AndroidResearchSyncPacket(instance.type, researchPayload, null))
} }
} }
for (instance in features.values) { for (instance in features.values) {
if (instance.isDirty) { val featurePayload = instance.collectNetworkPayload()
instance.isDirty = false
sendNetwork(AndroidFeatureSyncPacket(instance)) if (featurePayload != null) {
sendNetwork(AndroidFeatureSyncPacket(instance.type, featurePayload, null))
} }
} }

View File

@ -1,6 +1,5 @@
package ru.dbotthepony.mc.otm.network package ru.dbotthepony.mc.otm.network
import it.unimi.dsi.fastutil.bytes.ByteArrayList
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
@ -13,13 +12,9 @@ import ru.dbotthepony.mc.otm.android.AndroidFeature
import ru.dbotthepony.mc.otm.android.AndroidFeatureType import ru.dbotthepony.mc.otm.android.AndroidFeatureType
import ru.dbotthepony.mc.otm.android.AndroidResearch import ru.dbotthepony.mc.otm.android.AndroidResearch
import ru.dbotthepony.mc.otm.android.AndroidResearchType import ru.dbotthepony.mc.otm.android.AndroidResearchType
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.client.MatteryGUI import ru.dbotthepony.mc.otm.client.MatteryGUI
import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.core.readImpreciseFraction
import ru.dbotthepony.mc.otm.core.writeImpreciseFraction
import ru.dbotthepony.mc.otm.menu.AndroidStationMenu import ru.dbotthepony.mc.otm.menu.AndroidStationMenu
import ru.dbotthepony.mc.otm.registry.MRegistry import ru.dbotthepony.mc.otm.registry.MRegistry
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
@ -75,15 +70,7 @@ class AndroidResearchRequestPacket(val type: AndroidResearchType<*>) : MatteryPa
} }
} }
private fun getData(invoke: (stream: OutputStream) -> Unit): FastByteArrayOutputStream {
val stream = FastByteArrayOutputStream()
invoke(stream)
return stream
}
class AndroidResearchSyncPacket(val type: AndroidResearchType<*>, val dataList: FastByteArrayOutputStream?, val dataBytes: ByteArray?) : MatteryPacket { class AndroidResearchSyncPacket(val type: AndroidResearchType<*>, val dataList: FastByteArrayOutputStream?, val dataBytes: ByteArray?) : MatteryPacket {
constructor(feature: AndroidResearch) : this(feature.type, getData(feature::writeNetwork), null)
override fun write(buff: FriendlyByteBuf) { override fun write(buff: FriendlyByteBuf) {
dataList ?: throw NullPointerException("No byte list is present") dataList ?: throw NullPointerException("No byte list is present")
buff.writeInt(MRegistry.ANDROID_RESEARCH.getID(type)) buff.writeInt(MRegistry.ANDROID_RESEARCH.getID(type))
@ -97,7 +84,7 @@ class AndroidResearchSyncPacket(val type: AndroidResearchType<*>, val dataList:
context.get().enqueueWork { context.get().enqueueWork {
val android = minecraft.player?.matteryPlayer ?: return@enqueueWork val android = minecraft.player?.matteryPlayer ?: return@enqueueWork
android.getResearch(type).readNetwork(ByteArrayInputStream(dataBytes)) android.getResearch(type).applyNetworkPayload(ByteArrayInputStream(dataBytes))
} }
} }
@ -112,8 +99,6 @@ class AndroidResearchSyncPacket(val type: AndroidResearchType<*>, val dataList:
} }
class AndroidFeatureSyncPacket(val type: AndroidFeatureType<*>, val dataList: FastByteArrayOutputStream?, val dataBytes: ByteArray?) : MatteryPacket { class AndroidFeatureSyncPacket(val type: AndroidFeatureType<*>, val dataList: FastByteArrayOutputStream?, val dataBytes: ByteArray?) : MatteryPacket {
constructor(feature: AndroidFeature) : this(feature.type, getData(feature::writeNetwork), null)
override fun write(buff: FriendlyByteBuf) { override fun write(buff: FriendlyByteBuf) {
dataList ?: throw NullPointerException("No byte list is present") dataList ?: throw NullPointerException("No byte list is present")
buff.writeInt(MRegistry.ANDROID_FEATURES.getID(type)) buff.writeInt(MRegistry.ANDROID_FEATURES.getID(type))
@ -127,7 +112,7 @@ class AndroidFeatureSyncPacket(val type: AndroidFeatureType<*>, val dataList: Fa
context.get().enqueueWork { context.get().enqueueWork {
val android = minecraft.player?.matteryPlayer ?: return@enqueueWork val android = minecraft.player?.matteryPlayer ?: return@enqueueWork
android.computeIfAbsent(type).readNetwork(ByteArrayInputStream(dataBytes)) android.computeIfAbsent(type).applyNetworkPayload(ByteArrayInputStream(dataBytes))
} }
} }