Fix brain event snapshotting; remove obsolete synchronization

This commit is contained in:
Fingercomp 2025-08-11 23:48:53 +03:00
parent fd6400f39a
commit 094ac8cb48
No known key found for this signature in database
GPG Key ID: BBC71CEE45D86E37
3 changed files with 24 additions and 26 deletions

View File

@ -26,6 +26,7 @@ import javax.imageio.ImageIO
import javax.swing.JFileChooser
import scala.annotation.tailrec
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
import scala.concurrent.duration.DurationInt
import scala.util.Try
@ -437,24 +438,24 @@ object UiHandler extends Logging {
}
private def dispatchBrainEvents(): Unit = {
import totoro.ocelot.brain
val cutoff = BrainEvents.events.peekLast()
if (cutoff == null) {
return
}
// we're effectively taking a snapshot of all events we have received at the point of the call.
// we're taking a snapshot of all events we have received at the point of the call.
// new events may still be added to the queue, but we'll defer everything after the cutoff until the next update.
val events = LazyList.continually(BrainEvents.events.poll()).takeWhile({
var inSnapshot = true
var cutoffReached = false
val events = ArrayBuffer.empty[brain.event.Event]
{ event =>
val pass = inSnapshot
inSnapshot = !(event eq cutoff)
pass
}
})
while (!cutoffReached) {
val event = BrainEvents.events.poll()
cutoffReached = event eq cutoff
events += event
}
for (event <- events) {
root.workspaceView.dispatchBrainEvent(event)

View File

@ -9,7 +9,7 @@ import ocelot.desktop.ui.widget.LogWidget.{BorderThickness, EntryMargin, EntryPa
import ocelot.desktop.util.{DrawUtils, Orientation}
import scala.annotation.tailrec
import scala.collection.mutable.ArrayBuffer
import scala.collection.mutable
abstract class LogWidget extends Widget {
override protected val layout: Layout = new LinearLayout(this, orientation = Orientation.Vertical)
@ -17,18 +17,17 @@ abstract class LogWidget extends Widget {
private object MessageListWidget extends Widget { messageList =>
override protected val layout: Layout = new Layout(this)
// NOTE: access to entries must be synchronized!
private val entries = ArrayBuffer.empty[Entry]
private val entries = mutable.ArrayDeque.empty[Entry]
val dummyEntry: Entry = new RxEntry("", nextMessageY)
override def minimumSize: Size2D = Size2D(dummyEntry.minimumSize.width + 2 * EntryMargin, nextMessageY)
private def nextMessageY: Float = entries.synchronized {
private def nextMessageY: Float = {
entries.lastOption.map(_.maxY).getOrElse(0f) + EntryMargin
}
def addEntry(entry: LogEntry): Unit = entries.synchronized {
def addEntry(entry: LogEntry): Unit = {
entries += (entry match {
case LogEntry.Rx(message) => new RxEntry(message, nextMessageY)
case LogEntry.Tx(message) => new TxEntry(message, nextMessageY)
@ -37,7 +36,7 @@ abstract class LogWidget extends Widget {
parent.get.recalculateBoundsAndRelayout()
}
def removeFirst(count: Int): Unit = entries.synchronized {
def removeFirst(count: Int): Unit = {
if (count >= entries.length) {
entries.clear()
} else {
@ -68,7 +67,7 @@ abstract class LogWidget extends Widget {
}
}
override def draw(g: Graphics): Unit = entries.synchronized {
override def draw(g: Graphics): Unit = {
val firstVisibleIdx = firstVisibleIdxSearch(parent.get.asInstanceOf[ScrollView].offset.y)
for (entry <- entries.iterator.drop(firstVisibleIdx).takeWhile(_.absoluteBounds.y <= clippedBounds.max.y)) {

View File

@ -22,8 +22,6 @@ trait OcelotInterfaceLogStorage extends EventAware with Persistable with Windowe
private var _messageLimit: Int = 1000
// NOTE: access must be synchronized!
// ocelot.log() is a direct method, so it may push events even if the tick lock is not acquired
private val _entries = mutable.ArrayDeque.empty[LogEntry]
eventHandlers += {
@ -98,7 +96,7 @@ trait OcelotInterfaceLogStorage extends EventAware with Persistable with Windowe
addEntries(entries.toSeq)
}
override def save(nbt: NBTTagCompound): Unit = _entries.synchronized {
override def save(nbt: NBTTagCompound): Unit = {
super.save(nbt)
nbt.setTagList(EntriesTag, _entries.map(saveEntry(_).asInstanceOf[NBTBase]).asJava)
@ -107,36 +105,36 @@ trait OcelotInterfaceLogStorage extends EventAware with Persistable with Windowe
def messageLimit: Int = _messageLimit
def messageLimit_=(limit: Int): Unit = _entries.synchronized {
def messageLimit_=(limit: Int): Unit = {
require(limit > 0)
ensureFreeSpace(_entries.length - limit)
_messageLimit = limit
}
def entryCount: Int = _entries.synchronized {
def entryCount: Int = {
_entries.length
}
def clear(): Unit = _entries.synchronized {
def clear(): Unit = {
val count = _entries.length
_entries.clear()
window.onMessagesRemoved(count)
}
private def addEntry(entry: LogEntry): Unit = _entries.synchronized {
private def addEntry(entry: LogEntry): Unit = {
ensureFreeSpace(1)
_entries += entry
onMessagesAdded(Some(entry))
}
private def addEntries(entries: Seq[LogEntry]): Unit = _entries.synchronized {
private def addEntries(entries: Seq[LogEntry]): Unit = {
ensureFreeSpace(entries.length)
val prevCount = _entries.length
_entries ++= entries.view.takeRight(messageLimit)
onMessagesAdded(_entries.view.takeRight(_entries.length - prevCount))
}
private def ensureFreeSpace(n: Int): Unit = _entries.synchronized {
private def ensureFreeSpace(n: Int): Unit = {
val prevCount = _entries.length
_entries.takeRightInPlace(messageLimit - n)
val removedCount = prevCount - _entries.length