diff --git a/lib/ocelot-brain b/lib/ocelot-brain index e1968df..648e47c 160000 --- a/lib/ocelot-brain +++ b/lib/ocelot-brain @@ -1 +1 @@ -Subproject commit e1968df8a58fab83572e657d981b7263c7edd72a +Subproject commit 648e47c42ca2ab4eb676ccc3dcddf129eac771af diff --git a/src/main/scala/ocelot/desktop/inventory/PersistedInventory.scala b/src/main/scala/ocelot/desktop/inventory/PersistedInventory.scala index 6d456b9..cea5551 100644 --- a/src/main/scala/ocelot/desktop/inventory/PersistedInventory.scala +++ b/src/main/scala/ocelot/desktop/inventory/PersistedInventory.scala @@ -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)) } } diff --git a/src/main/scala/ocelot/desktop/inventory/SyncedInventory.scala b/src/main/scala/ocelot/desktop/inventory/SyncedInventory.scala index 3d92d95..d593725 100644 --- a/src/main/scala/ocelot/desktop/inventory/SyncedInventory.scala +++ b/src/main/scala/ocelot/desktop/inventory/SyncedInventory.scala @@ -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 diff --git a/src/main/scala/ocelot/desktop/inventory/item/ApuItem.scala b/src/main/scala/ocelot/desktop/inventory/item/ApuItem.scala index 2f9c09d..012e07a 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/ApuItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/ApuItem.scala @@ -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) } diff --git a/src/main/scala/ocelot/desktop/inventory/item/ComponentBusItem.scala b/src/main/scala/ocelot/desktop/inventory/item/ComponentBusItem.scala index a014e3c..bd7c704 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/ComponentBusItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/ComponentBusItem.scala @@ -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 = { diff --git a/src/main/scala/ocelot/desktop/inventory/item/CpuItem.scala b/src/main/scala/ocelot/desktop/inventory/item/CpuItem.scala index 2901908..44b5668 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/CpuItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/CpuItem.scala @@ -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) } diff --git a/src/main/scala/ocelot/desktop/inventory/item/DataCardItem.scala b/src/main/scala/ocelot/desktop/inventory/item/DataCardItem.scala index 485996d..49a67f5 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/DataCardItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/DataCardItem.scala @@ -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 } diff --git a/src/main/scala/ocelot/desktop/inventory/item/DiskDriveMountableItem.scala b/src/main/scala/ocelot/desktop/inventory/item/DiskDriveMountableItem.scala index a3a84f6..2da6072 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/DiskDriveMountableItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/DiskDriveMountableItem.scala @@ -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 = { diff --git a/src/main/scala/ocelot/desktop/inventory/item/EepromItem.scala b/src/main/scala/ocelot/desktop/inventory/item/EepromItem.scala index 99a7b94..727a06d 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/EepromItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/EepromItem.scala @@ -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) diff --git a/src/main/scala/ocelot/desktop/inventory/item/FloppyItem.scala b/src/main/scala/ocelot/desktop/inventory/item/FloppyItem.scala index 8129efe..097ec56 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/FloppyItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/FloppyItem.scala @@ -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" diff --git a/src/main/scala/ocelot/desktop/inventory/item/GraphicsCardItem.scala b/src/main/scala/ocelot/desktop/inventory/item/GraphicsCardItem.scala index f1e21a6..c3590ef 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/GraphicsCardItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/GraphicsCardItem.scala @@ -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) } diff --git a/src/main/scala/ocelot/desktop/inventory/item/HddItem.scala b/src/main/scala/ocelot/desktop/inventory/item/HddItem.scala index 6da9467..87f1a61 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/HddItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/HddItem.scala @@ -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" diff --git a/src/main/scala/ocelot/desktop/inventory/item/InternetCardItem.scala b/src/main/scala/ocelot/desktop/inventory/item/InternetCardItem.scala index 47b92fc..359a1eb 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/InternetCardItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/InternetCardItem.scala @@ -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 } diff --git a/src/main/scala/ocelot/desktop/inventory/item/LinkedCardItem.scala b/src/main/scala/ocelot/desktop/inventory/item/LinkedCardItem.scala index 6076d4a..6ccdda9 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/LinkedCardItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/LinkedCardItem.scala @@ -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) diff --git a/src/main/scala/ocelot/desktop/inventory/item/MemoryItem.scala b/src/main/scala/ocelot/desktop/inventory/item/MemoryItem.scala index d7f83e2..9431b15 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/MemoryItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/MemoryItem.scala @@ -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) diff --git a/src/main/scala/ocelot/desktop/inventory/item/NetworkCardItem.scala b/src/main/scala/ocelot/desktop/inventory/item/NetworkCardItem.scala index 70156a8..7cd41d6 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/NetworkCardItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/NetworkCardItem.scala @@ -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 diff --git a/src/main/scala/ocelot/desktop/inventory/item/OcelotCardItem.scala b/src/main/scala/ocelot/desktop/inventory/item/OcelotCardItem.scala index 4cd357e..69a6629 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/OcelotCardItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/OcelotCardItem.scala @@ -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 diff --git a/src/main/scala/ocelot/desktop/inventory/item/RedstoneCardItem.scala b/src/main/scala/ocelot/desktop/inventory/item/RedstoneCardItem.scala index 374cbfb..29635dc 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/RedstoneCardItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/RedstoneCardItem.scala @@ -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 diff --git a/src/main/scala/ocelot/desktop/inventory/item/SelfDestructingCardItem.scala b/src/main/scala/ocelot/desktop/inventory/item/SelfDestructingCardItem.scala index 23fbc29..380c87c 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/SelfDestructingCardItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/SelfDestructingCardItem.scala @@ -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 diff --git a/src/main/scala/ocelot/desktop/inventory/item/ServerItem.scala b/src/main/scala/ocelot/desktop/inventory/item/ServerItem.scala index 5f6f4dd..dfdf032 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/ServerItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/ServerItem.scala @@ -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 = { diff --git a/src/main/scala/ocelot/desktop/inventory/item/SoundCardItem.scala b/src/main/scala/ocelot/desktop/inventory/item/SoundCardItem.scala index bad4fb4..a473d2a 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/SoundCardItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/SoundCardItem.scala @@ -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) { diff --git a/src/main/scala/ocelot/desktop/inventory/item/TapeItem.scala b/src/main/scala/ocelot/desktop/inventory/item/TapeItem.scala index 4e129e6..ad0b6d9 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/TapeItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/TapeItem.scala @@ -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) diff --git a/src/main/scala/ocelot/desktop/inventory/traits/ComponentItem.scala b/src/main/scala/ocelot/desktop/inventory/traits/ComponentItem.scala index 87fa07d..a35f2a5 100644 --- a/src/main/scala/ocelot/desktop/inventory/traits/ComponentItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/traits/ComponentItem.scala @@ -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) diff --git a/src/main/scala/ocelot/desktop/inventory/traits/CpuLikeItem.scala b/src/main/scala/ocelot/desktop/inventory/traits/CpuLikeItem.scala index 044b0fb..ee98e5e 100644 --- a/src/main/scala/ocelot/desktop/inventory/traits/CpuLikeItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/traits/CpuLikeItem.scala @@ -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}") } } } diff --git a/src/main/scala/ocelot/desktop/inventory/traits/DiskItem.scala b/src/main/scala/ocelot/desktop/inventory/traits/DiskItem.scala index 71af1d8..d006806 100644 --- a/src/main/scala/ocelot/desktop/inventory/traits/DiskItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/traits/DiskItem.scala @@ -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") } } } diff --git a/src/main/scala/ocelot/desktop/inventory/traits/EntityItem.scala b/src/main/scala/ocelot/desktop/inventory/traits/EntityItem.scala new file mode 100644 index 0000000..c35feaf --- /dev/null +++ b/src/main/scala/ocelot/desktop/inventory/traits/EntityItem.scala @@ -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() + } +} diff --git a/src/main/scala/ocelot/desktop/inventory/traits/GpuLikeItem.scala b/src/main/scala/ocelot/desktop/inventory/traits/GpuLikeItem.scala index dff1330..dc36a72 100644 --- a/src/main/scala/ocelot/desktop/inventory/traits/GpuLikeItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/traits/GpuLikeItem.scala @@ -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}") } } } diff --git a/src/main/scala/ocelot/desktop/inventory/traits/RackMountableItem.scala b/src/main/scala/ocelot/desktop/inventory/traits/RackMountableItem.scala index f5d3ed3..e53e7c1 100644 --- a/src/main/scala/ocelot/desktop/inventory/traits/RackMountableItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/traits/RackMountableItem.scala @@ -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]) diff --git a/src/main/scala/ocelot/desktop/node/nodes/RackNode.scala b/src/main/scala/ocelot/desktop/node/nodes/RackNode.scala index b2853f4..2081665 100644 --- a/src/main/scala/ocelot/desktop/node/nodes/RackNode.scala +++ b/src/main/scala/ocelot/desktop/node/nodes/RackNode.scala @@ -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 } diff --git a/src/main/scala/ocelot/desktop/ui/widget/DiskEditWindow.scala b/src/main/scala/ocelot/desktop/ui/widget/DiskEditWindow.scala index 152a563..488d4d7 100644 --- a/src/main/scala/ocelot/desktop/ui/widget/DiskEditWindow.scala +++ b/src/main/scala/ocelot/desktop/ui/widget/DiskEditWindow.scala @@ -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("")