From 17a855a4bdfcca00b29f85981d8fb86968d9038c Mon Sep 17 00:00:00 2001 From: Linnea Gräf Date: Tue, 11 Mar 2025 12:44:59 +0100 Subject: feat: add SBItemData implementation --- src/main/kotlin/repo/item/SBItemData.kt | 122 ++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 src/main/kotlin/repo/item/SBItemData.kt (limited to 'src/main/kotlin/repo/item/SBItemData.kt') diff --git a/src/main/kotlin/repo/item/SBItemData.kt b/src/main/kotlin/repo/item/SBItemData.kt new file mode 100644 index 0000000..7a6b081 --- /dev/null +++ b/src/main/kotlin/repo/item/SBItemData.kt @@ -0,0 +1,122 @@ +package moe.nea.firmament.repo.item + +import kotlin.collections.runningFold +import net.minecraft.item.ItemStack +import moe.nea.firmament.repo.RepoManager + +class SBItemData { + private var itemCache: ItemStack? = null + + private val data: MutableMap, Any> = mutableMapOf() + + fun getData(prop: SBItemProperty): T? { + return data[prop] as T? + } + + fun , T> set(property: Prop, data: T) { + if (data != null) { + (this.data as MutableMap)[property] = data + } else { + this.data.remove(property) + } + itemCache = null + } + + private fun enhanceStack(stack: ItemStack, property: SBItemProperty.State): ItemStack { + val data = getData(property) + return property.applyToStack(stack, this, data) + } + + private fun createStack(): ItemStack { + return SBItemProperty.allStates.fold(ItemStack.EMPTY) { stack, prop -> + enhanceStack(stack, prop) + } + } + + fun debugStackCreation(): List> { + fun combinedEnhanceStack(previous: PartialStack<*>, mod: SBItemProperty.State): PartialStack { + val nextStack = enhanceStack(previous.stack.copy(), mod) + return PartialStack(mod, getData(mod), nextStack) + } + return SBItemProperty.allStates + .runningFold( + PartialStack(null, null, ItemStack.EMPTY)) { stack: PartialStack<*>, prop -> + combinedEnhanceStack(stack, prop) + } + } + + /** + * Creates an [ItemStack] based on the current properties. The returned item stack must not be modified by the + * caller. + */ + fun toImmutableStack(): ItemStack { + var cached = itemCache + if (cached == null) { + cached = createStack() + itemCache = cached + } + return cached + } + + data class PartialStack( + val lastAppliedModifier: SBItemProperty?, + val data: T?, + val stack: ItemStack, + ) + + companion object { + /** + * Create an [SBItemData] from only the given characteristica. Any unspecified characteristica will be non-existent. + * If you want to compute all other properties based on the given properties, use [roundtrip]. + */ + fun fromCharacteristica( + vararg char: SBItemProperty.BoundState<*> + ): SBItemData { + val store = SBItemData() + char.forEach { + it.applyTo(store) + } + return store + } + + fun fromStack(itemStack: ItemStack): SBItemData { + val store = SBItemData() + store.loadFrom(itemStack) + return store + } + } + + /** + * Creates a new [SBItemData] from the item stack this [SBItemData] produces. This will initialize all properties. + */ + fun roundtrip(): SBItemData { + return fromStack(toImmutableStack()) + } + + /** + * Creates a new [SBItemData] with cheap inferences completed only by using data available in [io.github.moulberry.repo.data.NEUItem]. This is a cheaper version of [roundtrip], that does not create any [ItemStack]s, and preserves all properties already provided. Check if the property you need overrides [SBItemProperty.fromNeuItem]. + */ + fun cheapInfer(): SBItemData { + val neuItem = getData(SBItemId)?.let { RepoManager.getNEUItem(it) } ?: return this + val store = SBItemData() + SBItemProperty.allProperties.forEach { + it.fromNeuItem(neuItem, this) + } + store.data.putAll(this.data) + return store + } + + private fun loadFrom(stack: ItemStack) { + SBItemProperty.allProperties.forEach { + loadModifier(stack, it) + } + } + + private fun loadModifier( + stack: ItemStack, + modifier: SBItemProperty + ) { + val data = modifier.fromStack(stack, this) ?: return + set(modifier, data) + } +} -- cgit