[WIP] async block texture reloading

This commit is contained in:
octarine-noise
2020-01-05 16:32:45 +01:00
parent b4f18c1e1d
commit c4ee768025
31 changed files with 587 additions and 704 deletions

View File

@@ -12,6 +12,7 @@ import mods.betterfoliage.client.texture.*
import mods.octarinecore.client.gui.textComponent
import mods.octarinecore.client.render.RenderDecorator
import mods.octarinecore.client.resource.CenteringTextureGenerator
import mods.octarinecore.client.resource.AsyncSpriteProviderManager
import mods.octarinecore.client.resource.IConfigChangeListener
import net.minecraft.block.BlockState
import net.minecraft.client.Minecraft
@@ -59,7 +60,6 @@ object Client {
// init other singletons
val singletons = listOf(
BlockConfig,
StandardCactusRegistry,
LeafParticleRegistry,
ChunkOverlayManager,
LeafWindTracker,
@@ -76,9 +76,10 @@ object Client {
)
// add basic block support instances as last
GrassRegistry.addRegistry(StandardGrassRegistry)
LeafRegistry.addRegistry(StandardLeafRegistry)
LogRegistry.addRegistry(StandardLogRegistry)
AsyncLeafDiscovery.init()
AsyncGrassDiscovery.init()
AsyncLogDiscovery.init()
AsyncCactusDiscovery.init()
configListeners = listOf(renderers, singletons, integrations).flatten().filterIsInstance<IConfigChangeListener>()
configListeners.forEach { it.onConfigChange() }

View File

@@ -6,12 +6,10 @@ import mods.betterfoliage.client.chunk.ChunkOverlayManager
import mods.betterfoliage.client.config.BlockConfig
import mods.betterfoliage.client.config.Config
import mods.betterfoliage.client.render.*
import mods.betterfoliage.loader.Refs
import mods.octarinecore.ThreadLocalDelegate
import mods.octarinecore.client.render.*
import mods.octarinecore.client.render.lighting.DefaultLightingCtx
import mods.octarinecore.client.render.lighting.LightingCtx
import mods.octarinecore.client.resource.LoadModelDataEvent
import mods.octarinecore.common.plus
import mods.octarinecore.metaprog.allAvailable
import net.minecraft.block.Block
@@ -35,9 +33,6 @@ import net.minecraft.world.World
import net.minecraftforge.client.model.data.IModelData
import java.util.*
var isAfterPostInit = false
val isOptifinePresent = allAvailable(Refs.OptifineClassTransformer)
fun getAmbientOcclusionLightValueOverride(original: Float, state: BlockState): Float {
if (Config.enabled && Config.roundLogs.enabled && BlockConfig.logBlocks.matchesClass(state.block)) return Config.roundLogs.dimming.toFloat();
return original
@@ -69,10 +64,6 @@ fun onRandomDisplayTick(block: Block, state: BlockState, world: World, pos: Bloc
}
}
fun onLoadModelDefinitions(bakery: Any) {
BetterFoliage.modBus.post(LoadModelDataEvent(bakery as ModelBakery))
}
fun getVoxelShapeOverride(state: BlockState, reader: IBlockReader, pos: BlockPos, dir: Direction): VoxelShape {
if (LogRegistry[state, reader, pos] != null) return VoxelShapes.empty()
return state.func_215702_a(reader, pos, dir)

View File

@@ -1,10 +1,9 @@
package mods.betterfoliage.client.chunk
import mods.betterfoliage.BetterFoliage
import mods.betterfoliage.client.Client
import mods.betterfoliage.loader.Refs
import mods.octarinecore.client.render.BasicBlockCtx
import mods.octarinecore.ChunkCacheOF
import mods.octarinecore.client.render.BlockCtx
import mods.octarinecore.metaprog.get
import mods.octarinecore.metaprog.isInstance
import net.minecraft.client.renderer.chunk.ChunkRenderCache
import net.minecraft.client.world.ClientWorld
import net.minecraft.util.math.BlockPos
@@ -16,13 +15,19 @@ import net.minecraftforge.common.MinecraftForge
import net.minecraftforge.event.world.ChunkEvent
import net.minecraftforge.event.world.WorldEvent
import net.minecraftforge.eventbus.api.SubscribeEvent
import org.apache.logging.log4j.Level
import java.util.*
import kotlin.collections.List
import kotlin.collections.MutableMap
import kotlin.collections.associateWith
import kotlin.collections.forEach
import kotlin.collections.mutableListOf
import kotlin.collections.mutableMapOf
import kotlin.collections.set
val IEnviromentBlockReader.dimType: DimensionType get() = when {
this is IWorldReader -> dimension.type
this is ChunkRenderCache -> world.dimension.type
Refs.OptifineChunkCache.isInstance(this) -> (Refs.CCOFChunkCache.get(this) as ChunkRenderCache).world.dimension.type
this.isInstance(ChunkCacheOF) -> this[ChunkCacheOF.chunkCache].world.dimension.type
else -> throw IllegalArgumentException("DimensionType of world with class ${this::class.qualifiedName} cannot be determined!")
}
@@ -42,7 +47,6 @@ object ChunkOverlayManager {
var tempCounter = 0
init {
Client.log(Level.INFO, "Initializing client overlay manager")
MinecraftForge.EVENT_BUS.register(this)
}
@@ -84,13 +88,11 @@ object ChunkOverlayManager {
@SubscribeEvent
fun handleLoadWorld(event: WorldEvent.Load) = (event.world as? ClientWorld)?.let { world ->
BetterFoliage.log.debug("Unloaded world: id=${world.dimType.id} name=${world.dimType.registryName}")
chunkData[world.dimType] = mutableMapOf()
}
@SubscribeEvent
fun handleUnloadWorld(event: WorldEvent.Unload) = (event.world as? ClientWorld)?.let { world ->
BetterFoliage.log.debug("Unloaded world: id=${world.dimType.id} name=${world.dimType.registryName}")
chunkData.remove(world.dimType)
}
@@ -121,26 +123,3 @@ class ChunkOverlayData(layers: List<ChunkOverlayLayer<*>>) {
val validYRange = 0 until 256
}
}
/**
* IWorldEventListener helper subclass
* No-op for everything except notifyBlockUpdate()
*/
/*
interface IBlockUpdateListener : IWorldEventListener {
override fun playSoundToAllNearExcept(player: EntityPlayer?, soundIn: SoundEvent, category: SoundCategory, x: Double, y: Double, z: Double, volume: Float, pitch: Float) {}
override fun onEntityAdded(entityIn: Entity) {}
override fun broadcastSound(soundID: Int, pos: BlockPos, data: Int) {}
override fun playEvent(player: EntityPlayer?, type: Int, blockPosIn: BlockPos, data: Int) {}
override fun onEntityRemoved(entityIn: Entity) {}
override fun notifyLightSet(pos: BlockPos) {}
override fun spawnParticle(particleID: Int, ignoreRange: Boolean, xCoord: Double, yCoord: Double, zCoord: Double, xSpeed: Double, ySpeed: Double, zSpeed: Double, vararg parameters: Int) {}
override fun spawnParticle(id: Int, ignoreRange: Boolean, minimiseParticleLevel: Boolean, x: Double, y: Double, z: Double, xSpeed: Double, ySpeed: Double, zSpeed: Double, vararg parameters: Int) {}
override fun playRecord(soundIn: SoundEvent, pos: BlockPos) {}
override fun sendBlockBreakProgress(breakerId: Int, pos: BlockPos, progress: Int) {}
override fun markBlockRangeForRenderUpdate(x1: Int, y1: Int, z1: Int, x2: Int, y2: Int, z2: Int) {}
override fun addParticle(p0: IParticleData, p1: Boolean, p2: Double, p3: Double, p4: Double, p5: Double, p6: Double, p7: Double) {}
override fun addParticle(p0: IParticleData, p1: Boolean, p2: Boolean, p3: Double, p4: Double, p5: Double, p6: Double, p7: Double, p8: Double) {}
}
*/

View File

@@ -2,10 +2,8 @@ package mods.betterfoliage.client.config
import mods.betterfoliage.BetterFoliage
import mods.betterfoliage.client.integration.ShadersModIntegration
import mods.octarinecore.client.resource.LoadModelDataEvent
import mods.octarinecore.common.config.*
import net.minecraft.util.ResourceLocation
import net.minecraftforge.eventbus.api.SubscribeEvent
private fun featureEnable() = boolean(true).lang("enabled")
@@ -165,12 +163,4 @@ object BlockConfig {
init { BetterFoliage.modBus.register(this) }
private fun blocks(cfgName: String) = ConfigurableBlockMatcher(BetterFoliage.logDetail, ResourceLocation(BetterFoliage.MOD_ID, cfgName)).apply { list.add(this) }
private fun models(cfgName: String) = ModelTextureListConfiguration(BetterFoliage.logDetail, ResourceLocation(BetterFoliage.MOD_ID, cfgName)).apply { list.add(this) }
@SubscribeEvent
fun handleLoadModelData(event: LoadModelDataEvent) {
list.forEach { when(it) {
is ConfigurableBlockMatcher -> it.readDefaults()
is ModelTextureListConfiguration -> it.readDefaults()
} }
}
}

View File

@@ -1,153 +1,133 @@
package mods.betterfoliage.client.integration
import mods.betterfoliage.BetterFoliage
import mods.betterfoliage.client.Client
import mods.betterfoliage.client.config.BlockConfig
import mods.betterfoliage.client.render.LogRegistry
import mods.betterfoliage.client.render.StandardLogRegistry
import mods.betterfoliage.client.render.AsyncLogDiscovery
import mods.betterfoliage.client.render.column.ColumnTextureInfo
import mods.betterfoliage.client.render.column.SimpleColumnInfo
import mods.betterfoliage.client.resource.Identifier
import mods.betterfoliage.client.texture.LeafInfo
import mods.betterfoliage.client.texture.LeafRegistry
import mods.betterfoliage.client.texture.StandardLeafKey
import mods.betterfoliage.loader.Refs
import mods.octarinecore.client.resource.ModelRenderKey
import mods.octarinecore.client.resource.ModelRenderRegistry
import mods.octarinecore.client.resource.ModelRenderRegistryBase
import mods.octarinecore.getTileEntitySafe
import mods.octarinecore.metaprog.ClassRef
import mods.octarinecore.metaprog.FieldRef
import mods.octarinecore.metaprog.MethodRef
import mods.octarinecore.metaprog.allAvailable
import mods.betterfoliage.client.texture.defaultRegisterLeaf
import mods.octarinecore.HasLogger
import mods.octarinecore.Map
import mods.octarinecore.ResourceLocation
import mods.octarinecore.String
import mods.octarinecore.client.resource.*
import mods.octarinecore.metaprog.*
import mods.octarinecore.metaprog.ClassRef.Companion.boolean
import net.minecraft.block.BlockState
import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.model.IUnbakedModel
import net.minecraft.client.renderer.model.ModelResourceLocation
import net.minecraft.util.ResourceLocation
import net.minecraft.client.renderer.model.ModelBakery
import net.minecraft.util.math.BlockPos
import net.minecraft.world.IBlockReader
import net.minecraft.world.IWorldReader
import net.minecraftforge.client.event.TextureStitchEvent
import net.minecraftforge.client.model.IModel
import net.minecraftforge.eventbus.api.EventPriority
import net.minecraftforge.eventbus.api.SubscribeEvent
import net.minecraftforge.fml.ModList
import org.apache.logging.log4j.Level
import kotlin.collections.Map
import java.util.concurrent.CompletableFuture
import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.collections.emptyMap
import kotlin.collections.find
import kotlin.collections.forEach
import kotlin.collections.get
import kotlin.collections.listOf
import kotlin.collections.mapValues
import kotlin.collections.mutableMapOf
import kotlin.collections.set
val TextureLeaves = ClassRef<Any>("forestry.arboriculture.models.TextureLeaves")
val TextureLeaves_leafTextures = FieldRef(TextureLeaves, "leafTextures", Map)
val TextureLeaves_plain = FieldRef(TextureLeaves, "plain", ResourceLocation)
val TextureLeaves_fancy = FieldRef(TextureLeaves, "fancy", ResourceLocation)
val TextureLeaves_pollinatedPlain = FieldRef(TextureLeaves, "pollinatedPlain", ResourceLocation)
val TextureLeaves_pollinatedFancy = FieldRef(TextureLeaves, "pollinatedFancy", ResourceLocation)
val TileLeaves = ClassRef<Any>("forestry.arboriculture.tiles.TileLeaves")
val TileLeaves_getLeaveSprite = MethodRef(TileLeaves, "getLeaveSprite", ResourceLocation, boolean)
val PropertyWoodType = ClassRef<Any>("forestry.arboriculture.blocks.PropertyWoodType")
val IWoodType = ClassRef<Any>("forestry.api.arboriculture.IWoodType")
val IWoodType_barkTex = MethodRef(IWoodType, "getBarkTexture", String)
val IWoodType_heartTex = MethodRef(IWoodType, "getHeartTexture", String)
val PropertyTreeType = ClassRef<Any>("forestry.arboriculture.blocks.PropertyTreeType")
val IAlleleTreeSpecies = ClassRef<Any>("forestry.api.arboriculture.IAlleleTreeSpecies")
val ILeafSpriteProvider = ClassRef<Any>("forestry.api.arboriculture.ILeafSpriteProvider")
val TreeDefinition = ClassRef<Any>("forestry.arboriculture.genetics.TreeDefinition")
val IAlleleTreeSpecies_getLeafSpriteProvider = MethodRef(IAlleleTreeSpecies, "getLeafSpriteProvider", ILeafSpriteProvider)
val TreeDefinition_species = FieldRef(TreeDefinition, "species", IAlleleTreeSpecies)
val ILeafSpriteProvider_getSprite = MethodRef(ILeafSpriteProvider, "getSprite", ResourceLocation, boolean, boolean)
object ForestryIntegration {
val TextureLeaves = ClassRef("forestry.arboriculture.models.TextureLeaves")
val TeLleafTextures = FieldRef(TextureLeaves, "leafTextures", Refs.Map)
val TeLplain = FieldRef(TextureLeaves, "plain", Refs.ResourceLocation)
val TeLfancy = FieldRef(TextureLeaves, "fancy", Refs.ResourceLocation)
val TeLpollplain = FieldRef(TextureLeaves, "pollinatedPlain", Refs.ResourceLocation)
val TeLpollfancy = FieldRef(TextureLeaves, "pollinatedFancy", Refs.ResourceLocation)
val TileLeaves = ClassRef("forestry.arboriculture.tiles.TileLeaves")
val TiLgetLeaveSprite = MethodRef(TileLeaves, "getLeaveSprite", Refs.ResourceLocation, ClassRef.boolean)
val PropertyWoodType = ClassRef("forestry.arboriculture.blocks.PropertyWoodType")
val IWoodType = ClassRef("forestry.api.arboriculture.IWoodType")
val barkTex = MethodRef(IWoodType, "getBarkTexture", Refs.String)
val heartTex = MethodRef(IWoodType, "getHeartTexture", Refs.String)
val PropertyTreeType = ClassRef("forestry.arboriculture.blocks.PropertyTreeType")
val TreeDefinition = ClassRef("forestry.arboriculture.genetics.TreeDefinition")
val IAlleleTreeSpecies = ClassRef("forestry.api.arboriculture.IAlleleTreeSpecies")
val ILeafSpriteProvider = ClassRef("forestry.api.arboriculture.ILeafSpriteProvider")
val TdSpecies = FieldRef(TreeDefinition, "species", IAlleleTreeSpecies)
val getLeafSpriteProvider = MethodRef(IAlleleTreeSpecies, "getLeafSpriteProvider", ILeafSpriteProvider)
val getSprite = MethodRef(ILeafSpriteProvider, "getSprite", Refs.ResourceLocation, ClassRef.boolean, ClassRef.boolean)
init {
if (ModList.get().isLoaded("forestry") && allAvailable(TiLgetLeaveSprite, getLeafSpriteProvider, getSprite)) {
Client.log(Level.INFO, "Forestry support initialized")
LeafRegistry.addRegistry(ForestryLeafRegistry)
LogRegistry.addRegistry(ForestryLogRegistry)
if (ModList.get().isLoaded("forestry") && allAvailable(TileLeaves_getLeaveSprite, IAlleleTreeSpecies_getLeafSpriteProvider, ILeafSpriteProvider_getSprite)) {
}
}
}
object ForestryLeafRegistry : ModelRenderRegistry<LeafInfo> {
val logger = BetterFoliage.logDetail
val textureToKey = mutableMapOf<ResourceLocation, ModelRenderKey<LeafInfo>>()
var textureToValue = emptyMap<ResourceLocation, LeafInfo>()
object ForestryLeafDiscovery : HasLogger, AsyncSpriteProvider, ModelRenderRegistry<LeafInfo> {
override val logger = BetterFoliage.logDetail
var idToValue = emptyMap<Identifier, LeafInfo>()
override fun get(state: BlockState, world: IBlockReader, pos: BlockPos): LeafInfo? {
// check variant property (used in decorative leaves)
state.values.entries.find {
ForestryIntegration.PropertyTreeType.isInstance(it.key) && ForestryIntegration.TreeDefinition.isInstance(it.value)
PropertyTreeType.isInstance(it.key) && TreeDefinition.isInstance(it.value)
} ?.let {
val species = ForestryIntegration.TdSpecies.get(it.value)
val spriteProvider = ForestryIntegration.getLeafSpriteProvider.invoke(species!!)
val textureLoc = ForestryIntegration.getSprite.invoke(spriteProvider!!, false, Minecraft.isFancyGraphicsEnabled())
return textureToValue[textureLoc]
val species = it.value[TreeDefinition_species]
val spriteProvider = species[IAlleleTreeSpecies_getLeafSpriteProvider]()
val textureLoc = spriteProvider[ILeafSpriteProvider_getSprite](false, Minecraft.isFancyGraphicsEnabled())
return idToValue[textureLoc]
}
// extract leaf texture information from TileEntity
val tile = world.getTileEntity(pos) ?: return null
if (!ForestryIntegration.TileLeaves.isInstance(tile)) return null
val textureLoc = ForestryIntegration.TiLgetLeaveSprite.invoke(tile, Minecraft.isFancyGraphicsEnabled()) ?: return null
return textureToValue[textureLoc]
if (!TileLeaves.isInstance(tile)) return null
val textureLoc = tile[TileLeaves_getLeaveSprite](Minecraft.isFancyGraphicsEnabled())
return idToValue[textureLoc]
}
@SubscribeEvent
fun handlePreStitch(event: TextureStitchEvent.Pre) {
textureToValue = emptyMap()
override fun setup(bakeryFuture: CompletableFuture<ModelBakery>, atlasFuture: AtlasFuture): StitchPhases {
val futures = mutableMapOf<Identifier, CompletableFuture<LeafInfo>>()
val allLeaves = ForestryIntegration.TeLleafTextures.getStatic() as Map<*, *>
allLeaves.entries.forEach {
logger.log(Level.DEBUG, "ForestryLeavesSupport: base leaf type ${it.key.toString()}")
listOf(
ForestryIntegration.TeLplain.get(it.value) as ResourceLocation,
ForestryIntegration.TeLfancy.get(it.value) as ResourceLocation,
ForestryIntegration.TeLpollplain.get(it.value) as ResourceLocation,
ForestryIntegration.TeLpollfancy.get(it.value) as ResourceLocation
).forEach { textureLocation ->
val key = StandardLeafKey(logger, textureLocation.toString()).apply { onPreStitch(event) }
textureToKey[textureLocation] = key
return StitchPhases(
discovery = bakeryFuture.thenRunAsync {
val allLeaves = TextureLeaves_leafTextures.getStatic()
allLeaves.entries.forEach { (type, leaves) ->
log("base leaf type $type")
leaves!!
listOf(
leaves[TextureLeaves_plain], leaves[TextureLeaves_pollinatedPlain],
leaves[TextureLeaves_fancy], leaves[TextureLeaves_pollinatedFancy]
).forEach { textureLocation ->
futures[textureLocation] = defaultRegisterLeaf(textureLocation, atlasFuture)
}
}
},
cleanup = atlasFuture.sheet.thenRunAsync {
idToValue = futures.mapValues { it.value.get() }
}
}
}
@SubscribeEvent(priority = EventPriority.LOW)
fun handlePostStitch(event: TextureStitchEvent.Post) {
textureToValue = textureToKey.mapValues { (_, key) -> key.resolveSprites(event.map) }
textureToKey.clear()
)
}
}
object ForestryLogRegistry : ModelRenderRegistryBase<ColumnTextureInfo>() {
object ForestryLogDiscovery : ModelDiscovery<ColumnTextureInfo>() {
override val logger = BetterFoliage.logDetail
override fun processModel(state: BlockState, modelLoc: ModelResourceLocation, models: List<Pair<IUnbakedModel, ResourceLocation>>): ModelRenderKey<ColumnTextureInfo>? {
override fun processModel(ctx: ModelDiscoveryContext, atlas: AtlasFuture): CompletableFuture<ColumnTextureInfo>? {
// respect class list to avoid triggering on fences, stairs, etc.
if (!BlockConfig.logBlocks.matchesClass(state.block)) return null
if (!BlockConfig.logBlocks.matchesClass(ctx.state.block)) return null
// find wood type property
val woodType = state.values.entries.find {
ForestryIntegration.PropertyWoodType.isInstance(it.key) && ForestryIntegration.IWoodType.isInstance(it.value)
} ?: return null
val woodType = ctx.state.values.entries.find {
PropertyWoodType.isInstance(it.key) && IWoodType.isInstance(it.value)
}
if (woodType != null) {
logger.log(Level.DEBUG, "ForestryLogRegistry: block state ${ctx.state}")
logger.log(Level.DEBUG, "ForestryLogRegistry: variant ${woodType.value}")
logger.log(Level.DEBUG, "ForestryLogRegistry: block state $state")
logger.log(Level.DEBUG, "ForestryLogRegistry: variant ${woodType.value}")
// get texture names for wood type
val bark = woodType.value[IWoodType_barkTex]()
val heart = woodType.value[IWoodType_heartTex]()
logger.log(Level.DEBUG, "ForestryLogSupport: textures [heart=$heart, bark=$bark]")
// get texture names for wood type
val bark = ForestryIntegration.barkTex.invoke(woodType.value) as String?
val heart = ForestryIntegration.heartTex.invoke(woodType.value) as String?
logger.log(Level.DEBUG, "ForestryLogSupport: textures [heart=$heart, bark=$bark]")
if (bark != null && heart != null) return SimpleColumnInfo.Key(logger, StandardLogRegistry.getAxis(state), listOf(heart, heart, bark))
val heartSprite = atlas.sprite(heart)
val barkSprite = atlas.sprite(bark)
return atlas.afterStitch {
SimpleColumnInfo(AsyncLogDiscovery.getAxis(ctx.state), heartSprite.get(), heartSprite.get(), listOf(barkSprite.get()))
}
}
return null
}
}

View File

@@ -1,10 +1,8 @@
package mods.betterfoliage.client.integration
import mods.betterfoliage.client.Client
import mods.betterfoliage.loader.Refs
import mods.octarinecore.ThreadLocalDelegate
import mods.octarinecore.*
import mods.octarinecore.client.render.CombinedContext
import mods.octarinecore.common.Int3
import mods.octarinecore.metaprog.allAvailable
import mods.octarinecore.metaprog.reflectField
import net.minecraft.block.BlockState
@@ -13,7 +11,6 @@ import net.minecraft.client.renderer.model.BakedQuad
import net.minecraft.client.renderer.vertex.DefaultVertexFormats
import net.minecraft.util.Direction.UP
import net.minecraft.util.math.BlockPos
import net.minecraft.world.IBlockReader
import org.apache.logging.log4j.Level
/**
@@ -22,9 +19,7 @@ import org.apache.logging.log4j.Level
@Suppress("UNCHECKED_CAST")
object OptifineCustomColors {
val isColorAvailable = allAvailable(
Refs.CustomColors, Refs.getColorMultiplier
)
val isColorAvailable = allAvailable(CustomColors, CustomColors.getColorMultiplier)
init {
Client.log(Level.INFO, "Optifine custom color support is ${if (isColorAvailable) "enabled" else "disabled" }")
@@ -36,21 +31,19 @@ object OptifineCustomColors {
fun getBlockColor(ctx: CombinedContext): Int {
val ofColor = if (isColorAvailable && Minecraft.getInstance().gameSettings.reflectField<Boolean>("ofCustomColors") == true) {
renderEnv.reset(ctx.state, ctx.pos)
Refs.getColorMultiplier.invokeStatic(fakeQuad, ctx.state, ctx.world, ctx.pos, renderEnv.wrapped) as? Int
CustomColors.getColorMultiplier.invokeStatic(fakeQuad, ctx.state, ctx.world, ctx.pos, renderEnv.wrapped) as? Int
} else null
return if (ofColor == null || ofColor == -1) ctx.lightingCtx.color else ofColor
}
}
class OptifineRenderEnv {
val wrapped: Any = Refs.RenderEnv.element!!.getDeclaredConstructor(
Refs.BlockState.element, Refs.BlockPos.element
).let {
val wrapped: Any = RenderEnv.element!!.getDeclaredConstructor(BlockState.element, BlockPos.element).let {
it.isAccessible = true
it.newInstance(null, null)
}
fun reset(state: BlockState, pos: BlockPos) {
Refs.RenderEnv_reset.invoke(wrapped, state, pos)
RenderEnv.reset.invoke(wrapped, state, pos)
}
}

View File

@@ -8,15 +8,11 @@ import mods.betterfoliage.client.render.column.SimpleColumnInfo
import mods.octarinecore.client.render.CombinedContext
import mods.octarinecore.client.render.Quad
import mods.octarinecore.client.render.lighting.QuadIconResolver
import mods.octarinecore.client.render.lighting.LightingCtx
import mods.octarinecore.client.resource.*
import mods.octarinecore.common.rotate
import mods.octarinecore.metaprog.ClassRef
import mods.octarinecore.metaprog.allAvailable
import net.minecraft.block.BlockState
import net.minecraft.client.renderer.model.BlockModel
import net.minecraft.client.renderer.model.IUnbakedModel
import net.minecraft.client.renderer.model.ModelResourceLocation
import net.minecraft.client.renderer.texture.AtlasTexture
import net.minecraft.client.renderer.texture.TextureAtlasSprite
import net.minecraft.util.Direction
@@ -24,29 +20,31 @@ import net.minecraft.util.Direction.*
import net.minecraft.util.ResourceLocation
import net.minecraftforge.fml.ModList
import org.apache.logging.log4j.Level
import org.apache.logging.log4j.Level.DEBUG
import org.apache.logging.log4j.Logger
import java.util.concurrent.CompletableFuture
object IC2RubberIntegration {
val BlockRubWood = ClassRef("ic2.core.block.BlockRubWood")
val BlockRubWood = ClassRef<Any>("ic2.core.block.BlockRubWood")
init {
if (ModList.get().isLoaded("ic2") && allAvailable(BlockRubWood)) {
Client.log(Level.INFO, "IC2 rubber support initialized")
LogRegistry.addRegistry(IC2LogSupport)
LogRegistry.registries.add(IC2LogDiscovery)
AsyncSpriteProviderManager.providers.add(IC2LogDiscovery)
}
}
}
object TechRebornRubberIntegration {
val BlockRubberLog = ClassRef("techreborn.blocks.BlockRubberLog")
val BlockRubberLog = ClassRef<Any>("techreborn.blocks.BlockRubberLog")
init {
if (ModList.get().isLoaded("techreborn") && allAvailable(BlockRubberLog)) {
Client.log(Level.INFO, "TechReborn rubber support initialized")
LogRegistry.addRegistry(TechRebornLogSupport)
LogRegistry.registries.add(TechRebornLogDiscovery)
AsyncSpriteProviderManager.providers.add(TechRebornLogDiscovery)
}
}
}
@@ -67,27 +65,16 @@ class RubberLogInfo(
this.sideTextures[sideIdx]
}
}
class Key(override val logger: Logger, val axis: Axis?, val spotDir: Direction, val textures: List<String>): ModelRenderKey<ColumnTextureInfo> {
override fun resolveSprites(atlas: AtlasTexture) = RubberLogInfo(
axis,
spotDir,
atlas[textures[0]] ?: missingSprite,
atlas[textures[1]] ?: missingSprite,
atlas[textures[2]] ?: missingSprite,
textures.drop(3).map { atlas[it] ?: missingSprite }
)
}
}
object IC2LogSupport : ModelRenderRegistryBase<ColumnTextureInfo>() {
object IC2LogDiscovery : ModelDiscovery<ColumnTextureInfo>() {
override val logger = BetterFoliage.logDetail
override fun processModel(state: BlockState, modelLoc: ModelResourceLocation, models: List<Pair<IUnbakedModel, ResourceLocation>>): ModelRenderKey<ColumnTextureInfo>? {
override fun processModel(ctx: ModelDiscoveryContext, atlas: AtlasFuture): CompletableFuture<ColumnTextureInfo>? {
// check for proper block class, existence of ModelBlock, and "state" blockstate property
if (!IC2RubberIntegration.BlockRubWood.isInstance(state.block)) return null
val blockLoc = models.firstOrNull() as Pair<BlockModel, ResourceLocation> ?: return null
val type = state.values.entries.find { it.key.getName() == "state" }?.value?.toString() ?: return null
if (!IC2RubberIntegration.BlockRubWood.isInstance(ctx.state.block)) return null
val blockLoc = ctx.models.firstOrNull() as Pair<BlockModel, ResourceLocation> ?: return null
val type = ctx.state.values.entries.find { it.key.getName() == "state" }?.value?.toString() ?: return null
// logs with no rubber spot
if (blockLoc.derivesFrom(ResourceLocation("block/cube_column"))) {
@@ -97,11 +84,15 @@ object IC2LogSupport : ModelRenderRegistryBase<ColumnTextureInfo>() {
"plain_z" -> Axis.Z
else -> null
}
val textureNames = listOf("end", "end", "side").map { blockLoc.first.resolveTextureName(it) }
val textureNames = listOf("end", "side").map { blockLoc.first.resolveTextureName(it) }
if (textureNames.any { it == "missingno" }) return null
logger.log(DEBUG, "IC2LogSupport: block state ${state.toString()}")
logger.log(DEBUG, "IC2LogSupport: axis=$axis, end=${textureNames[0]}, side=${textureNames[2]}")
return SimpleColumnInfo.Key(logger, axis, textureNames)
log("IC2LogSupport: block state ${ctx.state.toString()}")
log("IC2LogSupport: axis=$axis, end=${textureNames[0]}, side=${textureNames[1]}")
val endSprite = atlas.sprite(textureNames[0])
val sideSprite = atlas.sprite(textureNames[1])
return atlas.afterStitch {
SimpleColumnInfo(axis, endSprite.get(), endSprite.get(), listOf(sideSprite.get()))
}
}
// logs with rubber spot
@@ -114,32 +105,53 @@ object IC2LogSupport : ModelRenderRegistryBase<ColumnTextureInfo>() {
}
val textureNames = listOf("up", "down", "north", "south").map { blockLoc.first.resolveTextureName(it) }
if (textureNames.any { it == "missingno" }) return null
logger.log(DEBUG, "IC2LogSupport: block state ${state.toString()}")
logger.log(DEBUG, "IC2LogSupport: spotDir=$spotDir, up=${textureNames[0]}, down=${textureNames[1]}, side=${textureNames[2]}, spot=${textureNames[3]}")
return if (spotDir != null) RubberLogInfo.Key(logger, Axis.Y, spotDir, textureNames) else SimpleColumnInfo.Key(logger, Axis.Y, textureNames)
log("IC2LogSupport: block state ${ctx.state.toString()}")
log("IC2LogSupport: spotDir=$spotDir, up=${textureNames[0]}, down=${textureNames[1]}, side=${textureNames[2]}, spot=${textureNames[3]}")
val upSprite = atlas.sprite(textureNames[0])
val downSprite = atlas.sprite(textureNames[1])
val sideSprite = atlas.sprite(textureNames[2])
val spotSprite = atlas.sprite(textureNames[3])
return if (spotDir != null) atlas.afterStitch {
RubberLogInfo(Axis.Y, spotDir, upSprite.get(), downSprite.get(), spotSprite.get(), listOf(sideSprite.get()))
} else atlas.afterStitch {
SimpleColumnInfo(Axis.Y, upSprite.get(), downSprite.get(), listOf(sideSprite.get()))
}
}
}
object TechRebornLogSupport : ModelRenderRegistryBase<ColumnTextureInfo>() {
object TechRebornLogDiscovery : ModelDiscovery<ColumnTextureInfo>() {
override val logger = BetterFoliage.logDetail
override fun processModel(state: BlockState, modelLoc: ModelResourceLocation, models: List<Pair<IUnbakedModel, ResourceLocation>>): ModelRenderKey<ColumnTextureInfo>? {
override fun processModel(ctx: ModelDiscoveryContext, atlas: AtlasFuture): CompletableFuture<ColumnTextureInfo>? {
// check for proper block class, existence of ModelBlock
if (!TechRebornRubberIntegration.BlockRubberLog.isInstance(state.block)) return null
val blockLoc = models.firstOrNull() as Pair<BlockModel, ResourceLocation> ?: return null
if (!TechRebornRubberIntegration.BlockRubberLog.isInstance(ctx.state.block)) return null
val blockLoc = ctx.models.map { it as? Pair<BlockModel, ResourceLocation> }.firstOrNull() ?: return null
val hasSap = state.values.entries.find { it.key.getName() == "hassap" }?.value as? Boolean ?: return null
val sapSide = state.values.entries.find { it.key.getName() == "sapside" }?.value as? Direction ?: return null
val hasSap = ctx.state.values.entries.find { it.key.getName() == "hassap" }?.value as? Boolean ?: return null
val sapSide = ctx.state.values.entries.find { it.key.getName() == "sapside" }?.value as? Direction ?: return null
logger.log(DEBUG, "$logName: block state $state")
log("$logName: block state ${ctx.state}")
if (hasSap) {
val textureNames = listOf("end", "end", "sapside", "side").map { blockLoc.first.resolveTextureName(it) }
logger.log(DEBUG, "$logName: spotDir=$sapSide, end=${textureNames[0]}, side=${textureNames[2]}, spot=${textureNames[3]}")
if (textureNames.all { it != "missingno" }) return RubberLogInfo.Key(logger, Axis.Y, sapSide, textureNames)
val textureNames = listOf("end", "side", "sapside").map { blockLoc.first.resolveTextureName(it) }
log("$logName: spotDir=$sapSide, end=${textureNames[0]}, side=${textureNames[2]}, spot=${textureNames[3]}")
if (textureNames.all { it != "missingno" }) {
val endSprite = atlas.sprite(textureNames[0])
val sideSprite = atlas.sprite(textureNames[1])
val sapSprite = atlas.sprite(textureNames[2])
return atlas.afterStitch {
RubberLogInfo(Axis.Y, sapSide, endSprite.get(), endSprite.get(), sapSprite.get(), listOf(sideSprite.get()))
}
}
} else {
val textureNames = listOf("end", "end", "side").map { blockLoc.first.resolveTextureName(it) }
logger.log(DEBUG, "$logName: end=${textureNames[0]}, side=${textureNames[2]}")
if (textureNames.all { it != "missingno" })return SimpleColumnInfo.Key(logger, Axis.Y, textureNames)
val textureNames = listOf("end", "side").map { blockLoc.first.resolveTextureName(it) }
log("$logName: end=${textureNames[0]}, side=${textureNames[1]}")
if (textureNames.all { it != "missingno" }) {
val endSprite = atlas.sprite(textureNames[0])
val sideSprite = atlas.sprite(textureNames[1])
return atlas.afterStitch {
SimpleColumnInfo(Axis.Y, endSprite.get(), endSprite.get(), listOf(sideSprite.get()))
}
}
}
return null
}

View File

@@ -3,9 +3,10 @@ package mods.betterfoliage.client.integration
import mods.betterfoliage.client.Client
import mods.betterfoliage.client.config.BlockConfig
import mods.betterfoliage.client.config.Config
import mods.betterfoliage.loader.Refs
import mods.octarinecore.SVertexBuilder
import mods.octarinecore.client.render.CombinedContext
import mods.octarinecore.metaprog.allAvailable
import mods.octarinecore.metaprog.get
import net.minecraft.block.BlockRenderType
import net.minecraft.block.BlockRenderType.MODEL
import net.minecraft.block.BlockState
@@ -20,7 +21,7 @@ import org.apache.logging.log4j.Level.INFO
*/
object ShadersModIntegration {
@JvmStatic val isAvailable = allAvailable(Refs.sVertexBuilder, Refs.pushEntity_state, Refs.pushEntity_num, Refs.popEntity)
@JvmStatic val isAvailable = allAvailable(SVertexBuilder, SVertexBuilder.pushState, SVertexBuilder.pushNum, SVertexBuilder.pop)
val grassDefaultBlockId = 31L
val leavesDefaultBlockId = 18L
@@ -42,10 +43,10 @@ object ShadersModIntegration {
/** Quads rendered inside this block will use the given block entity data in shader programs. */
inline fun renderAs(blockId: Long, renderType: BlockRenderType, renderer: BufferBuilder, enabled: Boolean = true, func: ()->Unit) {
if ((isAvailable && enabled)) {
val vertexBuilder = Refs.sVertexBuilder.get(renderer)!!
Refs.pushEntity_num.invoke(vertexBuilder, blockId)
val vertexBuilder = renderer[mods.octarinecore.BufferBuilder.sVertexBuilder]!!
SVertexBuilder.pushNum.invoke(vertexBuilder, blockId)
func()
Refs.popEntity.invoke(vertexBuilder)
SVertexBuilder.pop.invoke(vertexBuilder)
} else {
func()
}

View File

@@ -5,30 +5,39 @@ import mods.betterfoliage.client.Client
import mods.betterfoliage.client.config.Config
import mods.betterfoliage.client.render.column.ColumnTextureInfo
import mods.betterfoliage.client.render.column.SimpleColumnInfo
import mods.betterfoliage.client.resource.Identifier
import mods.octarinecore.client.render.*
import mods.octarinecore.client.render.lighting.*
import mods.octarinecore.client.resource.ModelRenderRegistryConfigurable
import mods.octarinecore.common.Int3
import mods.octarinecore.client.resource.*
import mods.octarinecore.common.Rotation
import mods.octarinecore.common.config.ModelTextureList
import mods.octarinecore.common.config.SimpleBlockMatcher
import net.minecraft.block.BlockState
import net.minecraft.block.CactusBlock
import net.minecraft.client.renderer.BlockRendererDispatcher
import net.minecraft.client.renderer.BufferBuilder
import net.minecraft.util.BlockRenderLayer
import net.minecraft.util.Direction.*
import net.minecraft.util.ResourceLocation
import net.minecraftforge.client.model.data.IModelData
import org.apache.logging.log4j.Level.DEBUG
import java.util.*
import java.util.concurrent.CompletableFuture
object StandardCactusRegistry : ModelRenderRegistryConfigurable<ColumnTextureInfo>() {
object AsyncCactusDiscovery : ConfigurableModelDiscovery<ColumnTextureInfo>() {
override val logger = BetterFoliage.logDetail
override val matchClasses = SimpleBlockMatcher(CactusBlock::class.java)
override val modelTextures = listOf(ModelTextureList("block/cactus", "top", "bottom", "side"))
override fun processModel(state: BlockState, textures: List<String>) = SimpleColumnInfo.Key(logger, Axis.Y, textures)
init { BetterFoliage.modBus.register(this) }
override fun processModel(state: BlockState, textures: List<String>, atlas: AtlasFuture): CompletableFuture<ColumnTextureInfo>? {
val sprites = textures.map { atlas.sprite(Identifier(it)) }
return atlas.afterStitch {
SimpleColumnInfo(
Axis.Y,
sprites[0].get(),
sprites[1].get(),
sprites.drop(2).map { it.get() }
)
}
}
fun init() {
AsyncSpriteProviderManager.providers.add(this)
}
}
class RenderCactus : RenderDecorator(BetterFoliage.MOD_ID, BetterFoliage.modBus) {
@@ -73,12 +82,12 @@ class RenderCactus : RenderDecorator(BetterFoliage.MOD_ID, BetterFoliage.modBus)
override fun isEligible(ctx: CombinedContext): Boolean =
Config.enabled && Config.cactus.enabled &&
StandardCactusRegistry[ctx] != null
AsyncCactusDiscovery[ctx] != null
override val onlyOnCutout get() = true
override fun render(ctx: CombinedContext) {
val icons = StandardCactusRegistry[ctx]!!
val icons = AsyncCactusDiscovery[ctx]!!
ctx.render(
modelStem.model,

View File

@@ -8,18 +8,17 @@ import mods.betterfoliage.client.render.column.AbstractRenderColumn
import mods.betterfoliage.client.render.column.ColumnRenderLayer
import mods.betterfoliage.client.render.column.ColumnTextureInfo
import mods.betterfoliage.client.render.column.SimpleColumnInfo
import mods.octarinecore.client.render.BlockCtx
import mods.betterfoliage.client.resource.Identifier
import mods.octarinecore.client.render.CombinedContext
import mods.octarinecore.client.resource.ModelRenderRegistry
import mods.octarinecore.client.resource.ModelRenderRegistryConfigurable
import mods.octarinecore.client.resource.ModelRenderRegistryRoot
import mods.octarinecore.client.resource.*
import mods.octarinecore.common.config.ConfigurableBlockMatcher
import mods.octarinecore.common.config.ModelTextureList
import mods.octarinecore.tryDefault
import net.minecraft.block.BlockState
import net.minecraft.block.LogBlock
import net.minecraft.util.Direction.Axis
import net.minecraft.world.IEnviromentBlockReader
import org.apache.logging.log4j.Level
import java.util.concurrent.CompletableFuture
class RenderLog : AbstractRenderColumn(BetterFoliage.MOD_ID, BetterFoliage.modBus) {
@@ -49,12 +48,24 @@ class RoundLogOverlayLayer : ColumnRenderLayer() {
object LogRegistry : ModelRenderRegistryRoot<ColumnTextureInfo>()
object StandardLogRegistry : ModelRenderRegistryConfigurable<ColumnTextureInfo>() {
object AsyncLogDiscovery : ConfigurableModelDiscovery<ColumnTextureInfo>() {
override val logger = BetterFoliage.logDetail
override val matchClasses: ConfigurableBlockMatcher get() = BlockConfig.logBlocks
override val modelTextures: List<ModelTextureList> get() = BlockConfig.logModels.modelList
override fun processModel(state: BlockState, textures: List<String>) = SimpleColumnInfo.Key(logger, getAxis(state), textures)
init { BetterFoliage.modBus.register(this) }
override fun processModel(state: BlockState, textures: List<String>, atlas: AtlasFuture): CompletableFuture<ColumnTextureInfo> {
val axis = getAxis(state)
logger.log(Level.DEBUG, "$logName: axis $axis")
val spriteList = textures.map { atlas.sprite(Identifier(it)) }
return atlas.afterStitch {
SimpleColumnInfo(
axis,
spriteList[0].get(),
spriteList[1].get(),
spriteList.drop(2).map { it.get() }
)
}
}
fun getAxis(state: BlockState): Axis? {
val axis = tryDefault(null) { state.get(LogBlock.AXIS).toString() } ?:
@@ -66,4 +77,9 @@ object StandardLogRegistry : ModelRenderRegistryConfigurable<ColumnTextureInfo>(
else -> null
}
}
fun init() {
LogRegistry.registries.add(this)
AsyncSpriteProviderManager.providers.add(this)
}
}

View File

@@ -1,14 +1,9 @@
package mods.betterfoliage.client.render.column
import mods.octarinecore.client.render.lighting.QuadIconResolver
import mods.octarinecore.client.resource.ModelRenderKey
import mods.octarinecore.client.resource.get
import mods.octarinecore.client.resource.missingSprite
import mods.octarinecore.common.rotate
import net.minecraft.client.renderer.texture.AtlasTexture
import net.minecraft.client.renderer.texture.TextureAtlasSprite
import net.minecraft.util.Direction.*
import org.apache.logging.log4j.Logger
interface ColumnTextureInfo {
val axis: Axis?
@@ -34,13 +29,4 @@ open class SimpleColumnInfo(
val sideIdx = if (sideTextures.size > 1) (ctx.semiRandom(1) + dirToIdx[worldFace.ordinal]) % sideTextures.size else 0
sideTextures[sideIdx]
}
class Key(override val logger: Logger, val axis: Axis?, val textures: List<String>) : ModelRenderKey<ColumnTextureInfo> {
override fun resolveSprites(atlas: AtlasTexture) = SimpleColumnInfo(
axis,
atlas[textures[0]] ?: missingSprite,
atlas[textures[1]] ?: missingSprite,
textures.drop(2).map { atlas[it] ?: missingSprite }
)
}
}

View File

@@ -0,0 +1,10 @@
package mods.betterfoliage.client.resource
import net.minecraft.client.renderer.model.ModelResourceLocation
import net.minecraft.client.renderer.texture.TextureAtlasSprite
import net.minecraft.util.ResourceLocation
typealias Identifier = ResourceLocation
typealias ModelIdentifier = ModelResourceLocation
typealias Sprite = TextureAtlasSprite

View File

@@ -3,16 +3,16 @@ package mods.betterfoliage.client.texture
import mods.betterfoliage.BetterFoliage
import mods.betterfoliage.client.config.BlockConfig
import mods.betterfoliage.client.config.Config
import mods.betterfoliage.client.resource.Identifier
import mods.octarinecore.client.render.lighting.HSB
import mods.octarinecore.client.resource.*
import mods.octarinecore.common.config.ConfigurableBlockMatcher
import mods.octarinecore.common.config.ModelTextureList
import net.minecraft.block.BlockState
import net.minecraft.client.renderer.texture.AtlasTexture
import net.minecraft.client.renderer.texture.TextureAtlasSprite
import org.apache.logging.log4j.Level
import org.apache.logging.log4j.Logger
import java.lang.Math.min
import java.util.concurrent.CompletableFuture
const val defaultGrassColor = 0
@@ -32,28 +32,34 @@ class GrassInfo(
object GrassRegistry : ModelRenderRegistryRoot<GrassInfo>()
object StandardGrassRegistry : ModelRenderRegistryConfigurable<GrassInfo>() {
object AsyncGrassDiscovery : ConfigurableModelDiscovery<GrassInfo>() {
override val logger = BetterFoliage.logDetail
override val matchClasses: ConfigurableBlockMatcher get() = BlockConfig.grassBlocks
override val modelTextures: List<ModelTextureList> get() = BlockConfig.grassModels.modelList
override fun processModel(state: BlockState, textures: List<String>) = StandardGrassKey(logger, textures[0])
init { BetterFoliage.modBus.register(this) }
}
class StandardGrassKey(override val logger: Logger, val textureName: String) : ModelRenderKey<GrassInfo> {
override fun resolveSprites(atlas: AtlasTexture): GrassInfo {
val logName = "StandardGrassKey"
val texture = atlas[textureName] ?: missingSprite
logger.log(Level.DEBUG, "$logName: texture $textureName")
val hsb = HSB.fromColor(texture.averageColor ?: defaultGrassColor)
val overrideColor = if (hsb.saturation >= Config.shortGrass.saturationThreshold) {
logger.log(Level.DEBUG, "$logName: brightness ${hsb.brightness}")
logger.log(Level.DEBUG, "$logName: saturation ${hsb.saturation} >= ${Config.shortGrass.saturationThreshold}, using texture color")
hsb.copy(brightness = min(0.9f, hsb.brightness * 2.0f)).asColor
} else {
logger.log(Level.DEBUG, "$logName: saturation ${hsb.saturation} < ${Config.shortGrass.saturationThreshold}, using block color")
null
override fun processModel(state: BlockState, textures: List<String>, atlas: AtlasFuture): CompletableFuture<GrassInfo> {
val textureName = textures[0]
val spriteF = atlas.sprite(Identifier(textureName))
logger.log(Level.DEBUG, "$logName: texture $textureName")
return atlas.afterStitch {
val sprite = spriteF.get()
logger.log(Level.DEBUG, "$logName: block state $state")
logger.log(Level.DEBUG, "$logName: texture $textureName")
val hsb = HSB.fromColor(sprite.averageColor ?: defaultGrassColor)
val overrideColor = if (hsb.saturation >= Config.shortGrass.saturationThreshold) {
logger.log(Level.DEBUG, "$logName: brightness ${hsb.brightness}")
logger.log(Level.DEBUG, "$logName: saturation ${hsb.saturation} >= ${Config.shortGrass.saturationThreshold}, using texture color")
hsb.copy(brightness = min(0.9f, hsb.brightness * 2.0f)).asColor
} else {
logger.log(Level.DEBUG, "$logName: saturation ${hsb.saturation} < ${Config.shortGrass.saturationThreshold}, using block color")
null
}
GrassInfo(sprite, overrideColor)
}
return GrassInfo(texture, overrideColor)
}
fun init() {
GrassRegistry.registries.add(this)
AsyncSpriteProviderManager.providers.add(this)
}
}

View File

@@ -3,16 +3,14 @@ package mods.betterfoliage.client.texture
import mods.betterfoliage.BetterFoliage
import mods.betterfoliage.client.Client
import mods.betterfoliage.client.config.BlockConfig
import mods.betterfoliage.client.resource.Identifier
import mods.octarinecore.HasLogger
import mods.octarinecore.client.resource.*
import mods.octarinecore.common.config.ConfigurableBlockMatcher
import mods.octarinecore.common.config.ModelTextureList
import net.minecraft.block.BlockState
import net.minecraft.client.renderer.texture.TextureAtlasSprite
import net.minecraft.client.renderer.texture.AtlasTexture
import net.minecraft.util.ResourceLocation
import net.minecraftforge.client.event.TextureStitchEvent
import org.apache.logging.log4j.Level
import org.apache.logging.log4j.Logger
import java.util.concurrent.CompletableFuture
const val defaultLeafColor = 0
@@ -25,7 +23,7 @@ class LeafInfo(
val leafType: String,
/** Average color of the round leaf texture. */
val averageColor: Int = roundLeafTexture.averageColor ?: defaultLeafColor
val averageColor: Int = roundLeafTexture.averageColor
) {
/** [IconSet] of the textures to use for leaf particles emitted from this block. */
val particleTextures: IconSet get() = LeafParticleRegistry[leafType]
@@ -33,27 +31,27 @@ class LeafInfo(
object LeafRegistry : ModelRenderRegistryRoot<LeafInfo>()
object StandardLeafRegistry : ModelRenderRegistryConfigurable<LeafInfo>() {
object AsyncLeafDiscovery : ConfigurableModelDiscovery<LeafInfo>() {
override val logger = BetterFoliage.logDetail
override val matchClasses: ConfigurableBlockMatcher get() = BlockConfig.leafBlocks
override val modelTextures: List<ModelTextureList> get() = BlockConfig.leafModels.modelList
override fun processModel(state: BlockState, textures: List<String>) = StandardLeafKey(logger, textures[0])
init { BetterFoliage.modBus.register(this) }
override fun processModel(state: BlockState, textures: List<String>, atlas: AtlasFuture) = defaultRegisterLeaf(Identifier(textures[0]), atlas)
fun init() {
LeafRegistry.registries.add(this)
AsyncSpriteProviderManager.providers.add(this)
}
}
class StandardLeafKey(override val logger: Logger, val textureName: String) : ModelRenderKey<LeafInfo> {
lateinit var leafType: String
lateinit var generated: ResourceLocation
fun HasLogger.defaultRegisterLeaf(sprite: Identifier, atlas: AtlasFuture): CompletableFuture<LeafInfo> {
val leafType = LeafParticleRegistry.typeMappings.getType(sprite) ?: "default"
val generated = Client.genLeaves.register(sprite, leafType)
val roundLeaf = atlas.sprite(generated)
override fun onPreStitch(event: TextureStitchEvent.Pre) {
val logName = "StandardLeafKey"
leafType = LeafParticleRegistry.typeMappings.getType(textureName) ?: "default"
generated = Client.genLeaves.register(ResourceLocation(textureName), leafType)
event.addSprite(generated)
logger.log(Level.DEBUG, "$logName: leaf texture $textureName")
logger.log(Level.DEBUG, "$logName: particle $leafType")
log(" leaf texture $sprite")
log(" particle $leafType")
return atlas.afterStitch {
LeafInfo(roundLeaf.get(), leafType)
}
override fun resolveSprites(atlas: AtlasTexture) = LeafInfo(atlas[generated] ?: missingSprite, leafType)
}