diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidFeature.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidFeature.kt index f78e9bb32..80decd149 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidFeature.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidFeature.kt @@ -41,7 +41,7 @@ abstract class AndroidFeature(val type: AndroidFeatureType<*>, val android: Matt } open fun applyNetworkPayload(stream: InputStream) { - synchronizer.applyNetworkPayload(DataInputStream(stream)) + synchronizer.applyNetworkPayload(stream) } override fun serializeNBT(): CompoundTag { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearch.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearch.kt index 2175b6884..6e4ecd26e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearch.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/AndroidResearch.kt @@ -192,7 +192,7 @@ class AndroidResearch(val type: AndroidResearchType, val capability: MatteryPlay } fun applyNetworkPayload(stream: InputStream) { - synchronizer.applyNetworkPayload(DataInputStream(stream)) + synchronizer.applyNetworkPayload(stream) } val canResearch: Boolean get() { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt index 1bbeb51dc..def23507f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt @@ -75,9 +75,21 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial } } + /** + * For fields that need to be synchronized only to owning player + */ val synchronizer = FieldSynchronizer() - var hasExoSuit by synchronizer.bool() + /** + * For fields that need to be synchronized to everyone + */ + val publicSynchronizer = FieldSynchronizer() + + init { + publicSynchronizer.defaultEndpoint.markUnused() + } + + var hasExoSuit by publicSynchronizer.bool() private val exoSuitSlotCountModifiersMap: MutableMap by synchronizer.Map( keyCodec = UUIDValueCodec, @@ -99,7 +111,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial } }, backingMap = this.exoSuitSlotCountModifiersMap) - var exoSuitSlotCount by synchronizer.int(setter = setter@{ value, access, _ -> + var exoSuitSlotCount by publicSynchronizer.int(setter = setter@{ value, access, _ -> require(value >= 0) { "Invalid slot count $value" } if (value != access.read()) { @@ -113,7 +125,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial private set(value) { _exoSuitMenu = null - @Suppress("SENSELESS_COMPARISON") + @Suppress("SENSELESS_COMPARISON") // false positive - fields of player can easily be nulls, despite annotations saying otherwise if (ply.containerMenu != null && (ply !is ServerPlayer || ply.connection != null)) { ply.closeContainer() } @@ -131,7 +143,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial field = value } - var isExoSuitCraftingUpgraded by synchronizer.bool(setter = setter@{ value, access, _ -> + var isExoSuitCraftingUpgraded by publicSynchronizer.bool(setter = setter@{ value, access, _ -> if (value != access.read()) { access.write(value) _exoSuitMenu = null @@ -177,8 +189,8 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial var ticksIExist = 0 private set - var willBecomeAndroid by synchronizer.bool() - var isAndroid by synchronizer.bool() + var willBecomeAndroid by publicSynchronizer.bool() + var isAndroid by publicSynchronizer.bool() val androidEnergy = AndroidPowerSource(ply, synchronizer, ServerConfig.ANDROID_MAX_ENERGY, ServerConfig.ANDROID_MAX_ENERGY) @@ -636,6 +648,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial if (invalidateNetworkIn > 0 && --invalidateNetworkIn == 0) { synchronizer.invalidate() + publicSynchronizer.invalidate() for (instance in research.values) { instance.invalidateNetwork() @@ -655,7 +668,16 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial val payload = synchronizer.collectNetworkPayload() if (payload != null) { - MatteryPlayerNetworkChannel.send(ply, MatteryPlayerFieldPacket(payload)) + MatteryPlayerNetworkChannel.send(ply, MatteryPlayerFieldPacket(payload, false)) + } + + for (ply in MINECRAFT_SERVER.playerList.players) { + val endpoint = publicSynchronizer.computeEndpointFor(ply) + val payload2 = endpoint.collectNetworkPayload() + + if (payload2 != null) { + MatteryPlayerNetworkChannel.send(ply, MatteryPlayerFieldPacket(payload2, true, this.ply.uuid)) + } } if (networkQueue.size != 0) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerNetworkChannel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerNetworkChannel.kt index 40352588e..dfa4a4653 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerNetworkChannel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerNetworkChannel.kt @@ -22,6 +22,7 @@ import ru.dbotthepony.mc.otm.android.AndroidResearchType import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature import ru.dbotthepony.mc.otm.android.feature.TriggerJumpBoostPacket import ru.dbotthepony.mc.otm.android.feature.TriggerShockwavePacket +import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.client.MatteryGUI import ru.dbotthepony.mc.otm.client.minecraft @@ -35,27 +36,51 @@ import ru.dbotthepony.mc.otm.menu.ExoSuitInventoryMenu import ru.dbotthepony.mc.otm.registry.AndroidFeatures import ru.dbotthepony.mc.otm.registry.MRegistry import java.io.ByteArrayInputStream +import java.util.UUID import java.util.function.Supplier -class MatteryPlayerFieldPacket(val bytes: ByteArray, val length: Int) : MatteryPacket { - constructor(stream: FastByteArrayOutputStream) : this(stream.array, stream.length) +class MatteryPlayerFieldPacket(val bytes: ByteArray, val length: Int, val isPublic: Boolean, val target: UUID? = null) : MatteryPacket { + constructor(stream: FastByteArrayOutputStream, isPublic: Boolean, target: UUID? = null) : this(stream.array, stream.length, isPublic, target) override fun write(buff: FriendlyByteBuf) { + buff.writeBoolean(target != null) + + if (target != null) + buff.writeUUID(target) + + buff.writeBoolean(isPublic) buff.writeBytes(bytes, 0, length) } override fun play(context: Supplier) { context.packetHandled = true context.get().enqueueWork { - val player = minecraft.player?.matteryPlayer ?: return@enqueueWork - player.synchronizer.applyNetworkPayload(ByteArrayInputStream(bytes, 0, length)) + val player: MatteryPlayerCapability + + if (target != null) { + player = minecraft.level?.players()?.firstOrNull { it.uuid == target }?.matteryPlayer ?: return@enqueueWork + } else { + player = minecraft.player?.matteryPlayer ?: return@enqueueWork + } + + if (isPublic) { + player.publicSynchronizer.applyNetworkPayload(ByteArrayInputStream(bytes, 0, length)) + } else { + player.synchronizer.applyNetworkPayload(ByteArrayInputStream(bytes, 0, length)) + } } } companion object { fun read(buff: FriendlyByteBuf): MatteryPlayerFieldPacket { + val target = if (buff.readBoolean()) + buff.readUUID() + else + null + + val isPublic = buff.readBoolean() val readable = buff.readableBytes() - return MatteryPlayerFieldPacket(ByteArray(readable).also(buff::readBytes), readable) + return MatteryPlayerFieldPacket(ByteArray(readable).also(buff::readBytes), readable, isPublic, target) } } }