rewrite model and texture detection
expose in mod configuration
This commit is contained in:
@@ -5,10 +5,7 @@ import mods.betterfoliage.client.gui.ConfigGuiFactory
|
||||
import mods.betterfoliage.client.integration.OptifineCTM
|
||||
import mods.betterfoliage.client.integration.ShadersModIntegration
|
||||
import mods.betterfoliage.client.render.*
|
||||
import mods.betterfoliage.client.texture.GrassGenerator
|
||||
import mods.betterfoliage.client.texture.GrassRegistry
|
||||
import mods.betterfoliage.client.texture.LeafGenerator
|
||||
import mods.betterfoliage.client.texture.LeafRegistry
|
||||
import mods.betterfoliage.client.texture.*
|
||||
import mods.octarinecore.client.KeyHandler
|
||||
import mods.octarinecore.client.resource.CenteringTextureGenerator
|
||||
import mods.octarinecore.client.resource.GeneratorPack
|
||||
@@ -63,14 +60,21 @@ object Client {
|
||||
)
|
||||
|
||||
val singletons = listOf(
|
||||
LeafRegistry,
|
||||
GrassRegistry,
|
||||
StandardLeafSupport,
|
||||
StandardGrassSupport,
|
||||
LeafWindTracker,
|
||||
RisingSoulTextures,
|
||||
ShadersModIntegration,
|
||||
OptifineCTM
|
||||
)
|
||||
|
||||
fun log(level: Level, msg: String) = BetterFoliageMod.log.log(level, msg)
|
||||
fun log(level: Level, msg: String) {
|
||||
BetterFoliageMod.log.log(level, msg)
|
||||
BetterFoliageMod.logDetail.log(level, msg)
|
||||
}
|
||||
|
||||
fun logDetail(msg: String) {
|
||||
BetterFoliageMod.logDetail.log(Level.DEBUG, msg)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,35 +15,38 @@ import net.minecraft.block.Block
|
||||
import net.minecraft.block.state.IBlockState
|
||||
import net.minecraft.client.renderer.BlockRendererDispatcher
|
||||
import net.minecraft.client.renderer.VertexBuffer
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel
|
||||
import net.minecraft.init.Blocks
|
||||
import net.minecraft.util.BlockRenderLayer
|
||||
import net.minecraft.util.BlockRenderLayer.*
|
||||
import net.minecraft.util.BlockRenderLayer.CUTOUT
|
||||
import net.minecraft.util.BlockRenderLayer.CUTOUT_MIPPED
|
||||
import net.minecraft.util.EnumFacing
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.world.IBlockAccess
|
||||
import net.minecraft.world.World
|
||||
import net.minecraftforge.client.model.IModel
|
||||
import net.minecraftforge.client.model.ModelLoader
|
||||
import net.minecraftforge.common.MinecraftForge
|
||||
import net.minecraftforge.fml.relauncher.Side
|
||||
import net.minecraftforge.fml.relauncher.SideOnly
|
||||
|
||||
fun doesSideBlockRenderingOverride(original: Boolean, blockAccess: IBlockAccess, pos: BlockPos, side: EnumFacing): Boolean {
|
||||
return original && !(Config.enabled && Config.roundLogs.enabled && Config.blocks.logs.matchesID(blockAccess.getBlockState(pos).block));
|
||||
return original && !(Config.enabled && Config.roundLogs.enabled && Config.blocks.logs.matchesClass(blockAccess.getBlockState(pos).block));
|
||||
}
|
||||
|
||||
fun isOpaqueCubeOverride(original: Boolean, state: IBlockState): Boolean {
|
||||
// caution: blocks are initialized and the method called during startup
|
||||
if (!BetterFoliageMod.isAfterPostInit) return original
|
||||
return original && !(Config.enabled && Config.roundLogs.enabled && Config.blocks.logs.matchesID(state.block))
|
||||
return original && !(Config.enabled && Config.roundLogs.enabled && Config.blocks.logs.matchesClass(state.block))
|
||||
}
|
||||
|
||||
fun getAmbientOcclusionLightValueOverride(original: Float, state: IBlockState): Float {
|
||||
if (Config.enabled && Config.roundLogs.enabled && Config.blocks.logs.matchesID(state.block)) return Config.roundLogs.dimming;
|
||||
if (Config.enabled && Config.roundLogs.enabled && Config.blocks.logs.matchesClass(state.block)) return Config.roundLogs.dimming;
|
||||
return original;
|
||||
}
|
||||
|
||||
fun getUseNeighborBrightnessOverride(original: Boolean, state: IBlockState): Boolean {
|
||||
return original || (Config.enabled && Config.roundLogs.enabled && Config.blocks.logs.matchesID(state.block));
|
||||
return original || (Config.enabled && Config.roundLogs.enabled && Config.blocks.logs.matchesClass(state.block));
|
||||
}
|
||||
|
||||
fun onRandomDisplayTick(world: World, state: IBlockState, pos: BlockPos) {
|
||||
@@ -57,7 +60,7 @@ fun onRandomDisplayTick(world: World, state: IBlockState, pos: BlockPos) {
|
||||
|
||||
if (Config.enabled &&
|
||||
Config.fallingLeaves.enabled &&
|
||||
Config.blocks.leaves.matchesID(state.block) &&
|
||||
Config.blocks.leavesClasses.matchesClass(state.block) &&
|
||||
world.isAirBlock(pos + down1) &&
|
||||
Math.random() < Config.fallingLeaves.chance) {
|
||||
EntityFallingLeavesFX(world, pos).addIfValid()
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
package mods.betterfoliage.client.config
|
||||
|
||||
import mods.octarinecore.client.gui.NonVerboseArrayEntry
|
||||
import mods.octarinecore.client.resource.get
|
||||
import mods.octarinecore.client.resource.getLines
|
||||
import mods.octarinecore.client.resource.resourceManager
|
||||
import mods.octarinecore.common.config.ConfigPropertyBase
|
||||
import mods.octarinecore.metaprog.getJavaClass
|
||||
import net.minecraft.block.Block
|
||||
import net.minecraft.client.multiplayer.WorldClient
|
||||
import net.minecraftforge.common.MinecraftForge
|
||||
import net.minecraftforge.common.config.Configuration
|
||||
import net.minecraftforge.common.config.Property
|
||||
import net.minecraftforge.event.world.WorldEvent
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
|
||||
|
||||
/**
|
||||
* Match blocks based on their class names. Caches block IDs for faster lookup.
|
||||
*
|
||||
* @param[domain] resource domain for defaults file
|
||||
* @param[path] resource path for defaults file
|
||||
*/
|
||||
class BlockMatcher(val domain: String, val path: String) : ConfigPropertyBase() {
|
||||
|
||||
val blackList = mutableListOf<Class<*>>()
|
||||
val whiteList = mutableListOf<Class<*>>()
|
||||
val blockIDs = hashSetOf<Int>()
|
||||
var blacklistProperty: Property? = null
|
||||
var whitelistProperty: Property? = null
|
||||
|
||||
fun matchesClass(block: Block): Boolean {
|
||||
val blockClass = block.javaClass
|
||||
blackList.forEach { if (it.isAssignableFrom(blockClass)) return false }
|
||||
whiteList.forEach { if (it.isAssignableFrom(blockClass)) return true }
|
||||
return false
|
||||
}
|
||||
fun matchesID(block: Block) = blockIDs.contains(Block.REGISTRY.getIDForObject(block))
|
||||
fun matchesID(blockId: Int) = blockIDs.contains(blockId)
|
||||
|
||||
override fun attach(target: Configuration, langPrefix: String, categoryName: String, propertyName: String) {
|
||||
lang = null
|
||||
val defaults = readDefaults(domain, path)
|
||||
blacklistProperty = target.get(categoryName, "${propertyName}Blacklist", defaults.first)
|
||||
whitelistProperty = target.get(categoryName, "${propertyName}Whitelist", defaults.second)
|
||||
listOf(blacklistProperty!!, whitelistProperty!!).forEach {
|
||||
it.setConfigEntryClass(NonVerboseArrayEntry::class.java)
|
||||
it.setLanguageKey("$langPrefix.$categoryName.${it.name}")
|
||||
}
|
||||
read()
|
||||
}
|
||||
|
||||
override fun read() {
|
||||
listOf(Pair(blackList, blacklistProperty!!), Pair(whiteList, whitelistProperty!!)).forEach {
|
||||
it.first.clear()
|
||||
it.first.addAll(it.second.stringList.map { getJavaClass(it) }.filterNotNull())
|
||||
}
|
||||
updateIDs()
|
||||
}
|
||||
|
||||
fun updateIDs() {
|
||||
blockIDs.clear()
|
||||
Block.REGISTRY.forEach {
|
||||
if (matchesClass(it as Block)) blockIDs.add(Block.REGISTRY.getIDForObject(it))
|
||||
}
|
||||
}
|
||||
|
||||
override val hasChanged: Boolean
|
||||
get() = blacklistProperty?.hasChanged() ?: false || whitelistProperty?.hasChanged() ?: false
|
||||
|
||||
override val guiProperties: List<Property> get() = listOf(whitelistProperty!!, blacklistProperty!!)
|
||||
|
||||
fun readDefaults(domain: String, path: String): Pair<Array<String>, Array<String>> {
|
||||
val blackList = arrayListOf<String>()
|
||||
val whiteList = arrayListOf<String>()
|
||||
val defaults = resourceManager[domain, path]?.getLines()
|
||||
defaults?.map{ it.trim() }?.filter { !it.startsWith("//") && it.isNotEmpty() }?.forEach {
|
||||
if (it.startsWith("-")) { blackList.add(it.substring(1)) }
|
||||
else { whiteList.add(it) }
|
||||
}
|
||||
return (blackList.toTypedArray() to whiteList.toTypedArray())
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
fun onWorldLoad(event: WorldEvent.Load) { if (event.world is WorldClient) updateIDs() }
|
||||
|
||||
init { MinecraftForge.EVENT_BUS.register(this) }
|
||||
|
||||
}
|
||||
@@ -31,9 +31,11 @@ object Config : DelegatingConfig(BetterFoliageMod.MOD_ID, BetterFoliageMod.DOMAI
|
||||
var enabled by boolean(true)
|
||||
|
||||
object blocks {
|
||||
val leavesClasses = BlockMatcher(BetterFoliageMod.DOMAIN, "LeavesBlocksDefault.cfg")
|
||||
val leavesModels = ModelTextureListConfigOption(BetterFoliageMod.DOMAIN, "LeavesModelsDefault.cfg", 1)
|
||||
val grassClasses = BlockMatcher(BetterFoliageMod.DOMAIN, "GrassBlocksDefault.cfg")
|
||||
val grassModels = ModelTextureListConfigOption(BetterFoliageMod.DOMAIN, "GrassModelsDefault.cfg", 1)
|
||||
val dirt = BlockMatcher(BetterFoliageMod.DOMAIN, "DirtDefault.cfg")
|
||||
val grass = BlockMatcher(BetterFoliageMod.DOMAIN, "GrassDefault.cfg")
|
||||
val leaves = BlockMatcher(BetterFoliageMod.DOMAIN, "LeavesDefault.cfg")
|
||||
val crops = BlockMatcher(BetterFoliageMod.DOMAIN, "CropDefault.cfg")
|
||||
val logs = BlockMatcher(BetterFoliageMod.DOMAIN, "LogDefault.cfg")
|
||||
val sand = BlockMatcher(BetterFoliageMod.DOMAIN, "SandDefault.cfg")
|
||||
@@ -177,9 +179,17 @@ object Config : DelegatingConfig(BetterFoliageMod.MOD_ID, BetterFoliageMod.DOMAI
|
||||
val trailDensity by int(min=1, max=16, default=3)
|
||||
}
|
||||
|
||||
val forceReloadOptions = listOf(
|
||||
blocks.leavesClasses,
|
||||
blocks.leavesModels,
|
||||
blocks.grassClasses,
|
||||
blocks.grassModels,
|
||||
shortGrass["saturationThreshold"]
|
||||
)
|
||||
|
||||
override fun onChange(event: ConfigChangedEvent.OnConfigChangedEvent) {
|
||||
super.onChange(event)
|
||||
if (hasChanged(blocks, shortGrass["saturationThreshold"]))
|
||||
if (hasChanged(forceReloadOptions))
|
||||
Minecraft.getMinecraft().refreshResources()
|
||||
else
|
||||
Minecraft.getMinecraft().renderGlobal.loadRenderers()
|
||||
|
||||
@@ -61,6 +61,9 @@ object OptifineCTM {
|
||||
return result
|
||||
}
|
||||
|
||||
fun getAllCTM(states: List<IBlockState>, icon: TextureAtlasSprite): Collection<TextureAtlasSprite> =
|
||||
states.flatMap { getAllCTM(it, icon) }.toSet()
|
||||
|
||||
fun override(texture: TextureAtlasSprite, ctx: BlockContext, face: EnumFacing) =
|
||||
override(texture, ctx.world!!, ctx.pos, face)
|
||||
|
||||
|
||||
@@ -33,9 +33,9 @@ object ShadersModIntegration {
|
||||
* Called from transformed ShadersMod code.
|
||||
* @see mods.betterfoliage.loader.BetterFoliageTransformer
|
||||
*/
|
||||
@JvmStatic fun getBlockIdOverride(original: Long, blockState: IBlockState): Long {
|
||||
if (Config.blocks.leaves.matchesID(blockState.block)) return leavesEntityData
|
||||
if (Config.blocks.crops.matchesID(blockState.block)) return tallGrassEntityData
|
||||
@JvmStatic fun getBlockIdOverride(original: Long, blockState: IBlockState): Long {
|
||||
if (Config.blocks.leavesClasses.matchesClass(blockState.block)) return leavesEntityData
|
||||
if (Config.blocks.crops.matchesClass(blockState.block)) return tallGrassEntityData
|
||||
return original
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package mods.betterfoliage.client.render
|
||||
|
||||
import mods.betterfoliage.client.config.BlockMatcher
|
||||
import mods.betterfoliage.client.integration.OptifineCTM
|
||||
import mods.betterfoliage.client.integration.ShadersModIntegration
|
||||
import mods.betterfoliage.client.render.AbstractRenderColumn.BlockType.*
|
||||
@@ -8,6 +7,7 @@ import mods.betterfoliage.client.render.AbstractRenderColumn.QuadrantType.*
|
||||
import mods.octarinecore.client.render.*
|
||||
import mods.octarinecore.client.resource.BlockTextureInspector
|
||||
import mods.octarinecore.common.*
|
||||
import mods.octarinecore.common.config.BlockMatcher
|
||||
import net.minecraft.block.state.IBlockState
|
||||
import net.minecraft.client.renderer.BlockRendererDispatcher
|
||||
import net.minecraft.client.renderer.VertexBuffer
|
||||
|
||||
@@ -2,6 +2,7 @@ package mods.betterfoliage.client.render
|
||||
|
||||
import mods.betterfoliage.client.config.Config
|
||||
import mods.betterfoliage.client.texture.LeafRegistry
|
||||
import mods.betterfoliage.client.texture.defaultLeafColor
|
||||
import mods.octarinecore.PI2
|
||||
import mods.octarinecore.client.render.AbstractEntityFX
|
||||
import mods.octarinecore.client.render.HSB
|
||||
@@ -42,9 +43,14 @@ AbstractEntityFX(world, pos.x.toDouble() + 0.5, pos.y.toDouble(), pos.z.toDouble
|
||||
particleScale = Config.fallingLeaves.size.toFloat() * 0.1f
|
||||
|
||||
val state = world.getBlockState(pos)
|
||||
LeafRegistry[state, world, pos, DOWN]?.let {
|
||||
particleTexture = it.particleTextures[rand.nextInt(1024)]
|
||||
calculateParticleColor(it.averageColor, Minecraft.getMinecraft().blockColors.colorMultiplier(state, world, pos, 0))
|
||||
val blockColor = Minecraft.getMinecraft().blockColors.colorMultiplier(state, world, pos, 0)
|
||||
val leafInfo = LeafRegistry.get(state, world, pos, DOWN)
|
||||
if (leafInfo != null) {
|
||||
particleTexture = leafInfo.particleTextures?.get(rand.nextInt(1024))
|
||||
calculateParticleColor(leafInfo.averageColor, blockColor)
|
||||
} else {
|
||||
particleTexture = LeafRegistry.particles["default"]?.get(rand.nextInt(1024))
|
||||
setColor(blockColor)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ class RenderAlgae : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
||||
ctx.cameraDistance < Config.algae.distance &&
|
||||
ctx.blockState(up2).material == Material.WATER &&
|
||||
ctx.blockState(up1).material == Material.WATER &&
|
||||
Config.blocks.dirt.matchesID(ctx.block) &&
|
||||
Config.blocks.dirt.matchesClass(ctx.block) &&
|
||||
ctx.biomeId in Config.algae.biomes &&
|
||||
noise[ctx.pos] < Config.algae.population
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ class RenderCactus : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
||||
override fun isEligible(ctx: BlockContext): Boolean =
|
||||
Config.enabled && Config.cactus.enabled &&
|
||||
ctx.cameraDistance < Config.cactus.distance &&
|
||||
Config.blocks.cactus.matchesID(ctx.block)
|
||||
Config.blocks.cactus.matchesClass(ctx.block)
|
||||
|
||||
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: VertexBuffer, layer: BlockRenderLayer): Boolean {
|
||||
// get AO data
|
||||
|
||||
@@ -13,8 +13,8 @@ import net.minecraft.util.BlockRenderLayer
|
||||
class RenderConnectedGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
||||
override fun isEligible(ctx: BlockContext) =
|
||||
Config.enabled && Config.connectedGrass.enabled &&
|
||||
Config.blocks.dirt.matchesID(ctx.block) &&
|
||||
Config.blocks.grass.matchesID(ctx.block(up1)) &&
|
||||
Config.blocks.dirt.matchesClass(ctx.block) &&
|
||||
Config.blocks.grassClasses.matchesClass(ctx.block(up1)) &&
|
||||
(Config.connectedGrass.snowEnabled || !ctx.blockState(up2).isSnow)
|
||||
|
||||
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: VertexBuffer, layer: BlockRenderLayer): Boolean {
|
||||
|
||||
@@ -18,12 +18,12 @@ class RenderConnectedGrassLog : AbstractBlockRenderingHandler(BetterFoliageMod.M
|
||||
|
||||
override fun isEligible(ctx: BlockContext) =
|
||||
Config.enabled && Config.roundLogs.enabled && Config.roundLogs.connectGrass &&
|
||||
Config.blocks.dirt.matchesID(ctx.block) &&
|
||||
Config.blocks.logs.matchesID(ctx.block(up1))
|
||||
Config.blocks.dirt.matchesClass(ctx.block) &&
|
||||
Config.blocks.logs.matchesClass(ctx.block(up1))
|
||||
|
||||
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: VertexBuffer, layer: BlockRenderLayer): Boolean {
|
||||
val grassDir = grassCheckDirs.find {
|
||||
Config.blocks.grass.matchesID(ctx.block(it.offset))
|
||||
Config.blocks.grassClasses.matchesClass(ctx.block(it.offset))
|
||||
}
|
||||
|
||||
return if (grassDir != null) {
|
||||
|
||||
@@ -47,7 +47,7 @@ class RenderCoral : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
||||
ctx.cameraDistance < Config.coral.distance &&
|
||||
(ctx.blockState(up2).material == Material.WATER || Config.coral.shallowWater) &&
|
||||
ctx.blockState(up1).material == Material.WATER &&
|
||||
Config.blocks.sand.matchesID(ctx.block) &&
|
||||
Config.blocks.sand.matchesClass(ctx.block) &&
|
||||
ctx.biomeId in Config.coral.biomes &&
|
||||
noise[ctx.pos] < Config.coral.population
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package mods.betterfoliage.client.render
|
||||
import mods.betterfoliage.BetterFoliageMod
|
||||
import mods.betterfoliage.client.Client
|
||||
import mods.betterfoliage.client.config.Config
|
||||
import mods.betterfoliage.client.integration.OptifineCTM
|
||||
import mods.betterfoliage.client.integration.ShadersModIntegration
|
||||
import mods.betterfoliage.client.texture.GrassRegistry
|
||||
import mods.octarinecore.client.render.*
|
||||
@@ -47,16 +46,17 @@ class RenderGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
||||
Config.enabled &&
|
||||
ctx.cameraDistance < Config.shortGrass.distance &&
|
||||
(Config.shortGrass.grassEnabled || Config.connectedGrass.enabled) &&
|
||||
Config.blocks.grass.matchesID(ctx.block)
|
||||
GrassRegistry[ctx, UP] != null
|
||||
|
||||
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: VertexBuffer, layer: BlockRenderLayer): Boolean {
|
||||
val isConnected = ctx.block(down1).let { Config.blocks.dirt.matchesID(it) || Config.blocks.grass.matchesID(it) }
|
||||
val isConnected = ctx.block(down1).let {
|
||||
Config.blocks.dirt.matchesClass(it) ||
|
||||
Config.blocks.grassClasses.matchesClass(it)
|
||||
}
|
||||
val isSnowed = ctx.blockState(up1).isSnow
|
||||
val connectedGrass = isConnected && Config.connectedGrass.enabled && (!isSnowed || Config.connectedGrass.snowEnabled)
|
||||
|
||||
val grassInfo = GrassRegistry[ctx.blockState(Int3.zero)] ?: return renderWorldBlockBase(ctx, dispatcher, renderer, layer)
|
||||
val grassTopTexture = OptifineCTM.override(grassInfo.grassTopTexture, ctx, UP)
|
||||
|
||||
val grassInfo = GrassRegistry[ctx, UP]!!
|
||||
val blockColor = ctx.blockData(Int3.zero).color
|
||||
|
||||
if (connectedGrass) {
|
||||
@@ -70,7 +70,7 @@ class RenderGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
||||
fullCube,
|
||||
Rotation.identity,
|
||||
ctx.blockCenter,
|
||||
icon = { ctx, qi, q -> grassTopTexture },
|
||||
icon = { ctx, qi, q -> grassInfo.grassTopTexture },
|
||||
postProcess = { ctx, qi, q, vi, v ->
|
||||
rotateUV(2)
|
||||
if (isSnowed) {
|
||||
|
||||
@@ -41,14 +41,14 @@ class RenderLeaves : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
||||
Config.enabled &&
|
||||
Config.leaves.enabled &&
|
||||
ctx.cameraDistance < Config.leaves.distance &&
|
||||
Config.blocks.leaves.matchesID(ctx.block)
|
||||
LeafRegistry[ctx, DOWN] != null
|
||||
|
||||
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: VertexBuffer, layer: BlockRenderLayer): Boolean {
|
||||
val isSnowed = ctx.blockState(up1).material.let {
|
||||
it == Material.SNOW || it == Material.CRAFTED_SNOW
|
||||
}
|
||||
renderWorldBlockBase(ctx, dispatcher, renderer, null)
|
||||
val leafInfo = LeafRegistry[ctx, DOWN] ?: return false
|
||||
val leafInfo = LeafRegistry[ctx, DOWN]!!
|
||||
val blockColor = ctx.blockData(Int3.zero).color
|
||||
|
||||
modelRenderer.updateShading(Int3.zero, allFaces)
|
||||
|
||||
@@ -39,7 +39,7 @@ class RenderLilypad : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
||||
override fun isEligible(ctx: BlockContext): Boolean =
|
||||
Config.enabled && Config.lilypad.enabled &&
|
||||
ctx.cameraDistance < Config.lilypad.distance &&
|
||||
Config.blocks.lilypad.matchesID(ctx.block)
|
||||
Config.blocks.lilypad.matchesClass(ctx.block)
|
||||
|
||||
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: VertexBuffer, layer: BlockRenderLayer): Boolean {
|
||||
renderWorldBlockBase(ctx, dispatcher, renderer, null)
|
||||
|
||||
@@ -2,17 +2,12 @@ package mods.betterfoliage.client.render
|
||||
|
||||
import mods.betterfoliage.BetterFoliageMod
|
||||
import mods.betterfoliage.client.config.Config
|
||||
import mods.betterfoliage.client.integration.OptifineCTM
|
||||
import mods.octarinecore.client.render.BlockContext
|
||||
import mods.octarinecore.client.render.Quad
|
||||
import mods.octarinecore.client.render.ShadingContext
|
||||
import mods.octarinecore.client.render.blockContext
|
||||
import mods.octarinecore.common.Int3
|
||||
import mods.octarinecore.common.rotate
|
||||
import mods.octarinecore.tryDefault
|
||||
import net.minecraft.block.BlockLog
|
||||
import net.minecraft.block.state.IBlockState
|
||||
import net.minecraft.util.EnumFacing.*
|
||||
import net.minecraft.util.EnumFacing.Axis
|
||||
|
||||
class RenderLog : AbstractRenderColumn(BetterFoliageMod.MOD_ID) {
|
||||
|
||||
@@ -21,7 +16,7 @@ class RenderLog : AbstractRenderColumn(BetterFoliageMod.MOD_ID) {
|
||||
override fun isEligible(ctx: BlockContext) =
|
||||
Config.enabled && Config.roundLogs.enabled &&
|
||||
ctx.cameraDistance < Config.roundLogs.distance &&
|
||||
Config.blocks.logs.matchesID(ctx.block)
|
||||
Config.blocks.logs.matchesClass(ctx.block)
|
||||
|
||||
override var axisFunc = { state: IBlockState ->
|
||||
val axis = tryDefault(null) { state.getValue(BlockLog.LOG_AXIS).toString() } ?:
|
||||
@@ -44,8 +39,8 @@ class RenderLog : AbstractRenderColumn(BetterFoliageMod.MOD_ID) {
|
||||
|
||||
override fun resolver(ctx: BlockContext): ColumnTextureResolver? = columnTextures[ctx.blockState(Int3.zero)]
|
||||
|
||||
override val blockPredicate = { state: IBlockState -> Config.blocks.logs.matchesID(state.block) }
|
||||
override val surroundPredicate = { state: IBlockState -> state.isOpaqueCube && !Config.blocks.logs.matchesID(state.block) }
|
||||
override val blockPredicate = { state: IBlockState -> Config.blocks.logs.matchesClass(state.block) }
|
||||
override val surroundPredicate = { state: IBlockState -> state.isOpaqueCube && !Config.blocks.logs.matchesClass(state.block) }
|
||||
|
||||
override val connectPerpendicular: Boolean get() = Config.roundLogs.connectPerpendicular
|
||||
override val connectSolids: Boolean get() = Config.roundLogs.connectSolids
|
||||
|
||||
@@ -46,7 +46,7 @@ class RenderReeds : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
||||
ctx.cameraDistance < Config.reed.distance &&
|
||||
ctx.blockState(up2).material == Material.AIR &&
|
||||
ctx.blockState(up1).material == Material.WATER &&
|
||||
Config.blocks.dirt.matchesID(ctx.block) &&
|
||||
Config.blocks.dirt.matchesClass(ctx.block) &&
|
||||
ctx.biomeId in Config.reed.biomes &&
|
||||
noise[ctx.pos] < Config.reed.population
|
||||
|
||||
|
||||
@@ -1,16 +1,27 @@
|
||||
package mods.betterfoliage.client.texture
|
||||
|
||||
import mods.betterfoliage.client.Client
|
||||
import mods.betterfoliage.BetterFoliageMod
|
||||
import mods.betterfoliage.client.config.Config
|
||||
import mods.betterfoliage.client.integration.OptifineCTM
|
||||
import mods.octarinecore.client.render.BlockContext
|
||||
import mods.octarinecore.client.render.HSB
|
||||
import mods.octarinecore.client.resource.BlockTextureInspector
|
||||
import mods.octarinecore.client.resource.TextureListModelProcessor
|
||||
import mods.octarinecore.client.resource.TextureMediatedRegistry
|
||||
import mods.octarinecore.client.resource.averageColor
|
||||
import mods.octarinecore.client.resource.get
|
||||
import mods.octarinecore.common.Int3
|
||||
import mods.octarinecore.common.config.BlockMatcher
|
||||
import mods.octarinecore.common.config.ModelTextureList
|
||||
import mods.octarinecore.findFirst
|
||||
import net.minecraft.block.state.IBlockState
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite
|
||||
import net.minecraft.client.renderer.texture.TextureMap
|
||||
import net.minecraft.util.EnumFacing
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.world.IBlockAccess
|
||||
import net.minecraftforge.common.MinecraftForge
|
||||
import net.minecraftforge.fml.relauncher.Side
|
||||
import net.minecraftforge.fml.relauncher.SideOnly
|
||||
import org.apache.logging.log4j.Level.INFO
|
||||
|
||||
const val defaultGrassColor = 0
|
||||
|
||||
@@ -23,28 +34,66 @@ class GrassInfo(
|
||||
* Color to use for Short Grass rendering instead of the biome color.
|
||||
*
|
||||
* Value is null if the texture is mostly grey (the saturation of its average color is under a configurable limit),
|
||||
* the average color of the texture (significantly brightened) otherwise.
|
||||
* the average color of the texture (significantly ) otherwise.
|
||||
*/
|
||||
val overrideColor: Int?
|
||||
)
|
||||
|
||||
interface IGrassRegistry {
|
||||
fun get(state: IBlockState): GrassInfo?
|
||||
fun get(state: IBlockState, world: IBlockAccess, pos: BlockPos, face: EnumFacing): GrassInfo?
|
||||
}
|
||||
|
||||
/** Collects and manages rendering-related information for grass blocks. */
|
||||
@SideOnly(Side.CLIENT)
|
||||
object GrassRegistry : BlockTextureInspector<GrassInfo>() {
|
||||
object GrassRegistry : IGrassRegistry {
|
||||
val subRegistries = mutableListOf(StandardGrassSupport)
|
||||
|
||||
init {
|
||||
matchClassAndModel(Config.blocks.grass, "block/grass", listOf("top"))
|
||||
matchClassAndModel(Config.blocks.grass, "block/cube_bottom_top", listOf("top"))
|
||||
override fun get(state: IBlockState, world: IBlockAccess, pos: BlockPos, face: EnumFacing) =
|
||||
subRegistries.findFirst { it.get(state, world, pos, face) }
|
||||
|
||||
operator fun get(ctx: BlockContext, face: EnumFacing) = get(ctx.blockState(Int3.zero), ctx.world!!, ctx.pos, face)
|
||||
|
||||
override fun get(state: IBlockState) = subRegistries.findFirst { it.get(state) }
|
||||
}
|
||||
|
||||
object StandardGrassSupport :
|
||||
TextureListModelProcessor<TextureAtlasSprite>,
|
||||
TextureMediatedRegistry<List<String>, GrassInfo>,
|
||||
IGrassRegistry
|
||||
{
|
||||
init { MinecraftForge.EVENT_BUS.register(this) }
|
||||
|
||||
override var stateToKey = mutableMapOf<IBlockState, List<String>>()
|
||||
override var stateToValue = mapOf<IBlockState, TextureAtlasSprite>()
|
||||
override var textureToValue = mutableMapOf<TextureAtlasSprite, GrassInfo>()
|
||||
|
||||
override val logger = BetterFoliageMod.logDetail
|
||||
override val logName = "StandardGrassSupport"
|
||||
override val matchClasses: BlockMatcher get() = Config.blocks.grassClasses
|
||||
override val modelTextures: List<ModelTextureList> get() = Config.blocks.grassModels.list
|
||||
|
||||
override fun get(state: IBlockState, world: IBlockAccess, pos: BlockPos, face: EnumFacing): GrassInfo? {
|
||||
val baseTexture = stateToValue[state] ?: return null
|
||||
return textureToValue[OptifineCTM.override(baseTexture, world, pos, face)] ?: textureToValue[baseTexture]
|
||||
}
|
||||
|
||||
override fun onAfterModelLoad() {
|
||||
super.onAfterModelLoad()
|
||||
Client.log(INFO, "Inspecting grass textures")
|
||||
override fun get(state: IBlockState) = StandardLeafSupport.stateToValue[state].let {
|
||||
if (it == null) null else textureToValue[it]
|
||||
}
|
||||
|
||||
override fun processTextures(state: IBlockState, textures: List<TextureAtlasSprite>, atlas: TextureMap): GrassInfo {
|
||||
val hsb = HSB.fromColor(textures[0].averageColor ?: defaultGrassColor)
|
||||
override fun processStitch(state: IBlockState, key: List<String>, atlas: TextureMap) = atlas[key[0]]
|
||||
|
||||
override fun processTexture(states: List<IBlockState>, texture: TextureAtlasSprite, atlas: TextureMap) {
|
||||
registerGrass(texture, atlas)
|
||||
OptifineCTM.getAllCTM(states, texture).forEach {
|
||||
registerGrass(it, atlas)
|
||||
}
|
||||
}
|
||||
|
||||
fun registerGrass(texture: TextureAtlasSprite, atlas: TextureMap) {
|
||||
val hsb = HSB.fromColor(texture.averageColor ?: defaultGrassColor)
|
||||
val overrideColor = if (hsb.saturation > Config.shortGrass.saturationThreshold) hsb.copy(brightness = 0.8f).asColor else null
|
||||
return GrassInfo(textures[0], overrideColor)
|
||||
textureToValue[texture] = GrassInfo(texture, overrideColor)
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,29 @@
|
||||
package mods.betterfoliage.client.texture
|
||||
|
||||
import mods.betterfoliage.BetterFoliageMod
|
||||
import mods.betterfoliage.client.Client
|
||||
import mods.betterfoliage.client.config.Config
|
||||
import mods.betterfoliage.client.integration.OptifineCTM
|
||||
import mods.octarinecore.client.render.BlockContext
|
||||
import mods.octarinecore.client.resource.BlockTextureInspector
|
||||
import mods.octarinecore.client.resource.IconSet
|
||||
import mods.octarinecore.client.resource.averageColor
|
||||
import mods.octarinecore.client.resource.*
|
||||
import mods.octarinecore.common.Int3
|
||||
import mods.octarinecore.common.config.BlockMatcher
|
||||
import mods.octarinecore.common.config.ModelTextureList
|
||||
import mods.octarinecore.findFirst
|
||||
import net.minecraft.block.state.IBlockState
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite
|
||||
import net.minecraft.client.renderer.texture.TextureMap
|
||||
import net.minecraft.util.EnumFacing
|
||||
import net.minecraft.util.ResourceLocation
|
||||
import net.minecraft.util.math.BlockPos
|
||||
import net.minecraft.world.IBlockAccess
|
||||
import net.minecraftforge.client.event.TextureStitchEvent
|
||||
import net.minecraftforge.common.MinecraftForge
|
||||
import net.minecraftforge.fml.common.eventhandler.EventPriority
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
|
||||
import net.minecraftforge.fml.relauncher.Side
|
||||
import net.minecraftforge.fml.relauncher.SideOnly
|
||||
import org.apache.logging.log4j.Level.INFO
|
||||
import org.apache.logging.log4j.Level.WARN
|
||||
import org.apache.logging.log4j.Level
|
||||
import org.apache.logging.log4j.Logger
|
||||
|
||||
const val defaultLeafColor = 0
|
||||
|
||||
@@ -34,61 +39,94 @@ class LeafInfo(
|
||||
val averageColor: Int = roundLeafTexture.averageColor ?: defaultLeafColor
|
||||
) {
|
||||
/** [IconSet] of the textures to use for leaf particles emitted from this block. */
|
||||
val particleTextures: IconSet get() = LeafRegistry.particles[leafType]!!
|
||||
val particleTextures: IconSet? get() = LeafRegistry.particles[leafType]
|
||||
}
|
||||
|
||||
/** Collects and manages rendering-related information for leaf blocks. */
|
||||
@SideOnly(Side.CLIENT)
|
||||
object LeafRegistry : BlockTextureInspector<TextureAtlasSprite>() {
|
||||
interface ILeafRegistry {
|
||||
operator fun get(state: IBlockState): LeafInfo?
|
||||
operator fun get(state: IBlockState, world: IBlockAccess, pos: BlockPos, face: EnumFacing): LeafInfo?
|
||||
}
|
||||
|
||||
val leaves: MutableMap<TextureAtlasSprite, LeafInfo> = hashMapOf()
|
||||
val particles: MutableMap<String, IconSet> = hashMapOf()
|
||||
/** Collects and manages rendering-related information for grass blocks. */
|
||||
object LeafRegistry : ILeafRegistry {
|
||||
val subRegistries: MutableList<ILeafRegistry> = mutableListOf(StandardLeafSupport)
|
||||
val typeMappings = TextureMatcher()
|
||||
val particles = hashMapOf<String, IconSet>()
|
||||
|
||||
init {
|
||||
matchClassAndModel(Config.blocks.leaves, "minecraft:block/leaves", listOf("all"))
|
||||
matchClassAndModel(Config.blocks.leaves, "minecraft:block/cube_all", listOf("all"))
|
||||
matchClassAndModel(Config.blocks.leaves, "biomesoplenty:block/leaves_overlay", listOf("under"))
|
||||
init { MinecraftForge.EVENT_BUS.register(this) }
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.HIGHEST)
|
||||
fun handlePreStitch(event: TextureStitchEvent.Pre) {
|
||||
particles.clear()
|
||||
}
|
||||
|
||||
operator fun get(state: IBlockState, world: IBlockAccess, pos: BlockPos, face: EnumFacing): LeafInfo? {
|
||||
val baseTexture = get(state) ?: return null
|
||||
return leaves[OptifineCTM.override(baseTexture, world, pos, face)] ?: leaves[baseTexture]
|
||||
}
|
||||
override fun get(state: IBlockState, world: IBlockAccess, pos: BlockPos, face: EnumFacing) =
|
||||
subRegistries.findFirst { it.get(state, world, pos, face) }
|
||||
|
||||
operator fun get(ctx: BlockContext, face: EnumFacing) = get(ctx.blockState(Int3.zero), ctx.world!!, ctx.pos, face)
|
||||
|
||||
override fun onAfterModelLoad() {
|
||||
super.onAfterModelLoad()
|
||||
Client.log(INFO, "Inspecting leaf textures")
|
||||
particles.clear()
|
||||
typeMappings.loadMappings(ResourceLocation("betterfoliage", "leafTextureMappings.cfg"))
|
||||
}
|
||||
override fun get(state: IBlockState) = subRegistries.findFirst { it.get(state) }
|
||||
|
||||
override fun processTextures(state: IBlockState, textures: List<TextureAtlasSprite>, atlas: TextureMap): TextureAtlasSprite {
|
||||
val texture = textures[0]
|
||||
registerLeaf(texture, atlas)
|
||||
OptifineCTM.getAllCTM(state, texture).forEach { registerLeaf(it, atlas) }
|
||||
return texture
|
||||
}
|
||||
|
||||
fun registerLeaf(texture: TextureAtlasSprite, atlas: TextureMap) {
|
||||
fun getParticleType(texture: TextureAtlasSprite, atlas: TextureMap): String {
|
||||
var leafType = typeMappings.getType(texture) ?: "default"
|
||||
val generated = atlas.registerSprite(
|
||||
Client.genLeaves.generatedResource(texture.iconName, "type" to leafType)
|
||||
)
|
||||
|
||||
if (leafType !in particles.keys) {
|
||||
val particleSet = IconSet("betterfoliage", "blocks/falling_leaf_${leafType}_%d")
|
||||
particleSet.onStitch(atlas)
|
||||
if (particleSet.num == 0) {
|
||||
Client.log(WARN, "Leaf particle textures not found for leaf type: $leafType")
|
||||
Client.log(Level.WARN, "Leaf particle textures not found for leaf type: $leafType")
|
||||
leafType == "default"
|
||||
} else {
|
||||
particles.put(leafType, particleSet)
|
||||
}
|
||||
}
|
||||
|
||||
leaves[texture] = LeafInfo(generated, leafType)
|
||||
return leafType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
object StandardLeafSupport :
|
||||
TextureListModelProcessor<TextureAtlasSprite>,
|
||||
TextureMediatedRegistry<List<String>, LeafInfo>,
|
||||
ILeafRegistry
|
||||
{
|
||||
|
||||
init { MinecraftForge.EVENT_BUS.register(this) }
|
||||
|
||||
override val logName = "StandardLeafSupport"
|
||||
override val matchClasses: BlockMatcher get() = Config.blocks.leavesClasses
|
||||
override val modelTextures: List<ModelTextureList> get() = Config.blocks.leavesModels.list
|
||||
override val logger: Logger? get() = BetterFoliageMod.logDetail
|
||||
|
||||
override var stateToKey = mutableMapOf<IBlockState, List<String>>()
|
||||
override var stateToValue = mapOf<IBlockState, TextureAtlasSprite>()
|
||||
override var textureToValue = mutableMapOf<TextureAtlasSprite, LeafInfo>()
|
||||
|
||||
override fun get(state: IBlockState, world: IBlockAccess, pos: BlockPos, face: EnumFacing): LeafInfo? {
|
||||
val baseTexture = stateToValue[state] ?: return null
|
||||
return textureToValue[OptifineCTM.override(baseTexture, world, pos, face)] ?: textureToValue[baseTexture]
|
||||
}
|
||||
|
||||
override fun get(state: IBlockState) = stateToValue[state].let {
|
||||
if (it == null) null else textureToValue[it]
|
||||
}
|
||||
|
||||
override fun processStitch(state: IBlockState, key: List<String>, atlas: TextureMap) = atlas[key[0]]
|
||||
|
||||
override fun processTexture(states: List<IBlockState>, texture: TextureAtlasSprite, atlas: TextureMap) {
|
||||
registerLeaf(texture, atlas)
|
||||
OptifineCTM.getAllCTM(states, texture).forEach {
|
||||
registerLeaf(it, atlas)
|
||||
}
|
||||
}
|
||||
|
||||
fun registerLeaf(texture: TextureAtlasSprite, atlas: TextureMap) {
|
||||
var leafType = LeafRegistry.typeMappings.getType(texture) ?: "default"
|
||||
val generated = atlas.registerSprite(
|
||||
Client.genLeaves.generatedResource(texture.iconName, "type" to leafType)
|
||||
)
|
||||
textureToValue[texture] = LeafInfo(generated, LeafRegistry.getParticleType(texture, atlas))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user