reduced network bill by 99.99999% trust

This commit is contained in:
2026-04-28 17:57:48 +03:00
parent 9ac53a0f0e
commit 02114fc02a
9 changed files with 119 additions and 15 deletions

View File

@@ -111,6 +111,19 @@ object NeoComputers {
}
}
})
NetworkManager.registerReceiver(NetworkManager.c2s(),NodeSynchronizer.DeviceBlockStateRequest.TYPE, NodeSynchronizer.DeviceBlockStateRequest.CODEC, {
packet, ctx ->
val player = ctx.player
val level = player.level()
val dist = packet.blockPos.center.distanceTo(player.position())
if(player is ServerPlayer && dist <= NodeSynchronizer.MAX_STATE_DISTANCE_ALLOWED) {
val ent = level.getBlockEntity(packet.blockPos)
if(ent is DeviceBlockEntity) {
ent.sendStateToPlayer(player)
}
}
})
}
// we have to do this because the datagen task runs in the physical server

View File

@@ -2,10 +2,15 @@ package org.neoflock.neocomputers.block
import dev.architectury.networking.NetworkManager
import io.netty.buffer.Unpooled
import net.minecraft.client.Minecraft
import net.minecraft.client.multiplayer.ClientLevel
import net.minecraft.core.BlockPos
import net.minecraft.core.Direction
import net.minecraft.core.HolderLookup
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.EntityBlock
@@ -27,6 +32,7 @@ abstract class SingleDeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos,
abstract class DeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state: BlockState): BlockEntity(type, pos, state) {
val connetionsInDir = MutableList<DeviceNode?>(Direction.entries.size) { null }
var alreadySetup = false
var receivedServerState = false
abstract fun getDeviceNodes(): List<DeviceNode>
@@ -36,6 +42,7 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state:
abstract fun getNodeFromSide(directionToRequester: Direction): DeviceNode?
open fun processCommits(commits: Iterable<FriendlyByteBuf>) {
receivedServerState = true
val devs = getDeviceNodes()
for (buf in commits) {
val idx = buf.readVarInt()
@@ -89,32 +96,71 @@ abstract class DeviceBlockEntity(type: BlockEntityType<*>, pos: BlockPos, state:
}
open fun sendCommitsToClient(level: Level) {
if(level is ServerLevel) {
// synchronization!
val commits = mutableListOf<FriendlyByteBuf>()
val devs = getDeviceNodes()
for((i, dev) in devs.withIndex()) {
// TODO: use dev.outOfSync to only set commits if something changed, and allow client to request the commits (securely)
if(level !is ServerLevel) return
// synchronization!
val commits = mutableListOf<FriendlyByteBuf>()
val devs = getDeviceNodes()
for((i, dev) in devs.withIndex()) {
if(dev.outOfSync) {
dev.outOfSync = false
val buf = FriendlyByteBuf(Unpooled.buffer())
buf.writeVarInt(i)
dev.writeFullStateCommit(buf)
commits.addLast(buf)
}
if(commits.isNotEmpty()) {
level.players().forEach {
val dist = it.position().distanceTo(blockPos.center)
if(dist < 100) NetworkManager.sendToPlayer(it, NodeSynchronizer.DeviceBlockStatePayload(blockPos, commits))
}
}
if(commits.isNotEmpty()) {
level.players().forEach {
val dist = it.position().distanceTo(blockPos.center)
if(dist < 100) NetworkManager.sendToPlayer(it, NodeSynchronizer.DeviceBlockStatePayload(blockPos, commits))
}
}
}
open fun sendStateToPlayer(player: ServerPlayer) {
val world = level!!
if(world !is ServerLevel) return
// synchronization!
val commits = mutableListOf<FriendlyByteBuf>()
val devs = getDeviceNodes()
for((i, dev) in devs.withIndex()) {
val buf = FriendlyByteBuf(Unpooled.buffer())
buf.writeVarInt(i)
dev.writeFullStateCommit(buf)
commits.addLast(buf)
}
if(commits.isNotEmpty()) {
world.players().forEach {
val dist = it.position().distanceTo(blockPos.center)
if(dist <= NodeSynchronizer.MAX_STATE_DISTANCE_ALLOWED) NetworkManager.sendToPlayer(it, NodeSynchronizer.DeviceBlockStatePayload(blockPos, commits))
}
}
}
open fun requestServerState() {
// no point
if(receivedServerState) return
// we're the server bro :sob:
if(level?.isClientSide != true) return
val player = Minecraft.getInstance().player ?: return
// we assume the player will just reject, so we save on bandwidth
if(player.position().distanceTo(blockPos.center) > NodeSynchronizer.MAX_STATE_DISTANCE_ALLOWED) return
NetworkManager.sendToServer(NodeSynchronizer.DeviceBlockStateRequest(blockPos))
}
override fun setRemoved() {
super.setRemoved()
alreadySetup = false
Networking.removeNodes(getDeviceNodes())
}
override fun loadAdditional(tag: CompoundTag, registries: HolderLookup.Provider) {
super.loadAdditional(tag, registries)
for (node in getDeviceNodes()) {
node.markChanged()
}
receivedServerState = false
}
}
abstract class DeviceBlock(properties: Properties = Properties.of()): BaseBlock(properties), EntityBlock {
@@ -128,6 +174,9 @@ abstract class DeviceBlock(properties: Properties = Properties.of()): BaseBlock(
if(blockEntity !is DeviceBlockEntity) return
blockEntity.tickDevice(level)
blockEntity.sendCommitsToClient(level)
if(level.isClientSide) {
blockEntity.requestServerState()
}
}
}
}

View File

@@ -21,6 +21,11 @@ class CableEntity(pos: BlockPos, state: BlockState) : SingleDeviceBlockEntity(Bl
return
}
override fun requestServerState() {
// no state, we don't bother
return
}
override fun getNodeFromSide(directionToRequester: Direction): DeviceNode? {
if(CableBlock.shouldConnect(blockPos, blockPos.relative(directionToRequester), level!!)) {
return deviceNode

View File

@@ -152,6 +152,7 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): SingleDeviceB
fun setRunning(value: Boolean) {
if(isOn == value) return
deviceNode.markChanged()
NeoComputers.LOGGER.info("[${deviceNode.address}] Going from $isOn to $value")
isOn = value
val world = level ?: return

View File

@@ -35,9 +35,11 @@ class ScreenEntity(blockPos: BlockPos, blockState: BlockState) :
textBuf.set(0, 0, address.toString())
}
isOn = mEnv.nowRunning
markChanged()
}
if(mEnv is MachineCrashEvent) {
lastError = mEnv.error
markChanged()
}
}
}

View File

@@ -70,7 +70,7 @@ class CaseScreen : GenericContainerScreen<CaseMenu> {
if(hasShiftDown()) {
msgs.addLast(Component.translatable("neocomputers.computer.energy", energy, maxEnergy).withStyle(if(energy < maxEnergy/5) ChatFormatting.RED else ChatFormatting.WHITE))
msgs.addLast(Component.translatable("neocomputers.computer.memory", Formatting.formatMemory(memory), Formatting.formatMemory(maxMemory)))
msgs.addLast(Component.translatable("neocomputers.computer.components", components, maxEnergy).withStyle(if(components <= maxComponents) ChatFormatting.WHITE else ChatFormatting.RED))
msgs.addLast(Component.translatable("neocomputers.computer.components", components, maxComponents).withStyle(if(components <= maxComponents) ChatFormatting.WHITE else ChatFormatting.RED))
}
return msgs
}

View File

@@ -51,4 +51,11 @@ interface ComponentItem {
}
fun onMachineEvent(itemStack: ItemStack, machine: MachineEntity, event: MachineEvent) {}
}
// A special ComponentItem which specifies upgrades specific to the relay
interface RelayUpgrade: ComponentItem {
fun getRelayInterval(itemStack: ItemStack): Int? = null
fun getRelayBufferSize(itemStack: ItemStack): Int? = null
fun getRelayQueueSize(itemStack: ItemStack): Int? = null
}

View File

@@ -211,7 +211,7 @@ open class DeviceNode(_address: UUID? = null) {
// Network synchronization with the NodeSynchronizer
// TODO: process shi
var outOfSync = true
var outOfSync = false
fun markChanged() {
outOfSync = true
}
@@ -227,6 +227,12 @@ open class DeviceNode(_address: UUID? = null) {
open fun processCommit(buf: FriendlyByteBuf) {}
}
// Used by the relay
// If the ComponentItem in the card slot
interface ConventionalNetworkDevice {
fun sendClassicPacket(packet: Networking.ClassicPacket)
}
abstract class WirelessEndpoint(address: UUID?) : DeviceNode(address) {
abstract fun getRange(): Double

View File

@@ -15,10 +15,12 @@ import org.neoflock.neocomputers.NeoComputers
import java.time.Duration
object NodeSynchronizer {
val MAX_STATE_DISTANCE_ALLOWED = 128
class DeviceBlockStatePayload(var blockPos: BlockPos, var buffers: List<FriendlyByteBuf>): CustomPacketPayload {
companion object {
val NODE_SYNC_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "node_sync")
val TYPE = CustomPacketPayload.Type<DeviceBlockStatePayload>(NODE_SYNC_ID)
val BLOCKDEV_SYNC_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "blockdev_sync")
val TYPE = CustomPacketPayload.Type<DeviceBlockStatePayload>(BLOCKDEV_SYNC_ID)
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, DeviceBlockStatePayload> {
override fun decode(buf: RegistryFriendlyByteBuf): DeviceBlockStatePayload {
val blockPos = buf.readBlockPos()
@@ -45,6 +47,25 @@ object NodeSynchronizer {
override fun type() = TYPE
}
class DeviceBlockStateRequest(var blockPos: BlockPos): CustomPacketPayload {
companion object {
val BLOCKDEV_REQ_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "blockdev_statereq")
val TYPE = CustomPacketPayload.Type<DeviceBlockStateRequest>(BLOCKDEV_REQ_ID)
val CODEC = object : StreamCodec<RegistryFriendlyByteBuf, DeviceBlockStateRequest> {
override fun decode(buf: RegistryFriendlyByteBuf): DeviceBlockStateRequest {
val blockPos = buf.readBlockPos()
return DeviceBlockStateRequest(blockPos)
}
override fun encode(buf: RegistryFriendlyByteBuf, payload: DeviceBlockStateRequest) {
buf.writeBlockPos(payload.blockPos)
}
}
}
override fun type() = TYPE
}
class ScreenPayload(var buffer: FriendlyByteBuf): CustomPacketPayload {
companion object {
val SCREEN_SYNC_ID = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "screen_sync")