parent
1b0fc4bf2e
commit
8f6af0061a
@ -141,7 +141,6 @@ public final class OverdriveThatMatters {
|
|||||||
EVENT_BUS.addListener(EventPriority.NORMAL, AndroidResearchManager.INSTANCE::syncEvent);
|
EVENT_BUS.addListener(EventPriority.NORMAL, AndroidResearchManager.INSTANCE::syncEvent);
|
||||||
|
|
||||||
EVENT_BUS.addListener(EventPriority.NORMAL, SynchronizedBlockEntity.Companion::onServerStopping);
|
EVENT_BUS.addListener(EventPriority.NORMAL, SynchronizedBlockEntity.Companion::onServerStopping);
|
||||||
EVENT_BUS.addListener(EventPriority.NORMAL, SynchronizedBlockEntity.Companion::onServerStarting);
|
|
||||||
EVENT_BUS.addListener(EventPriority.NORMAL, SynchronizedBlockEntity.Companion::onWatch);
|
EVENT_BUS.addListener(EventPriority.NORMAL, SynchronizedBlockEntity.Companion::onWatch);
|
||||||
EVENT_BUS.addListener(EventPriority.NORMAL, SynchronizedBlockEntity.Companion::onForget);
|
EVENT_BUS.addListener(EventPriority.NORMAL, SynchronizedBlockEntity.Companion::onForget);
|
||||||
EVENT_BUS.addListener(EventPriority.NORMAL, SynchronizedBlockEntity.Companion::playerDisconnected);
|
EVENT_BUS.addListener(EventPriority.NORMAL, SynchronizedBlockEntity.Companion::playerDisconnected);
|
||||||
|
@ -301,8 +301,6 @@ class BatteryBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matte
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun tick() {
|
fun tick() {
|
||||||
synchronizeToPlayers()
|
|
||||||
|
|
||||||
if (isBlockedByRedstone)
|
if (isBlockedByRedstone)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -394,7 +394,6 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat
|
|||||||
lastTick = history[historyTick]
|
lastTick = history[historyTick]
|
||||||
historyTick = (historyTick + 1) % history.size
|
historyTick = (historyTick + 1) % history.size
|
||||||
history[historyTick] = ImpreciseFraction.ZERO
|
history[historyTick] = ImpreciseFraction.ZERO
|
||||||
synchronizeToPlayers()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clientTick() {
|
fun clientTick() {
|
||||||
|
@ -353,7 +353,6 @@ abstract class MatteryWorkerBlockEntity<JobType : MatteryWorkerBlockEntity.Job>(
|
|||||||
fun basicTicker() {
|
fun basicTicker() {
|
||||||
batteryChargeLoop()
|
batteryChargeLoop()
|
||||||
workerLoop()
|
workerLoop()
|
||||||
synchronizeToPlayers()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -19,6 +19,8 @@ import net.minecraftforge.event.level.ChunkWatchEvent
|
|||||||
import net.minecraftforge.event.server.ServerStartingEvent
|
import net.minecraftforge.event.server.ServerStartingEvent
|
||||||
import net.minecraftforge.event.server.ServerStoppingEvent
|
import net.minecraftforge.event.server.ServerStoppingEvent
|
||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
|
import ru.dbotthepony.mc.otm.NULLABLE_MINECRAFT_SERVER
|
||||||
|
import ru.dbotthepony.mc.otm.SERVER_IS_LIVE
|
||||||
import ru.dbotthepony.mc.otm.core.component1
|
import ru.dbotthepony.mc.otm.core.component1
|
||||||
import ru.dbotthepony.mc.otm.core.component2
|
import ru.dbotthepony.mc.otm.core.component2
|
||||||
import ru.dbotthepony.mc.otm.core.component3
|
import ru.dbotthepony.mc.otm.core.component3
|
||||||
@ -26,12 +28,13 @@ import ru.dbotthepony.mc.otm.core.position
|
|||||||
import ru.dbotthepony.mc.otm.network.BlockEntitySyncPacket
|
import ru.dbotthepony.mc.otm.network.BlockEntitySyncPacket
|
||||||
import ru.dbotthepony.mc.otm.network.FieldSynchronizer
|
import ru.dbotthepony.mc.otm.network.FieldSynchronizer
|
||||||
import ru.dbotthepony.mc.otm.network.WorldNetworkChannel
|
import ru.dbotthepony.mc.otm.network.WorldNetworkChannel
|
||||||
|
import ru.dbotthepony.mc.otm.onceServer
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
import java.util.LinkedList
|
import java.util.LinkedList
|
||||||
import java.util.WeakHashMap
|
import java.util.WeakHashMap
|
||||||
|
|
||||||
private data class Subscribers(
|
private data class Subscribers(
|
||||||
val blockEntities: LinkedList<WeakReference<BlockEntity>> = LinkedList(),
|
val blockEntities: LinkedList<WeakReference<SynchronizedBlockEntity>> = LinkedList(),
|
||||||
val players: LinkedList<ServerPlayer> = LinkedList(),
|
val players: LinkedList<ServerPlayer> = LinkedList(),
|
||||||
val level: WeakReference<Level>,
|
val level: WeakReference<Level>,
|
||||||
val chunkPos: Long,
|
val chunkPos: Long,
|
||||||
@ -47,18 +50,28 @@ private data class Subscribers(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun subscribe(blockEntity: BlockEntity) {
|
fun subscribe(blockEntity: SynchronizedBlockEntity) {
|
||||||
for (value in blockEntities) {
|
val iterator = blockEntities.listIterator()
|
||||||
if (value.get() === blockEntity) {
|
|
||||||
|
for (value in iterator) {
|
||||||
|
val ref = value.get()
|
||||||
|
|
||||||
|
if (ref === blockEntity) {
|
||||||
return
|
return
|
||||||
|
} else if (ref == null) {
|
||||||
|
iterator.remove()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
blockEntities.add(WeakReference(blockEntity))
|
blockEntities.add(WeakReference(blockEntity))
|
||||||
changeset++
|
changeset++
|
||||||
|
|
||||||
|
onceServer {
|
||||||
|
blockEntity.synchronizeToPlayers()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun unsubscribe(blockEntity: BlockEntity): Boolean {
|
fun unsubscribe(blockEntity: SynchronizedBlockEntity): Boolean {
|
||||||
val listIterator = blockEntities.listIterator()
|
val listIterator = blockEntities.listIterator()
|
||||||
|
|
||||||
for (value in listIterator) {
|
for (value in listIterator) {
|
||||||
@ -88,18 +101,39 @@ private data class Subscribers(
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract class SynchronizedBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: BlockPos, p_155230_: BlockState) : BlockEntity(p_155228_, p_155229_, p_155230_) {
|
abstract class SynchronizedBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: BlockPos, p_155230_: BlockState) : BlockEntity(p_155228_, p_155229_, p_155230_) {
|
||||||
val synchronizer = FieldSynchronizer()
|
val synchronizer = FieldSynchronizer {
|
||||||
|
if (!isRemoved && level?.isClientSide == false) {
|
||||||
|
onceServer {
|
||||||
|
synchronizeToPlayers(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
synchronizer.defaultEndpoint.markUnused()
|
synchronizer.defaultEndpoint.markUnused()
|
||||||
}
|
}
|
||||||
|
|
||||||
open val synchronizationRadius: Double = 32.0
|
|
||||||
|
|
||||||
override fun setLevel(p_155231_: Level) {
|
override fun setLevel(p_155231_: Level) {
|
||||||
super.setLevel(p_155231_)
|
super.setLevel(p_155231_)
|
||||||
unsubscribe()
|
unsubscribe()
|
||||||
_subCache = null
|
_subCache = null
|
||||||
|
|
||||||
|
if (!p_155231_.isClientSide) {
|
||||||
|
subscribe()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setRemoved() {
|
||||||
|
super.setRemoved()
|
||||||
|
unsubscribe()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearRemoved() {
|
||||||
|
super.clearRemoved()
|
||||||
|
|
||||||
|
if (level?.isClientSide == false) {
|
||||||
|
subscribe()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var _subCache: Subscribers? = null
|
private var _subCache: Subscribers? = null
|
||||||
@ -119,6 +153,8 @@ abstract class SynchronizedBlockEntity(p_155228_: BlockEntityType<*>, p_155229_:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun subscribe(): Subscribers {
|
private fun subscribe(): Subscribers {
|
||||||
|
val level = level
|
||||||
|
check(level is ServerLevel) { "Invalid realm" }
|
||||||
unsubscribe()
|
unsubscribe()
|
||||||
val subs = playerMap.computeIfAbsent(level) { Long2ObjectAVLTreeMap() }.computeIfAbsent(ChunkPos(blockPos).toLong(), Long2ObjectFunction { Subscribers(level = WeakReference(level), chunkPos = ChunkPos(blockPos).toLong()) })
|
val subs = playerMap.computeIfAbsent(level) { Long2ObjectAVLTreeMap() }.computeIfAbsent(ChunkPos(blockPos).toLong(), Long2ObjectFunction { Subscribers(level = WeakReference(level), chunkPos = ChunkPos(blockPos).toLong()) })
|
||||||
subs.subscribe(this)
|
subs.subscribe(this)
|
||||||
@ -130,7 +166,12 @@ abstract class SynchronizedBlockEntity(p_155228_: BlockEntityType<*>, p_155229_:
|
|||||||
private var lastSubscriptionChangeset = -1
|
private var lastSubscriptionChangeset = -1
|
||||||
|
|
||||||
fun synchronizeToPlayers() {
|
fun synchronizeToPlayers() {
|
||||||
if (synchronizationRadius <= 0.0 || synchronizer.isEmpty) {
|
synchronizeToPlayers(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun synchronizeToPlayers(callbedBySynchronizer: Boolean) {
|
||||||
|
if (synchronizer.isEmpty || isRemoved) {
|
||||||
|
if (callbedBySynchronizer) synchronizer.markClean()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,35 +182,21 @@ abstract class SynchronizedBlockEntity(p_155228_: BlockEntityType<*>, p_155229_:
|
|||||||
val subscription = subscription
|
val subscription = subscription
|
||||||
|
|
||||||
if (subscription.players.isEmpty() || lastSubscriptionChangeset == subscription.changeset && !synchronizer.hasChanges) {
|
if (subscription.players.isEmpty() || lastSubscriptionChangeset == subscription.changeset && !synchronizer.hasChanges) {
|
||||||
|
if (callbedBySynchronizer) synchronizer.markClean()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
lastSubscriptionChangeset = subscription.changeset
|
lastSubscriptionChangeset = subscription.changeset
|
||||||
|
|
||||||
val (xi, yi, zi) = blockPos
|
for (player in subscription.players) {
|
||||||
val bx = xi + 0.5
|
val payload = synchronizer.computeEndpointFor(player).collectNetworkPayload()
|
||||||
val by = yi + 0.5
|
|
||||||
val bz = zi + 0.5
|
|
||||||
|
|
||||||
val double = synchronizationRadius * synchronizationRadius
|
|
||||||
|
|
||||||
subscription.players.stream().filter {
|
|
||||||
if (!it.isAlive) {
|
|
||||||
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) {
|
if (payload != null) {
|
||||||
WorldNetworkChannel.send(it, BlockEntitySyncPacket(blockPos, payload.array, payload.length))
|
WorldNetworkChannel.send(player, BlockEntitySyncPacket(blockPos, payload.array, payload.length))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
synchronizer.markClean()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -187,16 +214,12 @@ abstract class SynchronizedBlockEntity(p_155228_: BlockEntityType<*>, p_155229_:
|
|||||||
* [net.minecraft.server.level.ChunkMap.getPlayers], which is not something we want
|
* [net.minecraft.server.level.ChunkMap.getPlayers], which is not something we want
|
||||||
*/
|
*/
|
||||||
companion object {
|
companion object {
|
||||||
private val playerMap = WeakHashMap<Level, Long2ObjectAVLTreeMap<Subscribers>>()
|
private val playerMap = WeakHashMap<ServerLevel, Long2ObjectAVLTreeMap<Subscribers>>()
|
||||||
|
|
||||||
fun onServerStopping(event: ServerStoppingEvent) {
|
fun onServerStopping(event: ServerStoppingEvent) {
|
||||||
playerMap.clear()
|
playerMap.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onServerStarting(event: ServerStartingEvent) {
|
|
||||||
playerMap.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onWatch(event: ChunkWatchEvent.Watch) {
|
fun onWatch(event: ChunkWatchEvent.Watch) {
|
||||||
playerMap.computeIfAbsent(event.level) { Long2ObjectAVLTreeMap() }.computeIfAbsent(event.pos.toLong(), Long2ObjectFunction { Subscribers(level = WeakReference(event.level), chunkPos = event.pos.toLong()) }).let {
|
playerMap.computeIfAbsent(event.level) { Long2ObjectAVLTreeMap() }.computeIfAbsent(event.pos.toLong(), Long2ObjectFunction { Subscribers(level = WeakReference(event.level), chunkPos = event.pos.toLong()) }).let {
|
||||||
val (blocks, players) = it
|
val (blocks, players) = it
|
||||||
@ -204,6 +227,22 @@ abstract class SynchronizedBlockEntity(p_155228_: BlockEntityType<*>, p_155229_:
|
|||||||
if (event.player !in players) {
|
if (event.player !in players) {
|
||||||
players.add(event.player)
|
players.add(event.player)
|
||||||
it.changeset++
|
it.changeset++
|
||||||
|
|
||||||
|
onceServer(20) {
|
||||||
|
if (!event.player.hasDisconnected()) {
|
||||||
|
val iterator = blocks.listIterator()
|
||||||
|
|
||||||
|
for (block in iterator) {
|
||||||
|
val deref = block.get()
|
||||||
|
|
||||||
|
if (deref == null) {
|
||||||
|
iterator.remove()
|
||||||
|
} else {
|
||||||
|
deref.synchronizeToPlayers(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -216,6 +255,18 @@ abstract class SynchronizedBlockEntity(p_155228_: BlockEntityType<*>, p_155229_:
|
|||||||
playerMap.get(event.level)?.remove(event.pos.toLong())
|
playerMap.get(event.level)?.remove(event.pos.toLong())
|
||||||
} else {
|
} else {
|
||||||
subs.changeset++
|
subs.changeset++
|
||||||
|
|
||||||
|
val iterator = subs.blockEntities.listIterator()
|
||||||
|
|
||||||
|
for (block in iterator) {
|
||||||
|
val deref = block.get()
|
||||||
|
|
||||||
|
if (deref == null) {
|
||||||
|
iterator.remove()
|
||||||
|
} else {
|
||||||
|
deref.synchronizer.removeEndpointFor(event.player)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -167,8 +167,6 @@ class BlackHoleBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Synchro
|
|||||||
nbt["spin_direction"] = spinDirection
|
nbt["spin_direction"] = spinDirection
|
||||||
}
|
}
|
||||||
|
|
||||||
override val synchronizationRadius: Double = 256.0
|
|
||||||
|
|
||||||
override fun load(tag: CompoundTag) {
|
override fun load(tag: CompoundTag) {
|
||||||
super.load(tag)
|
super.load(tag)
|
||||||
mass = tag.mapIf("mass", ImpreciseFraction::deserializeNBT) ?: BASELINE_MASS
|
mass = tag.mapIf("mass", ImpreciseFraction::deserializeNBT) ?: BASELINE_MASS
|
||||||
@ -223,8 +221,6 @@ class BlackHoleBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Synchro
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun tick() {
|
fun tick() {
|
||||||
synchronizeToPlayers()
|
|
||||||
|
|
||||||
sleepTicks--
|
sleepTicks--
|
||||||
if (sleepTicks > 0) return
|
if (sleepTicks > 0) return
|
||||||
val level = level as? ServerLevel ?: return
|
val level = level as? ServerLevel ?: return
|
||||||
|
@ -27,14 +27,6 @@ class MatterCapacitorBankBlock : RotatableMatteryBlock(), EntityBlock {
|
|||||||
return MatterCapacitorBankBlockEntity(blockPos, blockState)
|
return MatterCapacitorBankBlockEntity(blockPos, blockState)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T : BlockEntity> getTicker(
|
|
||||||
p_153212_: Level,
|
|
||||||
p_153213_: BlockState,
|
|
||||||
p_153214_: BlockEntityType<T>
|
|
||||||
): BlockEntityTicker<T>? {
|
|
||||||
return SynchronizedBlockEntity::synchronizeToPlayers.blockServerTicker(p_153212_, MBlockEntities.MATTER_CAPACITOR_BANK, p_153214_)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getStateForPlacement(context: BlockPlaceContext): BlockState? {
|
override fun getStateForPlacement(context: BlockPlaceContext): BlockState? {
|
||||||
var state = super.getStateForPlacement(context) ?: return null
|
var state = super.getStateForPlacement(context) ?: return null
|
||||||
|
|
||||||
|
@ -69,7 +69,10 @@ enum class MapAction {
|
|||||||
CLEAR, ADD, REMOVE
|
CLEAR, ADD, REMOVE
|
||||||
}
|
}
|
||||||
|
|
||||||
class FieldSynchronizer {
|
class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCallback: Boolean) {
|
||||||
|
constructor() : this(Runnable {}, false)
|
||||||
|
constructor(callback: Runnable) : this(callback, false)
|
||||||
|
|
||||||
private val fields = ArrayList<IField<*>>()
|
private val fields = ArrayList<IField<*>>()
|
||||||
private val observers = LinkedList<IField<*>>()
|
private val observers = LinkedList<IField<*>>()
|
||||||
|
|
||||||
@ -77,7 +80,23 @@ class FieldSynchronizer {
|
|||||||
val isNotEmpty: Boolean get() = fields.isNotEmpty()
|
val isNotEmpty: Boolean get() = fields.isNotEmpty()
|
||||||
|
|
||||||
var hasChanges: Boolean = false
|
var hasChanges: Boolean = false
|
||||||
private set
|
private set(value) {
|
||||||
|
if (value != field) {
|
||||||
|
field = value
|
||||||
|
|
||||||
|
if (value && !alwaysCallCallback) {
|
||||||
|
callback.run()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alwaysCallCallback && value) {
|
||||||
|
callback.run()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun markClean() {
|
||||||
|
hasChanges = false
|
||||||
|
}
|
||||||
|
|
||||||
fun byte(
|
fun byte(
|
||||||
value: Byte = 0,
|
value: Byte = 0,
|
||||||
@ -345,6 +364,10 @@ class FieldSynchronizer {
|
|||||||
return boundEndpoints.computeIfAbsent(obj) { Endpoint() }
|
return boundEndpoints.computeIfAbsent(obj) { Endpoint() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun removeEndpointFor(obj: Any): Endpoint? {
|
||||||
|
return boundEndpoints.remove(obj)
|
||||||
|
}
|
||||||
|
|
||||||
fun endpointFor(obj: Any): Endpoint? {
|
fun endpointFor(obj: Any): Endpoint? {
|
||||||
return boundEndpoints[obj]
|
return boundEndpoints[obj]
|
||||||
}
|
}
|
||||||
@ -820,8 +843,11 @@ class FieldSynchronizer {
|
|||||||
* [defaultEndpoint]#collectNetworkPayload
|
* [defaultEndpoint]#collectNetworkPayload
|
||||||
*/
|
*/
|
||||||
fun collectNetworkPayload(): FastByteArrayOutputStream? {
|
fun collectNetworkPayload(): FastByteArrayOutputStream? {
|
||||||
|
check(!defaultEndpoint.unused) { "Default endpoint is not used" }
|
||||||
observe()
|
observe()
|
||||||
return defaultEndpoint.collectNetworkPayload()
|
val values = defaultEndpoint.collectNetworkPayload()
|
||||||
|
markClean()
|
||||||
|
return values
|
||||||
}
|
}
|
||||||
|
|
||||||
fun applyNetworkPayload(stream: DataInputStream): Int {
|
fun applyNetworkPayload(stream: DataInputStream): Int {
|
||||||
|
Loading…
Reference in New Issue
Block a user