Use weak caches for custom textures
This commit is contained in:
@@ -3,8 +3,15 @@ package moe.nea.firmament.features.debug
|
||||
|
||||
import net.minecraft.text.Text
|
||||
import moe.nea.firmament.util.MC
|
||||
import moe.nea.firmament.util.collections.InstanceList
|
||||
|
||||
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 log(text: () -> String) {
|
||||
if (!isEnabled()) return
|
||||
|
||||
@@ -14,7 +14,7 @@ import moe.nea.firmament.events.WorldRenderLastEvent
|
||||
import moe.nea.firmament.events.subscription.SubscriptionOwner
|
||||
import moe.nea.firmament.features.FirmamentFeature
|
||||
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
|
||||
|
||||
object NearbyBurrowsSolver : SubscriptionOwner {
|
||||
|
||||
@@ -14,9 +14,8 @@ import moe.nea.firmament.features.FirmamentFeature
|
||||
import moe.nea.firmament.gui.config.ManagedConfig
|
||||
import moe.nea.firmament.util.MC
|
||||
import moe.nea.firmament.util.item.loreAccordingToNbt
|
||||
import moe.nea.firmament.util.lastNotNullOfOrNull
|
||||
import moe.nea.firmament.util.memoize
|
||||
import moe.nea.firmament.util.memoizeIdentity
|
||||
import moe.nea.firmament.util.collections.lastNotNullOfOrNull
|
||||
import moe.nea.firmament.util.collections.memoizeIdentity
|
||||
import moe.nea.firmament.util.unformattedString
|
||||
|
||||
object ItemRarityCosmetics : FirmamentFeature {
|
||||
|
||||
@@ -17,7 +17,7 @@ import moe.nea.firmament.repo.ItemCache.asItemStack
|
||||
import moe.nea.firmament.repo.RepoManager
|
||||
import moe.nea.firmament.util.MC
|
||||
import moe.nea.firmament.util.SkyblockId
|
||||
import moe.nea.firmament.util.memoize
|
||||
import moe.nea.firmament.util.collections.memoize
|
||||
|
||||
@Serializable
|
||||
data class InventoryButton(
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
package moe.nea.firmament.features.texturepack
|
||||
|
||||
import com.google.gson.JsonArray
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
|
||||
@file:UseSerializers(IdentifierSerializer::class)
|
||||
|
||||
package moe.nea.firmament.features.texturepack
|
||||
|
||||
import java.util.Optional
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Transient
|
||||
import kotlinx.serialization.UseSerializers
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
import net.minecraft.item.ArmorMaterial
|
||||
import net.minecraft.item.ItemStack
|
||||
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.texturepack.CustomGlobalTextures.logger
|
||||
import moe.nea.firmament.util.IdentifierSerializer
|
||||
import moe.nea.firmament.util.IdentityCharacteristics
|
||||
import moe.nea.firmament.util.computeNullableFunction
|
||||
import moe.nea.firmament.util.collections.WeakCache
|
||||
import moe.nea.firmament.util.skyBlockId
|
||||
|
||||
object CustomGlobalArmorOverrides : SubscriptionOwner {
|
||||
@@ -59,21 +59,21 @@ object CustomGlobalArmorOverrides : SubscriptionOwner {
|
||||
override val delegateFeature: FirmamentFeature
|
||||
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
|
||||
fun overrideArmor(stack: ItemStack): List<ArmorMaterial.Layer>? {
|
||||
if (!CustomSkyBlockTextures.TConfig.enableArmorOverrides) return null
|
||||
return overrideCache.computeNullableFunction(IdentityCharacteristics(stack)) {
|
||||
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
|
||||
}
|
||||
return overrideCache.invoke(stack).getOrNull()
|
||||
}
|
||||
|
||||
var overrides: Map<String, ArmorOverride> = mapOf()
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
|
||||
@file:UseSerializers(IdentifierSerializer::class, CustomModelOverrideParser.FirmamentRootPredicateSerializer::class)
|
||||
|
||||
package moe.nea.firmament.features.texturepack
|
||||
|
||||
|
||||
import java.util.Optional
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import org.slf4j.LoggerFactory
|
||||
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.features.FirmamentFeature
|
||||
import moe.nea.firmament.util.IdentifierSerializer
|
||||
import moe.nea.firmament.util.IdentityCharacteristics
|
||||
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.runNull
|
||||
|
||||
@@ -140,7 +140,17 @@ object CustomGlobalTextures : SinglePreparationResourceReloader<CustomGlobalText
|
||||
.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
|
||||
fun replaceGlobalModel(
|
||||
@@ -148,19 +158,8 @@ object CustomGlobalTextures : SinglePreparationResourceReloader<CustomGlobalText
|
||||
stack: ItemStack,
|
||||
cir: CallbackInfoReturnable<BakedModel>
|
||||
) {
|
||||
val value = overrideCache.computeNullableFunction(IdentityCharacteristics(stack)) {
|
||||
for (guiClassOverride in matchingOverrides) {
|
||||
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
|
||||
overrideCache.invoke(stack, models)
|
||||
.ifPresent(cir::setReturnValue)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@ package moe.nea.firmament.features.texturepack
|
||||
|
||||
import com.mojang.authlib.minecraft.MinecraftProfileTexture
|
||||
import com.mojang.authlib.properties.Property
|
||||
import java.util.Optional
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
import net.minecraft.block.SkullBlock
|
||||
import net.minecraft.client.MinecraftClient
|
||||
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.events.BakeExtraModelsEvent
|
||||
import moe.nea.firmament.events.CustomItemModelEvent
|
||||
import moe.nea.firmament.events.FinalizeResourceManagerEvent
|
||||
import moe.nea.firmament.events.TickEvent
|
||||
import moe.nea.firmament.features.FirmamentFeature
|
||||
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.skyBlockId
|
||||
|
||||
@@ -26,7 +29,8 @@ object CustomSkyBlockTextures : FirmamentFeature {
|
||||
object TConfig : ManagedConfig(identifier) {
|
||||
val enabled by toggle("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 enableArmorOverrides by toggle("armor-overrides") { true }
|
||||
val enableBlockOverrides by toggle("block-overrides") { true }
|
||||
@@ -36,14 +40,31 @@ object CustomSkyBlockTextures : FirmamentFeature {
|
||||
override val config: ManagedConfig
|
||||
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
|
||||
fun onTick(it: TickEvent) {
|
||||
if (TConfig.cacheForever) return
|
||||
if (TConfig.cacheDuration < 1 || it.tickCount % TConfig.cacheDuration == 0) {
|
||||
// TODO: unify all of those caches somehow
|
||||
CustomItemModelEvent.clearCache()
|
||||
skullTextureCache.clear()
|
||||
CustomGlobalTextures.overrideCache.clear()
|
||||
CustomGlobalArmorOverrides.overrideCache.clear()
|
||||
clearAllCaches()
|
||||
}
|
||||
}
|
||||
|
||||
@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))
|
||||
}
|
||||
|
||||
private val skullTextureCache = mutableMapOf<IdentityCharacteristics<ProfileComponent>, Any>()
|
||||
private val sentinelPresentInvalid = Object()
|
||||
private val skullTextureCache =
|
||||
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()
|
||||
|
||||
@@ -100,16 +127,8 @@ object CustomSkyBlockTextures : FirmamentFeature {
|
||||
if (type != SkullBlock.Type.PLAYER) return
|
||||
if (!TConfig.skullsEnabled) return
|
||||
if (component == null) return
|
||||
val ic = IdentityCharacteristics(component)
|
||||
|
||||
val n = skullTextureCache.getOrPut(ic) {
|
||||
val id = getSkullTexture(component) ?: return@getOrPut sentinelPresentInvalid
|
||||
if (!MinecraftClient.getInstance().resourceManager.getResource(id).isPresent) {
|
||||
return@getOrPut sentinelPresentInvalid
|
||||
}
|
||||
return@getOrPut id
|
||||
}
|
||||
if (n === sentinelPresentInvalid) return
|
||||
cir.returnValue = RenderLayer.getEntityTranslucent(n as Identifier)
|
||||
val n = skullTextureCache.invoke(component).getOrNull() ?: return
|
||||
cir.returnValue = RenderLayer.getEntityTranslucent(n)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user