Use weak caches for custom textures
This commit is contained in:
@@ -23,6 +23,8 @@ import moe.nea.firmament.util.MC
|
|||||||
import moe.nea.firmament.util.SBData
|
import moe.nea.firmament.util.SBData
|
||||||
import moe.nea.firmament.util.ScreenUtil
|
import moe.nea.firmament.util.ScreenUtil
|
||||||
import moe.nea.firmament.util.SkyblockId
|
import moe.nea.firmament.util.SkyblockId
|
||||||
|
import moe.nea.firmament.util.collections.InstanceList
|
||||||
|
import moe.nea.firmament.util.collections.WeakCache
|
||||||
|
|
||||||
|
|
||||||
fun firmamentCommand() = literal("firmament") {
|
fun firmamentCommand() = literal("firmament") {
|
||||||
@@ -229,6 +231,18 @@ fun firmamentCommand() = literal("firmament") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
thenLiteral("caches") {
|
||||||
|
thenExecute {
|
||||||
|
source.sendFeedback(Text.literal("Caches:"))
|
||||||
|
WeakCache.allInstances.getAll().forEach {
|
||||||
|
source.sendFeedback(Text.literal(" - ${it.name}: ${it.size}"))
|
||||||
|
}
|
||||||
|
source.sendFeedback(Text.translatable("Instance lists:"))
|
||||||
|
InstanceList.allInstances.getAll().forEach {
|
||||||
|
source.sendFeedback(Text.literal(" - ${it.name}: ${it.size}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
thenLiteral("mixins") {
|
thenLiteral("mixins") {
|
||||||
thenExecute {
|
thenExecute {
|
||||||
source.sendFeedback(Text.translatable("firmament.mixins.start"))
|
source.sendFeedback(Text.translatable("firmament.mixins.start"))
|
||||||
|
|||||||
@@ -1,24 +1,25 @@
|
|||||||
|
|
||||||
|
|
||||||
package moe.nea.firmament.events
|
package moe.nea.firmament.events
|
||||||
|
|
||||||
import java.util.*
|
import java.util.Optional
|
||||||
|
import kotlin.jvm.optionals.getOrNull
|
||||||
import net.minecraft.client.render.model.BakedModel
|
import net.minecraft.client.render.model.BakedModel
|
||||||
import net.minecraft.client.render.model.BakedModelManager
|
import net.minecraft.client.render.model.BakedModelManager
|
||||||
import net.minecraft.client.util.ModelIdentifier
|
import net.minecraft.client.util.ModelIdentifier
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
|
import moe.nea.firmament.util.collections.WeakCache
|
||||||
|
|
||||||
data class CustomItemModelEvent(
|
data class CustomItemModelEvent(
|
||||||
val itemStack: ItemStack,
|
val itemStack: ItemStack,
|
||||||
var overrideModel: ModelIdentifier? = null,
|
var overrideModel: ModelIdentifier? = null,
|
||||||
) : FirmamentEvent() {
|
) : FirmamentEvent() {
|
||||||
companion object : FirmamentEventBus<CustomItemModelEvent>() {
|
companion object : FirmamentEventBus<CustomItemModelEvent>() {
|
||||||
private val cache = IdentityHashMap<ItemStack?, Any>()
|
val cache =
|
||||||
private val sentinelNull = Object()
|
WeakCache.memoize<ItemStack, BakedModelManager, Optional<BakedModel>>("CustomItemModels") { stack, models ->
|
||||||
|
val modelId = getModelIdentifier(stack) ?: return@memoize Optional.empty()
|
||||||
fun clearCache() {
|
val bakedModel = models.getModel(modelId)
|
||||||
cache.clear()
|
if (bakedModel === models.missingModel) return@memoize Optional.empty()
|
||||||
}
|
Optional.of(bakedModel)
|
||||||
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getModelIdentifier(itemStack: ItemStack?): ModelIdentifier? {
|
fun getModelIdentifier(itemStack: ItemStack?): ModelIdentifier? {
|
||||||
@@ -29,15 +30,7 @@ data class CustomItemModelEvent(
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getModel(itemStack: ItemStack?, thing: BakedModelManager): BakedModel? {
|
fun getModel(itemStack: ItemStack?, thing: BakedModelManager): BakedModel? {
|
||||||
if (itemStack == null) return null
|
if (itemStack == null) return null
|
||||||
val cachedValue = cache.getOrPut(itemStack) {
|
return cache.invoke(itemStack, thing).getOrNull()
|
||||||
val modelId = getModelIdentifier(itemStack) ?: return@getOrPut sentinelNull
|
|
||||||
val bakedModel = thing.getModel(modelId)
|
|
||||||
if (bakedModel === thing.missingModel) return@getOrPut sentinelNull
|
|
||||||
bakedModel
|
|
||||||
}
|
|
||||||
if (cachedValue === sentinelNull)
|
|
||||||
return null
|
|
||||||
return cachedValue as BakedModel
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,35 @@
|
|||||||
|
|
||||||
package moe.nea.firmament.events
|
package moe.nea.firmament.events
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture
|
||||||
|
import java.util.concurrent.Executor
|
||||||
import net.minecraft.resource.ReloadableResourceManagerImpl
|
import net.minecraft.resource.ReloadableResourceManagerImpl
|
||||||
|
import net.minecraft.resource.ResourceManager
|
||||||
|
import net.minecraft.resource.ResourceReloader
|
||||||
|
import net.minecraft.util.profiler.Profiler
|
||||||
|
|
||||||
data class FinalizeResourceManagerEvent(
|
data class FinalizeResourceManagerEvent(
|
||||||
val resourceManager: ReloadableResourceManagerImpl,
|
val resourceManager: ReloadableResourceManagerImpl,
|
||||||
) : FirmamentEvent() {
|
) : FirmamentEvent() {
|
||||||
companion object : FirmamentEventBus<FinalizeResourceManagerEvent>()
|
companion object : FirmamentEventBus<FinalizeResourceManagerEvent>()
|
||||||
|
|
||||||
|
inline fun registerOnApply(name: String, crossinline function: () -> Unit) {
|
||||||
|
resourceManager.registerReloader(object : ResourceReloader {
|
||||||
|
override fun reload(
|
||||||
|
synchronizer: ResourceReloader.Synchronizer,
|
||||||
|
manager: ResourceManager?,
|
||||||
|
prepareProfiler: Profiler?,
|
||||||
|
applyProfiler: Profiler?,
|
||||||
|
prepareExecutor: Executor?,
|
||||||
|
applyExecutor: Executor
|
||||||
|
): CompletableFuture<Void> {
|
||||||
|
return CompletableFuture.completedFuture(Unit)
|
||||||
|
.thenCompose(synchronizer::whenPrepared)
|
||||||
|
.thenAcceptAsync({ function() }, applyExecutor)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getName(): String {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,15 @@ package moe.nea.firmament.features.debug
|
|||||||
|
|
||||||
import net.minecraft.text.Text
|
import net.minecraft.text.Text
|
||||||
import moe.nea.firmament.util.MC
|
import moe.nea.firmament.util.MC
|
||||||
|
import moe.nea.firmament.util.collections.InstanceList
|
||||||
|
|
||||||
class DebugLogger(val tag: String) {
|
class DebugLogger(val tag: String) {
|
||||||
|
companion object {
|
||||||
|
val allInstances = InstanceList<DebugLogger>("DebugLogger")
|
||||||
|
}
|
||||||
|
init {
|
||||||
|
allInstances.add(this)
|
||||||
|
}
|
||||||
fun isEnabled() = DeveloperFeatures.isEnabled // TODO: allow filtering by tag
|
fun isEnabled() = DeveloperFeatures.isEnabled // TODO: allow filtering by tag
|
||||||
fun log(text: () -> String) {
|
fun log(text: () -> String) {
|
||||||
if (!isEnabled()) return
|
if (!isEnabled()) return
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import moe.nea.firmament.events.WorldRenderLastEvent
|
|||||||
import moe.nea.firmament.events.subscription.SubscriptionOwner
|
import moe.nea.firmament.events.subscription.SubscriptionOwner
|
||||||
import moe.nea.firmament.features.FirmamentFeature
|
import moe.nea.firmament.features.FirmamentFeature
|
||||||
import moe.nea.firmament.util.TimeMark
|
import moe.nea.firmament.util.TimeMark
|
||||||
import moe.nea.firmament.util.mutableMapWithMaxSize
|
import moe.nea.firmament.util.collections.mutableMapWithMaxSize
|
||||||
import moe.nea.firmament.util.render.RenderInWorldContext.Companion.renderInWorld
|
import moe.nea.firmament.util.render.RenderInWorldContext.Companion.renderInWorld
|
||||||
|
|
||||||
object NearbyBurrowsSolver : SubscriptionOwner {
|
object NearbyBurrowsSolver : SubscriptionOwner {
|
||||||
|
|||||||
@@ -14,9 +14,8 @@ import moe.nea.firmament.features.FirmamentFeature
|
|||||||
import moe.nea.firmament.gui.config.ManagedConfig
|
import moe.nea.firmament.gui.config.ManagedConfig
|
||||||
import moe.nea.firmament.util.MC
|
import moe.nea.firmament.util.MC
|
||||||
import moe.nea.firmament.util.item.loreAccordingToNbt
|
import moe.nea.firmament.util.item.loreAccordingToNbt
|
||||||
import moe.nea.firmament.util.lastNotNullOfOrNull
|
import moe.nea.firmament.util.collections.lastNotNullOfOrNull
|
||||||
import moe.nea.firmament.util.memoize
|
import moe.nea.firmament.util.collections.memoizeIdentity
|
||||||
import moe.nea.firmament.util.memoizeIdentity
|
|
||||||
import moe.nea.firmament.util.unformattedString
|
import moe.nea.firmament.util.unformattedString
|
||||||
|
|
||||||
object ItemRarityCosmetics : FirmamentFeature {
|
object ItemRarityCosmetics : FirmamentFeature {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import moe.nea.firmament.repo.ItemCache.asItemStack
|
|||||||
import moe.nea.firmament.repo.RepoManager
|
import moe.nea.firmament.repo.RepoManager
|
||||||
import moe.nea.firmament.util.MC
|
import moe.nea.firmament.util.MC
|
||||||
import moe.nea.firmament.util.SkyblockId
|
import moe.nea.firmament.util.SkyblockId
|
||||||
import moe.nea.firmament.util.memoize
|
import moe.nea.firmament.util.collections.memoize
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class InventoryButton(
|
data class InventoryButton(
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
package moe.nea.firmament.features.texturepack
|
package moe.nea.firmament.features.texturepack
|
||||||
|
|
||||||
import com.google.gson.JsonArray
|
import com.google.gson.JsonArray
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
|
|
||||||
@file:UseSerializers(IdentifierSerializer::class)
|
@file:UseSerializers(IdentifierSerializer::class)
|
||||||
|
|
||||||
package moe.nea.firmament.features.texturepack
|
package moe.nea.firmament.features.texturepack
|
||||||
|
|
||||||
|
import java.util.Optional
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.Transient
|
import kotlinx.serialization.Transient
|
||||||
import kotlinx.serialization.UseSerializers
|
import kotlinx.serialization.UseSerializers
|
||||||
|
import kotlin.jvm.optionals.getOrNull
|
||||||
import net.minecraft.item.ArmorMaterial
|
import net.minecraft.item.ArmorMaterial
|
||||||
import net.minecraft.item.ItemStack
|
import net.minecraft.item.ItemStack
|
||||||
import net.minecraft.resource.ResourceManager
|
import net.minecraft.resource.ResourceManager
|
||||||
@@ -20,8 +21,7 @@ import moe.nea.firmament.events.subscription.SubscriptionOwner
|
|||||||
import moe.nea.firmament.features.FirmamentFeature
|
import moe.nea.firmament.features.FirmamentFeature
|
||||||
import moe.nea.firmament.features.texturepack.CustomGlobalTextures.logger
|
import moe.nea.firmament.features.texturepack.CustomGlobalTextures.logger
|
||||||
import moe.nea.firmament.util.IdentifierSerializer
|
import moe.nea.firmament.util.IdentifierSerializer
|
||||||
import moe.nea.firmament.util.IdentityCharacteristics
|
import moe.nea.firmament.util.collections.WeakCache
|
||||||
import moe.nea.firmament.util.computeNullableFunction
|
|
||||||
import moe.nea.firmament.util.skyBlockId
|
import moe.nea.firmament.util.skyBlockId
|
||||||
|
|
||||||
object CustomGlobalArmorOverrides : SubscriptionOwner {
|
object CustomGlobalArmorOverrides : SubscriptionOwner {
|
||||||
@@ -59,21 +59,21 @@ object CustomGlobalArmorOverrides : SubscriptionOwner {
|
|||||||
override val delegateFeature: FirmamentFeature
|
override val delegateFeature: FirmamentFeature
|
||||||
get() = CustomSkyBlockTextures
|
get() = CustomSkyBlockTextures
|
||||||
|
|
||||||
val overrideCache = mutableMapOf<IdentityCharacteristics<ItemStack>, Any>()
|
val overrideCache = WeakCache.memoize<ItemStack, Optional<List<ArmorMaterial.Layer>>>("ArmorOverrides") { stack ->
|
||||||
|
val id = stack.skyBlockId ?: return@memoize Optional.empty()
|
||||||
|
val override = overrides[id.neuItem] ?: return@memoize Optional.empty()
|
||||||
|
for (suboverride in override.overrides) {
|
||||||
|
if (suboverride.predicate.test(stack)) {
|
||||||
|
return@memoize Optional.of(suboverride.bakedLayers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return@memoize Optional.of(override.bakedLayers)
|
||||||
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun overrideArmor(stack: ItemStack): List<ArmorMaterial.Layer>? {
|
fun overrideArmor(stack: ItemStack): List<ArmorMaterial.Layer>? {
|
||||||
if (!CustomSkyBlockTextures.TConfig.enableArmorOverrides) return null
|
if (!CustomSkyBlockTextures.TConfig.enableArmorOverrides) return null
|
||||||
return overrideCache.computeNullableFunction(IdentityCharacteristics(stack)) {
|
return overrideCache.invoke(stack).getOrNull()
|
||||||
val id = stack.skyBlockId ?: return@computeNullableFunction null
|
|
||||||
val override = overrides[id.neuItem] ?: return@computeNullableFunction null
|
|
||||||
for (suboverride in override.overrides) {
|
|
||||||
if (suboverride.predicate.test(stack)) {
|
|
||||||
return@computeNullableFunction suboverride.bakedLayers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return@computeNullableFunction override.bakedLayers
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var overrides: Map<String, ArmorOverride> = mapOf()
|
var overrides: Map<String, ArmorOverride> = mapOf()
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
|
||||||
@file:UseSerializers(IdentifierSerializer::class, CustomModelOverrideParser.FirmamentRootPredicateSerializer::class)
|
@file:UseSerializers(IdentifierSerializer::class, CustomModelOverrideParser.FirmamentRootPredicateSerializer::class)
|
||||||
|
|
||||||
package moe.nea.firmament.features.texturepack
|
package moe.nea.firmament.features.texturepack
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Optional
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable
|
||||||
@@ -28,9 +28,9 @@ import moe.nea.firmament.events.ScreenChangeEvent
|
|||||||
import moe.nea.firmament.events.subscription.SubscriptionOwner
|
import moe.nea.firmament.events.subscription.SubscriptionOwner
|
||||||
import moe.nea.firmament.features.FirmamentFeature
|
import moe.nea.firmament.features.FirmamentFeature
|
||||||
import moe.nea.firmament.util.IdentifierSerializer
|
import moe.nea.firmament.util.IdentifierSerializer
|
||||||
import moe.nea.firmament.util.IdentityCharacteristics
|
|
||||||
import moe.nea.firmament.util.MC
|
import moe.nea.firmament.util.MC
|
||||||
import moe.nea.firmament.util.computeNullableFunction
|
import moe.nea.firmament.util.collections.WeakCache
|
||||||
|
import moe.nea.firmament.util.intoOptional
|
||||||
import moe.nea.firmament.util.json.SingletonSerializableList
|
import moe.nea.firmament.util.json.SingletonSerializableList
|
||||||
import moe.nea.firmament.util.runNull
|
import moe.nea.firmament.util.runNull
|
||||||
|
|
||||||
@@ -140,7 +140,17 @@ object CustomGlobalTextures : SinglePreparationResourceReloader<CustomGlobalText
|
|||||||
.filterTo(mutableSetOf()) { it.screenFilter.title.matches(newTitle) }
|
.filterTo(mutableSetOf()) { it.screenFilter.title.matches(newTitle) }
|
||||||
}
|
}
|
||||||
|
|
||||||
val overrideCache = mutableMapOf<IdentityCharacteristics<ItemStack>, Any>()
|
val overrideCache = WeakCache.memoize<ItemStack, ItemModels, Optional<BakedModel>>("CustomGlobalTextureModelOverrides") { stack, models ->
|
||||||
|
matchingOverrides
|
||||||
|
.firstNotNullOfOrNull {
|
||||||
|
it.overrides
|
||||||
|
.asSequence()
|
||||||
|
.filter { it.predicate.test(stack) }
|
||||||
|
.map { models.modelManager.getModel(ModelIdentifier(it.model, "inventory")) }
|
||||||
|
.firstOrNull()
|
||||||
|
}
|
||||||
|
.intoOptional()
|
||||||
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun replaceGlobalModel(
|
fun replaceGlobalModel(
|
||||||
@@ -148,19 +158,8 @@ object CustomGlobalTextures : SinglePreparationResourceReloader<CustomGlobalText
|
|||||||
stack: ItemStack,
|
stack: ItemStack,
|
||||||
cir: CallbackInfoReturnable<BakedModel>
|
cir: CallbackInfoReturnable<BakedModel>
|
||||||
) {
|
) {
|
||||||
val value = overrideCache.computeNullableFunction(IdentityCharacteristics(stack)) {
|
overrideCache.invoke(stack, models)
|
||||||
for (guiClassOverride in matchingOverrides) {
|
.ifPresent(cir::setReturnValue)
|
||||||
for (override in guiClassOverride.overrides) {
|
|
||||||
if (override.predicate.test(stack)) {
|
|
||||||
return@computeNullableFunction models.modelManager.getModel(
|
|
||||||
ModelIdentifier(override.model, "inventory"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
null
|
|
||||||
}
|
|
||||||
if (value != null)
|
|
||||||
cir.returnValue = value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ package moe.nea.firmament.features.texturepack
|
|||||||
|
|
||||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture
|
import com.mojang.authlib.minecraft.MinecraftProfileTexture
|
||||||
import com.mojang.authlib.properties.Property
|
import com.mojang.authlib.properties.Property
|
||||||
|
import java.util.Optional
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable
|
||||||
|
import kotlin.jvm.optionals.getOrNull
|
||||||
import net.minecraft.block.SkullBlock
|
import net.minecraft.block.SkullBlock
|
||||||
import net.minecraft.client.MinecraftClient
|
import net.minecraft.client.MinecraftClient
|
||||||
import net.minecraft.client.render.RenderLayer
|
import net.minecraft.client.render.RenderLayer
|
||||||
@@ -12,10 +14,11 @@ import net.minecraft.util.Identifier
|
|||||||
import moe.nea.firmament.annotations.Subscribe
|
import moe.nea.firmament.annotations.Subscribe
|
||||||
import moe.nea.firmament.events.BakeExtraModelsEvent
|
import moe.nea.firmament.events.BakeExtraModelsEvent
|
||||||
import moe.nea.firmament.events.CustomItemModelEvent
|
import moe.nea.firmament.events.CustomItemModelEvent
|
||||||
|
import moe.nea.firmament.events.FinalizeResourceManagerEvent
|
||||||
import moe.nea.firmament.events.TickEvent
|
import moe.nea.firmament.events.TickEvent
|
||||||
import moe.nea.firmament.features.FirmamentFeature
|
import moe.nea.firmament.features.FirmamentFeature
|
||||||
import moe.nea.firmament.gui.config.ManagedConfig
|
import moe.nea.firmament.gui.config.ManagedConfig
|
||||||
import moe.nea.firmament.util.IdentityCharacteristics
|
import moe.nea.firmament.util.collections.WeakCache
|
||||||
import moe.nea.firmament.util.item.decodeProfileTextureProperty
|
import moe.nea.firmament.util.item.decodeProfileTextureProperty
|
||||||
import moe.nea.firmament.util.skyBlockId
|
import moe.nea.firmament.util.skyBlockId
|
||||||
|
|
||||||
@@ -26,7 +29,8 @@ object CustomSkyBlockTextures : FirmamentFeature {
|
|||||||
object TConfig : ManagedConfig(identifier) {
|
object TConfig : ManagedConfig(identifier) {
|
||||||
val enabled by toggle("enabled") { true }
|
val enabled by toggle("enabled") { true }
|
||||||
val skullsEnabled by toggle("skulls-enabled") { true }
|
val skullsEnabled by toggle("skulls-enabled") { true }
|
||||||
val cacheDuration by integer("cache-duration", 0, 20) { 1 }
|
val cacheForever by toggle("cache-forever") { true }
|
||||||
|
val cacheDuration by integer("cache-duration", 0, 100) { 1 }
|
||||||
val enableModelOverrides by toggle("model-overrides") { true }
|
val enableModelOverrides by toggle("model-overrides") { true }
|
||||||
val enableArmorOverrides by toggle("armor-overrides") { true }
|
val enableArmorOverrides by toggle("armor-overrides") { true }
|
||||||
val enableBlockOverrides by toggle("block-overrides") { true }
|
val enableBlockOverrides by toggle("block-overrides") { true }
|
||||||
@@ -36,14 +40,31 @@ object CustomSkyBlockTextures : FirmamentFeature {
|
|||||||
override val config: ManagedConfig
|
override val config: ManagedConfig
|
||||||
get() = TConfig
|
get() = TConfig
|
||||||
|
|
||||||
|
val allItemCaches by lazy {
|
||||||
|
listOf(
|
||||||
|
CustomItemModelEvent.cache.cache,
|
||||||
|
skullTextureCache.cache,
|
||||||
|
CustomGlobalTextures.overrideCache.cache,
|
||||||
|
CustomGlobalArmorOverrides.overrideCache.cache
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clearAllCaches() {
|
||||||
|
allItemCaches.forEach(WeakCache<*, *, *>::clear)
|
||||||
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
fun onTick(it: TickEvent) {
|
fun onTick(it: TickEvent) {
|
||||||
|
if (TConfig.cacheForever) return
|
||||||
if (TConfig.cacheDuration < 1 || it.tickCount % TConfig.cacheDuration == 0) {
|
if (TConfig.cacheDuration < 1 || it.tickCount % TConfig.cacheDuration == 0) {
|
||||||
// TODO: unify all of those caches somehow
|
clearAllCaches()
|
||||||
CustomItemModelEvent.clearCache()
|
}
|
||||||
skullTextureCache.clear()
|
}
|
||||||
CustomGlobalTextures.overrideCache.clear()
|
|
||||||
CustomGlobalArmorOverrides.overrideCache.clear()
|
@Subscribe
|
||||||
|
fun onStart(event: FinalizeResourceManagerEvent) {
|
||||||
|
event.registerOnApply("Clear firmament CIT caches") {
|
||||||
|
clearAllCaches()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,8 +95,14 @@ object CustomSkyBlockTextures : FirmamentFeature {
|
|||||||
it.overrideModel = ModelIdentifier.ofInventoryVariant(Identifier.of("firmskyblock", id.identifier.path))
|
it.overrideModel = ModelIdentifier.ofInventoryVariant(Identifier.of("firmskyblock", id.identifier.path))
|
||||||
}
|
}
|
||||||
|
|
||||||
private val skullTextureCache = mutableMapOf<IdentityCharacteristics<ProfileComponent>, Any>()
|
private val skullTextureCache =
|
||||||
private val sentinelPresentInvalid = Object()
|
WeakCache.memoize<ProfileComponent, Optional<Identifier>>("SkullTextureCache") { component ->
|
||||||
|
val id = getSkullTexture(component) ?: return@memoize Optional.empty()
|
||||||
|
if (!MinecraftClient.getInstance().resourceManager.getResource(id).isPresent) {
|
||||||
|
return@memoize Optional.empty()
|
||||||
|
}
|
||||||
|
return@memoize Optional.of(id)
|
||||||
|
}
|
||||||
|
|
||||||
private val mcUrlRegex = "https?://textures.minecraft.net/texture/([a-fA-F0-9]+)".toRegex()
|
private val mcUrlRegex = "https?://textures.minecraft.net/texture/([a-fA-F0-9]+)".toRegex()
|
||||||
|
|
||||||
@@ -100,16 +127,8 @@ object CustomSkyBlockTextures : FirmamentFeature {
|
|||||||
if (type != SkullBlock.Type.PLAYER) return
|
if (type != SkullBlock.Type.PLAYER) return
|
||||||
if (!TConfig.skullsEnabled) return
|
if (!TConfig.skullsEnabled) return
|
||||||
if (component == null) return
|
if (component == null) return
|
||||||
val ic = IdentityCharacteristics(component)
|
|
||||||
|
|
||||||
val n = skullTextureCache.getOrPut(ic) {
|
val n = skullTextureCache.invoke(component).getOrNull() ?: return
|
||||||
val id = getSkullTexture(component) ?: return@getOrPut sentinelPresentInvalid
|
cir.returnValue = RenderLayer.getEntityTranslucent(n)
|
||||||
if (!MinecraftClient.getInstance().resourceManager.getResource(id).isPresent) {
|
|
||||||
return@getOrPut sentinelPresentInvalid
|
|
||||||
}
|
|
||||||
return@getOrPut id
|
|
||||||
}
|
|
||||||
if (n === sentinelPresentInvalid) return
|
|
||||||
cir.returnValue = RenderLayer.getEntityTranslucent(n as Identifier)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ object SBItemEntryDefinition : EntryDefinition<SBItemStack> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun asFormattedText(entry: EntryStack<SBItemStack>, value: SBItemStack): Text {
|
override fun asFormattedText(entry: EntryStack<SBItemStack>, value: SBItemStack): Text {
|
||||||
return VanillaEntryTypes.ITEM.definition.asFormattedText(entry.asItemEntry(), value.asItemStack())
|
return VanillaEntryTypes.ITEM.definition.asFormattedText(entry.asItemEntry(), value.asImmutableItemStack())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hash(entry: EntryStack<SBItemStack>, value: SBItemStack, context: ComparisonContext): Long {
|
override fun hash(entry: EntryStack<SBItemStack>, value: SBItemStack, context: ComparisonContext): Long {
|
||||||
|
|||||||
5
src/main/kotlin/util/Optionalutil.kt
Normal file
5
src/main/kotlin/util/Optionalutil.kt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package moe.nea.firmament.util
|
||||||
|
|
||||||
|
import java.util.Optional
|
||||||
|
|
||||||
|
fun <T : Any> T?.intoOptional(): Optional<T> = Optional.ofNullable(this)
|
||||||
57
src/main/kotlin/util/collections/InstanceList.kt
Normal file
57
src/main/kotlin/util/collections/InstanceList.kt
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
package moe.nea.firmament.util.collections
|
||||||
|
|
||||||
|
import java.lang.ref.ReferenceQueue
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
|
|
||||||
|
class InstanceList<T : Any>(val name: String) {
|
||||||
|
val queue = object : ReferenceQueue<T>() {}
|
||||||
|
val set = mutableSetOf<Ref>()
|
||||||
|
|
||||||
|
val size: Int
|
||||||
|
get() {
|
||||||
|
clearOldReferences()
|
||||||
|
return set.size
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clearOldReferences() {
|
||||||
|
while (true) {
|
||||||
|
val reference = queue.poll() ?: break
|
||||||
|
set.remove(reference)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAll(): List<T> {
|
||||||
|
clearOldReferences()
|
||||||
|
return set.mapNotNull { it.get() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun add(t: T) {
|
||||||
|
set.add(Ref(t))
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (init)
|
||||||
|
allInstances.add(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class Ref(referent: T) : WeakReference<T>(referent) {
|
||||||
|
val hashCode = System.identityHashCode(referent)
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
return other is InstanceList<*>.Ref && hashCode == other.hashCode && get() === other.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return hashCode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private var init = false
|
||||||
|
val allInstances = InstanceList<InstanceList<*>>("InstanceLists")
|
||||||
|
|
||||||
|
init {
|
||||||
|
init = true
|
||||||
|
allInstances.add(allInstances)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
|
|
||||||
package moe.nea.firmament.util
|
package moe.nea.firmament.util.collections
|
||||||
|
|
||||||
|
import moe.nea.firmament.util.IdentityCharacteristics
|
||||||
|
|
||||||
fun <K, V> mutableMapWithMaxSize(maxSize: Int): MutableMap<K, V> = object : LinkedHashMap<K, V>() {
|
fun <K, V> mutableMapWithMaxSize(maxSize: Int): MutableMap<K, V> = object : LinkedHashMap<K, V>() {
|
||||||
override fun removeEldestEntry(eldest: MutableMap.MutableEntry<K, V>): Boolean {
|
override fun removeEldestEntry(eldest: MutableMap.MutableEntry<K, V>): Boolean {
|
||||||
110
src/main/kotlin/util/collections/WeakCache.kt
Normal file
110
src/main/kotlin/util/collections/WeakCache.kt
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
package moe.nea.firmament.util.collections
|
||||||
|
|
||||||
|
import java.lang.ref.ReferenceQueue
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
|
import moe.nea.firmament.features.debug.DebugLogger
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache class that uses [WeakReferences][WeakReference] to only cache values while there is still a life reference to
|
||||||
|
* the key. Each key can have additional extra data that is used to look up values. That extra data is not required to
|
||||||
|
* be a life reference. The main Key is compared using strict reference equality. This map is not synchronized.
|
||||||
|
*/
|
||||||
|
class WeakCache<Key : Any, ExtraKey : Any, Value : Any>(val name: String) {
|
||||||
|
private val queue = object : ReferenceQueue<Key>() {}
|
||||||
|
private val map = mutableMapOf<Ref, Value>()
|
||||||
|
|
||||||
|
val size: Int
|
||||||
|
get() {
|
||||||
|
clearOldReferences()
|
||||||
|
return map.size
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clearOldReferences() {
|
||||||
|
var successCount = 0
|
||||||
|
var totalCount = 0
|
||||||
|
while (true) {
|
||||||
|
val reference = queue.poll() ?: break
|
||||||
|
totalCount++
|
||||||
|
if (map.remove(reference) != null)
|
||||||
|
successCount++
|
||||||
|
}
|
||||||
|
if (totalCount > 0)
|
||||||
|
logger.log { "Cleared $successCount/$totalCount references from queue" }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun get(key: Key, extraData: ExtraKey): Value? {
|
||||||
|
clearOldReferences()
|
||||||
|
return map[Ref(key, extraData)]
|
||||||
|
}
|
||||||
|
|
||||||
|
fun put(key: Key, extraData: ExtraKey, value: Value) {
|
||||||
|
clearOldReferences()
|
||||||
|
map[Ref(key, extraData)] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getOrPut(key: Key, extraData: ExtraKey, value: (Key, ExtraKey) -> Value): Value {
|
||||||
|
clearOldReferences()
|
||||||
|
return map.getOrPut(Ref(key, extraData)) { value(key, extraData) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
map.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
allInstances.add(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val allInstances = InstanceList<WeakCache<*, *, *>>("WeakCaches")
|
||||||
|
private val logger = DebugLogger("WeakCache")
|
||||||
|
fun <Key : Any, Value : Any> memoize(name: String, function: (Key) -> Value):
|
||||||
|
CacheFunction.NoExtraData<Key, Value> {
|
||||||
|
return CacheFunction.NoExtraData(WeakCache(name), function)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <Key : Any, ExtraKey : Any, Value : Any> memoize(name: String, function: (Key, ExtraKey) -> Value):
|
||||||
|
CacheFunction.WithExtraData<Key, ExtraKey, Value> {
|
||||||
|
return CacheFunction.WithExtraData(WeakCache(name), function)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class Ref(
|
||||||
|
weakInstance: Key,
|
||||||
|
val extraData: ExtraKey,
|
||||||
|
) : WeakReference<Key>(weakInstance, queue) {
|
||||||
|
val hashCode = System.identityHashCode(weakInstance) * 31 + extraData.hashCode()
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (other !is WeakCache<*, *, *>.Ref) return false
|
||||||
|
return other.hashCode == this.hashCode
|
||||||
|
&& other.get() === this.get()
|
||||||
|
&& other.extraData == this.extraData
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return hashCode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CacheFunction {
|
||||||
|
val cache: WeakCache<*, *, *>
|
||||||
|
|
||||||
|
data class NoExtraData<Key : Any, Value : Any>(
|
||||||
|
override val cache: WeakCache<Key, Unit, Value>,
|
||||||
|
val wrapped: (Key) -> Value,
|
||||||
|
) : CacheFunction, (Key) -> Value {
|
||||||
|
override fun invoke(p1: Key): Value {
|
||||||
|
return cache.getOrPut(p1, Unit, { a, _ -> wrapped(a) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class WithExtraData<Key : Any, ExtraKey : Any, Value : Any>(
|
||||||
|
override val cache: WeakCache<Key, ExtraKey, Value>,
|
||||||
|
val wrapped: (Key, ExtraKey) -> Value,
|
||||||
|
) : CacheFunction, (Key, ExtraKey) -> Value {
|
||||||
|
override fun invoke(p1: Key, p2: ExtraKey): Value {
|
||||||
|
return cache.getOrPut(p1, p2, wrapped)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
package moe.nea.firmament.util
|
package moe.nea.firmament.util.collections
|
||||||
|
|
||||||
fun <T, R> List<T>.lastNotNullOfOrNull(func: (T) -> R?): R? {
|
fun <T, R> List<T>.lastNotNullOfOrNull(func: (T) -> R?): R? {
|
||||||
for (i in indices.reversed()) {
|
for (i in indices.reversed()) {
|
||||||
@@ -173,6 +173,7 @@
|
|||||||
"firmament.config.custom-skyblock-textures.block-overrides": "Enable Block re-modelling",
|
"firmament.config.custom-skyblock-textures.block-overrides": "Enable Block re-modelling",
|
||||||
"firmament.config.custom-skyblock-textures.enabled": "Enable Custom Item Textures",
|
"firmament.config.custom-skyblock-textures.enabled": "Enable Custom Item Textures",
|
||||||
"firmament.config.custom-skyblock-textures.skulls-enabled": "Enable Custom Placed Skull Textures",
|
"firmament.config.custom-skyblock-textures.skulls-enabled": "Enable Custom Placed Skull Textures",
|
||||||
|
"firmament.config.custom-skyblock-textures.cache-forever": "Disable cache clearing",
|
||||||
"firmament.config.fixes": "Fixes",
|
"firmament.config.fixes": "Fixes",
|
||||||
"firmament.config.fixes.player-skins": "Fix unsigned Player Skins",
|
"firmament.config.fixes.player-skins": "Fix unsigned Player Skins",
|
||||||
"firmament.config.power-user.show-item-id": "Show SkyBlock Ids",
|
"firmament.config.power-user.show-item-id": "Show SkyBlock Ids",
|
||||||
|
|||||||
Reference in New Issue
Block a user