From c98ec2fc99b1f898b89adc01ee86aa80dd8578b7 Mon Sep 17 00:00:00 2001 From: IonutParau Date: Wed, 22 Apr 2026 18:02:45 +0200 Subject: [PATCH] more work on computer stuff --- .../org/neoflock/neocomputers/NeoComputers.kt | 20 ++++-- .../neoflock/neocomputers/block/NodeBlock.kt | 6 +- .../neocomputers/entity/BlockEntities.kt | 1 + .../neocomputers/entity/CaseBlockEntity.kt | 59 ++++++++++++++--- .../neocomputers/entity/MachineEntity.kt | 3 + .../neocomputers/gui/menu/CaseMenu.kt | 8 +-- .../neocomputers/gui/screen/CaseScreen.kt | 64 +++++++++++++++---- .../org/neoflock/neocomputers/item/CPUItem.kt | 2 + .../neocomputers/item/ComponentItem.kt | 1 + .../neocomputers/item/DataComponents.kt | 4 ++ .../neoflock/neocomputers/item/EEPROMItem.kt | 6 +- .../org/neoflock/neocomputers/item/Tabs.kt | 1 + .../neocomputers/network/Networking.kt | 55 +++++++++------- 13 files changed, 172 insertions(+), 58 deletions(-) diff --git a/src/main/kotlin/org/neoflock/neocomputers/NeoComputers.kt b/src/main/kotlin/org/neoflock/neocomputers/NeoComputers.kt index ed77ec1..2ef8caf 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/NeoComputers.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/NeoComputers.kt @@ -4,6 +4,7 @@ import dev.architectury.event.events.client.ClientLifecycleEvent import dev.architectury.event.events.common.PlayerEvent import dev.architectury.event.events.common.TickEvent import dev.architectury.networking.NetworkManager +import dev.architectury.platform.Platform import net.minecraft.resources.ResourceLocation import org.neoflock.neocomputers.block.Blocks import org.neoflock.neocomputers.entity.BlockEntities @@ -73,13 +74,18 @@ object NeoComputers { NodeSynchronizer.playerScreenClosed(player) } - NetworkManager.registerReceiver(NetworkManager.c2s(),NodeSynchronizer.ScreenDataPayload.TYPE, NodeSynchronizer.ScreenDataPayload.CODEC, { - packet, ctx -> - val player = ctx.player - if(player is ServerPlayer) { - NodeSynchronizer.screenMap[player]?.processScreenInteraction(player, packet.buffer) - } - }) + // networking has no way to define a C2S packet type, so we need the listener on both + // however, defining it separately on both breaks both ends + // so we define it once, but on both platforms + if(Platform.getEnvironment() == Env.CLIENT || Platform.getEnvironment() == Env.SERVER) { + NetworkManager.registerReceiver(NetworkManager.c2s(),NodeSynchronizer.ScreenDataPayload.TYPE, NodeSynchronizer.ScreenDataPayload.CODEC, { + packet, ctx -> + val player = ctx.player + if(player is ServerPlayer) { + NodeSynchronizer.screenMap[player]?.processScreenInteraction(player, packet.buffer) + } + }) + } // we have to do this because the datagen task runs in the physical server EnvExecutor.runInEnv(Env.CLIENT) {{ diff --git a/src/main/kotlin/org/neoflock/neocomputers/block/NodeBlock.kt b/src/main/kotlin/org/neoflock/neocomputers/block/NodeBlock.kt index 5309df1..0cfa79c 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/block/NodeBlock.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/block/NodeBlock.kt @@ -24,6 +24,7 @@ import net.minecraft.world.level.block.entity.BlockEntityType import net.minecraft.world.level.block.state.BlockState import org.neoflock.neocomputers.NeoComputers import org.neoflock.neocomputers.network.Networking +import org.neoflock.neocomputers.network.PowerRole object NodeSynchronizer { class StatePayload(var blockPos: BlockPos, var buffer: FriendlyByteBuf): CustomPacketPayload { @@ -134,7 +135,7 @@ abstract class NodeBlockEntity(blockEntityType: BlockEntityType<*>, blockPos: Bl // runs on the client, meant to decode server state packets to synchronize client state open fun syncWithUpstream(packet: FriendlyByteBuf) { - node.address = packet.readUUID() + Networking.changeNodeAddress(node, packet.readUUID()) node.energy = packet.readLong() node.energyCapacity = packet.readLong() node.reachability = packet.readEnum(node.reachability.javaClass) @@ -202,6 +203,9 @@ abstract class NodeBlockEntity(blockEntityType: BlockEntityType<*>, blockPos: Bl override fun setRemoved() { super.setRemoved() + if(node.powerRole == PowerRole.GENERATOR) { + NeoComputers.LOGGER.info("removed generator ${node.address}") + } Networking.removeNode(node) } diff --git a/src/main/kotlin/org/neoflock/neocomputers/entity/BlockEntities.kt b/src/main/kotlin/org/neoflock/neocomputers/entity/BlockEntities.kt index c3b3255..d1b45eb 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/entity/BlockEntities.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/entity/BlockEntities.kt @@ -87,5 +87,6 @@ object BlockEntities { PowerManager.registerPowerBlockEntity(CAPACITOR3_ENTITY.get()) PowerManager.registerPowerBlockEntity(SOLARGEN_ENTITY.get()) PowerManager.registerPowerBlockEntity(COMBUSTGEN_ENTITY.get()) + PowerManager.registerPowerBlockEntity(CASE_ENTITY.get()) } } \ No newline at end of file diff --git a/src/main/kotlin/org/neoflock/neocomputers/entity/CaseBlockEntity.kt b/src/main/kotlin/org/neoflock/neocomputers/entity/CaseBlockEntity.kt index 08d423d..aebb6a4 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/entity/CaseBlockEntity.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/entity/CaseBlockEntity.kt @@ -40,6 +40,8 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti val stacks: NonNullList = NonNullList.withSize(7, ItemStack.EMPTY) var isOn = false + var err: String? = null + var arch = "Lua 5.3" var soundInstance: SoundInstance? = null override val node = object : Networking.Node() { @@ -70,6 +72,14 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti override fun encodeScreenData(player: ServerPlayer, packet: FriendlyByteBuf) { super.encodeScreenData(player, packet) packet.writeBoolean(isOn) + packet.writeByteArray((err ?: "").encodeToByteArray()) + packet.writeLong(node.energy) + packet.writeLong(node.energyCapacity) + packet.writeLong(getMachineMemoryUsed()) + packet.writeLong(getMachineMemoryTotal()) + packet.writeLong(getMachineComponentsUsed()) + packet.writeLong(getMachineComponentsTotal()) + packet.writeUtf(arch) } val redstoneIn = Array(Direction.entries.size) {0} @@ -120,6 +130,7 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti isOn = value val world = level ?: return blockState?.setValue(CaseBlock.COMPUTER_RUNNING, isOn) + if(value) beepAsync(8000, Duration.ofSeconds(1), 1.0) if(world.isClientSide) { if(value) { soundInstance = ComputerRunningSoundInstance(this, Sounds.COMPUTER_RUNNING.get(), SoundSource.AMBIENT) @@ -136,6 +147,19 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti } override fun start(): Boolean { + err = null + if(getMachineComponentsUsed() > getMachineComponentsTotal()) { + crash("too many components") + return false + } + if(node.energy < 100) { + crash("not enough energy") + return false + } + if(getMachineMemoryTotal() == 0L) { + crash("no memory provided") + return false + } setRunning(true) return isOn } @@ -146,11 +170,12 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti } override fun crash(error: String): Boolean { - NeoComputers.LOGGER.warn("Crashing cases is not implemented yet lol") - return false + setRunning(false) + err = error + return true } - override fun getLastError(): String? = null + override fun getLastError(): String? = err override fun getMachineNode(): Networking.Node = node @@ -172,12 +197,22 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti override fun getMachineMemoryTotal(): Long = stacks.mapNotNull { (it.item as? ComponentItem)?.getMemoryCapacity(it) }.sum().toLong() override fun getMachineMemoryUsed(): Long = 0 - override fun getMachineComponentsUsed(): Long = node.connections.size.toLong() + override fun getMachineComponentsUsed(): Long = node.getReachable().size.toLong() override fun getMachineComponentsTotal(): Long = stacks.mapNotNull { (it.item as? ComponentItem)?.getComponentCapacity(it) }.sum().toLong() + override fun getMachineArchitecture() = arch + override fun getMachineArchitectures() = stacks.mapNotNull { (it.item as? ComponentItem)?.getArchitecturesProvided(it) }.flatten().toSet() + override fun setMachineArchitecture(arch: String) { + if(this.arch == arch) return + this.arch = arch + if(isRunning()) { + stop() + start() + } + } override fun getItems(): NonNullList = stacks - override fun stillValid(player: Player): Boolean = true + override fun stillValid(player: Player): Boolean = !this.isRemoved override fun loadAdditional(compoundTag: CompoundTag, provider: HolderLookup.Provider) { super.loadAdditional(compoundTag, provider) @@ -196,9 +231,6 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti override fun getDisplayName(): Component? = Component.literal("Computer") override fun createMenu(i: Int, inventory: Inventory, player: Player) = CaseMenu(i, inventory, this) - override fun canPlaceItem(i: Int, itemStack: ItemStack): Boolean = false - override fun canTakeItem(container: Container, i: Int, itemStack: ItemStack): Boolean = false - override fun setChanged() { super.setChanged() } @@ -207,4 +239,15 @@ class CaseBlockEntity(blockPos: BlockPos, blockState: BlockState): NodeBlockEnti setRunning(false) super.setRemoved() } + + override fun tickNode(level: Level) { + super.tickNode(level) + if(!level.isClientSide) { + if (isRunning()) { + if (!node.consumeEnergy(1)) { + crash("out of energy") + } + } + } + } } \ No newline at end of file diff --git a/src/main/kotlin/org/neoflock/neocomputers/entity/MachineEntity.kt b/src/main/kotlin/org/neoflock/neocomputers/entity/MachineEntity.kt index 3d2b1be..ef7ccb9 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/entity/MachineEntity.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/entity/MachineEntity.kt @@ -34,6 +34,9 @@ interface MachineEntity { fun getMachineMemoryUsed(): Long fun getMachineComponentsUsed(): Long fun getMachineComponentsTotal(): Long + fun getMachineArchitecture(): String + fun getMachineArchitectures(): Set + fun setMachineArchitecture(arch: String) // Redstone signals fun getRedstoneInput(direction: Direction): Int diff --git a/src/main/kotlin/org/neoflock/neocomputers/gui/menu/CaseMenu.kt b/src/main/kotlin/org/neoflock/neocomputers/gui/menu/CaseMenu.kt index 8e7a674..e355b5a 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/gui/menu/CaseMenu.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/gui/menu/CaseMenu.kt @@ -20,20 +20,20 @@ open class CaseMenu : GenericContainerMenu { constructor(i: Int, inv: Inventory) : this(i, inv, SimpleContainer(7)) constructor(i: Int, inv: Inventory, container: Container) : super(Menus.CASE_MENU.get(), i, container) { - this.addInventorySlots(inv, 8, 84) - val machine = container as? CaseBlockEntity - this.addSlot(ComponentSlot(this.container, 0, 20, 34, machine, eepromRequirement)) + this.addSlot(ComponentSlot(container, 0, 20, 34, machine, eepromRequirement)) var i = 1 for ((col, slotCol) in slotRequirements.withIndex()) { for ((row, slotReq) in slotCol.withIndex()) { - this.addSlot(ComponentSlot(this.container, i, 98+(col*22), 18*(row+1)-2, machine, slotReq)) + this.addSlot(ComponentSlot(container, i, 98+(col*22), 18*(row+1)-2, machine, slotReq)) i++ } } + this.addInventorySlots(inv, 8, 84) + // for (int col=1; col<4; col++) { // for (int row=1; row<4; row++) { // int i = (row-1)*3+(col-1); diff --git a/src/main/kotlin/org/neoflock/neocomputers/gui/screen/CaseScreen.kt b/src/main/kotlin/org/neoflock/neocomputers/gui/screen/CaseScreen.kt index 22037cd..7f33d15 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/gui/screen/CaseScreen.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/gui/screen/CaseScreen.kt @@ -1,26 +1,22 @@ package org.neoflock.neocomputers.gui.screen; -import com.mojang.blaze3d.vertex.BufferBuilder -import com.mojang.blaze3d.vertex.DefaultVertexFormat -import com.mojang.blaze3d.vertex.Tesselator -import com.mojang.blaze3d.vertex.VertexFormat import io.netty.buffer.Unpooled +import net.minecraft.ChatFormatting import net.minecraft.client.Minecraft import net.minecraft.client.gui.GuiGraphics -import net.minecraft.client.gui.components.Button -import net.minecraft.client.gui.components.ImageButton -import net.minecraft.client.gui.components.WidgetSprites -import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.chat.Component import net.minecraft.resources.ResourceLocation import net.minecraft.world.entity.player.Inventory +import net.minecraft.world.inventory.tooltip.TooltipComponent import org.neoflock.neocomputers.NeoComputers import org.neoflock.neocomputers.block.NodeSynchronizer import org.neoflock.neocomputers.gui.menu.CaseMenu import org.neoflock.neocomputers.gui.widget.ButtonSprites import org.neoflock.neocomputers.gui.widget.ImagerButton +import org.neoflock.neocomputers.utils.Formatting import org.neoflock.neocomputers.utils.GenericContainerScreen +import java.util.Optional class CaseScreen : GenericContainerScreen { private val PCB: ResourceLocation = ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "textures/gui/computer.png") @@ -34,11 +30,49 @@ class CaseScreen : GenericContainerScreen { override fun shouldCenterTitle(): Boolean = false var isOn = false + var lastError: String? = null + var energy: Long = 0L + var maxEnergy: Long = 0L + var memory: Long = 0L + var maxMemory: Long = 0L + var components: Long = 0L + var maxComponents: Long = 0L + var arch = "" override fun processScreenStatePacket(buf: FriendlyByteBuf) { super.processScreenStatePacket(buf) isOn = buf.readBoolean() btn?.pressed = isOn + val error = buf.readByteArray().decodeToString() + if(error.isEmpty()) { + lastError = null + } else { + lastError = error + } + + energy = buf.readLong() + maxEnergy = buf.readLong() + memory = buf.readLong() + maxMemory = buf.readLong() + components = buf.readLong() + maxComponents = buf.readLong() + arch = buf.readUtf() + } + + fun computeButtonTooltip(): List { + val msgs = mutableListOf(Component.literal("Computer " + if(isOn) "ON" else "OFF").withStyle(if(isOn) ChatFormatting.GREEN else ChatFormatting.RED)) + if(lastError != null) { + msgs.addLast(Component.literal("Error: ").withStyle(ChatFormatting.RED).append(Component.literal(lastError!!))) + } + if(arch.isNotEmpty()) { + msgs.addLast(Component.literal("Architecture: $arch")) + } + if(hasShiftDown()) { + msgs.addLast(Component.literal("Energy: $energy / $maxEnergy J").withStyle(if(energy < 100) ChatFormatting.RED else ChatFormatting.WHITE)) + msgs.addLast(Component.literal("Memory: ${Formatting.formatMemory(memory)} / ${Formatting.formatMemory(maxMemory)}")) + msgs.addLast(Component.literal("Components: $components / $maxComponents").withStyle(if(components <= maxComponents) ChatFormatting.WHITE else ChatFormatting.RED)) + } + return msgs } constructor(abstractContainerMenu: CaseMenu, inventory: Inventory, component: Component) : super(abstractContainerMenu, inventory, component) { @@ -64,14 +98,20 @@ class CaseScreen : GenericContainerScreen { guiGraphics.blit(PCB, relX, relY, 0, 0, this.imageWidth, this.imageHeight) } + override fun renderCustomOverlay(graphics: GuiGraphics, mouseX: Int, mouseY: Int, blend: Float) { + super.renderCustomOverlay(graphics, mouseX, mouseY, blend) + if(btn!!.isHovered) { + graphics.renderTooltip(this.font, computeButtonTooltip(), Optional.empty(), mouseX, mouseY) + } + } + override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean { // todo: make a better widget system than mojang, practically not even using the fact it's a widget atp - NeoComputers.LOGGER.info(String.format("btn: %d %d %d %d, mouse %s %s", btn!!.x, btn!!.y, btn!!.x+btn!!.width, btn!!.y+btn!!.height, mouseX.toString(), mouseY.toString())) - if (button != 0) return false - if (btn!!.x < mouseX.toInt() && mouseX.toInt() < btn!!.x+btn!!.width && btn!!.y < mouseY.toInt() && mouseY.toInt() < btn!!.y+btn!!.height) { + if (button == 0 && btn!!.isHovered) { btn!!.playDownSound(Minecraft.getInstance().soundManager) btn!!.onClick(mouseX, mouseY) return true - } else return false + } + return super.mouseClicked(mouseX, mouseY, button) } } \ No newline at end of file diff --git a/src/main/kotlin/org/neoflock/neocomputers/item/CPUItem.kt b/src/main/kotlin/org/neoflock/neocomputers/item/CPUItem.kt index c6c70db..7ec8de4 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/item/CPUItem.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/item/CPUItem.kt @@ -13,6 +13,8 @@ open class CPUItem(val tier: Int, val maxComponents: Int): Item(Item.Properties( override fun getComponentCapacity(itemStack: ItemStack): Int = maxComponents + override fun getArchitecturesProvided(itemStack: ItemStack): Set = setOf("Lua 5.3") + override fun toComponentNode(itemStack: ItemStack, machine: MachineEntity): Networking.Node? = null } diff --git a/src/main/kotlin/org/neoflock/neocomputers/item/ComponentItem.kt b/src/main/kotlin/org/neoflock/neocomputers/item/ComponentItem.kt index b90bcc5..94c2126 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/item/ComponentItem.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/item/ComponentItem.kt @@ -14,6 +14,7 @@ interface ComponentItem { // Get machine properties they can influence fun getMemoryCapacity(itemStack: ItemStack): Int = 0 fun getComponentCapacity(itemStack: ItemStack): Int = 0 + fun getArchitecturesProvided(itemStack: ItemStack): Set = setOf() // Component placed, node must now exist fun whenComponentPlaced(itemStack: ItemStack, machine: MachineEntity, newRole: String) { diff --git a/src/main/kotlin/org/neoflock/neocomputers/item/DataComponents.kt b/src/main/kotlin/org/neoflock/neocomputers/item/DataComponents.kt index 0672974..1977f54 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/item/DataComponents.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/item/DataComponents.kt @@ -19,4 +19,8 @@ object DataComponents { DataComponentType.builder().persistent(Codec.BYTE_BUFFER).build()) val EEPROM_DATA = Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "eeprom_data"), DataComponentType.builder().persistent(Codec.BYTE_BUFFER).build()) + val EEPROM_CODESIZE = Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "eeprom_codesize"), + DataComponentType.builder().persistent(Codec.INT).build()) + val EEPROM_DATASIZE = Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, ResourceLocation.fromNamespaceAndPath(NeoComputers.MODID, "eeprom_datasize"), + DataComponentType.builder().persistent(Codec.INT).build()) } \ No newline at end of file diff --git a/src/main/kotlin/org/neoflock/neocomputers/item/EEPROMItem.kt b/src/main/kotlin/org/neoflock/neocomputers/item/EEPROMItem.kt index f925967..2252887 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/item/EEPROMItem.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/item/EEPROMItem.kt @@ -13,6 +13,8 @@ import java.nio.ByteBuffer fun getEEPROMProperties(codeCap: Int, dataCap: Int): Item.Properties = Item.Properties() .component(DataComponents.EEPROM_CODE, ByteBuffer.allocate(codeCap)) .component(DataComponents.EEPROM_DATA, ByteBuffer.allocate(dataCap)) + .component(DataComponents.EEPROM_CODESIZE, 0) + .component(DataComponents.EEPROM_DATASIZE, 0) .component(DataComponents.LABEL, "") .component(DataComponents.READONLY, false) @@ -39,8 +41,8 @@ open class EEPROMItem(val tier: Int, val codeCapacity: Int, val dataCapacity: In tooltipFlag: TooltipFlag ) { if(tooltipFlag.isAdvanced) { - val codeSize = itemStack.get(DataComponents.EEPROM_CODE)?.position() ?: 0 - val dataSize = itemStack.get(DataComponents.EEPROM_DATA)?.position() ?: 0 + val codeSize = itemStack.get(DataComponents.EEPROM_CODESIZE) ?: 0 + val dataSize = itemStack.get(DataComponents.EEPROM_DATASIZE) ?: 0 val addr = itemStack.get(DataComponents.ADDRESS) val readonly = itemStack.get(DataComponents.READONLY) ?: false val addrComp = if(addr == null) Component.translatable("neocomputers.noaddr") else Component.literal(addr) diff --git a/src/main/kotlin/org/neoflock/neocomputers/item/Tabs.kt b/src/main/kotlin/org/neoflock/neocomputers/item/Tabs.kt index 1273835..16848a2 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/item/Tabs.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/item/Tabs.kt @@ -72,6 +72,7 @@ object Tabs { codeBuf.put(code) luaBios.set(DataComponents.LABEL, "Lua BIOS") luaBios.set(DataComponents.EEPROM_CODE, codeBuf) + luaBios.set(DataComponents.EEPROM_CODESIZE, code.size) output.accept(luaBios) } while(false) } diff --git a/src/main/kotlin/org/neoflock/neocomputers/network/Networking.kt b/src/main/kotlin/org/neoflock/neocomputers/network/Networking.kt index cddae74..97eea46 100644 --- a/src/main/kotlin/org/neoflock/neocomputers/network/Networking.kt +++ b/src/main/kotlin/org/neoflock/neocomputers/network/Networking.kt @@ -246,8 +246,8 @@ object Networking { abstract fun receiveWireless(message: Message, emitter: WirelessEndpoint) } - val wirelessNodes = mutableSetOf() - val allNodes = mutableMapOf() + val wirelessNodes = ThreadLocal.withInitial { mutableSetOf() } + val allNodes = ThreadLocal.withInitial { mutableMapOf() } // node may differ from message.sender in the case of relays, // as they might have DIRECT reachability but @@ -267,7 +267,7 @@ object Networking { val startPos = starter.getPosition(); val startDim = starter.getDimension(); val range = starter.getRange(); - wirelessNodes.forEach { + wirelessNodes.get().forEach { if(it.getDimension() != startDim) return; val pos = it.getPosition(); val d = distanceBetween(startPos, pos); @@ -279,27 +279,30 @@ object Networking { } fun tickAllNodes() { - allNodes.forEach { it.value.tick() } + allNodes.get().forEach { it.value.tick() } tickCount++ } - fun getNode(address: UUID): Node? = allNodes[address] + fun getNode(address: UUID): Node? = allNodes.get()[address] // TODO: use setter, more convenient fun changeNodeAddress(node: Node, address: UUID) { - allNodes.remove(node.address) + if(node.address.equals(address)) return + NeoComputers.LOGGER.info("remapping node from ${node.address} to $address") + allNodes.get().remove(node.address) node.address = address - allNodes[address] = node + allNodes.get()[address] = node } fun addNode(node: Node) { - if(node.address in allNodes) return; - allNodes[node.address] = node + if(node.address in allNodes.get()) return + NeoComputers.LOGGER.info("adding node ${node.address}") + allNodes.get()[node.address] = node if(node is WirelessEndpoint) { - wirelessNodes.add(node); + wirelessNodes.get().add(node); } // notify at the end so it is notified of its own creation - allNodes.forEach { it.value.onNodeAdded(node) } + allNodes.get().forEach { it.value.onNodeAdded(node) } } fun addNodes(vararg nodes: Node) { @@ -307,16 +310,17 @@ object Networking { } fun removeNode(node: Node) { - if(node.address !in allNodes) return - allNodes.forEach { it.value.onNodeRemoved(node) } + if(node.address !in allNodes.get()) return + NeoComputers.LOGGER.info("removing node ${node.address}") + allNodes.get().forEach { it.value.onNodeRemoved(node) } // toList() in order to copy it node.connections.toList().forEach { node.disconnectFrom(it) } // actually remove at the end so it can listen to its own removal - allNodes.remove(node.address) + allNodes.get().remove(node.address) if(node is WirelessEndpoint) { - wirelessNodes.remove(node); + wirelessNodes.get().remove(node); } } @@ -324,25 +328,28 @@ object Networking { nodes.forEach { removeNode(it) } } - val channels = mutableMapOf>(); + val channels = ThreadLocal.withInitial { mutableMapOf>() } fun addToChannel(channel: String, node: Node) { - if(!channels.containsKey(channel)) { - channels[channel] = mutableSetOf(); + val localChannels = channels.get() + if(!localChannels.containsKey(channel)) { + localChannels[channel] = mutableSetOf(); } - channels[channel]!!.add(node); + localChannels[channel]!!.add(node); } fun removeFromChannel(channel: String, node: Node) { - if(!channels.containsKey(channel)) return; - channels[channel]?.remove(node); - if(channels[channel].isNullOrEmpty()) { - channels.remove(channel); + val localChannels = channels.get() + if(!localChannels.containsKey(channel)) return; + localChannels[channel]?.remove(node); + if(localChannels[channel].isNullOrEmpty()) { + localChannels.remove(channel); } } fun emitChannelMessage(starter: Node, channel: String, message: Message) { - val c = channels[channel] ?: return; + val localChannels = channels.get() + val c = localChannels[channel] ?: return; c.forEach { if(it != starter) it.received(message); }; } } \ No newline at end of file