Merge branch 'refactor/entity-id' into develop

This commit is contained in:
Fingercomp 2025-02-01 16:02:44 +03:00
commit 6f9558bed1
No known key found for this signature in database
GPG Key ID: BBC71CEE45D86E37
30 changed files with 159 additions and 143 deletions

@ -1 +1 @@
Subproject commit e1968df8a58fab83572e657d981b7263c7edd72a
Subproject commit 648e47c42ca2ab4eb676ccc3dcddf129eac771af

View File

@ -2,7 +2,7 @@ package ocelot.desktop.inventory
import ocelot.desktop.OcelotDesktop
import ocelot.desktop.inventory.PersistedInventory._
import ocelot.desktop.inventory.traits.{ComponentItem, PersistableItem}
import ocelot.desktop.inventory.traits.{EntityItem, PersistableItem}
import ocelot.desktop.util.ReflectionUtils.findUnaryConstructor
import ocelot.desktop.util.{Logging, Persistable}
import totoro.ocelot.brain.nbt.ExtendedNBT.{extendNBTTagCompound, extendNBTTagList}
@ -13,9 +13,9 @@ import scala.collection.mutable
/** Provides persistence for an [[Inventory]].
*
* [[ComponentItem]]s are treated specially: their [[ComponentItem.component component]] is persisted
* along with the item when saving. When loading the item, it first loads the component and uses it to instantiate
* the item (as required by [[ComponentItem]]).
* [[EntityItem]]s are treated specially: their [[EntityItem.entity entities]] are persisted
* along with the item when saving. When loading the item, it first loads the entity and uses it to instantiate
* the item (as required by [[EntityItem]]).
*/
trait PersistedInventory extends Inventory with Logging with Persistable {
override type I <: Item with PersistableItem
@ -33,8 +33,8 @@ trait PersistedInventory extends Inventory with Logging with Persistable {
val itemClass = Class.forName(slotNbt.getString(SlotItemClassTag))
try {
val item = if (classOf[ComponentItem].isAssignableFrom(itemClass))
loadComponentItem(itemClass, slotNbt)
val item = if (classOf[EntityItem].isAssignableFrom(itemClass))
loadEntityItem(itemClass, slotNbt)
else
loadPlainItem(itemClass)
@ -43,7 +43,7 @@ trait PersistedInventory extends Inventory with Logging with Persistable {
} catch {
case ItemLoadException(message) =>
logger.error(
s"Could not restore an item in the slot $slotIndex of " +
s"Could not load an item in the slot $slotIndex of " +
s"the inventory $this (class ${this.getClass.getName}): $message"
)
onSlotLoadFailed(slotIndex)
@ -72,7 +72,7 @@ trait PersistedInventory extends Inventory with Logging with Persistable {
slotNbt.setString(SlotItemClassTag, item.getClass.getName)
item match {
case item: ComponentItem => saveComponentItem(slotNbt, item)
case item: EntityItem => saveEntityItem(slotNbt, item)
case _ =>
}
@ -82,7 +82,7 @@ trait PersistedInventory extends Inventory with Logging with Persistable {
}
@throws[ItemLoadException]("if the item could not be loaded")
protected def loadComponentItem(itemClass: Class[_], slotNbt: NBTTagCompound): I = {
protected def loadEntityItem(itemClass: Class[_], slotNbt: NBTTagCompound): I = {
val entityNbt = slotNbt.getCompoundTag(SlotEntityTag)
val entity = NBTPersistence.load(entityNbt, OcelotDesktop.workspace)
@ -107,8 +107,8 @@ trait PersistedInventory extends Inventory with Logging with Persistable {
Slot(slotIndex).remove()
}
protected def saveComponentItem(slotNbt: NBTTagCompound, item: ComponentItem): Unit = {
slotNbt.setTag(SlotEntityTag, NBTPersistence.save(item.component))
protected def saveEntityItem(slotNbt: NBTTagCompound, item: EntityItem): Unit = {
slotNbt.setTag(SlotEntityTag, NBTPersistence.save(item.entity))
}
}

View File

@ -5,22 +5,22 @@ import ocelot.desktop.inventory.PersistedInventory.ItemLoadException
import ocelot.desktop.inventory.SyncedInventory.SlotStatus.SlotStatus
import ocelot.desktop.inventory.SyncedInventory.SyncDirection.SyncDirection
import ocelot.desktop.inventory.SyncedInventory._
import ocelot.desktop.inventory.traits.ComponentItem
import ocelot.desktop.inventory.traits.EntityItem
import ocelot.desktop.ui.event.{BrainEvent, EventAware}
import ocelot.desktop.util.Logging
import ocelot.desktop.util.ReflectionUtils.findUnaryConstructor
import totoro.ocelot.brain.entity.traits.{Entity, Environment, Inventory => BrainInventory}
import totoro.ocelot.brain.event.{InventoryEntityAddedEvent, InventoryEntityRemovedEvent}
import totoro.ocelot.brain.nbt.NBTTagCompound
import totoro.ocelot.brain.network.Network
import java.util.UUID
import scala.annotation.tailrec
/** A [[PersistedInventory]] backed by a [[BrainInventory brain Inventory]].
*
* Synchronizes the contents of the two inventories, propagating changes from one to the other.
*
* When a new [[Item]] is added to the Desktop inventory, its [[ComponentItem.component]] is added to
* When a new [[Item]] is added to the Desktop inventory, its [[EntityItem.entity]] is added to
* the [[brainInventory]]. When a new [[Entity]] is added to the [[brainInventory]], an [[Item]] is recovered from it
* by using an appropriate [[ItemRecoverer]] from [[Items the registry]].
*
@ -28,7 +28,7 @@ import scala.annotation.tailrec
* by limiting the recursion depth.
*/
trait SyncedInventory extends PersistedInventory with EventAware with Logging {
override type I <: Item with ComponentItem
override type I <: EntityItem
// to avoid synchronization while we're loading stuff
private var isLoading = false
@ -54,20 +54,41 @@ trait SyncedInventory extends PersistedInventory with EventAware with Logging {
}
@throws[ItemLoadException]("if the item could not be loaded")
override protected def loadComponentItem(itemClass: Class[_], slotNbt: NBTTagCompound): I = {
val entityAddress = slotNbt.getString(SlotEntityAddressTag)
// why not OcelotDesktop.workspace.entityByAddress?
// well, that one only looks for tile entities (computers, screens, etc.), and our items are none of that...
val matchingEntities = brainInventory.inventory.iterator
.flatMap(_.get)
.collect { case env: Environment if env.node.address == entityAddress => env }
val entity = matchingEntities.nextOption() match {
case Some(entity) => entity
case None => throw ItemLoadException(s"entity $entityAddress has disappeared")
override protected def loadEntityItem(itemClass: Class[_], slotNbt: NBTTagCompound): I = {
trait Matcher {
def matches(entity: Entity): Boolean
}
val matcher = if (slotNbt.hasKey(SlotEntityIdTag)) {
new Matcher {
private val entityId = UUID.fromString(slotNbt.getString(SlotEntityIdTag))
override def toString: String = s"entity with id `$entityId`"
override def matches(entity: Entity): Boolean = entity.entityId == entityId
}
} else {
// migration code for older saves, which relied on entity addresses.
new Matcher {
private val entityAddress = slotNbt.getString(SlotEntityAddressTag)
override def toString: String = s"entity with address `$entityAddress"
override def matches(entity: Entity): Boolean = entity match {
// why not OcelotDesktop.workspace.entityByAddress?
// well, that one only looks for tile entities (computers, screens, etc.),
// and our items are none of that...
case env: Environment => env.node.address == entityAddress
case _ => false
}
}
}
val entity = brainInventory.inventory.iterator
.flatMap(_.get)
.find(matcher.matches)
.getOrElse(throw ItemLoadException(s"$matcher has disappeared"))
findUnaryConstructor(itemClass, entity.getClass) match {
case Some(constructor) => constructor.newInstance(entity).asInstanceOf[I]
@ -83,8 +104,8 @@ trait SyncedInventory extends PersistedInventory with EventAware with Logging {
// we'll deal with it the during synchronization
}
override protected def saveComponentItem(slotNbt: NBTTagCompound, item: ComponentItem): Unit = {
slotNbt.setString(SlotEntityAddressTag, item.component.node.address)
override protected def saveEntityItem(slotNbt: NBTTagCompound, item: EntityItem): Unit = {
slotNbt.setString(SlotEntityIdTag, item.entity.entityId.toString)
}
eventHandlers += {
@ -97,17 +118,6 @@ trait SyncedInventory extends PersistedInventory with EventAware with Logging {
override def onItemAdded(slot: Slot): Unit = {
if (!isLoading) {
// FIXME: the sheer scope of this atrocity is mind-blowing:
// we strip nodes of their free will and forcefully imprint onto them an address
// and only because there is no other way to identify brain entities!
// in an ideal world, persistable objects should have a stable identifier
// which is in no way tied to environments and their addresses.
// alas, for the time being we have to bear the burden of grave sins and war crimes.
val component = slot.get.get.asInstanceOf[ComponentItem].component
if (component.node.address == null) {
Network.joinNewNetwork(component.node)
}
sync(slot.index, SyncDirection.DesktopToBrain)
}
}
@ -177,7 +187,7 @@ trait SyncedInventory extends PersistedInventory with EventAware with Logging {
case SyncDirection.DesktopToBrain =>
// the `asInstanceOf` is indeed entirely superfluous, but IntelliJ IDEA complains otherwise...
OcelotDesktop.withTickLockAcquired {
brainInventory.inventory(slotIndex).set(Slot(slotIndex).get.map(_.asInstanceOf[ComponentItem].component))
brainInventory.inventory(slotIndex).set(Slot(slotIndex).get.map(_.asInstanceOf[EntityItem].entity))
}
case SyncDirection.BrainToDesktop =>
@ -248,7 +258,7 @@ trait SyncedInventory extends PersistedInventory with EventAware with Logging {
private def checkSlotStatus(slotIndex: Int): SlotStatus = {
(Slot(slotIndex).get, brainInventory.inventory(slotIndex).get) match {
case (Some(item), Some(entity)) if item.component eq entity => SlotStatus.Synchronized
case (Some(item), Some(entity)) if item.entity eq entity => SlotStatus.Synchronized
case (Some(_), Some(_)) => SlotStatus.Conflict
case (Some(_), None) => SlotStatus.DesktopNonEmpty
case (None, Some(_)) => SlotStatus.BrainNonEmpty
@ -259,6 +269,7 @@ trait SyncedInventory extends PersistedInventory with EventAware with Logging {
object SyncedInventory {
private val SlotEntityAddressTag = "entity"
private val SlotEntityIdTag = "entity_id"
private val InitialSyncFuel = 5

View File

@ -8,7 +8,7 @@ import totoro.ocelot.brain.entity.traits.{Entity, GenericCPU, GenericGPU}
import totoro.ocelot.brain.util.Tier.Tier
class ApuItem(val apu: APU) extends Item with ComponentItem with PersistableItem with CpuLikeItem with GpuLikeItem {
override def component: Entity with GenericCPU with GenericGPU = apu
override def entity: Entity with GenericCPU with GenericGPU = apu
override def factory: ApuItem.Factory = new ApuItem.Factory(apu.tier)
}

View File

@ -1,16 +1,14 @@
package ocelot.desktop.inventory.item
import ocelot.desktop.graphics.IconSource
import ocelot.desktop.inventory.traits.ComponentItem
import ocelot.desktop.inventory.traits.EntityItem
import ocelot.desktop.inventory.{Item, ItemFactory, ItemRecoverer}
import ocelot.desktop.ui.widget.tooltip.ItemTooltip
import totoro.ocelot.brain.entity.ComponentBus
import totoro.ocelot.brain.entity.traits.{Entity, Environment}
import totoro.ocelot.brain.util.Tier.Tier
class ComponentBusItem(val componentBus: ComponentBus) extends Item with ComponentItem {
override def component: Entity with Environment = componentBus
override def showAddress: Boolean = false
class ComponentBusItem(val componentBus: ComponentBus) extends Item with EntityItem {
override def entity: ComponentBus = componentBus
override def factory: ItemFactory = new ComponentBusItem.Factory(componentBus.tier)
override def fillTooltip(tooltip: ItemTooltip): Unit = {

View File

@ -8,7 +8,7 @@ import totoro.ocelot.brain.entity.traits.{Entity, GenericCPU}
import totoro.ocelot.brain.util.Tier.Tier
class CpuItem(val cpu: CPU) extends Item with ComponentItem with PersistableItem with CpuLikeItem {
override def component: Entity with GenericCPU = cpu
override def entity: Entity with GenericCPU = cpu
override def factory: CpuItem.Factory = new CpuItem.Factory(cpu.tier)
}

View File

@ -28,7 +28,7 @@ object DataCardItem {
}
class Tier1(val dataCard: DataCard.Tier1) extends DataCardItem {
override def component: Entity with Environment = dataCard
override def entity: Entity with Environment = dataCard
override def factory: Factory = DataCardItem.Tier1.Factory
}
@ -48,7 +48,7 @@ object DataCardItem {
}
class Tier2(val dataCard: DataCard.Tier2) extends DataCardItem {
override def component: Entity with Environment = dataCard
override def entity: Entity with Environment = dataCard
override def factory: Factory = DataCardItem.Tier2.Factory
}
@ -68,7 +68,7 @@ object DataCardItem {
}
class Tier3(val dataCard: DataCard.Tier3) extends DataCardItem {
override def component: Entity with Environment = dataCard
override def entity: Entity with Environment = dataCard
override def factory: Factory = DataCardItem.Tier3.Factory
}

View File

@ -12,7 +12,7 @@ import totoro.ocelot.brain.util.Tier.Tier
class DiskDriveMountableItem(val diskDriveMountable: DiskDriveMountable) extends RackMountableItem with DiskDriveAware {
override def floppyDiskDrive: FloppyDiskDrive = diskDriveMountable
override def component: DiskDriveMountable = diskDriveMountable
override def entity: DiskDriveMountable = diskDriveMountable
override def factory: ItemFactory = DiskDriveMountableItem.Factory
override def fillTooltip(tooltip: ItemTooltip): Unit = {

View File

@ -18,7 +18,7 @@ import javax.swing.JFileChooser
import scala.util.Try
class EepromItem(val eeprom: EEPROM) extends Item with ComponentItem with PersistableItem {
override def component: Entity with Environment = eeprom
override def entity: Entity with Environment = eeprom
override def fillTooltip(tooltip: ItemTooltip): Unit = {
super.fillTooltip(tooltip)

View File

@ -12,7 +12,7 @@ import totoro.ocelot.brain.util.DyeColor
import totoro.ocelot.brain.util.Tier.Tier
class FloppyItem(var floppy: Floppy) extends Item with ComponentItem with PersistableItem with DiskItem {
override def component: Entity with Disk = floppy
override def entity: Entity with Disk = floppy
override def diskKind: String = "Floppy"

View File

@ -9,7 +9,7 @@ import totoro.ocelot.brain.util.Tier.Tier
class GraphicsCardItem(val gpu: GraphicsCard)
extends Item with ComponentItem with PersistableItem with CardItem with GpuLikeItem {
override def component: Entity with GenericGPU = gpu
override def entity: Entity with GenericGPU = gpu
override def factory: GraphicsCardItem.Factory = new GraphicsCardItem.Factory(gpu.tier)
}

View File

@ -20,7 +20,7 @@ class HddItem(var hdd: Hdd) extends Item with ComponentItem with PersistableItem
this(Hdd.Unmanaged(hdd))
}
override def component: Entity with Disk = hdd.hdd
override def entity: Entity with Disk = hdd.hdd
override def diskKind: String = "HDD"

View File

@ -9,7 +9,7 @@ import totoro.ocelot.brain.util.Tier
import totoro.ocelot.brain.util.Tier.Tier
class InternetCardItem(val card: InternetCard) extends Item with ComponentItem with PersistableItem with CardItem {
override def component: Entity with Environment = card
override def entity: Entity with Environment = card
override def factory: ItemFactory = InternetCardItem.Factory
}

View File

@ -12,7 +12,7 @@ import totoro.ocelot.brain.util.Tier
import totoro.ocelot.brain.util.Tier.Tier
class LinkedCardItem(val linkedCard: LinkedCard) extends Item with ComponentItem with PersistableItem with CardItem {
override def component: Entity with Environment = linkedCard
override def entity: Entity with Environment = linkedCard
override def fillTooltip(tooltip: ItemTooltip): Unit = {
super.fillTooltip(tooltip)

View File

@ -10,7 +10,7 @@ import totoro.ocelot.brain.util.ExtendedTier.ExtendedTier
import totoro.ocelot.brain.util.Tier.Tier
class MemoryItem(val memory: Memory) extends Item with ComponentItem with PersistableItem {
override def component: Entity with Environment = memory
override def entity: Entity with Environment = memory
override def factory: ItemFactory = new MemoryItem.Factory(memory.memoryTier)

View File

@ -10,7 +10,7 @@ import totoro.ocelot.brain.util.Tier
import totoro.ocelot.brain.util.Tier.Tier
class NetworkCardItem(val card: NetworkCard) extends Item with ComponentItem with PersistableItem with CardItem {
override def component: Entity with NetworkCard = card
override def entity: Entity with NetworkCard = card
override def factory: ItemFactory = NetworkCardItem.Factory

View File

@ -16,7 +16,7 @@ import totoro.ocelot.brain.util.Tier.Tier
class OcelotCardItem(val ocelotCard: OcelotCard)
extends Item with ComponentItem with OcelotInterfaceLogStorage with PersistableItem with CardItem with Logging {
override def component: OcelotCard = ocelotCard
override def entity: OcelotCard = ocelotCard
override def ocelotInterface: OcelotInterface = ocelotCard

View File

@ -23,7 +23,7 @@ object RedstoneCardItem {
}
class Tier1(val redstoneCard: Redstone.Tier1) extends RedstoneCardItem {
override def component: Entity with Environment = redstoneCard
override def entity: Entity with Environment = redstoneCard
override def factory: Factory = RedstoneCardItem.Tier1.Factory
@ -80,7 +80,7 @@ object RedstoneCardItem {
}
class Tier2(override val redstoneCard: Redstone.Tier2) extends RedstoneCardItem.Tier1(redstoneCard) {
override def component: Entity with Environment = redstoneCard
override def entity: Entity with Environment = redstoneCard
override def factory: Factory = RedstoneCardItem.Tier2.Factory

View File

@ -12,7 +12,7 @@ import totoro.ocelot.brain.util.Tier.Tier
class SelfDestructingCardItem(val card: SelfDestructingCard)
extends Item with ComponentItem with PersistableItem with CardItem {
override def component: Entity with Environment = card
override def entity: Entity with Environment = card
override def factory: ItemFactory = SelfDestructingCardItem.Factory

View File

@ -12,7 +12,7 @@ import totoro.ocelot.brain.util.Tier
import totoro.ocelot.brain.util.Tier.Tier
class ServerItem(val server: Server) extends RackMountableItem with AudibleComputerAware {
override def component: Server = server
override def entity: Server = server
override def factory: ItemFactory = new ServerItem.Factory(server.tier)
override def onRemoved(): Unit = {

View File

@ -16,7 +16,7 @@ class SoundCardItem(val soundCard: SoundCard)
override def createWindow(): SoundCardWindow = new SoundCardWindow(soundCard)
override def component: Entity with Environment = soundCard
override def entity: Entity with Environment = soundCard
override def fillRmbMenu(menu: ContextMenu): Unit = {
menu.addEntry(ContextMenuEntry("Open card interface", IconSource.Window) {

View File

@ -2,7 +2,7 @@ package ocelot.desktop.inventory.item
import ocelot.desktop.OcelotDesktop
import ocelot.desktop.graphics.IconSource
import ocelot.desktop.inventory.traits.ComponentItem
import ocelot.desktop.inventory.traits.EntityItem
import ocelot.desktop.inventory.{Item, ItemFactory, ItemRecoverer}
import ocelot.desktop.ui.widget.tooltip.ItemTooltip
import ocelot.desktop.util.SizeFormatting.formatSize
@ -10,12 +10,10 @@ import totoro.ocelot.brain.entity.tape.Tape
import totoro.ocelot.brain.nbt.NBTTagCompound
import totoro.ocelot.brain.util.Tier.Tier
class TapeItem(var tape: Tape) extends Item with ComponentItem {
class TapeItem(var tape: Tape) extends Item with EntityItem {
def this() = this(new Tape)
override def component: Tape = tape
override def showAddress: Boolean = false
override def entity: Tape = tape
override def fillTooltip(tooltip: ItemTooltip): Unit = {
super.fillTooltip(tooltip)

View File

@ -1,70 +1,30 @@
package ocelot.desktop.inventory.traits
import ocelot.desktop.OcelotDesktop
import ocelot.desktop.graphics.IconSource
import ocelot.desktop.inventory.Item
import ocelot.desktop.ui.UiHandler
import ocelot.desktop.ui.widget.contextmenu.{ContextMenu, ContextMenuEntry}
import ocelot.desktop.ui.widget.tooltip.ItemTooltip
import totoro.ocelot.brain.entity.traits.{Entity, Environment, WorkspaceAware}
import totoro.ocelot.brain.entity.traits.{Entity, Environment}
/** Implemented by [[Item]]s that wrap a component.
*
* @note Subclasses must provide a unary constructor that accepts the [[component]].
*/
trait ComponentItem extends Item with PersistableItem {
/** The component wrapped by this item.
*
* @note The value must already be available during the initialization.
*/
def component: Entity with Environment
private def setWorkspace(): Unit = component match {
case component: WorkspaceAware => component.workspace = OcelotDesktop.workspace
case _ =>
}
override def reinserting(f: => Unit): Unit = super.reinserting {
// removal may have set the workspace to null
setWorkspace()
f
// since we have absolutely no idea what f does, workspace could've been set to null again
setWorkspace()
}
setWorkspace()
override def onInserted(): Unit = {
super.onInserted()
// this one isn't strictly necessary, I believe, but I'll keep this for the sake of symmetry and safety
setWorkspace()
}
override def onRemoved(): Unit = {
super.onRemoved()
// fix up ComponentInventory's zeroing out the workspace
setWorkspace()
}
/** Implemented by [[Item]]s that wrap a component. */
trait ComponentItem extends EntityItem {
override def entity: Entity with Environment
override def shouldReceiveEventsFor(address: String): Boolean =
super.shouldReceiveEventsFor(address) || Option(component.node).exists(_.address == address)
super.shouldReceiveEventsFor(address) || Option(entity.node).exists(_.address == address)
override def fillTooltip(tooltip: ItemTooltip): Unit = {
super.fillTooltip(tooltip)
if (showAddress) {
tooltip.addLine(s"Address: ${component.node.address}")
tooltip.addLine(s"Address: ${entity.node.address}")
}
}
override def fillRmbMenu(menu: ContextMenu): Unit = {
menu.addEntry(ContextMenuEntry("Copy address", IconSource.Copy) {
UiHandler.clipboard = component.node.address
UiHandler.clipboard = entity.node.address
})
super.fillRmbMenu(menu)

View File

@ -10,19 +10,19 @@ import totoro.ocelot.brain.entity.traits.{Entity, GenericCPU}
/** An [[Item]] that acts as a CPU and can therefore be inserted into a CPU slot. */
trait CpuLikeItem extends ComponentItem {
override def component: Entity with GenericCPU
override def entity: Entity with GenericCPU
override def fillRmbMenu(menu: ContextMenu): Unit = {
menu.addEntry(new ContextMenuSubmenu("Set architecture", Some(ContextMenuIcon(IconSource.Microchip))) {
for (arch <- component.allArchitectures) {
for (arch <- entity.allArchitectures) {
val name = MachineAPI.getArchitectureName(arch) +
(if (arch == component.architecture) " (current)" else "")
(if (arch == entity.architecture) " (current)" else "")
val entry = ContextMenuEntry(name) {
component.setArchitecture(arch)
entity.setArchitecture(arch)
notifySlot(CpuArchitectureChangedNotification)
}
entry.setEnabled(arch != component.architecture)
entry.setEnabled(arch != entity.architecture)
addEntry(entry)
}
})
@ -32,8 +32,8 @@ trait CpuLikeItem extends ComponentItem {
override def fillTooltip(tooltip: ItemTooltip): Unit = {
super.fillTooltip(tooltip)
if (component != null) {
tooltip.addLine(s"Components: ${component.supportedComponents}")
if (entity != null) {
tooltip.addLine(s"Components: ${entity.supportedComponents}")
}
}
}

View File

@ -15,7 +15,7 @@ import scala.util.Try
/** A utility mixin for HDDs and floppies. */
trait DiskItem extends ComponentItem with Windowed[DiskEditWindow] {
override def component: Entity with Disk
override def entity: Entity with Disk
def diskKind: String
@ -32,7 +32,7 @@ trait DiskItem extends ComponentItem with Windowed[DiskEditWindow] {
def setManaged(managed: Boolean): Unit
def lock(): Unit = reinserting {
component.setLocked(OcelotDesktop.player.nickname)
entity.setLocked(OcelotDesktop.player.nickname)
}
override def createWindow(): DiskEditWindow = new DiskEditWindow(DiskItem.this)
@ -47,7 +47,7 @@ trait DiskItem extends ComponentItem with Windowed[DiskEditWindow] {
override def fillRmbMenu(menu: ContextMenu): Unit = {
if (isEditingAllowed) {
// Real path
component match {
entity match {
case diskManaged: DiskManaged =>
DiskItem.addRealPathContextMenuEntries(menu, diskManaged,
realPathSetter => {
@ -86,8 +86,8 @@ trait DiskItem extends ComponentItem with Windowed[DiskEditWindow] {
override def fillTooltip(tooltip: ItemTooltip): Unit = {
super.fillTooltip(tooltip)
if (component != null) {
tooltip.addLine(s"Capacity: ${component.capacity / 1024} kB")
if (entity != null) {
tooltip.addLine(s"Capacity: ${entity.capacity / 1024} kB")
}
}
}

View File

@ -0,0 +1,48 @@
package ocelot.desktop.inventory.traits
import ocelot.desktop.OcelotDesktop
import ocelot.desktop.inventory.Item
import totoro.ocelot.brain.entity.traits.{Entity, WorkspaceAware}
/** Implemented by [[Item]]s that wrap an [[Entity]].
*
* @note Subclasses must provide a unary constructor that accepts the [[entity]].
*/
trait EntityItem extends Item with PersistableItem {
/** The entity wrapped by this item.
*
* @note The value must already be available during the trait's initialization.
*/
def entity: Entity
private def setWorkspace(): Unit = entity match {
case entity: WorkspaceAware => entity.workspace = OcelotDesktop.workspace
case _ =>
}
override def reinserting(f: => Unit): Unit = super.reinserting {
// removal may have set the workspace to null
setWorkspace()
f
// since we have absolutely no idea what f does, workspace could've been set to null again
setWorkspace()
}
setWorkspace()
override def onInserted(): Unit = {
super.onInserted()
// this one isn't strictly necessary, I believe, but I'll keep this for the sake of symmetry and safety
setWorkspace()
}
override def onRemoved(): Unit = {
super.onRemoved()
// fix up ComponentInventory's zeroing out the workspace
setWorkspace()
}
}

View File

@ -6,20 +6,20 @@ import totoro.ocelot.brain.entity.traits.{Entity, GenericGPU}
import totoro.ocelot.brain.util.ColorDepth
trait GpuLikeItem extends ComponentItem {
override def component: Entity with GenericGPU
override def entity: Entity with GenericGPU
override def fillTooltip(tooltip: ItemTooltip): Unit = {
super.fillTooltip(tooltip)
if (component != null) {
val resolution = Settings.screenResolutionsByTier(component.tier.id)
if (entity != null) {
val resolution = Settings.screenResolutionsByTier(entity.tier.id)
tooltip.addLine(s"Max resolution: ${resolution._1}×${resolution._2}")
val depth = Settings.screenDepthsByTier(component.tier.id) match {
val depth = Settings.screenDepthsByTier(entity.tier.id) match {
case ColorDepth.OneBit => "1 bit"
case ColorDepth.FourBit => "4 bit"
case ColorDepth.EightBit => "8 bit"
}
tooltip.addLine(s"Max color depth: $depth")
tooltip.addLine(s"VRAM: ${component.totalVRAM.toInt}")
tooltip.addLine(s"VRAM: ${entity.totalVRAM.toInt}")
}
}
}

View File

@ -7,7 +7,7 @@ import totoro.ocelot.brain.entity.result
import totoro.ocelot.brain.entity.traits.{Entity, RackMountable}
trait RackMountableItem extends Item with ComponentItem {
override def component: Entity with RackMountable
override def entity: Entity with RackMountable
def isInRack: Boolean = slot.exists(_.inventory.isInstanceOf[RackNode])

View File

@ -37,6 +37,7 @@ class RackNode(val rack: Rack) extends ComputerAwareNode(rack) with WindowedNode
case mountable: RackMountable if mountable.node.address == address => true
case mountable: RackMountable with ComponentInventory => mountable.inventory.entities.exists {
case environment: Environment => environment.node.address == address
case _ => false
}
case _ => false
}

View File

@ -14,23 +14,23 @@ import totoro.ocelot.brain.entity.traits.{DiskManaged, DiskUnmanaged}
import totoro.ocelot.brain.util.DyeColor
class DiskEditWindow(item: DiskItem) extends PanelWindow {
private def diskSize: Option[Long] = Some(item.component).collect { case disk: DiskManaged =>
private def diskSize: Option[Long] = Some(item.entity).collect { case disk: DiskManaged =>
disk.fileSystem.fileSystem.spaceUsed
}
private def diskCapacity: Long = item.component.capacity
private def diskCapacity: Long = item.entity.capacity
private def isWriteable: Boolean = item.component match {
private def isWriteable: Boolean = item.entity match {
case disk: DiskManaged => !disk.fileSystem.fileSystem.isReadOnly
case disk: DiskUnmanaged => !disk.isLocked
}
private def isManaged: Boolean = item.component match {
private def isManaged: Boolean = item.entity match {
case _: DiskManaged => true
case _: DiskUnmanaged => false
}
private def address: Option[String] = Option(item.component.node).flatMap(node => Option(node.address))
private def address: Option[String] = Option(item.entity.node).flatMap(node => Option(node.address))
override protected def title: String = s"${item.diskKind} " + address.getOrElse("")