Merge branch 'kotlin-1.11.2' into kotlin-1.12

This commit is contained in:
octarine-noise
2017-08-12 19:12:46 +02:00
26 changed files with 277 additions and 130 deletions

1
.gitignore vendored
View File

@@ -6,3 +6,4 @@ run/
.gradle/ .gradle/
build/ build/
classes/ classes/
temp/

View File

@@ -2,7 +2,7 @@ apply plugin: "net.minecraftforge.gradle.forge"
apply plugin: 'kotlin' apply plugin: 'kotlin'
group = 'com.github.octarine-noise' group = 'com.github.octarine-noise'
version = "2.1.7" version = "2.1.8"
archivesBaseName = rootProject.name + '-MC1.12' archivesBaseName = rootProject.name + '-MC1.12'
buildscript { buildscript {

View File

@@ -8,6 +8,7 @@ import net.minecraft.world.biome.Biome
import net.minecraftforge.fml.client.event.ConfigChangedEvent import net.minecraftforge.fml.client.event.ConfigChangedEvent
import net.minecraftforge.fml.relauncher.Side import net.minecraftforge.fml.relauncher.Side
import net.minecraftforge.fml.relauncher.SideOnly import net.minecraftforge.fml.relauncher.SideOnly
import org.lwjgl.opengl.GL11
// BetterFoliage-specific property delegates // BetterFoliage-specific property delegates
private val OBSOLETE = ObsoleteConfigProperty() private val OBSOLETE = ObsoleteConfigProperty()
@@ -30,12 +31,14 @@ private fun Biome.filterClass(vararg name: String) = name.any { it in this.javaC
object Config : DelegatingConfig(BetterFoliageMod.MOD_ID, BetterFoliageMod.DOMAIN) { object Config : DelegatingConfig(BetterFoliageMod.MOD_ID, BetterFoliageMod.DOMAIN) {
var enabled by boolean(true) var enabled by boolean(true)
var nVidia by boolean(GL11.glGetString(GL11.GL_VENDOR).toLowerCase().contains("nvidia"))
object blocks { object blocks {
val leavesClasses = ConfigurableBlockMatcher(BetterFoliageMod.DOMAIN, "leaves_blocks_default.cfg") val leavesClasses = ConfigurableBlockMatcher(BetterFoliageMod.DOMAIN, "leaves_blocks_default.cfg")
val leavesModels = ModelTextureListConfigOption(BetterFoliageMod.DOMAIN, "leaves_models_default.cfg", 1) val leavesModels = ModelTextureListConfigOption(BetterFoliageMod.DOMAIN, "leaves_models_default.cfg", 1)
val grassClasses = ConfigurableBlockMatcher(BetterFoliageMod.DOMAIN, "grass_blocks_default.cfg") val grassClasses = ConfigurableBlockMatcher(BetterFoliageMod.DOMAIN, "grass_blocks_default.cfg")
val grassModels = ModelTextureListConfigOption(BetterFoliageMod.DOMAIN, "grass_models_default.cfg", 1) val grassModels = ModelTextureListConfigOption(BetterFoliageMod.DOMAIN, "grass_models_default.cfg", 1)
val mycelium = ConfigurableBlockMatcher(BetterFoliageMod.DOMAIN, "mycelium_blocks_default.cfg")
val dirt = ConfigurableBlockMatcher(BetterFoliageMod.DOMAIN, "dirt_default.cfg") val dirt = ConfigurableBlockMatcher(BetterFoliageMod.DOMAIN, "dirt_default.cfg")
val crops = ConfigurableBlockMatcher(BetterFoliageMod.DOMAIN, "crop_default.cfg") val crops = ConfigurableBlockMatcher(BetterFoliageMod.DOMAIN, "crop_default.cfg")
val logClasses = ConfigurableBlockMatcher(BetterFoliageMod.DOMAIN, "log_blocks_default.cfg") val logClasses = ConfigurableBlockMatcher(BetterFoliageMod.DOMAIN, "log_blocks_default.cfg")
@@ -43,6 +46,7 @@ object Config : DelegatingConfig(BetterFoliageMod.MOD_ID, BetterFoliageMod.DOMAI
val sand = ConfigurableBlockMatcher(BetterFoliageMod.DOMAIN, "sand_default.cfg") val sand = ConfigurableBlockMatcher(BetterFoliageMod.DOMAIN, "sand_default.cfg")
val lilypad = ConfigurableBlockMatcher(BetterFoliageMod.DOMAIN, "lilypad_default.cfg") val lilypad = ConfigurableBlockMatcher(BetterFoliageMod.DOMAIN, "lilypad_default.cfg")
val cactus = ConfigurableBlockMatcher(BetterFoliageMod.DOMAIN, "cactus_default.cfg") val cactus = ConfigurableBlockMatcher(BetterFoliageMod.DOMAIN, "cactus_default.cfg")
val netherrack = ConfigurableBlockMatcher(BetterFoliageMod.DOMAIN, "netherrack_blocks_default.cfg")
val leavesWhitelist = OBSOLETE val leavesWhitelist = OBSOLETE
val leavesBlacklist = OBSOLETE val leavesBlacklist = OBSOLETE

View File

@@ -7,10 +7,9 @@ import mods.betterfoliage.client.render.*
import mods.betterfoliage.client.texture.ILeafRegistry import mods.betterfoliage.client.texture.ILeafRegistry
import mods.betterfoliage.client.texture.LeafInfo import mods.betterfoliage.client.texture.LeafInfo
import mods.betterfoliage.client.texture.LeafRegistry import mods.betterfoliage.client.texture.LeafRegistry
import mods.betterfoliage.client.texture.StandardLeafSupport
import mods.betterfoliage.loader.Refs import mods.betterfoliage.loader.Refs
import mods.octarinecore.client.resource.ModelProcessor import mods.octarinecore.client.resource.ModelProcessor
import mods.octarinecore.client.resource.get import mods.octarinecore.client.resource.ModelVariant
import mods.octarinecore.client.resource.registerSprite import mods.octarinecore.client.resource.registerSprite
import mods.octarinecore.metaprog.ClassRef import mods.octarinecore.metaprog.ClassRef
import mods.octarinecore.metaprog.FieldRef import mods.octarinecore.metaprog.FieldRef
@@ -20,7 +19,6 @@ import mods.octarinecore.tryDefault
import net.minecraft.block.state.IBlockState import net.minecraft.block.state.IBlockState
import net.minecraft.client.Minecraft import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.block.model.ModelResourceLocation import net.minecraft.client.renderer.block.model.ModelResourceLocation
import net.minecraft.client.renderer.texture.TextureAtlasSprite
import net.minecraft.client.renderer.texture.TextureMap import net.minecraft.client.renderer.texture.TextureMap
import net.minecraft.util.EnumFacing import net.minecraft.util.EnumFacing
import net.minecraft.util.ResourceLocation import net.minecraft.util.ResourceLocation
@@ -35,6 +33,7 @@ import net.minecraftforge.fml.relauncher.Side
import net.minecraftforge.fml.relauncher.SideOnly import net.minecraftforge.fml.relauncher.SideOnly
import org.apache.logging.log4j.Level import org.apache.logging.log4j.Level
@SideOnly(Side.CLIENT) @SideOnly(Side.CLIENT)
object ForestryIntegration { object ForestryIntegration {
@@ -104,9 +103,9 @@ object ForestryLeavesSupport : ILeafRegistry {
textureToValue[textureLocation] = LeafInfo(generated, LeafRegistry.getParticleType(texture, atlas)) textureToValue[textureLocation] = LeafInfo(generated, LeafRegistry.getParticleType(texture, atlas))
} }
override fun get(state: IBlockState) = null override fun get(state: IBlockState, rand: Int) = null
override fun get(state: IBlockState, world: IBlockAccess, pos: BlockPos, face: EnumFacing): LeafInfo? { override fun get(state: IBlockState, world: IBlockAccess, pos: BlockPos, face: EnumFacing, rand: Int): LeafInfo? {
// check variant property (used in decorative leaves) // check variant property (used in decorative leaves)
state.properties.entries.find { state.properties.entries.find {
ForestryIntegration.PropertyTreeType.isInstance(it.key) && ForestryIntegration.TreeDefinition.isInstance(it.value) ForestryIntegration.PropertyTreeType.isInstance(it.key) && ForestryIntegration.TreeDefinition.isInstance(it.value)
@@ -128,21 +127,22 @@ object ForestryLeavesSupport : ILeafRegistry {
@SideOnly(Side.CLIENT) @SideOnly(Side.CLIENT)
object ForestryLogSupport : ModelProcessor<List<String>, IColumnTextureInfo>, IColumnRegistry { object ForestryLogSupport : ModelProcessor<List<String>, IColumnTextureInfo>, IColumnRegistry {
override var stateToKey = mutableMapOf<IBlockState, List<String>>() override var variants = mutableMapOf<IBlockState, MutableList<ModelVariant>>()
override var stateToValue = mapOf<IBlockState, IColumnTextureInfo>() override var variantToKey = mutableMapOf<ModelVariant, List<String>>()
override var variantToValue = mapOf<ModelVariant, IColumnTextureInfo>()
override val logger = BetterFoliageMod.logDetail override val logger = BetterFoliageMod.logDetail
init { MinecraftForge.EVENT_BUS.register(this) } init { MinecraftForge.EVENT_BUS.register(this) }
override fun processModelLoad(state: IBlockState, modelLoc: ModelResourceLocation, model: IModel): List<String>? { override fun processModelLoad(state: IBlockState, modelLoc: ModelResourceLocation, model: IModel) {
// respect class list to avoid triggering on fences, stairs, etc. // respect class list to avoid triggering on fences, stairs, etc.
if (!Config.blocks.logClasses.matchesClass(state.block)) return null if (!Config.blocks.logClasses.matchesClass(state.block)) return
// find wood type property // find wood type property
val woodType = state.properties.entries.find { val woodType = state.properties.entries.find {
ForestryIntegration.PropertyWoodType.isInstance(it.key) && ForestryIntegration.IWoodType.isInstance(it.value) ForestryIntegration.PropertyWoodType.isInstance(it.key) && ForestryIntegration.IWoodType.isInstance(it.value)
} ?: return null } ?: return
logger.log(Level.DEBUG, "ForestryLogSupport: block state ${state.toString()}") logger.log(Level.DEBUG, "ForestryLogSupport: block state ${state.toString()}")
logger.log(Level.DEBUG, "ForestryLogSupport: variant ${woodType.value.toString()}") logger.log(Level.DEBUG, "ForestryLogSupport: variant ${woodType.value.toString()}")
@@ -152,14 +152,14 @@ object ForestryLogSupport : ModelProcessor<List<String>, IColumnTextureInfo>, IC
val heart = ForestryIntegration.heartTex.invoke(woodType.value) as String? val heart = ForestryIntegration.heartTex.invoke(woodType.value) as String?
logger.log(Level.DEBUG, "ForestryLogSupport: textures [heart=$heart, bark=$bark]") logger.log(Level.DEBUG, "ForestryLogSupport: textures [heart=$heart, bark=$bark]")
return if (bark != null && heart != null) listOf(heart, bark) else null if (bark != null && heart != null) putKeySingle(state, listOf(heart, bark))
} }
override fun processStitch(state: IBlockState, key: List<String>, atlas: TextureMap): IColumnTextureInfo? { override fun processStitch(variant: ModelVariant, key: List<String>, atlas: TextureMap): IColumnTextureInfo? {
val heart = atlas.registerSprite(key[0]) val heart = atlas.registerSprite(key[0])
val bark = atlas.registerSprite(key[1]) val bark = atlas.registerSprite(key[1])
return StaticColumnInfo(StandardLogSupport.getAxis(state), heart, heart, bark) return StaticColumnInfo(StandardLogSupport.getAxis(variant.state), heart, heart, listOf(bark))
} }
override fun get(state: IBlockState) = stateToValue[state] override fun get(state: IBlockState, rand: Int) = variants[state]?.let { variantToValue[it[0]] }
} }

View File

@@ -4,10 +4,15 @@ import mods.betterfoliage.client.Client
import mods.betterfoliage.loader.Refs import mods.betterfoliage.loader.Refs
import mods.octarinecore.ThreadLocalDelegate import mods.octarinecore.ThreadLocalDelegate
import mods.octarinecore.client.render.BlockContext import mods.octarinecore.client.render.BlockContext
import mods.octarinecore.common.Int3
import mods.octarinecore.metaprog.allAvailable import mods.octarinecore.metaprog.allAvailable
import mods.octarinecore.metaprog.reflectField
import net.minecraft.block.state.BlockStateBase import net.minecraft.block.state.BlockStateBase
import net.minecraft.block.state.IBlockState import net.minecraft.block.state.IBlockState
import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.block.model.BakedQuad
import net.minecraft.client.renderer.texture.TextureAtlasSprite import net.minecraft.client.renderer.texture.TextureAtlasSprite
import net.minecraft.client.renderer.vertex.DefaultVertexFormats
import net.minecraft.util.EnumFacing import net.minecraft.util.EnumFacing
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
import net.minecraft.world.IBlockAccess import net.minecraft.world.IBlockAccess
@@ -22,18 +27,24 @@ import org.apache.logging.log4j.Level.INFO
@SideOnly(Side.CLIENT) @SideOnly(Side.CLIENT)
object OptifineCTM { object OptifineCTM {
val isAvailable = allAvailable( val isCTMAvailable = allAvailable(
Refs.ConnectedTextures, Refs.ConnectedProperties, Refs.ConnectedTextures, Refs.ConnectedProperties,
Refs.getConnectedTexture, Refs.getConnectedTexture,
Refs.CTblockProperties, Refs.CTtileProperties, Refs.CTblockProperties, Refs.CTtileProperties,
Refs.CPtileIcons, Refs.CPmatchesIcon Refs.CPtileIcons, Refs.CPmatchesIcon
) )
val isColorAvailable = allAvailable(
Refs.CustomColors, Refs.getColorMultiplier
)
init { init {
Client.log(INFO, "Optifine CTM support is ${if (isAvailable) "enabled" else "disabled" }") Client.log(INFO, "Optifine CTM support is ${if (isCTMAvailable) "enabled" else "disabled" }")
Client.log(INFO, "Optifine custom color support is ${if (isColorAvailable) "enabled" else "disabled" }")
} }
val renderEnv by ThreadLocalDelegate { OptifineRenderEnv() } val renderEnv by ThreadLocalDelegate { OptifineRenderEnv() }
val fakeQuad = BakedQuad(IntArray(0), 1, EnumFacing.UP, null, true, DefaultVertexFormats.BLOCK)
val isCustomColors: Boolean get() = if (!isCTMAvailable) false else Minecraft.getMinecraft().gameSettings.reflectField<Boolean>("ofCustomColors") ?: false
val connectedProperties: Iterable<Any> get() { val connectedProperties: Iterable<Any> get() {
val result = hashSetOf<Any>() val result = hashSetOf<Any>()
@@ -49,7 +60,7 @@ object OptifineCTM {
/** Get all the CTM [TextureAtlasSprite]s that could possibly be used for this block. */ /** Get all the CTM [TextureAtlasSprite]s that could possibly be used for this block. */
fun getAllCTM(state: IBlockState, icon: TextureAtlasSprite): Collection<TextureAtlasSprite> { fun getAllCTM(state: IBlockState, icon: TextureAtlasSprite): Collection<TextureAtlasSprite> {
val result = hashSetOf<TextureAtlasSprite>() val result = hashSetOf<TextureAtlasSprite>()
if (state !is BlockStateBase || !isAvailable) return result if (state !is BlockStateBase || !isCTMAvailable) return result
connectedProperties.forEach { cp -> connectedProperties.forEach { cp ->
if (Refs.CPmatchesBlock.invoke(cp, Refs.getBlockId.invoke(state), Refs.getMetadata.invoke(state)) as Boolean && if (Refs.CPmatchesBlock.invoke(cp, Refs.getBlockId.invoke(state), Refs.getMetadata.invoke(state)) as Boolean &&
@@ -68,7 +79,7 @@ object OptifineCTM {
override(texture, ctx.world!!, ctx.pos, face) override(texture, ctx.world!!, ctx.pos, face)
fun override(texture: TextureAtlasSprite, world: IBlockAccess, pos: BlockPos, face: EnumFacing): TextureAtlasSprite { fun override(texture: TextureAtlasSprite, world: IBlockAccess, pos: BlockPos, face: EnumFacing): TextureAtlasSprite {
if (!isAvailable) return texture if (!isCTMAvailable) return texture
val state = world.getBlockState(pos) val state = world.getBlockState(pos)
return renderEnv.let { return renderEnv.let {
@@ -76,6 +87,14 @@ object OptifineCTM {
Refs.getConnectedTexture.invokeStatic(world, state, pos, face, texture, it.wrapped) as TextureAtlasSprite Refs.getConnectedTexture.invokeStatic(world, state, pos, face, texture, it.wrapped) as TextureAtlasSprite
} }
} }
fun getBlockColor(ctx: BlockContext): Int {
val ofColor = if (isColorAvailable && Minecraft.getMinecraft().gameSettings.reflectField<Boolean>("ofCustomColors") == true) {
renderEnv.reset(ctx.world!!, ctx.blockState(Int3.zero), ctx.pos)
Refs.getColorMultiplier.invokeStatic(fakeQuad, ctx.blockState(Int3.zero), ctx.world!!, ctx.pos, renderEnv.wrapped) as? Int
} else null
return if (ofColor == null || ofColor == -1) ctx.blockData(Int3.zero).color else ofColor
}
} }
@SideOnly(Side.CLIENT) @SideOnly(Side.CLIENT)

View File

@@ -7,7 +7,6 @@ import mods.betterfoliage.client.render.IColumnRegistry
import mods.betterfoliage.client.render.IColumnTextureInfo import mods.betterfoliage.client.render.IColumnTextureInfo
import mods.betterfoliage.client.render.LogRegistry import mods.betterfoliage.client.render.LogRegistry
import mods.betterfoliage.client.render.StaticColumnInfo import mods.betterfoliage.client.render.StaticColumnInfo
import mods.betterfoliage.client.texture.LeafRegistry
import mods.betterfoliage.client.texture.StandardLeafSupport import mods.betterfoliage.client.texture.StandardLeafSupport
import mods.betterfoliage.loader.Refs import mods.betterfoliage.loader.Refs
import mods.octarinecore.client.render.Quad import mods.octarinecore.client.render.Quad
@@ -18,8 +17,6 @@ import mods.octarinecore.common.rotate
import mods.octarinecore.metaprog.ClassRef import mods.octarinecore.metaprog.ClassRef
import mods.octarinecore.metaprog.MethodRef import mods.octarinecore.metaprog.MethodRef
import mods.octarinecore.metaprog.allAvailable import mods.octarinecore.metaprog.allAvailable
import mods.octarinecore.tryDefault
import net.minecraft.block.properties.PropertyDirection
import net.minecraft.block.state.IBlockState import net.minecraft.block.state.IBlockState
import net.minecraft.client.renderer.block.model.ModelResourceLocation import net.minecraft.client.renderer.block.model.ModelResourceLocation
import net.minecraft.client.renderer.texture.TextureAtlasSprite import net.minecraft.client.renderer.texture.TextureAtlasSprite
@@ -91,36 +88,40 @@ data class RubberLogColumnInfo(override val axis: EnumFacing.Axis?,
@SideOnly(Side.CLIENT) @SideOnly(Side.CLIENT)
abstract class RubberLogSupportBase : ModelProcessor<RubberLogModelInfo, IColumnTextureInfo>, IColumnRegistry { abstract class RubberLogSupportBase : ModelProcessor<RubberLogModelInfo, IColumnTextureInfo>, IColumnRegistry {
override var stateToKey = mutableMapOf<IBlockState, RubberLogModelInfo>() override var variants = mutableMapOf<IBlockState, MutableList<ModelVariant>>()
override var stateToValue = mapOf<IBlockState, IColumnTextureInfo>() override var variantToKey = mutableMapOf<ModelVariant, RubberLogModelInfo>()
override var variantToValue = mapOf<ModelVariant, IColumnTextureInfo>()
override val logger = BetterFoliageMod.logDetail override val logger = BetterFoliageMod.logDetail
init { MinecraftForge.EVENT_BUS.register(this) } init { MinecraftForge.EVENT_BUS.register(this) }
override fun processStitch(state: IBlockState, key: RubberLogModelInfo, atlas: TextureMap): IColumnTextureInfo? { override fun processStitch(variant: ModelVariant, key: RubberLogModelInfo, atlas: TextureMap): IColumnTextureInfo? {
val topTex = atlas.registerSprite(key.textures[0]) val topTex = atlas.registerSprite(key.textures[0])
val bottomTex = atlas.registerSprite(key.textures[1]) val bottomTex = atlas.registerSprite(key.textures[1])
val sideTex = atlas.registerSprite(key.textures[2]) val sideTex = atlas.registerSprite(key.textures[2])
if (key.spotDir == null) if (key.spotDir == null)
return StaticColumnInfo(key.axis, topTex, bottomTex, sideTex) return StaticColumnInfo(key.axis, topTex, bottomTex, listOf(sideTex))
else { else {
val spotTex = atlas.registerSprite(key.textures[3]) val spotTex = atlas.registerSprite(key.textures[3])
return RubberLogColumnInfo(key.axis, key.spotDir, topTex, bottomTex, sideTex, spotTex) return RubberLogColumnInfo(key.axis, key.spotDir, topTex, bottomTex, sideTex, spotTex)
} }
} }
override fun get(state: IBlockState) = stateToValue[state] override fun get(state: IBlockState, rand: Int): IColumnTextureInfo? {
val variant = getVariant(state, rand) ?: return null
return variantToValue[variant]
}
} }
@SideOnly(Side.CLIENT) @SideOnly(Side.CLIENT)
object IC2LogSupport : RubberLogSupportBase() { object IC2LogSupport : RubberLogSupportBase() {
override fun processModelLoad(state: IBlockState, modelLoc: ModelResourceLocation, model: IModel): RubberLogModelInfo? { override fun processModelLoad(state: IBlockState, modelLoc: ModelResourceLocation, model: IModel) {
// check for proper block class, existence of ModelBlock, and "state" blockstate property // check for proper block class, existence of ModelBlock, and "state" blockstate property
if (!IC2Integration.BlockRubWood.isInstance(state.block)) return null if (!IC2Integration.BlockRubWood.isInstance(state.block)) return
val blockLoc = model.modelBlockAndLoc.firstOrNull() ?: return null val blockLoc = model.modelBlockAndLoc.firstOrNull() ?: return
val type = state.properties.entries.find { it.key.getName() == "state" }?.value?.toString() ?: return null val type = state.properties.entries.find { it.key.getName() == "state" }?.value?.toString() ?: return
// logs with no rubber spot // logs with no rubber spot
if (blockLoc.derivesFrom(ResourceLocation("block/cube_column"))) { if (blockLoc.derivesFrom(ResourceLocation("block/cube_column"))) {
@@ -133,7 +134,10 @@ object IC2LogSupport : RubberLogSupportBase() {
val textureNames = listOf("end", "end", "side").map { blockLoc.first.resolveTextureName(it) } val textureNames = listOf("end", "end", "side").map { blockLoc.first.resolveTextureName(it) }
logger.log(Level.DEBUG, "IC2LogSupport: block state ${state.toString()}") logger.log(Level.DEBUG, "IC2LogSupport: block state ${state.toString()}")
logger.log(Level.DEBUG, "IC2LogSupport: axis=$axis, end=${textureNames[0]}, side=${textureNames[2]}") logger.log(Level.DEBUG, "IC2LogSupport: axis=$axis, end=${textureNames[0]}, side=${textureNames[2]}")
return if (textureNames.all { it != "missingno" }) RubberLogModelInfo(axis, null, textureNames) else null if (textureNames.all { it != "missingno" }) {
putKeySingle(state, RubberLogModelInfo(axis, null, textureNames))
}
return
} }
// logs with rubber spot // logs with rubber spot
@@ -147,30 +151,36 @@ object IC2LogSupport : RubberLogSupportBase() {
val textureNames = listOf("up", "down", "south", "north").map { blockLoc.first.resolveTextureName(it) } val textureNames = listOf("up", "down", "south", "north").map { blockLoc.first.resolveTextureName(it) }
logger.log(Level.DEBUG, "IC2LogSupport: block state ${state.toString()}") logger.log(Level.DEBUG, "IC2LogSupport: block state ${state.toString()}")
logger.log(Level.DEBUG, "IC2LogSupport: spotDir=$spotDir, up=${textureNames[0]}, down=${textureNames[1]}, side=${textureNames[2]}, spot=${textureNames[3]}") logger.log(Level.DEBUG, "IC2LogSupport: spotDir=$spotDir, up=${textureNames[0]}, down=${textureNames[1]}, side=${textureNames[2]}, spot=${textureNames[3]}")
return if (textureNames.all { it != "missingno" }) RubberLogModelInfo(EnumFacing.Axis.Y, spotDir, textureNames) else null if (textureNames.all { it != "missingno" }) {
putKeySingle(state, RubberLogModelInfo(EnumFacing.Axis.Y, spotDir, textureNames))
}
} }
} }
@SideOnly(Side.CLIENT) @SideOnly(Side.CLIENT)
object TechRebornLogSupport : RubberLogSupportBase() { object TechRebornLogSupport : RubberLogSupportBase() {
override fun processModelLoad(state: IBlockState, modelLoc: ModelResourceLocation, model: IModel): RubberLogModelInfo? { override fun processModelLoad(state: IBlockState, modelLoc: ModelResourceLocation, model: IModel) {
// check for proper block class, existence of ModelBlock // check for proper block class, existence of ModelBlock
if (!TechRebornIntegration.BlockRubberLog.isInstance(state.block)) return null if (!TechRebornIntegration.BlockRubberLog.isInstance(state.block)) return
val blockLoc = model.modelBlockAndLoc.firstOrNull() ?: return null val blockLoc = model.modelBlockAndLoc.firstOrNull() ?: return
val hasSap = state.properties.entries.find { it.key.getName() == "hassap" }?.value as? Boolean ?: return null val hasSap = state.properties.entries.find { it.key.getName() == "hassap" }?.value as? Boolean ?: return
val sapSide = state.properties.entries.find { it.key.getName() == "sapside" }?.value as? EnumFacing ?: return null val sapSide = state.properties.entries.find { it.key.getName() == "sapside" }?.value as? EnumFacing ?: return
val textureNames = listOf("end", "end", "side", "sapside").map { blockLoc.first.resolveTextureName(it) } val textureNames = listOf("end", "end", "side", "sapside").map { blockLoc.first.resolveTextureName(it) }
logger.log(Level.DEBUG, "TechRebornLogSupport: block state ${state.toString()}") logger.log(Level.DEBUG, "TechRebornLogSupport: block state ${state.toString()}")
if (hasSap) { if (hasSap) {
logger.log(Level.DEBUG, "TechRebornLogSupport: spotDir=$sapSide, end=${textureNames[0]}, side=${textureNames[2]}, spot=${textureNames[3]}") logger.log(Level.DEBUG, "TechRebornLogSupport: spotDir=$sapSide, end=${textureNames[0]}, side=${textureNames[2]}, spot=${textureNames[3]}")
return if (textureNames.all { it != "missingno" }) RubberLogModelInfo(EnumFacing.Axis.Y, sapSide, textureNames) else null if (textureNames.all { it != "missingno" }) {
putKeySingle(state, RubberLogModelInfo(EnumFacing.Axis.Y, sapSide, textureNames))
}
} else { } else {
logger.log(Level.DEBUG, "TechRebornLogSupport: end=${textureNames[0]}, side=${textureNames[2]}") logger.log(Level.DEBUG, "TechRebornLogSupport: end=${textureNames[0]}, side=${textureNames[2]}")
return if (textureNames.all { it != "missingno" }) RubberLogModelInfo(EnumFacing.Axis.Y, null, textureNames) else null if (textureNames.all { it != "missingno" }) {
putKeySingle(state, RubberLogModelInfo(EnumFacing.Axis.Y, null, textureNames))
}
} }
} }
} }

View File

@@ -27,14 +27,18 @@ interface IColumnTextureInfo {
@SideOnly(Side.CLIENT) @SideOnly(Side.CLIENT)
interface IColumnRegistry { interface IColumnRegistry {
operator fun get(state: IBlockState): IColumnTextureInfo? operator fun get(state: IBlockState, rand: Int): IColumnTextureInfo?
} }
@SideOnly(Side.CLIENT) @SideOnly(Side.CLIENT)
data class StaticColumnInfo(override val axis: Axis?, data class StaticColumnInfo(override val axis: Axis?,
val topTexture: TextureAtlasSprite, val topTexture: TextureAtlasSprite,
val bottomTexture: TextureAtlasSprite, val bottomTexture: TextureAtlasSprite,
val sideTexture: TextureAtlasSprite) : IColumnTextureInfo { val sideTextures: List<TextureAtlasSprite>) : IColumnTextureInfo {
// index offsets for EnumFacings, to make it less likely for neighboring faces to get the same bark texture
val dirToIdx = arrayOf(0, 1, 2, 4, 3, 5)
override val top: QuadIconResolver = { ctx, _, _ -> override val top: QuadIconResolver = { ctx, _, _ ->
OptifineCTM.override(topTexture, blockContext, UP.rotate(ctx.rotation)) OptifineCTM.override(topTexture, blockContext, UP.rotate(ctx.rotation))
} }
@@ -42,7 +46,9 @@ data class StaticColumnInfo(override val axis: Axis?,
OptifineCTM.override(bottomTexture, blockContext, DOWN.rotate(ctx.rotation)) OptifineCTM.override(bottomTexture, blockContext, DOWN.rotate(ctx.rotation))
} }
override val side: QuadIconResolver = { ctx, idx, _ -> override val side: QuadIconResolver = { ctx, idx, _ ->
OptifineCTM.override(sideTexture, blockContext, (if ((idx and 1) == 0) SOUTH else EAST).rotate(ctx.rotation)) val worldFace = (if ((idx and 1) == 0) SOUTH else EAST).rotate(ctx.rotation)
val baseTexture = sideTextures[(blockContext.random(1) + dirToIdx[worldFace.ordinal]) % sideTextures.size]
OptifineCTM.override(baseTexture, blockContext, worldFace)
} }
} }
@@ -140,7 +146,7 @@ abstract class AbstractRenderColumn(modId: String) : AbstractBlockRenderingHandl
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, layer: BlockRenderLayer): Boolean { override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, layer: BlockRenderLayer): Boolean {
if (ctx.isSurroundedBy(surroundPredicate) ) return false if (ctx.isSurroundedBy(surroundPredicate) ) return false
val columnTextures = registry[ctx.blockState(Int3.zero)] val columnTextures = registry[ctx.blockState(Int3.zero), ctx.random(0)]
if (columnTextures == null) { if (columnTextures == null) {
Client.logRenderError(ctx.blockState(Int3.zero), ctx.pos) Client.logRenderError(ctx.blockState(Int3.zero), ctx.pos)
return renderWorldBlockBase(ctx, dispatcher, renderer, null) return renderWorldBlockBase(ctx, dispatcher, renderer, null)
@@ -345,7 +351,7 @@ abstract class AbstractRenderColumn(modId: String) : AbstractBlockRenderingHandl
return if (!blockPredicate(state)) { return if (!blockPredicate(state)) {
if (state.isOpaqueCube) SOLID else NONSOLID if (state.isOpaqueCube) SOLID else NONSOLID
} else { } else {
(registry[state]?.axis ?: if (Config.roundLogs.defaultY) Axis.Y else null)?.let { (registry[state, random(0)]?.axis ?: if (Config.roundLogs.defaultY) Axis.Y else null)?.let {
if (it == axis) PARALLEL else PERPENDICULAR if (it == axis) PARALLEL else PERPENDICULAR
} ?: SOLID } ?: SOLID
} }

View File

@@ -8,6 +8,7 @@ import mods.octarinecore.client.render.HSB
import mods.octarinecore.common.Double3 import mods.octarinecore.common.Double3
import mods.octarinecore.minmax import mods.octarinecore.minmax
import mods.octarinecore.random import mods.octarinecore.random
import mods.octarinecore.semiRandom
import net.minecraft.client.Minecraft import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.BufferBuilder import net.minecraft.client.renderer.BufferBuilder
import net.minecraft.util.EnumFacing.DOWN import net.minecraft.util.EnumFacing.DOWN
@@ -44,7 +45,7 @@ AbstractEntityFX(world, pos.x.toDouble() + 0.5, pos.y.toDouble(), pos.z.toDouble
val state = world.getBlockState(pos) val state = world.getBlockState(pos)
val blockColor = 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) val leafInfo = LeafRegistry.get(state, world, pos, DOWN, semiRandom(pos.x, pos.y, pos.z, 0))
if (leafInfo != null) { if (leafInfo != null) {
particleTexture = leafInfo.particleTextures?.get(rand.nextInt(1024)) particleTexture = leafInfo.particleTextures?.get(rand.nextInt(1024))
calculateParticleColor(leafInfo.averageColor, blockColor) calculateParticleColor(leafInfo.averageColor, blockColor)

View File

@@ -14,9 +14,6 @@ const val chamferAffinity = 0.9f
/** Amount to shrink column extension bits to stop Z-fighting. */ /** Amount to shrink column extension bits to stop Z-fighting. */
val zProtectionScale: Double3 get() = Double3(Config.roundLogs.zProtection, 1.0, Config.roundLogs.zProtection) val zProtectionScale: Double3 get() = Double3(Config.roundLogs.zProtection, 1.0, Config.roundLogs.zProtection)
/** nVidia does it different... */
val nVidia = GL11.glGetString(GL11.GL_VENDOR).toLowerCase().contains("nvidia")
fun Model.columnSide(radius: Double, yBottom: Double, yTop: Double, transform: (Quad) -> Quad = { it }) { fun Model.columnSide(radius: Double, yBottom: Double, yTop: Double, transform: (Quad) -> Quad = { it }) {
val halfRadius = radius * 0.5 val halfRadius = radius * 0.5
listOf( listOf(
@@ -96,14 +93,14 @@ fun Model.columnLid(radius: Double, transform: (Quad)->Quad = { it }) {
1 -> EdgeInterpolateFallback(UP, SOUTH, 0.0) 1 -> EdgeInterpolateFallback(UP, SOUTH, 0.0)
else -> vertex.aoShader else -> vertex.aoShader
})} })}
.cycleVertices(if (nVidia) 0 else 1) .cycleVertices(if (Config.nVidia) 0 else 1)
val q2 = Quad(v1, v4, v5, v6).setAoShader(faceOrientedAuto(overrideFace = UP, corner = cornerAo(Axis.Y))) val q2 = Quad(v1, v4, v5, v6).setAoShader(faceOrientedAuto(overrideFace = UP, corner = cornerAo(Axis.Y)))
.transformVI { vertex, idx -> vertex.copy(aoShader = when(idx) { .transformVI { vertex, idx -> vertex.copy(aoShader = when(idx) {
0 -> FaceCenter(UP) 0 -> FaceCenter(UP)
3 -> EdgeInterpolateFallback(UP, EAST, 0.0) 3 -> EdgeInterpolateFallback(UP, EAST, 0.0)
else -> vertex.aoShader else -> vertex.aoShader
})} })}
.cycleVertices(if (nVidia) 0 else 1) .cycleVertices(if (Config.nVidia) 0 else 1)
listOf(q1, q2).forEach { transform(it.setFlatShader(FaceFlat(UP))).add() } listOf(q1, q2).forEach { transform(it.setFlatShader(FaceFlat(UP))).add() }
} }

View File

@@ -4,6 +4,7 @@ import mods.betterfoliage.BetterFoliageMod
import mods.betterfoliage.client.Client import mods.betterfoliage.client.Client
import mods.betterfoliage.client.config.Config import mods.betterfoliage.client.config.Config
import mods.octarinecore.client.render.* import mods.octarinecore.client.render.*
import mods.octarinecore.client.resource.ModelVariant
import mods.octarinecore.client.resource.TextureListModelProcessor import mods.octarinecore.client.resource.TextureListModelProcessor
import mods.octarinecore.client.resource.registerSprite import mods.octarinecore.client.resource.registerSprite
import mods.octarinecore.common.Int3 import mods.octarinecore.common.Int3
@@ -35,8 +36,9 @@ class RenderCactus : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
init { MinecraftForge.EVENT_BUS.register(this) } init { MinecraftForge.EVENT_BUS.register(this) }
override var stateToKey = mutableMapOf<IBlockState, List<String>>() override var variants = mutableMapOf<IBlockState, MutableList<ModelVariant>>()
override var stateToValue = mapOf<IBlockState, IColumnTextureInfo>() override var variantToKey = mutableMapOf<ModelVariant, List<String>>()
override var variantToValue = mapOf<ModelVariant, IColumnTextureInfo>()
override val logger = BetterFoliageMod.logDetail override val logger = BetterFoliageMod.logDetail
override val logName = "CactusTextures" override val logName = "CactusTextures"
@@ -45,14 +47,17 @@ class RenderCactus : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
modelTextures("block/cactus", "top", "bottom", "side") modelTextures("block/cactus", "top", "bottom", "side")
) )
override fun processStitch(state: IBlockState, key: List<String>, atlas: TextureMap): IColumnTextureInfo? { override fun processStitch(variant: ModelVariant, key: List<String>, atlas: TextureMap): IColumnTextureInfo? {
val topTex = atlas.registerSprite(key[0]) val topTex = atlas.registerSprite(key[0])
val bottomTex = atlas.registerSprite(key[1]) val bottomTex = atlas.registerSprite(key[1])
val sideTex = atlas.registerSprite(key[2]) val sideTex = atlas.registerSprite(key[2])
return StaticColumnInfo(Axis.Y, topTex, bottomTex, sideTex) return StaticColumnInfo(Axis.Y, topTex, bottomTex, listOf(sideTex))
} }
override fun get(state: IBlockState) = stateToValue[state] override fun get(state: IBlockState, rand: Int): IColumnTextureInfo? {
val variant = getVariant(state, rand) ?: return null
return variantToValue[variant]
}
} }
val modelStem = model { val modelStem = model {
@@ -98,7 +103,7 @@ class RenderCactus : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
// get AO data // get AO data
modelRenderer.updateShading(Int3.zero, allFaces) modelRenderer.updateShading(Int3.zero, allFaces)
val icons = cactusTextures[ctx.blockState(Int3.zero)] ?: return renderWorldBlockBase(ctx, dispatcher, renderer, null) val icons = cactusTextures[ctx.blockState(Int3.zero), ctx.random(0)] ?: return renderWorldBlockBase(ctx, dispatcher, renderer, null)
modelRenderer.render( modelRenderer.render(
renderer, renderer,

View File

@@ -3,6 +3,7 @@ package mods.betterfoliage.client.render
import mods.betterfoliage.BetterFoliageMod import mods.betterfoliage.BetterFoliageMod
import mods.betterfoliage.client.Client import mods.betterfoliage.client.Client
import mods.betterfoliage.client.config.Config import mods.betterfoliage.client.config.Config
import mods.betterfoliage.client.integration.OptifineCTM
import mods.betterfoliage.client.integration.ShadersModIntegration import mods.betterfoliage.client.integration.ShadersModIntegration
import mods.betterfoliage.client.texture.GrassRegistry import mods.betterfoliage.client.texture.GrassRegistry
import mods.octarinecore.client.render.* import mods.octarinecore.client.render.*
@@ -68,7 +69,7 @@ class RenderGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
Client.logRenderError(ctx.blockState(Int3.zero), ctx.pos) Client.logRenderError(ctx.blockState(Int3.zero), ctx.pos)
return renderWorldBlockBase(ctx, dispatcher, renderer, null) return renderWorldBlockBase(ctx, dispatcher, renderer, null)
} }
val blockColor = ctx.blockData(Int3.zero).color val blockColor = OptifineCTM.getBlockColor(ctx)
if (connectedGrass) { if (connectedGrass) {
// get full AO data // get full AO data

View File

@@ -3,6 +3,7 @@ package mods.betterfoliage.client.render
import mods.betterfoliage.BetterFoliageMod import mods.betterfoliage.BetterFoliageMod
import mods.betterfoliage.client.Client import mods.betterfoliage.client.Client
import mods.betterfoliage.client.config.Config import mods.betterfoliage.client.config.Config
import mods.betterfoliage.client.integration.OptifineCTM
import mods.betterfoliage.client.integration.ShadersModIntegration import mods.betterfoliage.client.integration.ShadersModIntegration
import mods.betterfoliage.client.texture.LeafRegistry import mods.betterfoliage.client.texture.LeafRegistry
import mods.octarinecore.PI2 import mods.octarinecore.PI2
@@ -57,7 +58,7 @@ class RenderLeaves : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
Client.logRenderError(ctx.blockState(Int3.zero), ctx.pos) Client.logRenderError(ctx.blockState(Int3.zero), ctx.pos)
return renderWorldBlockBase(ctx, dispatcher, renderer, layer) return renderWorldBlockBase(ctx, dispatcher, renderer, layer)
} }
val blockColor = ctx.blockData(Int3.zero).color val blockColor = OptifineCTM.getBlockColor(ctx)
renderWorldBlockBase(ctx, dispatcher, renderer, layer) renderWorldBlockBase(ctx, dispatcher, renderer, layer)
if (!layer.isCutout) return true if (!layer.isCutout) return true

View File

@@ -3,6 +3,7 @@ package mods.betterfoliage.client.render
import mods.betterfoliage.BetterFoliageMod import mods.betterfoliage.BetterFoliageMod
import mods.betterfoliage.client.config.Config import mods.betterfoliage.client.config.Config
import mods.octarinecore.client.render.BlockContext import mods.octarinecore.client.render.BlockContext
import mods.octarinecore.client.resource.ModelVariant
import mods.octarinecore.client.resource.TextureListModelProcessor import mods.octarinecore.client.resource.TextureListModelProcessor
import mods.octarinecore.client.resource.registerSprite import mods.octarinecore.client.resource.registerSprite
import mods.octarinecore.common.config.ConfigurableBlockMatcher import mods.octarinecore.common.config.ConfigurableBlockMatcher
@@ -43,7 +44,7 @@ class RenderLog : AbstractRenderColumn(BetterFoliageMod.MOD_ID) {
@SideOnly(Side.CLIENT) @SideOnly(Side.CLIENT)
object LogRegistry : IColumnRegistry { object LogRegistry : IColumnRegistry {
val subRegistries: MutableList<IColumnRegistry> = mutableListOf() val subRegistries: MutableList<IColumnRegistry> = mutableListOf()
override fun get(state: IBlockState) = subRegistries.findFirst { it[state] } override fun get(state: IBlockState, rand: Int) = subRegistries.findFirst { it[state, rand] }
} }
@SideOnly(Side.CLIENT) @SideOnly(Side.CLIENT)
@@ -54,22 +55,27 @@ object StandardLogSupport : TextureListModelProcessor<IColumnTextureInfo>, IColu
MinecraftForge.EVENT_BUS.register(this) MinecraftForge.EVENT_BUS.register(this)
} }
override var stateToKey = mutableMapOf<IBlockState, List<String>>() override var variants = mutableMapOf<IBlockState, MutableList<ModelVariant>>()
override var stateToValue = mapOf<IBlockState, IColumnTextureInfo>() override var variantToKey = mutableMapOf<ModelVariant, List<String>>()
override var variantToValue = mapOf<ModelVariant, IColumnTextureInfo>()
override val logger = BetterFoliageMod.logDetail override val logger = BetterFoliageMod.logDetail
override val logName = "StandardLogSupport" override val logName = "StandardLogSupport"
override val matchClasses: ConfigurableBlockMatcher get() = Config.blocks.logClasses override val matchClasses: ConfigurableBlockMatcher get() = Config.blocks.logClasses
override val modelTextures: List<ModelTextureList> get() = Config.blocks.logModels.list override val modelTextures: List<ModelTextureList> get() = Config.blocks.logModels.list
override fun processStitch(state: IBlockState, key: List<String>, atlas: TextureMap): IColumnTextureInfo? { override fun processStitch(variant: ModelVariant, key: List<String>, atlas: TextureMap): IColumnTextureInfo? {
val topTex = atlas.registerSprite(key[0]) val topTex = atlas.registerSprite(key[0])
val bottomTex = atlas.registerSprite(key[1]) val bottomTex = atlas.registerSprite(key[1])
val sideTex = atlas.registerSprite(key[2]) val sideTexList = key.drop(2).map { atlas.registerSprite(it) }
return StaticColumnInfo(getAxis(state), topTex, bottomTex, sideTex) if (sideTexList.isEmpty()) return null
return StaticColumnInfo(getAxis(variant.state), topTex, bottomTex, sideTexList)
} }
override fun get(state: IBlockState) = stateToValue[state] override fun get(state: IBlockState, rand: Int): IColumnTextureInfo? {
val variant = getVariant(state, rand) ?: return null
return variantToValue[variant]
}
fun getAxis(state: IBlockState): Axis? { fun getAxis(state: IBlockState): Axis? {
val axis = tryDefault(null) { state.getValue(BlockLog.LOG_AXIS).toString() } ?: val axis = tryDefault(null) { state.getValue(BlockLog.LOG_AXIS).toString() } ?:

View File

@@ -11,7 +11,6 @@ import mods.octarinecore.common.Double3
import mods.octarinecore.common.Rotation import mods.octarinecore.common.Rotation
import net.minecraft.client.renderer.BlockRendererDispatcher import net.minecraft.client.renderer.BlockRendererDispatcher
import net.minecraft.client.renderer.BufferBuilder import net.minecraft.client.renderer.BufferBuilder
import net.minecraft.init.Blocks
import net.minecraft.util.BlockRenderLayer import net.minecraft.util.BlockRenderLayer
import net.minecraftforge.fml.relauncher.Side import net.minecraftforge.fml.relauncher.Side
import net.minecraftforge.fml.relauncher.SideOnly import net.minecraftforge.fml.relauncher.SideOnly
@@ -29,8 +28,8 @@ class RenderMycelium : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
override fun isEligible(ctx: BlockContext): Boolean { override fun isEligible(ctx: BlockContext): Boolean {
if (!Config.enabled || !Config.shortGrass.myceliumEnabled) return false if (!Config.enabled || !Config.shortGrass.myceliumEnabled) return false
return ctx.block == Blocks.MYCELIUM && return Config.blocks.mycelium.matchesClass(ctx.block) &&
ctx.cameraDistance < Config.shortGrass.distance ctx.cameraDistance < Config.shortGrass.distance
} }
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, layer: BlockRenderLayer): Boolean { override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, layer: BlockRenderLayer): Boolean {

View File

@@ -9,7 +9,6 @@ import mods.octarinecore.common.Rotation
import mods.octarinecore.random import mods.octarinecore.random
import net.minecraft.client.renderer.BlockRendererDispatcher import net.minecraft.client.renderer.BlockRendererDispatcher
import net.minecraft.client.renderer.BufferBuilder import net.minecraft.client.renderer.BufferBuilder
import net.minecraft.init.Blocks
import net.minecraft.util.BlockRenderLayer import net.minecraft.util.BlockRenderLayer
import net.minecraft.util.EnumFacing.* import net.minecraft.util.EnumFacing.*
import net.minecraftforge.fml.relauncher.Side import net.minecraftforge.fml.relauncher.Side
@@ -35,8 +34,8 @@ class RenderNetherrack : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID)
override fun isEligible(ctx: BlockContext): Boolean { override fun isEligible(ctx: BlockContext): Boolean {
if (!Config.enabled || !Config.netherrack.enabled) return false if (!Config.enabled || !Config.netherrack.enabled) return false
return ctx.block == Blocks.NETHERRACK && return Config.blocks.netherrack.matchesClass(ctx.block) &&
ctx.cameraDistance < Config.netherrack.distance ctx.cameraDistance < Config.netherrack.distance
} }
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, layer: BlockRenderLayer): Boolean { override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, layer: BlockRenderLayer): Boolean {

View File

@@ -39,8 +39,8 @@ class GrassInfo(
) )
interface IGrassRegistry { interface IGrassRegistry {
fun get(state: IBlockState): GrassInfo? operator fun get(state: IBlockState, rand: Int): GrassInfo?
fun get(state: IBlockState, world: IBlockAccess, pos: BlockPos, face: EnumFacing): GrassInfo? operator fun get(state: IBlockState, world: IBlockAccess, pos: BlockPos, face: EnumFacing, rand: Int): GrassInfo?
} }
/** Collects and manages rendering-related information for grass blocks. */ /** Collects and manages rendering-related information for grass blocks. */
@@ -48,12 +48,12 @@ interface IGrassRegistry {
object GrassRegistry : IGrassRegistry { object GrassRegistry : IGrassRegistry {
val subRegistries: MutableList<IGrassRegistry> = mutableListOf(StandardGrassSupport) val subRegistries: MutableList<IGrassRegistry> = mutableListOf(StandardGrassSupport)
override fun get(state: IBlockState, world: IBlockAccess, pos: BlockPos, face: EnumFacing) = override fun get(state: IBlockState, world: IBlockAccess, pos: BlockPos, face: EnumFacing, rand: Int) =
subRegistries.findFirst { it.get(state, world, pos, face) } subRegistries.findFirst { it.get(state, world, pos, face, rand) }
operator fun get(ctx: BlockContext, face: EnumFacing) = get(ctx.blockState(Int3.zero), ctx.world!!, ctx.pos, face) operator fun get(ctx: BlockContext, face: EnumFacing) = get(ctx.blockState(Int3.zero), ctx.world!!, ctx.pos, face, ctx.random(0))
override fun get(state: IBlockState) = subRegistries.findFirst { it.get(state) } override fun get(state: IBlockState, rand: Int) = subRegistries.findFirst { it[state, rand] }
} }
object StandardGrassSupport : object StandardGrassSupport :
@@ -63,8 +63,9 @@ object StandardGrassSupport :
{ {
init { MinecraftForge.EVENT_BUS.register(this) } init { MinecraftForge.EVENT_BUS.register(this) }
override var stateToKey = mutableMapOf<IBlockState, List<String>>() override var variants = mutableMapOf<IBlockState, MutableList<ModelVariant>>()
override var stateToValue = mapOf<IBlockState, TextureAtlasSprite>() override var variantToKey = mutableMapOf<ModelVariant, List<String>>()
override var variantToValue = mapOf<ModelVariant, TextureAtlasSprite>()
override var textureToValue = mutableMapOf<TextureAtlasSprite, GrassInfo>() override var textureToValue = mutableMapOf<TextureAtlasSprite, GrassInfo>()
override val logger = BetterFoliageMod.logDetail override val logger = BetterFoliageMod.logDetail
@@ -72,20 +73,22 @@ object StandardGrassSupport :
override val matchClasses: ConfigurableBlockMatcher get() = Config.blocks.grassClasses override val matchClasses: ConfigurableBlockMatcher get() = Config.blocks.grassClasses
override val modelTextures: List<ModelTextureList> get() = Config.blocks.grassModels.list override val modelTextures: List<ModelTextureList> get() = Config.blocks.grassModels.list
override fun get(state: IBlockState, world: IBlockAccess, pos: BlockPos, face: EnumFacing): GrassInfo? { override fun get(state: IBlockState, world: IBlockAccess, pos: BlockPos, face: EnumFacing, rand: Int): GrassInfo? {
val baseTexture = stateToValue[state] ?: return null val variant = getVariant(state, rand) ?: return null
val baseTexture = variantToValue[variant] ?: return null
return textureToValue[OptifineCTM.override(baseTexture, world, pos, face)] ?: textureToValue[baseTexture] return textureToValue[OptifineCTM.override(baseTexture, world, pos, face)] ?: textureToValue[baseTexture]
} }
override fun get(state: IBlockState) = StandardLeafSupport.stateToValue[state].let { override fun get(state: IBlockState, rand: Int): GrassInfo? {
if (it == null) null else textureToValue[it] val variant = getVariant(state, rand) ?: return null
return variantToValue[variant].let { if (it == null) null else textureToValue[it] }
} }
override fun processStitch(state: IBlockState, key: List<String>, atlas: TextureMap) = atlas.registerSprite(key[0]) override fun processStitch(variant: ModelVariant, key: List<String>, atlas: TextureMap) = atlas.registerSprite(key[0])
override fun processTexture(states: List<IBlockState>, texture: TextureAtlasSprite, atlas: TextureMap) { override fun processTexture(variants: List<ModelVariant>, texture: TextureAtlasSprite, atlas: TextureMap) {
registerGrass(texture, atlas) registerGrass(texture, atlas)
OptifineCTM.getAllCTM(states, texture).forEach { OptifineCTM.getAllCTM(variants.map { it.state }, texture).forEach {
registerGrass(it, atlas) registerGrass(it, atlas)
} }
} }

View File

@@ -44,8 +44,8 @@ class LeafInfo(
} }
interface ILeafRegistry { interface ILeafRegistry {
operator fun get(state: IBlockState): LeafInfo? operator fun get(state: IBlockState, rand: Int): LeafInfo?
operator fun get(state: IBlockState, world: IBlockAccess, pos: BlockPos, face: EnumFacing): LeafInfo? operator fun get(state: IBlockState, world: IBlockAccess, pos: BlockPos, face: EnumFacing, rand: Int): LeafInfo?
} }
/** Collects and manages rendering-related information for grass blocks. */ /** Collects and manages rendering-related information for grass blocks. */
@@ -62,12 +62,12 @@ object LeafRegistry : ILeafRegistry {
typeMappings.loadMappings(ResourceLocation(BetterFoliageMod.DOMAIN, "leaf_texture_mappings.cfg")) typeMappings.loadMappings(ResourceLocation(BetterFoliageMod.DOMAIN, "leaf_texture_mappings.cfg"))
} }
override fun get(state: IBlockState, world: IBlockAccess, pos: BlockPos, face: EnumFacing) = override fun get(state: IBlockState, world: IBlockAccess, pos: BlockPos, face: EnumFacing, rand: Int) =
subRegistries.findFirst { it.get(state, world, pos, face) } subRegistries.findFirst { it.get(state, world, pos, face, rand) }
operator fun get(ctx: BlockContext, face: EnumFacing) = get(ctx.blockState(Int3.zero), ctx.world!!, ctx.pos, face) operator fun get(ctx: BlockContext, face: EnumFacing) = get(ctx.blockState(Int3.zero), ctx.world!!, ctx.pos, face, ctx.random(0))
override fun get(state: IBlockState) = subRegistries.findFirst { it.get(state) } override fun get(state: IBlockState, rand: Int) = subRegistries.findFirst { it[state, rand] }
fun getParticleType(texture: TextureAtlasSprite, atlas: TextureMap): String { fun getParticleType(texture: TextureAtlasSprite, atlas: TextureMap): String {
var leafType = typeMappings.getType(texture) ?: "default" var leafType = typeMappings.getType(texture) ?: "default"
@@ -100,26 +100,30 @@ object StandardLeafSupport :
override val modelTextures: List<ModelTextureList> get() = Config.blocks.leavesModels.list override val modelTextures: List<ModelTextureList> get() = Config.blocks.leavesModels.list
override val logger: Logger? get() = BetterFoliageMod.logDetail override val logger: Logger? get() = BetterFoliageMod.logDetail
override var stateToKey = mutableMapOf<IBlockState, List<String>>() override var variants = mutableMapOf<IBlockState, MutableList<ModelVariant>>()
override var stateToValue = mapOf<IBlockState, TextureAtlasSprite>() override var variantToKey = mutableMapOf<ModelVariant, List<String>>()
override var variantToValue = mapOf<ModelVariant, TextureAtlasSprite>()
override var textureToValue = mutableMapOf<TextureAtlasSprite, LeafInfo>() override var textureToValue = mutableMapOf<TextureAtlasSprite, LeafInfo>()
override fun get(state: IBlockState, world: IBlockAccess, pos: BlockPos, face: EnumFacing): LeafInfo? { override fun get(state: IBlockState, world: IBlockAccess, pos: BlockPos, face: EnumFacing, rand: Int): LeafInfo? {
val baseTexture = stateToValue[state] ?: return null val variant = getVariant(state, rand) ?: return null
val baseTexture = variantToValue[variant] ?: return null
return textureToValue[OptifineCTM.override(baseTexture, world, pos, face)] ?: textureToValue[baseTexture] return textureToValue[OptifineCTM.override(baseTexture, world, pos, face)] ?: textureToValue[baseTexture]
} }
override fun get(state: IBlockState) = stateToValue[state].let { override fun get(state: IBlockState, rand: Int): LeafInfo? {
if (it == null) null else textureToValue[it] val variant = getVariant(state, rand) ?: return null
return variantToValue[variant].let { if (it == null) null else textureToValue[it] }
} }
override fun processStitch(state: IBlockState, key: List<String>, atlas: TextureMap) = atlas.registerSprite(key[0]) override fun processStitch(variant: ModelVariant, key: List<String>, atlas: TextureMap) = atlas.registerSprite(key[0])
override fun processTexture(states: List<IBlockState>, texture: TextureAtlasSprite, atlas: TextureMap) { override fun processTexture(variants: List<ModelVariant>, texture: TextureAtlasSprite, atlas: TextureMap) {
logger?.log(Level.DEBUG, "$logName: leaf texture ${texture.iconName}") logger?.log(Level.DEBUG, "$logName: leaf texture ${texture.iconName}")
logger?.log(Level.DEBUG, "$logName: #states ${states.size}") logger?.log(Level.DEBUG, "$logName: #variants ${variants.size}")
logger?.log(Level.DEBUG, "$logName: #states ${variants.distinctBy { it.state }.size}")
registerLeaf(texture, atlas) registerLeaf(texture, atlas)
OptifineCTM.getAllCTM(states, texture).forEach { OptifineCTM.getAllCTM(variants.map { it.state }, texture).forEach {
logger?.log(Level.DEBUG, "$logName: CTM ${texture.iconName}") logger?.log(Level.DEBUG, "$logName: CTM ${texture.iconName}")
registerLeaf(it, atlas) registerLeaf(it, atlas)
} }

View File

@@ -70,8 +70,11 @@ object Refs {
val MultipartModel = ClassRef("net.minecraftforge.client.model.ModelLoader\$MultipartModel") val MultipartModel = ClassRef("net.minecraftforge.client.model.ModelLoader\$MultipartModel")
val partModels_MPM = FieldRef(MultipartModel, "partModels", List) val partModels_MPM = FieldRef(MultipartModel, "partModels", List)
val BakedQuad = ClassRef("net.minecraft.client.renderer.block.model.BakedQuad")
val resetChangedState = MethodRef(ClassRef("net.minecraftforge.common.config.Configuration"), "resetChangedState", ClassRef.void) val resetChangedState = MethodRef(ClassRef("net.minecraftforge.common.config.Configuration"), "resetChangedState", ClassRef.void)
// Better Foliage // Better Foliage
val BetterFoliageHooks = ClassRef("mods.betterfoliage.client.Hooks") val BetterFoliageHooks = ClassRef("mods.betterfoliage.client.Hooks")
val getAmbientOcclusionLightValueOverride = MethodRef(BetterFoliageHooks, "getAmbientOcclusionLightValueOverride", ClassRef.float, ClassRef.float, IBlockState) val getAmbientOcclusionLightValueOverride = MethodRef(BetterFoliageHooks, "getAmbientOcclusionLightValueOverride", ClassRef.float, ClassRef.float, IBlockState)
@@ -104,6 +107,10 @@ object Refs {
val quadSprite = FieldRef(BufferBuilder, "quadSprite", TextureAtlasSprite) val quadSprite = FieldRef(BufferBuilder, "quadSprite", TextureAtlasSprite)
val CustomColors = ClassRef("CustomColors")
val getColorMultiplier = MethodRef(CustomColors, "getColorMultiplier", ClassRef.int, BakedQuad, IBlockState, IBlockAccess, BlockPos, RenderEnv)
// ShadersMod // ShadersMod
val SVertexBuilder = ClassRef("shadersmod.client.SVertexBuilder") val SVertexBuilder = ClassRef("shadersmod.client.SVertexBuilder")
val sVertexBuilder = FieldRef(BufferBuilder, "sVertexBuilder", SVertexBuilder) val sVertexBuilder = FieldRef(BufferBuilder, "sVertexBuilder", SVertexBuilder)

View File

@@ -73,6 +73,11 @@ fun <T> tryDefault(default: T, work: ()->T) = try { work() } catch (e: Throwable
/** Return a random [Double] value between the given two limits (inclusive min, exclusive max). */ /** Return a random [Double] value between the given two limits (inclusive min, exclusive max). */
fun random(min: Double, max: Double) = Math.random().let { min + (max - min) * it } fun random(min: Double, max: Double) = Math.random().let { min + (max - min) * it }
fun semiRandom(x: Int, y: Int, z: Int, seed: Int): Int {
var value = (x * x + y * y + z * z + x * y + y * z + z * x + (seed * seed)) and 63
value = (3 * x * value + 5 * y * value + 7 * z * value + (11 * seed)) and 63
return value
}
/** /**
* Return this [Double] value if it lies between the two limits. If outside, return the * Return this [Double] value if it lies between the two limits. If outside, return the
* minimum/maximum value correspondingly. * minimum/maximum value correspondingly.

View File

@@ -10,6 +10,7 @@ import mods.octarinecore.common.Double3
import mods.octarinecore.common.Int3 import mods.octarinecore.common.Int3
import mods.octarinecore.common.forgeDirOffsets import mods.octarinecore.common.forgeDirOffsets
import mods.octarinecore.common.plus import mods.octarinecore.common.plus
import mods.octarinecore.semiRandom
import net.minecraft.block.Block import net.minecraft.block.Block
import net.minecraft.block.state.IBlockState import net.minecraft.block.state.IBlockState
import net.minecraft.client.Minecraft import net.minecraft.client.Minecraft
@@ -105,11 +106,7 @@ class BlockContext {
fun isSurroundedBy(predicate: (IBlockState)->Boolean) = forgeDirOffsets.all { predicate(blockState(it)) } fun isSurroundedBy(predicate: (IBlockState)->Boolean) = forgeDirOffsets.all { predicate(blockState(it)) }
/** Get a semi-random value based on the block coordinate and the given seed. */ /** Get a semi-random value based on the block coordinate and the given seed. */
fun random(seed: Int): Int { fun random(seed: Int) = semiRandom(pos.x, pos.y, pos.z, seed)
var value = (pos.x * pos.x + pos.y * pos.y + pos.z * pos.z + pos.x * pos.y + pos.y * pos.z + pos.z * pos.x + (seed * seed)) and 63
value = (3 * pos.x * value + 5 * pos.y * value + 7 * pos.z * value + (11 * seed)) and 63
return value
}
/** Get an array of semi-random values based on the block coordinate. */ /** Get an array of semi-random values based on the block coordinate. */
fun semiRandomArray(num: Int): Array<Int> = Array(num) { random(it) } fun semiRandomArray(num: Int): Array<Int> = Array(num) { random(it) }

View File

@@ -2,7 +2,6 @@ package mods.octarinecore.client.resource
import com.google.common.base.Joiner import com.google.common.base.Joiner
import mods.betterfoliage.loader.Refs import mods.betterfoliage.loader.Refs
import mods.octarinecore.common.config.ConfigurableBlockMatcher
import mods.octarinecore.common.config.IBlockMatcher import mods.octarinecore.common.config.IBlockMatcher
import mods.octarinecore.common.config.ModelTextureList import mods.octarinecore.common.config.ModelTextureList
import mods.octarinecore.filterValuesNotNull import mods.octarinecore.filterValuesNotNull
@@ -13,6 +12,7 @@ import net.minecraft.client.renderer.block.statemap.DefaultStateMapper
import net.minecraft.client.renderer.block.statemap.IStateMapper import net.minecraft.client.renderer.block.statemap.IStateMapper
import net.minecraft.client.renderer.texture.TextureAtlasSprite import net.minecraft.client.renderer.texture.TextureAtlasSprite
import net.minecraft.client.renderer.texture.TextureMap import net.minecraft.client.renderer.texture.TextureMap
import net.minecraft.util.ResourceLocation
import net.minecraftforge.client.event.TextureStitchEvent import net.minecraftforge.client.event.TextureStitchEvent
import net.minecraftforge.client.model.IModel import net.minecraftforge.client.model.IModel
import net.minecraftforge.client.model.ModelLoader import net.minecraftforge.client.model.ModelLoader
@@ -24,20 +24,36 @@ import org.apache.logging.log4j.Logger
class LoadModelDataEvent(val loader: ModelLoader) : Event() class LoadModelDataEvent(val loader: ModelLoader) : Event()
data class ModelVariant(
val state: IBlockState,
val modelLocation: ResourceLocation?,
val weight: Int
)
interface ModelProcessor<T1, T2> { interface ModelProcessor<T1, T2> {
val logger: Logger? val logger: Logger?
var stateToKey: MutableMap<IBlockState, T1> var variants: MutableMap<IBlockState, MutableList<ModelVariant>>
var stateToValue: Map<IBlockState, T2> var variantToKey: MutableMap<ModelVariant, T1>
var variantToValue: Map<ModelVariant, T2>
fun addVariant(state: IBlockState, variant: ModelVariant) { variants.getOrPut(state) { mutableListOf() }.add(variant) }
fun getVariant(state: IBlockState, rand: Int) = variants[state]?.let { it[rand % it.size] }
fun putKeySingle(state: IBlockState, key: T1) {
val variant = ModelVariant(state, null, 1)
variants[state] = mutableListOf(variant)
variantToKey[variant] = key
}
fun onPostLoad() { } fun onPostLoad() { }
fun onPreStitch() { } fun onPreStitch() { }
fun processModelLoad(state: IBlockState, modelLoc: ModelResourceLocation, model: IModel): T1? fun processModelLoad(state: IBlockState, modelLoc: ModelResourceLocation, model: IModel)
fun processStitch(state: IBlockState, key: T1, atlas: TextureMap): T2? fun processStitch(variant: ModelVariant, key: T1, atlas: TextureMap): T2?
@SubscribeEvent(priority = EventPriority.HIGHEST) @SubscribeEvent(priority = EventPriority.HIGHEST)
fun clearBeforeLoadModelData(event: LoadModelDataEvent) { fun clearBeforeLoadModelData(event: LoadModelDataEvent) {
stateToKey.clear() variants.clear()
variantToKey.clear()
} }
@SubscribeEvent @SubscribeEvent
@@ -52,7 +68,7 @@ interface ModelProcessor<T1, T2> {
stateMappings.forEach { mapping -> stateMappings.forEach { mapping ->
if (mapping.key.block != null) stateModels[mapping.value]?.let { model -> if (mapping.key.block != null) stateModels[mapping.value]?.let { model ->
processModelLoad(mapping.key, mapping.value, model)?.let { key -> stateToKey.put(mapping.key, key) } processModelLoad(mapping.key, mapping.value, model)
} }
} }
} }
@@ -61,7 +77,7 @@ interface ModelProcessor<T1, T2> {
@SubscribeEvent(priority = EventPriority.LOW) @SubscribeEvent(priority = EventPriority.LOW)
fun handlePreStitch(event: TextureStitchEvent.Pre) { fun handlePreStitch(event: TextureStitchEvent.Pre) {
onPreStitch() onPreStitch()
stateToValue = stateToKey.mapValues { processStitch(it.key, it.value, event.map) }.filterValuesNotNull() variantToValue = variantToKey.mapValues { processStitch(it.key, it.value, event.map) }.filterValuesNotNull()
} }
} }
@@ -70,30 +86,60 @@ interface TextureListModelProcessor<T2> : ModelProcessor<List<String>, T2> {
val matchClasses: IBlockMatcher val matchClasses: IBlockMatcher
val modelTextures: List<ModelTextureList> val modelTextures: List<ModelTextureList>
override fun processModelLoad(state: IBlockState, modelLoc: ModelResourceLocation, model: IModel): List<String>? { override fun processModelLoad(state: IBlockState, modelLoc: ModelResourceLocation, model: IModel) {
val matchClass = matchClasses.matchingClass(state.block) ?: return null val matchClass = matchClasses.matchingClass(state.block) ?: return
logger?.log(Level.DEBUG, "$logName: block state ${state.toString()}") logger?.log(Level.DEBUG, "$logName: block state ${state.toString()}")
logger?.log(Level.DEBUG, "$logName: class ${state.block.javaClass.name} matches ${matchClass.name}") logger?.log(Level.DEBUG, "$logName: class ${state.block.javaClass.name} matches ${matchClass.name}")
val allModels = model.modelBlockAndLoc val allModels = model.modelBlockAndLoc.distinctBy { it.second }
if (allModels.isEmpty()) { if (allModels.isEmpty()) {
logger?.log(Level.DEBUG, "$logName: no models found") logger?.log(Level.DEBUG, "$logName: no models found")
return null return
} }
allModels.forEach { blockLoc -> allModels.forEach { blockLoc ->
modelTextures.firstOrNull { blockLoc.derivesFrom(it.modelLocation) }?.let{ modelMatch -> val modelMatch = modelTextures.firstOrNull { blockLoc.derivesFrom(it.modelLocation) }
logger?.log(Level.DEBUG, "$logName: model ${blockLoc.second} matches ${modelMatch.modelLocation.toString()}") if (modelMatch != null) {
logger?.log(Level.DEBUG, "$logName: model ${blockLoc.second} matches ${modelMatch.modelLocation}")
val textures = modelMatch.textureNames.map { it to blockLoc.first.resolveTextureName(it) } val textures = modelMatch.textureNames.map { it to blockLoc.first.resolveTextureName(it) }
val texMapString = Joiner.on(", ").join(textures.map { "${it.first}=${it.second}" }) val texMapString = Joiner.on(", ").join(textures.map { "${it.first}=${it.second}" })
logger?.log(Level.DEBUG, "$logName: textures [$texMapString]") logger?.log(Level.DEBUG, "$logName: textures [$texMapString]")
return if (textures.all { it.second != "missingno" }) textures.map { it.second } else null if (textures.all { it.second != "missingno" }) {
// found a valid variant (all required textures exist)
val variant = ModelVariant(state, blockLoc.second, 1)
addVariant(state, variant)
variantToKey[variant] = textures.map { it.second }
}
} }
} }
logger?.log(Level.DEBUG, "$logName: no matching models found")
return null
} }
// override fun processModelLoad(state: IBlockState, modelLoc: ModelResourceLocation, model: IModel): List<String>? {
// val matchClass = matchClasses.matchingClass(state.block) ?: return null
// logger?.log(Level.DEBUG, "$logName: block state ${state.toString()}")
// logger?.log(Level.DEBUG, "$logName: class ${state.block.javaClass.name} matches ${matchClass.name}")
//
// val allModels = model.modelBlockAndLoc
// if (allModels.isEmpty()) {
// logger?.log(Level.DEBUG, "$logName: no models found")
// return null
// }
// allModels.forEach { blockLoc ->
// modelTextures.firstOrNull { blockLoc.derivesFrom(it.modelLocation) }?.let{ modelMatch ->
// logger?.log(Level.DEBUG, "$logName: model ${blockLoc.second} matches ${modelMatch.modelLocation.toString()}")
//
// val textures = modelMatch.textureNames.map { it to blockLoc.first.resolveTextureName(it) }
// val texMapString = Joiner.on(", ").join(textures.map { "${it.first}=${it.second}" })
// logger?.log(Level.DEBUG, "$logName: textures [$texMapString]")
//
// return if (textures.all { it.second != "missingno" }) textures.map { it.second } else null
// }
// }
// logger?.log(Level.DEBUG, "$logName: no matching models found")
// return null
// }
} }
interface TextureMediatedRegistry<T1, T3> : ModelProcessor<T1, TextureAtlasSprite> { interface TextureMediatedRegistry<T1, T3> : ModelProcessor<T1, TextureAtlasSprite> {
@@ -105,9 +151,9 @@ interface TextureMediatedRegistry<T1, T3> : ModelProcessor<T1, TextureAtlasSprit
textureToValue.clear() textureToValue.clear()
super.handlePreStitch(event) super.handlePreStitch(event)
val textureToStates = stateToValue.entries.groupBy(keySelector = { it.value }, valueTransform = { it.key }) val textureToVariants = variantToValue.entries.groupBy(keySelector = { it.value }, valueTransform = { it.key })
stateToValue.values.toSet().forEach { processTexture(textureToStates[it]!!, it, event.map) } variantToValue.values.toSet().forEach { processTexture(textureToVariants[it]!!, it, event.map) }
} }
fun processTexture(states: List<IBlockState>, texture: TextureAtlasSprite, atlas: TextureMap) fun processTexture(states: List<ModelVariant>, texture: TextureAtlasSprite, atlas: TextureMap)
} }

View File

@@ -1,2 +1,6 @@
// Vanilla
block/grass,top block/grass,top
block/cube_bottom_top,top block/cube_bottom_top,top
// Lithos Core
block/soil/grass_master,top

View File

@@ -2,6 +2,8 @@ key.betterfoliage.gui=Open Settings
betterfoliage.global.enabled=Enable Mod betterfoliage.global.enabled=Enable Mod
betterfoliage.global.enabled.tooltip=If set to false, BetterFoliage will not render anything betterfoliage.global.enabled.tooltip=If set to false, BetterFoliage will not render anything
betterfoliage.global.nVidia=nVidia GPU
betterfoliage.global.nVidia.tooltip=Specify whether you have an nVidia GPU
betterfoliage.enabled=Enable betterfoliage.enabled=Enable
betterfoliage.enabled.tooltip=Is this feature enabled? betterfoliage.enabled.tooltip=Is this feature enabled?
@@ -92,6 +94,19 @@ betterfoliage.blocks.cactusBlacklist.arrayEntry=%d entries
betterfoliage.blocks.cactusWhitelist.tooltip=Blocks recognized as Cactus. Has an impact on Better Cactus betterfoliage.blocks.cactusWhitelist.tooltip=Blocks recognized as Cactus. Has an impact on Better Cactus
betterfoliage.blocks.cactusBlacklist.tooltip=Blocks never accepted Cactus. Has an impact on Better Cactus betterfoliage.blocks.cactusBlacklist.tooltip=Blocks never accepted Cactus. Has an impact on Better Cactus
betterfoliage.blocks.myceliumWhitelist=Mycelium Whitelist
betterfoliage.blocks.myceliumBlacklist=Mycelium Blacklist
betterfoliage.blocks.myceliumWhitelist.arrayEntry=%d entries
betterfoliage.blocks.myceliumBlacklist.arrayEntry=%d entries
betterfoliage.blocks.myceliumWhitelist.tooltip=Blocks recognized as Mycelium. Has an impact on Better Grass
betterfoliage.blocks.myceliumBlacklist.tooltip=Blocks never accepted Mycelium. Has an impact on Better Grass
betterfoliage.blocks.netherrackWhitelist=Netherrack Whitelist
betterfoliage.blocks.netherrackBlacklist=Netherrack Blacklist
betterfoliage.blocks.netherrackWhitelist.arrayEntry=%d entries
betterfoliage.blocks.netherrackBlacklist.arrayEntry=%d entries
betterfoliage.blocks.netherrackWhitelist.tooltip=Blocks recognized as Netherrack. Has an impact on Netherrack Vines
betterfoliage.blocks.netherrackBlacklist.tooltip=Blocks never accepted Netherrack. Has an impact on Netherrack Vines
betterfoliage.leaves=Extra Leaves betterfoliage.leaves=Extra Leaves
betterfoliage.leaves.tooltip=Extra round leaves on leaf blocks betterfoliage.leaves.tooltip=Extra round leaves on leaf blocks

View File

@@ -1,5 +1,12 @@
// Vanilla
block/column_side,end,end,side block/column_side,end,end,side
block/cube_column,end,end,side block/cube_column,end,end,side
block/cube_all,all,all,all block/cube_all,all,all,all
// Agricultural Revolution
agriculturalrevolution:block/palmlog,top,top,texture agriculturalrevolution:block/palmlog,top,top,texture
// Lithos Core
block/column_top,end,end,side_a,side_b
block/column_side_x,end,end,side_a,side_b
block/column_side_z,end,end,side_a,side_b

View File

@@ -0,0 +1,5 @@
// Vanilla
net.minecraft.block.BlockMycelium
// NetherEx
nex.block.BlockMycelium

View File

@@ -0,0 +1,5 @@
// Vanilla
net.minecraft.block.BlockNetherrack
// NetherEx
nex.block.BlockNetherrack