aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/moe/nea/caelo/optifine/OptifineCustomItemCache.kt
blob: f34395886a73d3f3267452ba8ae2160578788bb9 (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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package moe.nea.caelo.optifine

import moe.nea.caelo.CaeloCommand
import moe.nea.caelo.config.CConfig
import moe.nea.caelo.event.NeaTickEvent
import moe.nea.caelo.util.Histogram
import moe.nea.caelo.util.MC
import net.minecraft.item.ItemStack
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import net.optifine.CustomItemProperties
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable
import java.lang.ref.ReferenceQueue
import java.lang.ref.WeakReference

object OptifineCustomItemCache {

	init {
		CaeloCommand.subcommand("opticache") { args ->
			val cache = cacheSizeHistory.lastOrNull() ?: CacheStats()
			MC.display("OptiCache stats:")
			MC.display("- History: §3${cacheSizeHistory.size}")
			MC.display("- Misses: §c${cache.cacheMisses}")
			MC.display("- Hits: §a${cache.cacheHits}")
			MC.display("- Insertions: §b${cache.insertions}")
			MC.display("- Evictions: §b${cache.removals}")
			MC.display("- Cache Size: §b${cache.size}")
			OptifineRegexCache.printStats()
		}
	}

	val referenceQueue = ReferenceQueue<ItemStack>()

	class CacheKeyReference(val cacheKey: CacheKey, itemStack: ItemStack) :
		WeakReference<ItemStack>(itemStack, referenceQueue)

	class CacheKey(itemStack: ItemStack, val type: Int) {
		val hashCode = System.identityHashCode(itemStack) * 31 + type
		val ref = CacheKeyReference(this, itemStack)

		override fun equals(other: Any?): Boolean {
			if (other === this) return true
			if (other !is CacheKey) return false
			return ref.get() === other.ref.get() && type == other.type
		}

		override fun hashCode(): Int {
			return hashCode
		}

		fun isPresent(): Boolean {
			return ref.get() != null
		}
	}

	data class CacheStats(
		var cacheHits: Int = 0,
		var cacheMisses: Int = 0,
		var insertions: Int = 0,
		var size: Int = 0,
		var removals: Int = 0,
	)

	private var map = mutableMapOf<CacheKey, CustomItemProperties?>()
	private val cacheSizeHistory = Histogram<CacheStats>(1000)
	private var cacheStats = CacheStats()

	@SubscribeEvent
	fun onTick(event: NeaTickEvent) {
		var removeCount = 0
		while (true) {
			val ref = referenceQueue.poll() as CacheKeyReference? ?: break
			removeCount++
			map.remove(ref.cacheKey)
		}
		cacheStats.size = map.size
		cacheStats.removals = removeCount
		cacheSizeHistory.append(cacheStats)
		cacheStats = CacheStats()
	}

	@JvmStatic
	fun retrieveCacheHit(
		itemStack: ItemStack,
		type: Int,
		cir: CallbackInfoReturnable<CustomItemProperties?>
	) {
		if (!CConfig.config.optiCache.citCache)
			return
		val key = CacheKey(itemStack, type)
		if (!map.containsKey(key)) {
			cacheStats.cacheMisses++
			return
		}
		cacheStats.cacheHits++
		cir.returnValue = map[key]
	}

	@JvmStatic
	fun storeCustomItemProperties(itemStack: ItemStack, type: Int, cip: CustomItemProperties) {
		map[CacheKey(itemStack, type)] = cip
		cacheStats.insertions++
	}

	@JvmStatic
	fun storeNoCustomItemProperties(itemStack: ItemStack, type: Int) {
		map[CacheKey(itemStack, type)] = null
		cacheStats.insertions++
	}
}