aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/repo/item/SBItemProperty.kt
blob: fd852517c24039236e4e8af91db5ade7ea2890d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package moe.nea.firmament.repo.item

import io.github.moulberry.repo.data.NEUItem
import net.minecraft.item.ItemStack
import moe.nea.firmament.repo.ItemCache.asItemStack
import moe.nea.firmament.util.compatloader.CompatLoader

/**
 * A property of a skyblock item. Not every skyblock item must have this property, but some should.
 *
 * Access to this class should be limited to [State.bind] and [SBItemData.getData].
 * @see State
 */
abstract class SBItemProperty<T> {
	data class BoundState<T>(val property: State<T>, val data: T) {
		fun applyTo(store: SBItemData) {
			store.set(property, data)
		}
	}

	// TODO: Actually implement and make use of this method.
	/**
	 * Extract this property's state from a [NEUItem]. If this method returns something, it may be equivalent to [fromStack] with the neu item resolved to an item stack according to [asItemStack], but *should not* instantiate an item stack. This method may return null to indicate that it needs a fully constructed item stack to extract a property. This method return one value and then later return another value from [fromStack], but behaviour is generally discouraged.
	 */
	open fun fromNeuItem(neuItem: NEUItem, store: SBItemData): T? {
		return null
	}

	/**
	 * Extract this property's state from an [ItemStack]. This should be fully reversible (i.e. all info used to in [fromStack] needs to be set by [State.applyToStack].
	 */
	abstract fun fromStack(stack: ItemStack, store: SBItemData): T?

	/**
	 * A property of a skyblock item that carriers state. Unlike a plain [SBItemProperty] these modifiers can be used
	 * to change the state of an item, including its rendering as a vanilla [ItemStack].
	 */
	abstract class State<T> : SBItemProperty<T>() {
		/**
		 * Apply the stored info back to the item stack. If possible [stack] should be modified and returned directly,
		 * instead of creating a new [ItemStack] instance. Information stored here should be recovered using [fromStack].
		 */
		abstract fun applyToStack(stack: ItemStack, store: SBItemData, value: T?): ItemStack
		fun bind(data: T) = BoundState(this, data)
	}

	/**
	 * The order of this property relative to other properties. Lower values get computed first, so higher values may
	 * rely on their data being stored already (if that item stack has any of that data), and they can overwrite the
	 * rendering of the lower states.
	 */
	open val order: Int get() = 0

	companion object {
		val loader = CompatLoader<SBItemProperty<*>>(SBItemProperty::class)
		val allProperties by lazy {
			loader.allValidInstances.sortedBy { it.order }
		}
		val allStates by lazy {
			allProperties.filterIsInstance<State<*>>()
		}
	}
}