From e7653d559ff3ccfcc64ecc5959a35d6aaaa0f6ca Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Mon, 5 Sep 2022 23:13:48 +0700 Subject: [PATCH] Synchronized maps, update save keys, exosuit inventory upgrades as items --- .../mc/otm/datagen/lang/English.kt | 7 + .../otm/capability/MatteryPlayerCapability.kt | 112 +++++--- .../mc/otm/capability/UUIDIntModifiersMap.kt | 96 +++++++ .../mc/otm/item/ExoSuitSlotUpgradeItem.kt | 96 +++++++ .../mc/otm/network/FieldSynchronizer.kt | 255 +++++++++++++++++- .../dbotthepony/mc/otm/registry/LazyList.kt | 1 + .../ru/dbotthepony/mc/otm/registry/MItems.kt | 36 +++ 7 files changed, 555 insertions(+), 48 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/capability/UUIDIntModifiersMap.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/item/ExoSuitSlotUpgradeItem.kt diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt index bd3a97cb0..5c25a6cd2 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt @@ -56,10 +56,17 @@ private fun misc(provider: MatteryLanguageProvider) { gui("exosuit.already_activated", "You already have exosuit following you") + gui("exosuit_upgrades.no_exosuit", "This piece of technology seems to be of no use to you.... Or is it?!") + + gui("exosuit_upgrades.already_activated", "Upgrade is already active!") + gui("exosuit_upgrades.slots_upgrade", "Using this will permanently grant %s slots in ExoSuit inventory.") + gui("power_supplier.active_nodes", "Currently demanding nodes: %s") misc("battery.single_use", "Single use battery, can not be recharged.") + misc("exosuit_upgrades.slots_upgraded", "Your exosuit has permanently gained %s slots") + misc("exosuit.granted1", "As you keep pressing fingerprint reader, you are getting hurt in finger.") misc("exosuit.granted2", "After you raise your finger, fingerprint reader glows very bright.") misc("exosuit.granted3", "Then, fingerprint reader fades, leaving faint trace not of your finger, but of your very soul.") diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt index bbd43abfd..4151bc1d8 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt @@ -1,5 +1,6 @@ package ru.dbotthepony.mc.otm.capability +import it.unimi.dsi.fastutil.objects.Object2IntAVLTreeMap import it.unimi.dsi.fastutil.objects.ObjectArraySet import net.minecraft.ChatFormatting import net.minecraft.core.Direction @@ -64,6 +65,26 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial var hasExoSuit by synchronizer.bool() + private val exoSuitSlotCountModifiersMap: MutableMap by synchronizer.Map( + keyCodec = UUIDValueCodec, + valueCodec = IntValueCodec, + backingMap = Object2IntAVLTreeMap(), + callback = { + this.exoSuitSlotCountModifiers.recompute() + } + ) + + val exoSuitSlotCountModifiers = UUIDIntModifiersMap(observer = observer@{ + if (ply !is ServerPlayer) + return@observer + + if (it < 0) { + exoSuitSlotCount = 0 + } else { + exoSuitSlotCount = it + } + }, backingMap = this.exoSuitSlotCountModifiersMap) + var exoSuitSlotCount by synchronizer.int(setter = setter@{ value, access, _ -> require(value >= 0) { "Invalid slot count $value" } @@ -334,37 +355,11 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial override fun serializeNBT(): CompoundTag { val tag = CompoundTag() - tag["androidEnergy"] = androidEnergy.serializeNBT() - - val featureList = ListTag() - - for (feature in features.values) { - val featureNbt = feature.serializeNBT() - - featureNbt["id"] = feature.type.registryName!!.toString() - featureList.add(featureNbt) - } - - tag["features"] = featureList - - tag["is_android"] = isAndroid - tag["will_become_android"] = willBecomeAndroid - - val list = ListTag() - - for ((type, instance) in research) { - val researchTag = instance.serializeNBT() - - researchTag["id"] = type.registryName!!.toString() - list.add(researchTag) - } - - tag["research"] = list - + // iteration tag["iteration"] = iteration - tag["should_send_iteration"] = shouldSendIteration + tag["shouldSendIteration"] = shouldSendIteration - tag["death_log"] = ListTag().also { + tag["deathLog"] = ListTag().also { for ((ticks, component) in deathLog) { it.add(CompoundTag().also { it["ticks"] = ticks @@ -373,21 +368,47 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial } } - tag["exo_suit_slot_count"] = exoSuitSlotCount - tag["has_exo_suit"] = hasExoSuit - tag["exo_suit_inventory"] = exoSuitContainer.serializeNBT() - tag["exo_suit_crafting_upgraded"] = isExoSuitCraftingUpgraded + // exosuit + tag["hasExoSuit"] = hasExoSuit + tag["exoSuitContainer"] = exoSuitContainer.serializeNBT() + tag["isExoSuitCraftingUpgraded"] = isExoSuitCraftingUpgraded + tag["exoSuitSlotCountModifiers"] = exoSuitSlotCountModifiers.serializeNBT() + + // android + tag["androidEnergy"] = androidEnergy.serializeNBT() + + tag["isAndroid"] = isAndroid + tag["willBecomeAndroid"] = willBecomeAndroid + + val featureList = ListTag() + val researchList = ListTag() + + for (feature in features.values) { + featureList.add(feature.serializeNBT().also { + it["id"] = feature.type.registryName!!.toString() + }) + } + + for ((type, instance) in research) { + researchList.add(instance.serializeNBT().also { + it["id"] = type.registryName!!.toString() + }) + } + + tag["features"] = featureList + tag["research"] = researchList return tag } override fun deserializeNBT(tag: CompoundTag) { + // iterations iteration = tag.getInt("iteration") - shouldSendIteration = tag.getBoolean("should_send_iteration") + shouldSendIteration = tag.getBoolean("shouldSendIteration") deathLog.clear() - for (value in tag.getCompoundList("death_log")) { + for (value in tag.getCompoundList("deathLog")) { val component = Component.Serializer.fromJson(value.getString("component")) if (component != null) { @@ -395,9 +416,21 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial } } + // exosuit + hasExoSuit = tag.getBoolean("hasExoSuit") + exoSuitContainer.deserializeNBT(tag["exoSuitContainer"]) + isExoSuitCraftingUpgraded = tag.getBoolean("isExoSuitCraftingUpgraded") + + tag.map("exoSuitSlotCountModifiers", exoSuitSlotCountModifiers::deserializeNBT) + + // android + isAndroid = tag.getBoolean("isAndroid") + willBecomeAndroid = tag.getBoolean("willBecomeAndroid") + tag.map("androidEnergy", androidEnergy::deserializeNBT) features.clear() + research.clear() for (featureTag in tag.getCompoundList("features")) { val feature = MRegistry.ANDROID_FEATURES.getValue(ResourceLocation(featureTag.getString("id"))) @@ -414,10 +447,6 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial } } - isAndroid = tag.getBoolean("is_android") - willBecomeAndroid = tag.getBoolean("will_become_android") - research.clear() - for (researchTag in tag.getCompoundList("research")) { val research = MRegistry.ANDROID_RESEARCH.getValue(ResourceLocation(researchTag.getString("id"))) @@ -427,11 +456,6 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial this.research[research] = instance } } - - hasExoSuit = tag.getBoolean("has_exo_suit") - exoSuitSlotCount = tag.getInt("exo_suit_slot_count") - exoSuitContainer.deserializeNBT(tag["exo_suit_inventory"]) - isExoSuitCraftingUpgraded = tag.getBoolean("exo_suit_crafting_upgraded") } fun dropBattery() { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/UUIDIntModifiersMap.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/UUIDIntModifiersMap.kt new file mode 100644 index 000000000..8ddafb76a --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/UUIDIntModifiersMap.kt @@ -0,0 +1,96 @@ +package ru.dbotthepony.mc.otm.capability + +import net.minecraft.nbt.CompoundTag +import net.minecraft.nbt.ListTag +import net.minecraft.nbt.Tag +import net.minecraftforge.common.util.INBTSerializable +import ru.dbotthepony.mc.otm.core.contains +import java.util.UUID + +class UUIDIntModifiersMap(private val observer: (Int) -> Unit, private val backingMap: MutableMap = HashMap()) : INBTSerializable { + var value: Int = 0 + private set + + fun recompute() { + var value = 0 + + for (mapValue in backingMap.values) { + value += mapValue + } + + if (this.value != value) { + this.value = value + observer.invoke(value) + } + } + + operator fun set(key: UUID, value: Int): Boolean { + val old = backingMap.put(key, value) + + if (old == value) { + return false + } + + this.value += value - (old ?: 0) + observer.invoke(this.value) + return true + } + + operator fun get(key: UUID): Int? { + return backingMap[key] + } + + operator fun contains(key: UUID): Boolean { + return backingMap.containsKey(key) + } + + fun remove(key: UUID): Boolean { + if (!backingMap.containsKey(key)) { + return false + } + + val old = backingMap.remove(key) ?: return true + value -= old + return true + } + + fun clear() { + backingMap.clear() + val old = this.value + this.value = 0 + if (old != this.value) { + observer.invoke(this.value) + } + } + + override fun serializeNBT(): ListTag { + return ListTag().also { + for ((key, value) in backingMap) { + it.add(CompoundTag().also { + it.putUUID("key", key) + it.putInt("value", value) + }) + } + } + } + + override fun deserializeNBT(nbt: ListTag) { + backingMap.clear() + val old = this.value + this.value = 0 + + for (value in nbt) { + value as CompoundTag + + if (value.contains("key", "value")) { + val int = value.getInt("value") + backingMap.put(value.getUUID("key"), int) + this.value += int + } + } + + if (old != this.value) { + observer.invoke(this.value) + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/ExoSuitSlotUpgradeItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/ExoSuitSlotUpgradeItem.kt new file mode 100644 index 000000000..8db4a8a0f --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/ExoSuitSlotUpgradeItem.kt @@ -0,0 +1,96 @@ +package ru.dbotthepony.mc.otm.item + +import net.minecraft.ChatFormatting +import net.minecraft.network.chat.Component +import net.minecraft.server.level.ServerPlayer +import net.minecraft.world.InteractionHand +import net.minecraft.world.InteractionResultHolder +import net.minecraft.world.entity.LivingEntity +import net.minecraft.world.entity.player.Player +import net.minecraft.world.item.Item +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Rarity +import net.minecraft.world.item.TooltipFlag +import net.minecraft.world.item.UseAnim +import net.minecraft.world.level.Level +import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.capability.matteryPlayer +import ru.dbotthepony.mc.otm.client.minecraft +import ru.dbotthepony.mc.otm.core.TranslatableComponent +import ru.dbotthepony.mc.otm.runIfClient +import java.util.UUID + +class ExoSuitSlotUpgradeItem( + val id: UUID?, + val slotCount: Int, + properties: Properties = Properties().stacksTo(64).rarity(Rarity.UNCOMMON).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB) +) : Item(properties) { + val isCreative: Boolean get() = id == null + + override fun getUseDuration(p_41454_: ItemStack): Int { + return 30 + } + + override fun appendHoverText(p_41421_: ItemStack, p_41422_: Level?, tooltip: MutableList, p_41424_: TooltipFlag) { + super.appendHoverText(p_41421_, p_41422_, tooltip, p_41424_) + + val alreadyHasExosuit = runIfClient(true) { + minecraft.player?.matteryPlayer?.hasExoSuit == true + } + + if (!alreadyHasExosuit) { + tooltip.add(TranslatableComponent("otm.gui.exosuit_upgrades.no_exosuit").withStyle(ChatFormatting.GRAY)) + + if (runIfClient(false) { minecraft.player?.isCreative != true }) { + return + } + } + + val alreadyHas = id != null && runIfClient(false) { + minecraft.player?.matteryPlayer?.exoSuitSlotCountModifiers?.contains(id) == true + } + + if (alreadyHas) { + tooltip.add(TranslatableComponent("otm.gui.exosuit_upgrades.already_activated").withStyle(ChatFormatting.DARK_RED)) + } + + tooltip.add(TranslatableComponent("otm.gui.exosuit_upgrades.slots_upgrade", slotCount).withStyle(ChatFormatting.DARK_GREEN)) + } + + override fun use(p_41432_: Level, player: Player, hand: InteractionHand): InteractionResultHolder { + val matteryPlayer = player.matteryPlayer ?: return super.use(p_41432_, player, hand) + + if (matteryPlayer.hasExoSuit && (id == null || id !in matteryPlayer.exoSuitSlotCountModifiers)) { + player.startUsingItem(hand) + return InteractionResultHolder.consume(player.getItemInHand(hand)) + } + + return super.use(p_41432_, player, hand) + } + + override fun finishUsingItem(itemStack: ItemStack, level: Level, player: LivingEntity): ItemStack { + if (player !is Player) return super.finishUsingItem(itemStack, level, player) + val matteryPlayer = player.matteryPlayer ?: return super.finishUsingItem(itemStack, level, player) + + if (!matteryPlayer.hasExoSuit || (id != null && id in matteryPlayer.exoSuitSlotCountModifiers)) { + return super.finishUsingItem(itemStack, level, player) + } + + if (!player.abilities.instabuild) + itemStack.shrink(1) + + if (player is ServerPlayer) { + if (id != null) { + matteryPlayer.exoSuitSlotCountModifiers[id] = slotCount + } else { + matteryPlayer.exoSuitSlotCountModifiers[UUID.randomUUID()] = slotCount + } + + player.displayClientMessage(TranslatableComponent("otm.exosuit_upgrades.slots_upgraded", slotCount).withStyle(ChatFormatting.WHITE), false) + } + + return itemStack + } + + override fun getUseAnimation(p_41452_: ItemStack): UseAnim = UseAnim.BOW +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/FieldSynchronizer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/FieldSynchronizer.kt index 065ea6203..1271d5c65 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/FieldSynchronizer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/FieldSynchronizer.kt @@ -8,7 +8,10 @@ import java.io.DataOutputStream import java.io.InputStream import java.math.BigDecimal import java.util.* +import kotlin.ConcurrentModificationException import kotlin.collections.ArrayList +import kotlin.collections.HashMap +import kotlin.properties.ReadOnlyProperty import kotlin.properties.ReadWriteProperty import kotlin.reflect.KMutableProperty0 import kotlin.reflect.KProperty @@ -95,20 +98,39 @@ class EnumValueCodec>(private val clazz: Class) : INetworkVal } } -sealed interface IField : ReadWriteProperty { +sealed interface IField : ReadOnlyProperty { fun observe() fun markDirty() - var value: V + val value: V + fun write(stream: DataOutputStream) fun read(stream: DataInputStream) override fun getValue(thisRef: Any, property: KProperty<*>): V { return value } +} + +sealed interface IMutableField : IField, ReadWriteProperty { + override var value: V override fun setValue(thisRef: Any, property: KProperty<*>, value: V) { this.value = value } + + override fun getValue(thisRef: Any, property: KProperty<*>): V { + return super.getValue(thisRef, property) + } +} + +data class MapChangeset( + val action: MapAction, + val key: K?, + val value: V? +) + +enum class MapAction { + CLEAR, ADD, REMOVE } class FieldSynchronizer { @@ -235,13 +257,29 @@ class FieldSynchronizer { return ObservedField(delegate, ItemStackValueCodec) } + fun map( + keyCodec: INetworkValueCodec, + valueCodec: INetworkValueCodec, + callback: ((changes: Collection>) -> Unit)? = null, + backingMap: MutableMap = HashMap(), + observingBackingMap: MutableMap? = null, + ): Map { + return Map( + keyCodec = keyCodec, + valueCodec = valueCodec, + callback = callback, + backingMap = backingMap, + observingBackingMap = observingBackingMap + ) + } + inner class Field( private var field: V, private val codec: INetworkValueCodec, private val getter: FieldGetter? = null, private val setter: FieldSetter? = null, isObserver: Boolean = false, - ) : IField { + ) : IMutableField { private var remote: V = codec.copy(field) val id = fields.size + 1 @@ -335,7 +373,7 @@ class FieldSynchronizer { } } - inner class ObservedField : IField { + inner class ObservedField : IMutableField { private val codec: NetworkValueCodec private val getter: () -> V private val setter: (V) -> Unit @@ -397,6 +435,211 @@ class FieldSynchronizer { } } + companion object { + private val ClearBacklogEntry = { stream: DataOutputStream -> stream.write(MapAction.CLEAR.ordinal + 1) } + private val MapActionList = MapAction.values() + private val ClearMapChangeset = MapChangeset(MapAction.CLEAR, null, null) + } + + inner class Map( + private val keyCodec: INetworkValueCodec, + private val valueCodec: INetworkValueCodec, + private val backingMap: MutableMap, + private val observingBackingMap: MutableMap? = null, + private val callback: ((changes: Collection>) -> Unit)? = null + ) : IField> { + private var isDirty = false + private var sentAllValues = false + private var isRemote = false + + val id = fields.size + 1 + + init { + fields.add(this) + + if (observingBackingMap != null) + observers.add(this) + } + + private val backlog = LinkedList<(DataOutputStream) -> Unit>() + + override fun observe() { + if (isRemote) { + return + } + + val observingBackingMap = observingBackingMap + + if (observingBackingMap != null) { + for ((key, value) in backingMap) { + val remoteValue = observingBackingMap[key] ?: throw ConcurrentModificationException("Backing map of $this was modified externally, or $value missed a modification") + + if (!valueCodec.compare(value, remoteValue)) { + val valueCopy = valueCodec.copy(value) + + backlog.add { + it.write(MapAction.ADD.ordinal + 1) + keyCodec.write(it, key) + valueCodec.write(it, valueCopy) + } + + observingBackingMap[key] = valueCopy + + if (!isDirty) { + dirtyFields.add(this) + isDirty = true + } + } + } + } + } + + override fun markDirty() { + if (isRemote) { + return + } + + if (!isDirty) { + dirtyFields.add(this) + isDirty = true + } + + if (!sentAllValues) { + for ((key, value) in backingMap) { + val valueCopy = valueCodec.copy(value) + + backlog.add { + it.write(MapAction.ADD.ordinal + 1) + keyCodec.write(it, key) + valueCodec.write(it, valueCopy) + } + + observingBackingMap?.put(key, valueCopy) + } + + sentAllValues = true + } + } + + override val value: MutableMap = object : ObservedMap(backingMap) { + override fun onClear() { + if (isRemote) { + return + } + + backlog.clear() + observingBackingMap?.clear() + backlog.add(ClearBacklogEntry) + + if (!isDirty) { + dirtyFields.add(this@Map) + isDirty = true + } + } + + override fun onValueAdded(key: K, value: V) { + if (isRemote) { + return + } + + val valueCopy = valueCodec.copy(value) + + backlog.add { + it.write(MapAction.ADD.ordinal + 1) + keyCodec.write(it, key) + valueCodec.write(it, valueCopy) + } + + observingBackingMap?.put(key, valueCopy) + + if (!isDirty) { + dirtyFields.add(this@Map) + isDirty = true + } + } + + override fun onValueRemoved(key: K, value: V) { + if (isRemote) { + return + } + + val keyCopy = keyCodec.copy(key) + + backlog.add { + it.write(MapAction.REMOVE.ordinal + 1) + keyCodec.write(it, keyCopy) + } + + observingBackingMap?.remove(key) + + if (!isDirty) { + dirtyFields.add(this@Map) + isDirty = true + } + } + } + + override fun write(stream: DataOutputStream) { + stream.write(id) + + sentAllValues = false + isDirty = false + + for (entry in backlog) { + entry.invoke(stream) + } + + backlog.clear() + + stream.write(0) + } + + override fun read(stream: DataInputStream) { + if (!isRemote) { + isRemote = true + backlog.clear() + observingBackingMap?.clear() + } + + isDirty = false + + val changeset = LinkedList>() + var readAction = stream.read() - 1 + + while (readAction != -1) { + if (readAction >= MapActionList.size) { + throw IndexOutOfBoundsException("Unknown map action with ID $readAction") + } + + when (MapActionList[readAction]) { + MapAction.CLEAR -> { + backingMap.clear() + changeset.add(ClearMapChangeset) + } + + MapAction.ADD -> { + val key = keyCodec.read(stream) + val value = valueCodec.read(stream) + backingMap[key] = value + changeset.add(MapChangeset(MapAction.ADD, key, value)) + } + + MapAction.REMOVE -> { + val key = keyCodec.read(stream) + backingMap.remove(key) + changeset.add(MapChangeset(MapAction.REMOVE, key, null)) + } + } + + readAction = stream.read() - 1 + } + + if (changeset.size != 0) { + callback?.invoke(changeset) + } + } + } + fun invalidate() { for (field in fields) { field.markDirty() @@ -438,6 +681,10 @@ class FieldSynchronizer { i++ } + if (stream.read() != -1) { + throw IllegalStateException("Stream wasn't fully drain!") + } + return i } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/LazyList.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/LazyList.kt index 83f418343..b2acbe5d8 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/LazyList.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/LazyList.kt @@ -7,6 +7,7 @@ import net.minecraftforge.registries.RegistryObject class LazyList(private val getters: ImmutableList<() -> T>) : AbstractList() { constructor(vararg getters: () -> T) : this(ImmutableList.copyOf(getters)) + constructor(getters: List<() -> T>) : this(ImmutableList.copyOf(getters)) override val size: Int get() = getters.size diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MItems.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MItems.kt index 275d8e1f7..b1f399638 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MItems.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MItems.kt @@ -14,11 +14,14 @@ import net.minecraftforge.eventbus.api.IEventBus import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext import net.minecraftforge.registries.DeferredRegister import net.minecraftforge.registries.ForgeRegistries +import net.minecraftforge.registries.RegistryObject import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.ImpreciseFraction import ru.dbotthepony.mc.otm.item.* import ru.dbotthepony.mc.otm.item.weapon.PlasmaRifleItem +import java.util.* +import kotlin.collections.ArrayList object MItems { private val DEFAULT_PROPERTIES = Item.Properties().stacksTo(64).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB) @@ -76,6 +79,39 @@ object MItems { } val EXOSUIT_PROBE: Item by registry.register(MNames.EXOSUIT_PROBE, ::ExoSuitProbeItem) + val EXOSUIT_INVENTORY_UPGRADE_CREATIVE: Item by registry.register("exosuit_inventory_upgrade_creative") { ExoSuitSlotUpgradeItem(null, 9, Item.Properties().stacksTo(64).rarity(Rarity.EPIC).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) } + + val EXOSUIT_INVENTORY_UPGRADES: List + val EXOSUIT_INVENTORY_UPGRADES_CRAFTABLE: List + val EXOSUIT_INVENTORY_UPGRADES_UNCRAFTABLE: List + + init { + val upgrades = ArrayList<() -> Item>() + val upgradesCraftable = ArrayList<() -> Item>() + val upgradesUncraftable = ArrayList<() -> Item>() + + val baseSignificant = 7344348239534784L + var baseInsignificant = 848473865769484L + + for (i in 1 .. 4) { + val obj = registry.register("exosuit_inventory_upgrade_$i") { ExoSuitSlotUpgradeItem(UUID(baseSignificant, baseInsignificant++), 9) } + upgrades.add(obj::get) + upgradesCraftable.add(obj::get) + } + + for (i in 1 .. 16) { + val obj = registry.register("exosuit_inventory_upgrade_uncraftable_$i") { ExoSuitSlotUpgradeItem(UUID(baseSignificant, baseInsignificant++), 9 + (i / 5) * 9) } + upgrades.add(obj::get) + upgradesUncraftable.add(obj::get) + } + + EXOSUIT_INVENTORY_UPGRADES = LazyList(upgrades) + EXOSUIT_INVENTORY_UPGRADES_CRAFTABLE = LazyList(upgradesCraftable) + EXOSUIT_INVENTORY_UPGRADES_UNCRAFTABLE = LazyList(upgradesUncraftable) + } + + val EXOSUIT_INVENTORY_UPGRADE_BIG: Item by registry.register("exosuit_inventory_upgrade_big") { ExoSuitSlotUpgradeItem(UUID.fromString("121a17a5-533c-9ac0-ff02-03aea75ed20c"), 45, Item.Properties().stacksTo(64).rarity(Rarity.RARE).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) } + val EXOSUIT_INVENTORY_UPGRADE_HUGE: Item by registry.register("exosuit_inventory_upgrade_huge") { ExoSuitSlotUpgradeItem(UUID.fromString("121a17a5-533c-9ac0-ff02-03aea75ed20d"), 90, Item.Properties().stacksTo(64).rarity(Rarity.RARE).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) } val DEBUG_EXPLOSION_SMALL: Item by registry.register(MNames.DEBUG_EXPLOSION_SMALL) { BlockItem(MBlocks.DEBUG_EXPLOSION_SMALL, DEFAULT_PROPERTIES) } val DEBUG_SPHERE_POINTS: Item by registry.register(MNames.DEBUG_SPHERE_POINTS) { BlockItem(MBlocks.DEBUG_SPHERE_POINTS, DEFAULT_PROPERTIES) }