Move energy counter synchronization to field synchronizer
This commit is contained in:
parent
7ae82eebfc
commit
284e4d404a
@ -1,12 +1,10 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity
|
||||
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.IntTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
@ -18,7 +16,6 @@ import net.minecraftforge.common.capabilities.Capability
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
||||
import net.minecraftforge.common.util.LazyOptional
|
||||
import net.minecraftforge.energy.IEnergyStorage
|
||||
import net.minecraftforge.network.NetworkEvent
|
||||
import net.minecraftforge.network.PacketDistributor
|
||||
import ru.dbotthepony.mc.otm.*
|
||||
import ru.dbotthepony.mc.otm.block.EnergyCounterBlock
|
||||
@ -26,62 +23,17 @@ import ru.dbotthepony.mc.otm.capability.*
|
||||
import ru.dbotthepony.mc.otm.compat.mekanism.Mattery2MekanismEnergyWrapper
|
||||
import ru.dbotthepony.mc.otm.core.*
|
||||
import ru.dbotthepony.mc.otm.menu.EnergyCounterMenu
|
||||
import ru.dbotthepony.mc.otm.network.MatteryPacket
|
||||
import ru.dbotthepony.mc.otm.network.WorldNetworkChannel
|
||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.*
|
||||
import java.util.function.Supplier
|
||||
|
||||
data class EnergyCounterPacket(val pos: BlockPos, val thisTick: ImpreciseFraction, val total: ImpreciseFraction, val index: Int, val value: ImpreciseFraction) : MatteryPacket {
|
||||
override fun write(buff: FriendlyByteBuf) {
|
||||
buff.writeBlockPos(pos)
|
||||
thisTick.write(buff)
|
||||
total.write(buff)
|
||||
buff.writeInt(index)
|
||||
value.write(buff)
|
||||
}
|
||||
|
||||
override fun play(context: Supplier<NetworkEvent.Context>) {
|
||||
context.get().packetHandled = true
|
||||
|
||||
context.get().enqueueWork {
|
||||
val ply = Minecraft.getInstance().player ?: return@enqueueWork
|
||||
val level = ply.level ?: return@enqueueWork
|
||||
val tile = level.getBlockEntity(pos) as? EnergyCounterBlockEntity ?: return@enqueueWork
|
||||
|
||||
tile.lastTick = thisTick
|
||||
tile.passed = total
|
||||
tile[index] = value
|
||||
tile.historyTick = index
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun read(buff: FriendlyByteBuf): EnergyCounterPacket {
|
||||
val pos = buff.readBlockPos()
|
||||
val thisTick = ImpreciseFraction.read(buff)
|
||||
val total = ImpreciseFraction.read(buff)
|
||||
val index = buff.readInt()
|
||||
val value = ImpreciseFraction.read(buff)
|
||||
return EnergyCounterPacket(pos, thisTick, total, index, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryBlockEntity(MBlockEntities.ENERGY_COUNTER, p_155229_, p_155230_) {
|
||||
var passed = ImpreciseFraction.ZERO
|
||||
var passed by synchronizer.fraction()
|
||||
|
||||
private val history = Array(10 * 20) { ImpreciseFraction.ZERO }
|
||||
internal var historyTick = 0
|
||||
|
||||
fun size() = history.size
|
||||
operator fun get(i: Int) = history[i]
|
||||
internal operator fun set(i: Int, value: ImpreciseFraction) {
|
||||
history[i] = value
|
||||
}
|
||||
|
||||
var lastTick = ImpreciseFraction.ZERO
|
||||
var lastTick by synchronizer.fraction()
|
||||
internal set
|
||||
|
||||
var ioLimit: ImpreciseFraction? = null
|
||||
@ -438,24 +390,16 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
|
||||
return super.getCapability(cap, side)
|
||||
}
|
||||
|
||||
private fun distributor(): PacketDistributor.TargetPoint {
|
||||
val x = blockPos.x.toDouble()
|
||||
val y = blockPos.y.toDouble()
|
||||
val z = blockPos.z.toDouble()
|
||||
return PacketDistributor.TargetPoint(x, y, z, 32.0, level!!.dimension())
|
||||
}
|
||||
|
||||
fun tick() {
|
||||
lastTick = history[historyTick]
|
||||
val index = historyTick
|
||||
val accumulated = history[historyTick]
|
||||
historyTick = (historyTick + 1) % history.size
|
||||
history[historyTick] = ImpreciseFraction.ZERO
|
||||
|
||||
WorldNetworkChannel.send(PacketDistributor.NEAR.with(this::distributor), EnergyCounterPacket(blockPos, lastTick, passed, index, accumulated))
|
||||
synchronizeToPlayers()
|
||||
}
|
||||
|
||||
fun clientTick() {
|
||||
historyTick = (historyTick + 1) % history.size
|
||||
history[historyTick] = lastTick
|
||||
passed += lastTick
|
||||
}
|
||||
|
||||
|
@ -23,8 +23,15 @@ import net.minecraft.world.level.Level
|
||||
import net.minecraftforge.common.capabilities.Capability
|
||||
import ru.dbotthepony.mc.otm.core.TextComponent
|
||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
import ru.dbotthepony.mc.otm.core.component1
|
||||
import ru.dbotthepony.mc.otm.core.component2
|
||||
import ru.dbotthepony.mc.otm.core.component3
|
||||
import ru.dbotthepony.mc.otm.core.ifHas
|
||||
import ru.dbotthepony.mc.otm.core.position
|
||||
import ru.dbotthepony.mc.otm.core.set
|
||||
import ru.dbotthepony.mc.otm.network.BlockEntitySyncPacket
|
||||
import ru.dbotthepony.mc.otm.network.FieldSynchronizer
|
||||
import ru.dbotthepony.mc.otm.network.WorldNetworkChannel
|
||||
import ru.dbotthepony.mc.otm.oncePre
|
||||
|
||||
abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: BlockPos, p_155230_: BlockState) : BlockEntity(p_155228_, p_155229_, p_155230_), MenuProvider {
|
||||
@ -67,6 +74,52 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
|
||||
}
|
||||
}
|
||||
|
||||
val synchronizer = FieldSynchronizer()
|
||||
|
||||
init {
|
||||
synchronizer.defaultEndpoint.markUnused()
|
||||
}
|
||||
|
||||
open val synchronizationRadius: Double = 32.0
|
||||
|
||||
// TODO: Optimize, if required
|
||||
fun synchronizeToPlayers() {
|
||||
if (synchronizationRadius <= 0.0 || synchronizer.isEmpty) {
|
||||
return
|
||||
}
|
||||
|
||||
val server = level?.server ?: return
|
||||
|
||||
if (server.playerCount <= 0) {
|
||||
return
|
||||
}
|
||||
|
||||
val (xi, yi, zi) = blockPos
|
||||
val bx = xi + 0.5
|
||||
val by = yi + 0.5
|
||||
val bz = zi + 0.5
|
||||
|
||||
val double = synchronizationRadius * synchronizationRadius
|
||||
|
||||
server.playerList.players.stream().filter {
|
||||
if (!it.isAlive || it.level != level) {
|
||||
return@filter false
|
||||
}
|
||||
|
||||
val (x, y, z) = it.position
|
||||
|
||||
(x - bx) * (x - bx) +
|
||||
(y - by) * (y - by) +
|
||||
(z - bz) * (z - bz) <= double
|
||||
}.forEach {
|
||||
val payload = synchronizer.computeEndpointFor(it).collectNetworkPayload()
|
||||
|
||||
if (payload != null) {
|
||||
WorldNetworkChannel.send(it, BlockEntitySyncPacket(blockPos, payload.array, payload.length))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected open val defaultDisplayName: Component
|
||||
get() = level?.getBlockState(blockPos)?.block?.name ?: TextComponent("null at $blockPos")
|
||||
|
||||
|
@ -353,6 +353,7 @@ abstract class MatteryWorkerBlockEntity<JobType : MatteryWorkerBlockEntity.Job>(
|
||||
fun basicTicker() {
|
||||
batteryChargeLoop()
|
||||
workerLoop()
|
||||
synchronizeToPlayers()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -70,6 +70,10 @@ operator fun Vector3f.component1() = x()
|
||||
operator fun Vector3f.component2() = y()
|
||||
operator fun Vector3f.component3() = z()
|
||||
|
||||
operator fun Vec3i.component1() = x
|
||||
operator fun Vec3i.component2() = y
|
||||
operator fun Vec3i.component3() = z
|
||||
|
||||
operator fun Vector.plus(direction: Vector): Vector = this.add(direction)
|
||||
operator fun Vector.minus(direction: Vector): Vector = this.subtract(direction)
|
||||
operator fun Vector.unaryMinus(): Vector = Vector(-x, -y, -z)
|
||||
|
@ -73,6 +73,12 @@ class FieldSynchronizer {
|
||||
private val fields = ArrayList<IField<*>>()
|
||||
private val observers = LinkedList<IField<*>>()
|
||||
|
||||
val isEmpty: Boolean get() = fields.isEmpty()
|
||||
val isNotEmpty: Boolean get() = fields.isNotEmpty()
|
||||
|
||||
var hasChanges: Boolean = false
|
||||
private set
|
||||
|
||||
fun byte(
|
||||
value: Byte = 0,
|
||||
getter: FieldGetter<Byte>? = null,
|
||||
@ -222,6 +228,8 @@ class FieldSynchronizer {
|
||||
private var lastEndpointsCleanup = System.nanoTime()
|
||||
|
||||
private fun notifyEndpoints(dirtyField: IField<*>) {
|
||||
hasChanges = true
|
||||
|
||||
forEachEndpoint {
|
||||
it.addDirtyField(dirtyField)
|
||||
}
|
||||
@ -267,6 +275,25 @@ class FieldSynchronizer {
|
||||
private val dirtyFields = LinkedList<IField<*>>()
|
||||
private val mapBacklogs = Reference2ObjectOpenHashMap<Map<*, *>, LinkedList<Pair<Any?, (DataOutputStream) -> Unit>>>()
|
||||
|
||||
var unused: Boolean = false
|
||||
private set
|
||||
|
||||
fun markUnused() {
|
||||
require(this === defaultEndpoint) { "This is not a default endpoint" }
|
||||
if (unused) return
|
||||
unused = true
|
||||
mapBacklogs.clear()
|
||||
dirtyFields.clear()
|
||||
|
||||
val iterator = endpoints.listIterator()
|
||||
|
||||
for (value in iterator) {
|
||||
if (value.get() === this) {
|
||||
iterator.remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
for (field in fields) {
|
||||
field.markDirty(this)
|
||||
@ -274,19 +301,27 @@ class FieldSynchronizer {
|
||||
}
|
||||
|
||||
internal fun addDirtyField(field: IField<*>) {
|
||||
if (unused) {
|
||||
return
|
||||
}
|
||||
|
||||
if (field !in dirtyFields) {
|
||||
dirtyFields.addLast(field)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun <K, V> getMapBacklog(map: Map<K, V>): LinkedList<Pair<Any?, (DataOutputStream) -> Unit>> {
|
||||
if (unused) {
|
||||
return LinkedList()
|
||||
}
|
||||
|
||||
return mapBacklogs.computeIfAbsent(map, Reference2ObjectFunction {
|
||||
LinkedList()
|
||||
})
|
||||
}
|
||||
|
||||
fun collectNetworkPayload(): FastByteArrayOutputStream? {
|
||||
if (dirtyFields.isEmpty()) {
|
||||
if (unused || dirtyFields.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
|
||||
@ -566,6 +601,15 @@ class FieldSynchronizer {
|
||||
return
|
||||
}
|
||||
|
||||
if (endpoints.isEmpty()) {
|
||||
val observingBackingMap = observingBackingMap ?: return
|
||||
|
||||
for ((key, value) in backingMap)
|
||||
observingBackingMap[key] = valueCodec.copy(value)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
isDirty = true
|
||||
val backlogs = LinkedList<LinkedList<Pair<Any?, (DataOutputStream) -> Unit>>>()
|
||||
|
||||
@ -621,6 +665,10 @@ class FieldSynchronizer {
|
||||
return
|
||||
}
|
||||
|
||||
if (endpoints.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
observingBackingMap?.clear()
|
||||
|
||||
forEachEndpoint {
|
||||
@ -634,6 +682,8 @@ class FieldSynchronizer {
|
||||
notifyEndpoints(this@Map)
|
||||
isDirty = true
|
||||
}
|
||||
|
||||
hasChanges = true
|
||||
}
|
||||
|
||||
override fun onValueAdded(key: K, value: V) {
|
||||
@ -641,6 +691,10 @@ class FieldSynchronizer {
|
||||
return
|
||||
}
|
||||
|
||||
if (endpoints.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
val valueCopy = valueCodec.copy(value)
|
||||
|
||||
pushBacklog(key) {
|
||||
@ -655,6 +709,8 @@ class FieldSynchronizer {
|
||||
notifyEndpoints(this@Map)
|
||||
isDirty = true
|
||||
}
|
||||
|
||||
hasChanges = true
|
||||
}
|
||||
|
||||
override fun onValueRemoved(key: K, value: V) {
|
||||
@ -662,6 +718,10 @@ class FieldSynchronizer {
|
||||
return
|
||||
}
|
||||
|
||||
if (endpoints.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
val keyCopy = keyCodec.copy(key)
|
||||
|
||||
pushBacklog(key) {
|
||||
@ -675,6 +735,8 @@ class FieldSynchronizer {
|
||||
notifyEndpoints(this@Map)
|
||||
isDirty = true
|
||||
}
|
||||
|
||||
hasChanges = true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,15 +1,48 @@
|
||||
package ru.dbotthepony.mc.otm.network
|
||||
|
||||
import it.unimi.dsi.fastutil.io.FastByteArrayInputStream
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraftforge.network.NetworkDirection
|
||||
import net.minecraftforge.network.NetworkEvent
|
||||
import ru.dbotthepony.mc.otm.android.feature.ItemEntityDataPacket
|
||||
import ru.dbotthepony.mc.otm.block.entity.EnergyCounterPacket
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity
|
||||
import ru.dbotthepony.mc.otm.client.minecraft
|
||||
import java.util.function.Supplier
|
||||
|
||||
class BlockEntitySyncPacket(val position: BlockPos, val buffer: ByteArray, val validBytes: Int) : MatteryPacket {
|
||||
override fun write(buff: FriendlyByteBuf) {
|
||||
buff.writeBlockPos(position)
|
||||
buff.writeBytes(buffer, 0, validBytes)
|
||||
}
|
||||
|
||||
override fun play(context: Supplier<NetworkEvent.Context>) {
|
||||
context.packetHandled = true
|
||||
|
||||
context.enqueueWork {
|
||||
val level = minecraft.player?.level ?: return@enqueueWork
|
||||
val blockEntity = level.getBlockEntity(position) as? MatteryBlockEntity ?: return@enqueueWork
|
||||
blockEntity.synchronizer.applyNetworkPayload(FastByteArrayInputStream(buffer, 0, validBytes))
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun read(buff: FriendlyByteBuf): BlockEntitySyncPacket {
|
||||
val position = buff.readBlockPos()
|
||||
val size = buff.readableBytes()
|
||||
val array = ByteArray(size)
|
||||
buff.readBytes(array)
|
||||
return BlockEntitySyncPacket(position, array, size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object WorldNetworkChannel : MatteryNetworkChannel(
|
||||
version = "1",
|
||||
version = "2",
|
||||
name = "world"
|
||||
) {
|
||||
fun register() {
|
||||
add(EnergyCounterPacket::class.java, EnergyCounterPacket.Companion::read, NetworkDirection.PLAY_TO_CLIENT)
|
||||
add(BlockEntitySyncPacket::class.java, BlockEntitySyncPacket.Companion::read, NetworkDirection.PLAY_TO_CLIENT)
|
||||
add(ItemEntityDataPacket::class.java, ItemEntityDataPacket.Companion::read, NetworkDirection.PLAY_TO_CLIENT)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user