diff --git a/src/main/scala/ocelot/desktop/OcelotDesktop.scala b/src/main/scala/ocelot/desktop/OcelotDesktop.scala index 64a53bb..35d6c40 100644 --- a/src/main/scala/ocelot/desktop/OcelotDesktop.scala +++ b/src/main/scala/ocelot/desktop/OcelotDesktop.scala @@ -2,6 +2,7 @@ package ocelot.desktop import buildinfo.BuildInfo import li.flor.nativejfilechooser.NativeJFileChooser +import ocelot.desktop.inventory.Items import ocelot.desktop.ui.UiHandler import ocelot.desktop.ui.swing.SplashScreen import ocelot.desktop.ui.widget._ @@ -64,6 +65,8 @@ object OcelotDesktop extends Logging { Messages.load(Source.fromURL(getClass.getResource("/ocelot/desktop/messages.txt"))) ColorScheme.load(Source.fromURL(getClass.getResource("/ocelot/desktop/colorscheme.txt"))) + Items.init() + splashScreen.setStatus("Initializing GUI...", 0.30f) createWorkspace() diff --git a/src/main/scala/ocelot/desktop/inventory/Item.scala b/src/main/scala/ocelot/desktop/inventory/Item.scala index 6629fd0..d1ecf39 100644 --- a/src/main/scala/ocelot/desktop/inventory/Item.scala +++ b/src/main/scala/ocelot/desktop/inventory/Item.scala @@ -64,6 +64,7 @@ trait Item { * * @example {{{ * override protected def fillTooltipBody(body: Widget): Unit = { + * super.fillTooltipBody(body) * body.children :+= new Label { * override def text: String = "Hello world" * override def color: Color = Color.Grey diff --git a/src/main/scala/ocelot/desktop/inventory/ItemFactory.scala b/src/main/scala/ocelot/desktop/inventory/ItemFactory.scala index 8d3ea99..23d5426 100644 --- a/src/main/scala/ocelot/desktop/inventory/ItemFactory.scala +++ b/src/main/scala/ocelot/desktop/inventory/ItemFactory.scala @@ -51,4 +51,9 @@ trait ItemFactory { * Constructs a new item instance. */ def build(): I + + /** + * Returns a list of recoverers provided by the factory, + */ + def recoverers: Iterable[ItemRecoverer[_, _]] } diff --git a/src/main/scala/ocelot/desktop/inventory/ItemRecoverer.scala b/src/main/scala/ocelot/desktop/inventory/ItemRecoverer.scala index 4bf4591..7a41969 100644 --- a/src/main/scala/ocelot/desktop/inventory/ItemRecoverer.scala +++ b/src/main/scala/ocelot/desktop/inventory/ItemRecoverer.scala @@ -1,12 +1,18 @@ package ocelot.desktop.inventory +import scala.reflect.{ClassTag, classTag} + /** * Allows recovering an [[Item]] from [[S]] (typically an [[totoro.ocelot.brain.entity.traits.Entity Entity]]). * * This is used for migration from old saves before the inventory system was introduced to Ocelot Desktop. */ -trait ItemRecoverer[S] { - type I <: Item +final class ItemRecoverer[S: ClassTag, I <: Item](f: S => I) { + val sourceClass: Class[_] = classTag[S].runtimeClass - def recover(source: S): I + def recover(source: S): I = f(source) +} + +object ItemRecoverer { + def apply[S: ClassTag, I <: Item](f: S => I): ItemRecoverer[S, I] = new ItemRecoverer(f) } diff --git a/src/main/scala/ocelot/desktop/inventory/Items.scala b/src/main/scala/ocelot/desktop/inventory/Items.scala new file mode 100644 index 0000000..f0cf262 --- /dev/null +++ b/src/main/scala/ocelot/desktop/inventory/Items.scala @@ -0,0 +1,140 @@ +package ocelot.desktop.inventory + +import ocelot.desktop.graphics.IconDef +import ocelot.desktop.inventory.item._ +import ocelot.desktop.util.Logging +import ocelot.desktop.util.ReflectionUtils.linearizationOrder +import totoro.ocelot.brain.loot.Loot +import totoro.ocelot.brain.util.ExtendedTier.ExtendedTier +import totoro.ocelot.brain.util.Tier.Tier +import totoro.ocelot.brain.util.{ExtendedTier, Tier} + +import scala.collection.mutable +import scala.collection.mutable.ArrayBuffer + +object Items extends Logging { + private val _groups = ArrayBuffer.empty[ItemGroup] + private val _recoverers = mutable.Map.empty[Class[_], ItemRecoverer[_, _]] + + // this is just to force load the class during initialization + def init(): Unit = {} + + /** Registers a recoverer for [[ItemRecoverer.sourceClass]]. + */ + def registerRecoverer(recoverer: ItemRecoverer[_, _]): Unit = { + if (!_recoverers.contains(recoverer.sourceClass)) { + _recoverers(recoverer.sourceClass) = recoverer + logger.info(s"Registered a recoverer for ${recoverer.sourceClass.getName}") + } + } + + private def registerItemFactoryRecoverers(factory: ItemFactory): Unit = { + for (recoverer <- factory.recoverers) { + registerRecoverer(recoverer) + } + } + + def registerSingleton(factory: ItemFactory): Unit = { + _groups += SingletonItemGroup(factory.name, factory) + registerItemFactoryRecoverers(factory) + } + + def registerTiered(name: String, tiers: IterableOnce[Tier])(factory: Tier => ItemFactory): Unit = { + val group = TieredItemGroup(name, tiers.iterator.map(tier => (tier, factory(tier))).toSeq) + _groups += group + + for ((_, factory) <- group.factories) { + registerItemFactoryRecoverers(factory) + } + } + + def registerExtendedTiered(name: String, tiers: IterableOnce[ExtendedTier])( + factory: ExtendedTier => ItemFactory + ): Unit = { + val group = ExtendedTieredItemGroup(name, tiers.iterator.map(tier => (tier, factory(tier))).toSeq) + _groups += group + + for ((_, factory) <- group.factories) { + registerItemFactoryRecoverers(factory) + } + } + + def registerArbitrary(name: String, icon: IconDef, factories: IterableOnce[(String, ItemFactory)]): Unit = { + val group = ArbitraryItemGroup(name, icon, factories.iterator.toSeq) + _groups += group + + for ((_, factory) <- group.factories) { + registerItemFactoryRecoverers(factory) + } + } + + def groups: Iterable[ItemGroup] = _groups + + /** Attempts to recover an [[Item]] from `source`. + * + * Checks superclasses and traits while looking for a recoverer. + */ + def recover[A](source: A): Option[Item] = { + linearizationOrder(source.getClass.asInstanceOf[Class[_]]) + .flatMap(_recoverers.get) + .map(_.asInstanceOf[ItemRecoverer[_ >: A, _ <: Item]].recover(source)) + .nextOption() + } + + sealed trait ItemGroup { + def name: String + } + + case class SingletonItemGroup(name: String, factory: ItemFactory) extends ItemGroup + + case class TieredItemGroup(name: String, factories: Seq[(Tier, ItemFactory)]) extends ItemGroup + + case class ExtendedTieredItemGroup(name: String, factories: Seq[(ExtendedTier, ItemFactory)]) extends ItemGroup + + case class ArbitraryItemGroup(name: String, icon: IconDef, factories: Seq[(String, ItemFactory)]) extends ItemGroup + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + registerTiered("CPU", Tier.One to Tier.Three)(new CpuItem.Factory(_)) + registerTiered("APU", Tier.Two to Tier.Creative)(tier => new ApuItem.Factory(tier.saturatingSub(1))) + + registerExtendedTiered("Memory", ExtendedTier.One to ExtendedTier.ThreeHalf)(new MemoryItem.Factory(_)) + + registerTiered("HDD", Tier.One to Tier.Three)(new HddItem.Factory(managed = true, _)) + + registerArbitrary( + "Floppy", + FloppyItem.Factory.Empty.icon, + Loot.Floppies.iterator + .map(new FloppyItem.Factory.Loot(_)) + .map(factory => (factory.name, factory)) ++ Some(("Empty", FloppyItem.Factory.Empty)) + ) + + registerArbitrary( + "EEPROM", + EepromItem.Factory.Empty.icon, + Loot.Eeproms.iterator + .map(new EepromItem.Factory.Loot(_)) + .map(factory => (factory.name, factory)) ++ Some(("Empty", EepromItem.Factory.Empty)) + ) + + registerTiered("Graphics Card", Tier.One to Tier.Three)(new GraphicsCardItem.Factory(_)) + registerSingleton(NetworkCardItem.Factory) + registerTiered("Wireless Net. Card", Tier.One to Tier.Two) { + case Tier.One => WirelessNetworkCardItem.Tier1.Factory + case Tier.Two => WirelessNetworkCardItem.Tier2.Factory + } + registerSingleton(LinkedCardItem.Factory) + registerSingleton(InternetCardItem.Factory) + registerTiered("Redstone Card", Tier.One to Tier.Two) { + case Tier.One => RedstoneCardItem.Tier1.Factory + case Tier.Two => RedstoneCardItem.Tier2.Factory + } + registerTiered("Data Card", Tier.One to Tier.Three) { + case Tier.One => DataCardItem.Tier1.Factory + case Tier.Two => DataCardItem.Tier2.Factory + case Tier.Three => DataCardItem.Tier3.Factory + } + registerSingleton(SoundCardItem.Factory) + registerSingleton(SelfDestructingCardItem.Factory) +} diff --git a/src/main/scala/ocelot/desktop/inventory/Recoverers.scala b/src/main/scala/ocelot/desktop/inventory/Recoverers.scala deleted file mode 100644 index 8fe01b8..0000000 --- a/src/main/scala/ocelot/desktop/inventory/Recoverers.scala +++ /dev/null @@ -1,57 +0,0 @@ -package ocelot.desktop.inventory - -import ocelot.desktop.inventory.item._ -import ocelot.desktop.util.ReflectionUtils.linearizationOrder -import totoro.ocelot.brain.entity -import totoro.ocelot.brain.entity.sound_card.SoundCard -import totoro.ocelot.brain.entity.traits.Floppy - -import scala.collection.mutable -import scala.reflect.{ClassTag, classTag} - -/** - * A registry of all available [[ItemRecoverer item recoverers]]. - */ -object Recoverers { - private val recoverers = mutable.HashMap.empty[Class[_], ItemRecoverer[_]] - - /** - * Registers a recoverer for [[S]]. - */ - def register[S: ClassTag](recoverer: ItemRecoverer[S]): Unit = { - recoverers(classTag[S].runtimeClass) = recoverer - } - - /** - * Attempts to recover an [[Item]] from `source`. - * - * Checks superclasses and traits while looking for a recoverer. - */ - def recover[A](source: A): Option[Item] = { - linearizationOrder(source.getClass.asInstanceOf[Class[_]]) - .flatMap(recoverers.get) - .map(_.asInstanceOf[ItemRecoverer[A]].recover(source)) - .nextOption() - } - - register[entity.APU](ApuItem.Factory) - register[entity.CPU](CpuItem.Factory) - register[entity.DataCard.Tier1](DataCardItem.Tier1.Factory) - register[entity.DataCard.Tier2](DataCardItem.Tier2.Factory) - register[entity.DataCard.Tier3](DataCardItem.Tier3.Factory) - register[entity.EEPROM](EepromItem.Factory) - register[Floppy](FloppyItem.Factory) - register[entity.GraphicsCard](GraphicsCardItem.Factory) - register[entity.HDDManaged](HddItem.Factory.ManagedRecoverer) - register[entity.HDDUnmanaged](HddItem.Factory.UnmangedRecoverer) - register[entity.InternetCard](InternetCardItem.Factory) - register[entity.LinkedCard](LinkedCardItem.Factory) - register[entity.Memory](MemoryItem.Factory) - register[entity.NetworkCard](NetworkCardItem.Factory) - register[entity.Redstone.Tier1](RedstoneCardItem.Tier1.Factory) - register[entity.Redstone.Tier2](RedstoneCardItem.Tier2.Factory) - register[entity.SelfDestructingCard](SelfDestructingCardItem.Factory) - register[SoundCard](SoundCardItem.Factory) - register[entity.WirelessNetworkCard.Tier1](WirelessNetworkCardItem.Tier1.Factory) - register[entity.WirelessNetworkCard.Tier2](WirelessNetworkCardItem.Tier2.Factory) -} diff --git a/src/main/scala/ocelot/desktop/inventory/SyncedInventory.scala b/src/main/scala/ocelot/desktop/inventory/SyncedInventory.scala index 5163c3c..4d0ef8d 100644 --- a/src/main/scala/ocelot/desktop/inventory/SyncedInventory.scala +++ b/src/main/scala/ocelot/desktop/inventory/SyncedInventory.scala @@ -23,7 +23,7 @@ import scala.annotation.tailrec * * When a new [[Item]] is added to the Desktop inventory, its [[ComponentItem.component]] 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 [[Recoverers the registry]]. + * by using an appropriate [[ItemRecoverer]] from [[Items the registry]]. * * While synchronizing, relies on the convergence of changes, but guards against stack overflows * by limiting the recursion depth. @@ -170,7 +170,7 @@ trait SyncedInventory extends PersistedInventory with Logging { case SyncDirection.BrainToDesktop => val item = brainInventory.inventory(slotIndex).get match { - case Some(entity) => Recoverers.recover(entity) match { + case Some(entity) => Items.recover(entity) match { case Some(item) => Some(item.asInstanceOf[I]) case None => diff --git a/src/main/scala/ocelot/desktop/inventory/item/ApuItem.scala b/src/main/scala/ocelot/desktop/inventory/item/ApuItem.scala index 7ef22d3..dbcaacb 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/ApuItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/ApuItem.scala @@ -26,11 +26,7 @@ object ApuItem { override def icon: IconDef = Icons.Apu(_tier) override def build(): ApuItem = new ApuItem(new APU(_tier)) - } - object Factory extends ItemRecoverer[APU] { - override type I = ApuItem - - override def recover(source: APU): ApuItem = new ApuItem(source) + override def recoverers: Iterable[ItemRecoverer[_, _]] = Some(ItemRecoverer(new ApuItem(_))) } } diff --git a/src/main/scala/ocelot/desktop/inventory/item/CpuItem.scala b/src/main/scala/ocelot/desktop/inventory/item/CpuItem.scala index debebd7..906f62c 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/CpuItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/CpuItem.scala @@ -26,11 +26,7 @@ object CpuItem { override def icon: IconDef = Icons.Cpu(_tier) override def build(): CpuItem = new CpuItem(new CPU(_tier)) - } - object Factory extends ItemRecoverer[CPU] { - override type I = CpuItem - - override def recover(source: CPU): CpuItem = new CpuItem(source) + override def recoverers: Iterable[ItemRecoverer[_, _]] = Some(ItemRecoverer(new CpuItem(_))) } } diff --git a/src/main/scala/ocelot/desktop/inventory/item/DataCardItem.scala b/src/main/scala/ocelot/desktop/inventory/item/DataCardItem.scala index b92563b..5e81b95 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/DataCardItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/DataCardItem.scala @@ -24,7 +24,7 @@ object DataCardItem { } object Tier1 { - object Factory extends Factory with ItemRecoverer[DataCard.Tier1] { + object Factory extends Factory { override type I = DataCardItem.Tier1 override val itemClass: Class[I] = classOf @@ -33,7 +33,7 @@ object DataCardItem { override def build(): DataCardItem.Tier1 = new DataCardItem.Tier1(new DataCard.Tier1) - override def recover(source: DataCard.Tier1): DataCardItem.Tier1 = new DataCardItem.Tier1(source) + override def recoverers: Iterable[ItemRecoverer[_, _]] = Some(ItemRecoverer(new DataCardItem.Tier1(_))) } } @@ -44,7 +44,7 @@ object DataCardItem { } object Tier2 { - object Factory extends Factory with ItemRecoverer[DataCard.Tier2] { + object Factory extends Factory { override type I = DataCardItem.Tier2 override val itemClass: Class[I] = classOf @@ -53,7 +53,7 @@ object DataCardItem { override def build(): DataCardItem.Tier2 = new DataCardItem.Tier2(new DataCard.Tier2) - override def recover(source: DataCard.Tier2): DataCardItem.Tier2 = new DataCardItem.Tier2(source) + override def recoverers: Iterable[ItemRecoverer[_, _]] = Some(ItemRecoverer(new DataCardItem.Tier2(_))) } } @@ -64,7 +64,7 @@ object DataCardItem { } object Tier3 { - object Factory extends Factory with ItemRecoverer[DataCard.Tier3] { + object Factory extends Factory { override type I = DataCardItem.Tier3 override val itemClass: Class[I] = classOf @@ -73,7 +73,7 @@ object DataCardItem { override def build(): DataCardItem.Tier3 = new DataCardItem.Tier3(new DataCard.Tier3) - override def recover(source: DataCard.Tier3): DataCardItem.Tier3 = new DataCardItem.Tier3(source) + override def recoverers: Iterable[ItemRecoverer[_, _]] = Some(ItemRecoverer(new DataCardItem.Tier3(_))) } } } diff --git a/src/main/scala/ocelot/desktop/inventory/item/EepromItem.scala b/src/main/scala/ocelot/desktop/inventory/item/EepromItem.scala index 947f916..b09e373 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/EepromItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/EepromItem.scala @@ -95,13 +95,11 @@ object EepromItem { override def tier: Option[Tier] = None override def icon: IconDef = Icons.Eeprom + + override def recoverers: Iterable[ItemRecoverer[_, _]] = Some(ItemRecoverer(new EepromItem(_))) } - object Factory extends ItemRecoverer[EEPROM] { - override type I = EepromItem - - override def recover(source: EEPROM): EepromItem = new EepromItem(source) - + object Factory { class Loot(factory: EEPROMFactory) extends Factory { override def name: String = factory.label diff --git a/src/main/scala/ocelot/desktop/inventory/item/FloppyItem.scala b/src/main/scala/ocelot/desktop/inventory/item/FloppyItem.scala index 40e9ab2..c6c0491 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/FloppyItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/FloppyItem.scala @@ -73,13 +73,11 @@ object FloppyItem { override def tier: Option[Tier] = None override def icon: IconDef = Icons.FloppyDisk(color) + + override def recoverers: Iterable[ItemRecoverer[_, _]] = Some(ItemRecoverer(new FloppyItem(_))) } - object Factory extends ItemRecoverer[Floppy] { - override type I = FloppyItem - - override def recover(source: Floppy): FloppyItem = new FloppyItem(source) - + object Factory { class Loot(factory: FloppyFactory) extends Factory(Some(factory.name), factory.color, managed = true) { override def name: String = factory.name diff --git a/src/main/scala/ocelot/desktop/inventory/item/GraphicsCardItem.scala b/src/main/scala/ocelot/desktop/inventory/item/GraphicsCardItem.scala index 78d9754..3b5e227 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/GraphicsCardItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/GraphicsCardItem.scala @@ -24,11 +24,7 @@ object GraphicsCardItem { override val icon: IconDef = Icons.GraphicsCard(_tier) override def build(): GraphicsCardItem = new GraphicsCardItem(new GraphicsCard(_tier)) - } - object Factory extends ItemRecoverer[GraphicsCard] { - override type I = GraphicsCardItem - - override def recover(source: GraphicsCard): GraphicsCardItem = new GraphicsCardItem(source) + override def recoverers: Iterable[ItemRecoverer[_, _]] = Some(ItemRecoverer(new GraphicsCardItem(_))) } } diff --git a/src/main/scala/ocelot/desktop/inventory/item/HddItem.scala b/src/main/scala/ocelot/desktop/inventory/item/HddItem.scala index 39b9c67..9200a11 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/HddItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/HddItem.scala @@ -74,19 +74,10 @@ object HddItem { if (managed) Hdd.Managed(new HDDManaged(_tier)) else Hdd.Unmanaged(new HDDUnmanaged(_tier)), ) - } - object Factory { - object ManagedRecoverer extends ItemRecoverer[HDDManaged] { - override type I = HddItem - - override def recover(source: HDDManaged): HddItem = new HddItem(Hdd.Managed(source)) - } - - object UnmangedRecoverer extends ItemRecoverer[HDDUnmanaged] { - override type I = HddItem - - override def recover(source: HDDUnmanaged): HddItem = new HddItem(Hdd.Unmanaged(source)) - } + override def recoverers: Iterable[ItemRecoverer[_, _]] = Seq( + ItemRecoverer((hdd: HDDManaged) => new HddItem(Hdd.Managed(hdd))), + ItemRecoverer((hdd: HDDUnmanaged) => new HddItem(Hdd.Unmanaged(hdd))), + ) } } diff --git a/src/main/scala/ocelot/desktop/inventory/item/InternetCardItem.scala b/src/main/scala/ocelot/desktop/inventory/item/InternetCardItem.scala index 36e6252..572a884 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/InternetCardItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/InternetCardItem.scala @@ -15,7 +15,7 @@ class InternetCardItem(val card: InternetCard) extends Item with ComponentItem w } object InternetCardItem { - object Factory extends ItemFactory with ItemRecoverer[InternetCard] { + object Factory extends ItemFactory { override type I = InternetCardItem override def itemClass: Class[InternetCardItem] = classOf @@ -28,6 +28,6 @@ object InternetCardItem { override def build(): InternetCardItem = new InternetCardItem(new InternetCard) - override def recover(source: InternetCard): InternetCardItem = new InternetCardItem(source) + override def recoverers: Iterable[ItemRecoverer[_, _]] = Some(ItemRecoverer(new InternetCardItem(_))) } } diff --git a/src/main/scala/ocelot/desktop/inventory/item/LinkedCardItem.scala b/src/main/scala/ocelot/desktop/inventory/item/LinkedCardItem.scala index 1062174..fed059d 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/LinkedCardItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/LinkedCardItem.scala @@ -40,7 +40,7 @@ class LinkedCardItem(val linkedCard: LinkedCard) extends Item with ComponentItem } object LinkedCardItem { - object Factory extends ItemFactory with ItemRecoverer[LinkedCard] { + object Factory extends ItemFactory { override type I = LinkedCardItem override val itemClass: Class[I] = classOf @@ -53,6 +53,6 @@ object LinkedCardItem { override def build(): LinkedCardItem = new LinkedCardItem(new LinkedCard) - override def recover(source: LinkedCard): LinkedCardItem = new LinkedCardItem(source) + override def recoverers: Iterable[ItemRecoverer[_, _]] = Some(ItemRecoverer(new LinkedCardItem(_))) } } diff --git a/src/main/scala/ocelot/desktop/inventory/item/MemoryItem.scala b/src/main/scala/ocelot/desktop/inventory/item/MemoryItem.scala index d8fc3e8..d7f0f76 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/MemoryItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/MemoryItem.scala @@ -27,11 +27,7 @@ object MemoryItem { override def icon: IconDef = Icons.Memory(memoryTier) override def build(): MemoryItem = new MemoryItem(new Memory(memoryTier)) - } - object Factory extends ItemRecoverer[Memory] { - override type I = MemoryItem - - override def recover(source: Memory): MemoryItem = new MemoryItem(source) + override def recoverers: Iterable[ItemRecoverer[_, _]] = Some(ItemRecoverer(new MemoryItem(_))) } } diff --git a/src/main/scala/ocelot/desktop/inventory/item/NetworkCardItem.scala b/src/main/scala/ocelot/desktop/inventory/item/NetworkCardItem.scala index 3da5e4a..cb686f9 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/NetworkCardItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/NetworkCardItem.scala @@ -15,7 +15,7 @@ class NetworkCardItem(val networkCard: NetworkCard) extends Item with ComponentI } object NetworkCardItem { - object Factory extends ItemFactory with ItemRecoverer[NetworkCard] { + object Factory extends ItemFactory { override type I = NetworkCardItem override val itemClass: Class[I] = classOf @@ -26,6 +26,6 @@ object NetworkCardItem { override def build(): NetworkCardItem = new NetworkCardItem(new NetworkCard) - override def recover(source: NetworkCard): NetworkCardItem = new NetworkCardItem(source) + override def recoverers: Iterable[ItemRecoverer[_, _]] = Some(ItemRecoverer(new NetworkCardItem(_))) } } diff --git a/src/main/scala/ocelot/desktop/inventory/item/RedstoneCardItem.scala b/src/main/scala/ocelot/desktop/inventory/item/RedstoneCardItem.scala index 908c44b..7a0cdb0 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/RedstoneCardItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/RedstoneCardItem.scala @@ -21,7 +21,7 @@ object RedstoneCardItem { } class Tier1(val redstoneCard: Redstone.Tier1) extends RedstoneCardItem { - protected val redstoneIoWindow: WindowProvider = new WindowProvider { + private val redstoneIoWindow: WindowProvider = new WindowProvider { override val windowEntryLabel: String = "Redstone I/O" override def makeWindow(): Window = new Redstone1Window(redstoneCard) @@ -42,7 +42,7 @@ object RedstoneCardItem { } object Tier1 { - object Factory extends Factory with ItemRecoverer[Redstone.Tier1] { + object Factory extends Factory { override type I = RedstoneCardItem.Tier1 override val itemClass: Class[I] = classOf @@ -51,7 +51,7 @@ object RedstoneCardItem { override def build(): RedstoneCardItem.Tier1 = new RedstoneCardItem.Tier1(new Redstone.Tier1) - override def recover(source: Redstone.Tier1): RedstoneCardItem.Tier1 = new RedstoneCardItem.Tier1(source) + override def recoverers: Iterable[ItemRecoverer[_, _]] = Some(ItemRecoverer(new RedstoneCardItem.Tier1(_))) } } @@ -73,7 +73,7 @@ object RedstoneCardItem { } object Tier2 { - object Factory extends Factory with ItemRecoverer[Redstone.Tier2] { + object Factory extends Factory { override type I = RedstoneCardItem.Tier2 override val itemClass: Class[I] = classOf @@ -82,7 +82,7 @@ object RedstoneCardItem { override def build(): RedstoneCardItem.Tier2 = new RedstoneCardItem.Tier2(new Redstone.Tier2) - override def recover(source: Redstone.Tier2): RedstoneCardItem.Tier2 = new RedstoneCardItem.Tier2(source) + override def recoverers: Iterable[ItemRecoverer[_, _]] = Some(ItemRecoverer(new RedstoneCardItem.Tier2(_))) } } } diff --git a/src/main/scala/ocelot/desktop/inventory/item/SelfDestructingCardItem.scala b/src/main/scala/ocelot/desktop/inventory/item/SelfDestructingCardItem.scala index 0c5d75c..f6a3a8b 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/SelfDestructingCardItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/SelfDestructingCardItem.scala @@ -20,7 +20,7 @@ class SelfDestructingCardItem(val card: SelfDestructingCard) } object SelfDestructingCardItem { - object Factory extends ItemFactory with ItemRecoverer[SelfDestructingCard] { + object Factory extends ItemFactory { override type I = SelfDestructingCardItem override val itemClass: Class[I] = classOf @@ -33,6 +33,6 @@ object SelfDestructingCardItem { override def build(): SelfDestructingCardItem = new SelfDestructingCardItem(new SelfDestructingCard) - override def recover(source: SelfDestructingCard): SelfDestructingCardItem = new SelfDestructingCardItem(source) + override def recoverers: Iterable[ItemRecoverer[_, _]] = Some(ItemRecoverer(new SelfDestructingCardItem(_))) } } diff --git a/src/main/scala/ocelot/desktop/inventory/item/SoundCardItem.scala b/src/main/scala/ocelot/desktop/inventory/item/SoundCardItem.scala index 7aba166..1fdf2ec 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/SoundCardItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/SoundCardItem.scala @@ -29,7 +29,7 @@ class SoundCardItem(val soundCard: SoundCard) extends Item with ComponentItem wi } object SoundCardItem { - object Factory extends ItemFactory with ItemRecoverer[SoundCard] { + object Factory extends ItemFactory { override type I = SoundCardItem override val itemClass: Class[I] = classOf @@ -42,6 +42,6 @@ object SoundCardItem { override def build(): SoundCardItem = new SoundCardItem(new SoundCard) - override def recover(source: SoundCard): SoundCardItem = new SoundCardItem(source) + override def recoverers: Iterable[ItemRecoverer[_, _]] = Some(ItemRecoverer(new SoundCardItem(_))) } } diff --git a/src/main/scala/ocelot/desktop/inventory/item/WirelessNetworkCardItem.scala b/src/main/scala/ocelot/desktop/inventory/item/WirelessNetworkCardItem.scala index c9fa0d0..7afde5c 100644 --- a/src/main/scala/ocelot/desktop/inventory/item/WirelessNetworkCardItem.scala +++ b/src/main/scala/ocelot/desktop/inventory/item/WirelessNetworkCardItem.scala @@ -29,7 +29,7 @@ object WirelessNetworkCardItem { } object Tier1 { - object Factory extends Factory with ItemRecoverer[WirelessNetworkCard.Tier1] { + object Factory extends Factory { override type I = WirelessNetworkCardItem.Tier1 override val itemClass: Class[I] = classOf @@ -39,8 +39,7 @@ object WirelessNetworkCardItem { override def build(): WirelessNetworkCardItem.Tier1 = new WirelessNetworkCardItem.Tier1(new WirelessNetworkCard.Tier1) - override def recover(source: WirelessNetworkCard.Tier1): WirelessNetworkCardItem.Tier1 = - new WirelessNetworkCardItem.Tier1(source) + override def recoverers: Iterable[ItemRecoverer[_, _]] = Some(ItemRecoverer(new WirelessNetworkCardItem.Tier1(_))) } } @@ -49,7 +48,7 @@ object WirelessNetworkCardItem { } object Tier2 { - object Factory extends Factory with ItemRecoverer[WirelessNetworkCard.Tier2] { + object Factory extends Factory { override type I = WirelessNetworkCardItem.Tier2 override val itemClass: Class[I] = classOf @@ -59,8 +58,7 @@ object WirelessNetworkCardItem { override def build(): WirelessNetworkCardItem.Tier2 = new WirelessNetworkCardItem.Tier2(new WirelessNetworkCard.Tier2) - override def recover(source: WirelessNetworkCard.Tier2): WirelessNetworkCardItem.Tier2 = - new WirelessNetworkCardItem.Tier2(source) + override def recoverers: Iterable[ItemRecoverer[_, _]] = Some(ItemRecoverer(new WirelessNetworkCardItem.Tier2(_))) } } } diff --git a/src/main/scala/ocelot/desktop/ui/widget/slot/ItemChooser.scala b/src/main/scala/ocelot/desktop/ui/widget/slot/ItemChooser.scala index d64dd9d..81ca0bb 100644 --- a/src/main/scala/ocelot/desktop/ui/widget/slot/ItemChooser.scala +++ b/src/main/scala/ocelot/desktop/ui/widget/slot/ItemChooser.scala @@ -1,145 +1,63 @@ package ocelot.desktop.ui.widget.slot -import ocelot.desktop.inventory.item._ -import ocelot.desktop.inventory.{Item, ItemFactory} +import ocelot.desktop.graphics.IconDef +import ocelot.desktop.inventory.Items.{ArbitraryItemGroup, ExtendedTieredItemGroup, SingletonItemGroup, TieredItemGroup} +import ocelot.desktop.inventory._ import ocelot.desktop.ui.widget.contextmenu.{ContextMenu, ContextMenuEntry, ContextMenuSubmenu} -import totoro.ocelot.brain.loot.Loot import totoro.ocelot.brain.util.ExtendedTier.ExtendedTier -import totoro.ocelot.brain.util.{ExtendedTier, Tier} import totoro.ocelot.brain.util.Tier.Tier -import scala.collection.mutable.ArrayBuffer - class ItemChooser[I <: Item](slot: SlotWidget[I]) extends ContextMenu { - for (entryFactory <- ItemChooser.Factories; entry <- entryFactory.make(slot)) { - addEntry(entry) + import ItemChooser._ + + private def makeMenuEntry(factory: ItemFactory, label: String): ContextMenuEntry = { + ContextMenuEntry(label, icon = Some(factory.icon)) { + slot.item = factory.build().asInstanceOf[I] + } + } + + private def addSubmenu[T: HasLabel]( + name: String, + factories: Seq[(T, ItemFactory)], + icon: Option[IconDef] = None + ): Unit = { + val tierLabel = implicitly[HasLabel[T]].label _ + + val acceptedFactories = factories.iterator.filter(p => slot.isItemAccepted(p._2)).toSeq + + if (acceptedFactories.nonEmpty) { + addEntry( + new ContextMenuSubmenu(name, icon = Some(icon.getOrElse(acceptedFactories.last._2.icon))) { + for ((tier, factory) <- acceptedFactories) { + addEntry(makeMenuEntry(factory, tierLabel(tier))) + } + } + ) + } + } + + for (group <- Items.groups) { + group match { + case SingletonItemGroup(name, factory) => + if (slot.isItemAccepted(factory)) { + addEntry(makeMenuEntry(factory, name)) + } + + case TieredItemGroup(name, factories) => addSubmenu(name, factories) + + case ExtendedTieredItemGroup(name, factories) => addSubmenu(name, factories) + + case ArbitraryItemGroup(name, icon, factories) => addSubmenu(name, factories, Some(icon)) + } } } object ItemChooser { - private trait EntryFactory { - def make[I <: Item](slot: SlotWidget[I]): Option[ContextMenuEntry] + private trait HasLabel[A] { + def label(value: A): String } - private def makeMenuEntry[I <: Item](slot: SlotWidget[I], factory: ItemFactory, label: String): ContextMenuEntry = - ContextMenuEntry(label, icon = Some(factory.icon)) { - slot.item = factory.build().asInstanceOf[I] - } - - private case class SingletonEntryFactory(factory: ItemFactory) extends EntryFactory { - override def make[I <: Item](slot: SlotWidget[I]): Option[ContextMenuEntry] = { - Option.when(slot.isItemAccepted(factory)) { - makeMenuEntry(slot, factory, factory.name) - } - } - } - - private case class TieredEntryFactory[T: TierLike]( - name: String, - tiers: Iterable[T], - )( - factoryMaker: T => ItemFactory, - ) extends EntryFactory { - - override def make[I <: Item](slot: SlotWidget[I]): Option[ContextMenuEntry] = { - val tierLabel = implicitly[TierLike[T]].label _ - - val factories = tiers - .map(tier => (tier, factoryMaker(tier))) - .filter(p => slot.isItemAccepted(p._2)) - .toArray - - Option.unless(factories.isEmpty) { - new ContextMenuSubmenu(name, icon = Some(factories.last._2.icon)) { - for ((tier, factory) <- factories) { - addEntry(makeMenuEntry(slot, factory, tierLabel(tier))) - } - } - } - } - } - - private trait TierLike[A] { - def label(tier: A): String - } - - private implicit val TierIsTierLike: TierLike[Tier] = _.label - private implicit val ExtendedTierIsTierLike: TierLike[ExtendedTier] = _.label - - private object FloppyEntryFactory extends EntryFactory { - override def make[I <: Item](slot: SlotWidget[I]): Option[ContextMenuEntry] = { - Option.when(slot.isItemAccepted(FloppyItem.Factory.Empty)) { - new ContextMenuSubmenu("Floppy", icon = Some(FloppyItem.Factory.Empty.icon)) { - def addEntry(factory: FloppyItem.Factory, label: String): Unit = { - addEntry(makeMenuEntry(slot, factory, label)) - } - - def addEntry(factory: FloppyItem.Factory): Unit = { - addEntry(factory, factory.name) - } - - for (lootFactory <- Loot.Floppies) { - addEntry(new FloppyItem.Factory.Loot(lootFactory)) - } - - addEntry(FloppyItem.Factory.Empty, "Empty") - } - } - } - } - - private object EepromEntryFactory extends EntryFactory { - override def make[I <: Item](slot: SlotWidget[I]): Option[ContextMenuEntry] = { - Option.when(slot.isItemAccepted(EepromItem.Factory.Empty)) { - new ContextMenuSubmenu("EEPROM", icon = Some(EepromItem.Factory.Empty.icon)) { - def addEntry(factory: EepromItem.Factory, label: String): Unit = { - addEntry(makeMenuEntry(slot, factory, label)) - } - - def addEntry(factory: EepromItem.Factory): Unit = { - addEntry(factory, factory.name) - } - - for (lootFactory <- Loot.Eeproms) { - addEntry(new EepromItem.Factory.Loot(lootFactory)) - } - - addEntry(EepromItem.Factory.Empty, "Empty") - } - } - } - } - - // Entry factories // - private val Factories = ArrayBuffer.empty[EntryFactory] - - Factories += TieredEntryFactory("CPU", Tier.One to Tier.Three)(new CpuItem.Factory(_)) - Factories += TieredEntryFactory("APU", Tier.One to Tier.Three)(new ApuItem.Factory(_))(_.saturatingAdd(1).label) - - Factories += TieredEntryFactory("Memory", ExtendedTier.One to ExtendedTier.ThreeHalf)(new MemoryItem.Factory(_)) - - // TODO: unmanaged - Factories += TieredEntryFactory("HDD", Tier.One to Tier.Three)(new HddItem.Factory(managed = true, _)) - Factories += FloppyEntryFactory - Factories += EepromEntryFactory - - Factories += TieredEntryFactory("Graphics Card", Tier.One to Tier.Three)(new GraphicsCardItem.Factory(_)) - Factories += SingletonEntryFactory(NetworkCardItem.Factory) - Factories += TieredEntryFactory("Wireless Net. Card", Tier.One to Tier.Two) { - case Tier.One => WirelessNetworkCardItem.Tier1.Factory - case Tier.Two => WirelessNetworkCardItem.Tier2.Factory - } - Factories += SingletonEntryFactory(LinkedCardItem.Factory) - Factories += SingletonEntryFactory(InternetCardItem.Factory) - Factories += TieredEntryFactory("Redstone Card", Tier.One to Tier.Two) { - case Tier.One => RedstoneCardItem.Tier1.Factory - case Tier.Two => RedstoneCardItem.Tier2.Factory - } - Factories += TieredEntryFactory("Data Card", Tier.One to Tier.Three) { - case Tier.One => DataCardItem.Tier1.Factory - case Tier.Two => DataCardItem.Tier2.Factory - case Tier.Three => DataCardItem.Tier3.Factory - } - Factories += SingletonEntryFactory(SoundCardItem.Factory) - Factories += SingletonEntryFactory(SelfDestructingCardItem.Factory) + private implicit val TierHasLabel: HasLabel[Tier] = _.label + private implicit val ExtendedTierHasLabel: HasLabel[ExtendedTier] = _.label + private implicit val StringHasLabel: HasLabel[String] = identity }