port to MC 1.8

This commit is contained in:
octarine-noise
2016-01-09 12:55:52 +01:00
parent f44043bb0b
commit 8460103030
87 changed files with 1144 additions and 940 deletions

View File

@@ -1,19 +1,15 @@
package mods.betterfoliage
import cpw.mods.fml.common.FMLCommonHandler
import cpw.mods.fml.common.Mod
import cpw.mods.fml.common.event.FMLPostInitializationEvent
import cpw.mods.fml.common.event.FMLPreInitializationEvent
import cpw.mods.fml.common.network.NetworkCheckHandler
import cpw.mods.fml.relauncher.Side
import mods.betterfoliage.client.Client
import mods.betterfoliage.client.config.Config
import mods.betterfoliage.client.integration.ShadersModIntegration
import mods.betterfoliage.client.integration.TFCIntegration
import mods.betterfoliage.loader.Refs
import mods.octarinecore.metaprog.ClassRef
import net.minecraftforge.common.config.Configuration
import org.apache.logging.log4j.Level.*
import net.minecraftforge.fml.common.FMLCommonHandler
import net.minecraftforge.fml.common.Mod
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent
import net.minecraftforge.fml.common.network.NetworkCheckHandler
import net.minecraftforge.fml.relauncher.Side
import org.apache.logging.log4j.Level.INFO
import org.apache.logging.log4j.Logger
@Mod(
@@ -28,7 +24,7 @@ object BetterFoliageMod {
const val MOD_NAME = "Better Foliage"
const val DOMAIN = "betterfoliage"
const val LEGACY_DOMAIN = "bettergrassandleaves"
const val MC_VERSIONS = "[1.7.10]"
const val MC_VERSIONS = "[1.8]"
const val GUI_FACTORY = "mods.betterfoliage.client.gui.ConfigGuiFactory"
var log: Logger? = null

View File

@@ -1,19 +1,20 @@
package mods.betterfoliage.client
import cpw.mods.fml.client.FMLClientHandler
import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly
import mods.betterfoliage.BetterFoliageMod
import mods.betterfoliage.client.gui.ConfigGuiFactory
import mods.betterfoliage.client.integration.CLCIntegration
import mods.betterfoliage.client.integration.ShadersModIntegration
import mods.betterfoliage.client.integration.TFCIntegration
import mods.betterfoliage.client.render.*
import mods.betterfoliage.client.texture.*
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.octarinecore.client.KeyHandler
import mods.octarinecore.client.resource.CenteringTextureGenerator
import mods.octarinecore.client.resource.GeneratorPack
import net.minecraft.client.Minecraft
import net.minecraftforge.fml.client.FMLClientHandler
import net.minecraftforge.fml.relauncher.Side
import net.minecraftforge.fml.relauncher.SideOnly
import org.apache.logging.log4j.Level
/**
@@ -65,9 +66,7 @@ object Client {
GrassRegistry,
LeafWindTracker,
RisingSoulTextures,
TFCIntegration,
ShadersModIntegration,
CLCIntegration
ShadersModIntegration
)
fun log(level: Level, msg: String) = BetterFoliageMod.log!!.log(level, msg)

View File

@@ -2,32 +2,33 @@
@file:SideOnly(Side.CLIENT)
package mods.betterfoliage.client
import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly
import mods.betterfoliage.client.config.Config
import mods.betterfoliage.client.render.EntityFallingLeavesFX
import mods.betterfoliage.client.render.EntityRisingSoulFX
import mods.betterfoliage.client.render.down1
import mods.betterfoliage.client.render.up1
import mods.octarinecore.client.render.blockContext
import mods.octarinecore.client.resource.LoadModelDataEvent
import mods.octarinecore.common.plus
import net.minecraft.block.Block
import net.minecraft.client.Minecraft
import net.minecraft.block.state.IBlockState
import net.minecraft.client.renderer.BlockRendererDispatcher
import net.minecraft.client.renderer.WorldRenderer
import net.minecraft.init.Blocks
import net.minecraft.util.BlockPos
import net.minecraft.util.EnumFacing
import net.minecraft.util.EnumWorldBlockLayer
import net.minecraft.util.EnumWorldBlockLayer.CUTOUT
import net.minecraft.util.EnumWorldBlockLayer.CUTOUT_MIPPED
import net.minecraft.world.IBlockAccess
import net.minecraft.world.World
import net.minecraftforge.client.model.ModelLoader
import net.minecraftforge.common.MinecraftForge
import net.minecraftforge.fml.relauncher.Side
import net.minecraftforge.fml.relauncher.SideOnly
fun getRenderTypeOverride(blockAccess: IBlockAccess, x: Int, y: Int, z: Int, block: Block, original: Int): Int {
if (!Config.enabled) return original;
// universal sign for DON'T RENDER ME!
if (original == -1) return original;
return blockContext.let { ctx ->
ctx.set(blockAccess, x, y, z)
Client.renderers.find { it.isEligible(ctx) }?.renderId ?: original
}
}
fun shouldRenderBlockSideOverride(original: Boolean, blockAccess: IBlockAccess, x: Int, y: Int, z: Int, side: Int): Boolean {
return original || (Config.enabled && Config.roundLogs.enabled && Config.blocks.logs.matchesID(blockAccess.getBlock(x, y, z)));
fun shouldRenderBlockSideOverride(original: Boolean, blockAccess: IBlockAccess, pos: BlockPos, side: EnumFacing): Boolean {
return original || (Config.enabled && Config.roundLogs.enabled && Config.blocks.logs.matchesID(blockAccess.getBlockState(pos).block));
}
fun getAmbientOcclusionLightValueOverride(original: Float, block: Block): Float {
@@ -39,20 +40,58 @@ fun getUseNeighborBrightnessOverride(original: Boolean, block: Block): Boolean {
return original || (Config.enabled && Config.roundLogs.enabled && Config.blocks.logs.matchesID(block));
}
fun onRandomDisplayTick(block: Block, world: World, x: Int, y: Int, z: Int) {
fun onRandomDisplayTick(world: World, state: IBlockState, pos: BlockPos) {
if (Config.enabled &&
Config.risingSoul.enabled &&
block == Blocks.soul_sand &&
world.isAirBlock(x, y + 1, z) &&
state.block == Blocks.soul_sand &&
world.isAirBlock(pos + up1) &&
Math.random() < Config.risingSoul.chance) {
EntityRisingSoulFX(world, x, y, z).addIfValid()
EntityRisingSoulFX(world, pos).addIfValid()
}
if (Config.enabled &&
Config.fallingLeaves.enabled &&
Config.blocks.leaves.matchesID(block) &&
world.isAirBlock(x, y - 1, z) &&
Config.blocks.leaves.matchesID(state.block) &&
world.isAirBlock(pos + down1) &&
Math.random() < Config.fallingLeaves.chance) {
EntityFallingLeavesFX(world, x, y, z).addIfValid()
EntityFallingLeavesFX(world, pos).addIfValid()
}
}
fun onAfterLoadModelDefinitions(loader: ModelLoader) {
MinecraftForge.EVENT_BUS.post(LoadModelDataEvent(loader))
}
fun renderWorldBlock(dispatcher: BlockRendererDispatcher,
state: IBlockState,
pos: BlockPos,
blockAccess: IBlockAccess,
worldRenderer: WorldRenderer,
layer: EnumWorldBlockLayer
): Boolean {
val isCutout = layer == CUTOUT_MIPPED || layer == CUTOUT
val needsCutout = state.block.canRenderInLayer(CUTOUT_MIPPED) || state.block.canRenderInLayer(CUTOUT)
val canRender = (isCutout && needsCutout) || state.block.canRenderInLayer(layer)
blockContext.let { ctx ->
ctx.set(blockAccess, pos)
Client.renderers.forEach { renderer ->
if (renderer.isEligible(ctx)) {
return if (renderer.moveToCutout) {
if (isCutout) renderer.render(ctx, dispatcher, worldRenderer, layer) else false
} else {
renderer.render(ctx, dispatcher, worldRenderer, layer)
}
}
}
}
return if (canRender) dispatcher.renderBlock(state, pos, blockAccess, worldRenderer) else false
}
fun canRenderBlockInLayer(block: Block, layer: EnumWorldBlockLayer): Boolean {
if (layer == CUTOUT_MIPPED && !block.canRenderInLayer(CUTOUT)) {
return true
}
return block.canRenderInLayer(layer)
}

View File

@@ -1,11 +1,10 @@
package mods.betterfoliage.client.config
import cpw.mods.fml.common.eventhandler.SubscribeEvent
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.config.ConfigPropertyBase
import mods.octarinecore.common.config.ConfigPropertyBase
import mods.octarinecore.metaprog.getJavaClass
import net.minecraft.block.Block
import net.minecraft.client.multiplayer.WorldClient
@@ -13,6 +12,7 @@ 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.

View File

@@ -1,14 +1,14 @@
package mods.betterfoliage.client.config
import cpw.mods.fml.client.event.ConfigChangedEvent
import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly
import mods.betterfoliage.BetterFoliageMod
import mods.betterfoliage.client.gui.BiomeListConfigEntry
import mods.octarinecore.config.*
import mods.octarinecore.common.config.*
import mods.octarinecore.metaprog.reflectField
import net.minecraft.client.Minecraft
import net.minecraft.world.biome.BiomeGenBase
import net.minecraftforge.fml.client.event.ConfigChangedEvent
import net.minecraftforge.fml.relauncher.Side
import net.minecraftforge.fml.relauncher.SideOnly
// BetterFoliage-specific property delegates
private fun featureEnable() = boolean(true).lang("enabled")

View File

@@ -1,16 +1,16 @@
package mods.betterfoliage.client.gui
import cpw.mods.fml.client.config.GuiConfig
import cpw.mods.fml.client.config.GuiConfigEntries
import cpw.mods.fml.client.config.IConfigElement
import mods.octarinecore.client.gui.IdListConfigEntry
import net.minecraft.world.biome.BiomeGenBase
import net.minecraftforge.fml.client.config.GuiConfig
import net.minecraftforge.fml.client.config.GuiConfigEntries
import net.minecraftforge.fml.client.config.IConfigElement
/** Toggleable list of all defined biomes. */
class BiomeListConfigEntry(
owningScreen: GuiConfig,
owningEntryList: GuiConfigEntries,
configElement: IConfigElement<*>)
owningScreen: GuiConfig,
owningEntryList: GuiConfigEntries,
configElement: IConfigElement)
: IdListConfigEntry<BiomeGenBase>(owningScreen, owningEntryList, configElement) {
override val baseSet: List<BiomeGenBase> get() = BiomeGenBase.getBiomeGenArray().filterNotNull()

View File

@@ -1,18 +1,17 @@
package mods.betterfoliage.client.gui
import cpw.mods.fml.client.IModGuiFactory
import cpw.mods.fml.client.IModGuiFactory.RuntimeOptionCategoryElement
import cpw.mods.fml.client.config.GuiConfig
import mods.betterfoliage.BetterFoliageMod
import mods.betterfoliage.client.config.Config
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiScreen
import net.minecraftforge.fml.client.IModGuiFactory
import net.minecraftforge.fml.client.config.GuiConfig
class ConfigGuiFactory : IModGuiFactory {
override fun mainConfigGuiClass() = ConfigGuiBetterFoliage::class.java
override fun runtimeGuiCategories() = hashSetOf<RuntimeOptionCategoryElement>()
override fun getHandlerFor(element: RuntimeOptionCategoryElement?) = null
override fun runtimeGuiCategories() = hashSetOf<IModGuiFactory.RuntimeOptionCategoryElement>()
override fun getHandlerFor(element: IModGuiFactory.RuntimeOptionCategoryElement?) = null
override fun initialize(minecraftInstance: Minecraft?) { }
class ConfigGuiBetterFoliage(parentScreen: GuiScreen?) : GuiConfig(

View File

@@ -1,19 +0,0 @@
package mods.betterfoliage.client.integration
import mods.betterfoliage.client.Client
import mods.betterfoliage.loader.Refs
import mods.octarinecore.client.render.brightnessComponents
import org.apache.logging.log4j.Level.*
/**
* Integration for Colored Lights Core.
*/
object CLCIntegration {
init {
if (Refs.CLCLoadingPlugin.element != null) {
Client.log(INFO, "Colored Lights Core integration enabled")
brightnessComponents = listOf(4, 8, 12, 16, 20)
}
}
}

View File

@@ -1,14 +1,17 @@
package mods.betterfoliage.client.integration
import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly
import mods.betterfoliage.client.Client
import mods.betterfoliage.client.config.Config
import mods.betterfoliage.loader.Refs
import mods.octarinecore.metaprog.allAvailable
import net.minecraft.block.Block
import net.minecraft.block.BlockTallGrass
import net.minecraft.block.state.IBlockState
import net.minecraft.client.renderer.WorldRenderer
import net.minecraft.init.Blocks
import org.apache.logging.log4j.Level.*
import net.minecraftforge.fml.relauncher.Side
import net.minecraftforge.fml.relauncher.SideOnly
import org.apache.logging.log4j.Level.INFO
/**
* Integration for ShadersMod.
@@ -17,37 +20,53 @@ import org.apache.logging.log4j.Level.*
object ShadersModIntegration {
@JvmStatic var isPresent = false
@JvmStatic val tallGrassEntityData = Block.blockRegistry.getIDForObject(Blocks.tallgrass) and 65535 or (Blocks.tallgrass.renderType shl 16)
@JvmStatic val leavesEntityData = Block.blockRegistry.getIDForObject(Blocks.leaves) and 65535 or (Blocks.leaves.renderType shl 16)
@JvmStatic val tallGrassEntityData = entityDataFor(Blocks.tallgrass.defaultState.withProperty(BlockTallGrass.TYPE, BlockTallGrass.EnumType.GRASS))
@JvmStatic val leavesEntityData = entityDataFor(Blocks.leaves.defaultState)
fun entityDataFor(blockState: IBlockState) =
(Block.blockRegistry.getIDForObject(blockState.block).toLong() and 65535) or
((blockState.block.renderType.toLong() and 65535) shl 16) or
(blockState.block.getMetaFromState(blockState).toLong() shl 32)
/**
* Called from transformed ShadersMod code.
* @see mods.betterfoliage.loader.BetterFoliageTransformer
*/
@JvmStatic fun getBlockIdOverride(original: Int, block: Block): Int {
if (Config.blocks.leaves.matchesID(original and 65535)) return leavesEntityData
if (Config.blocks.crops.matchesID(original and 65535)) return tallGrassEntityData
@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
return original
}
init {
if (allAvailable(Refs.pushEntity_I, Refs.popEntity)) {
if (allAvailable(Refs.sVertexBuilder, Refs.pushEntity_state, Refs.pushEntity_num, Refs.popEntity)) {
Client.log(INFO, "ShadersMod integration enabled")
isPresent = true
}
}
/** Quads rendered inside this block will behave as tallgrass blocks in shader programs. */
inline fun grass(enabled: Boolean = true, func: ()->Unit) {
if (isPresent && enabled) Refs.pushEntity_I.invokeStatic(tallGrassEntityData)
func()
if (isPresent && enabled) Refs.popEntity.invokeStatic()
inline fun grass(renderer: WorldRenderer, enabled: Boolean = true, func: ()->Unit) {
if ((isPresent && enabled)) {
val vertexBuilder = Refs.sVertexBuilder.get(renderer)!!
Refs.pushEntity_num.invoke(vertexBuilder, tallGrassEntityData)
func()
Refs.popEntity.invoke(vertexBuilder)
} else {
func()
}
}
/** Quads rendered inside this block will behave as leaf blocks in shader programs. */
inline fun leaves(enabled: Boolean = true, func: ()->Unit) {
if (isPresent && enabled) Refs.pushEntity_I.invokeStatic(leavesEntityData)
func()
if (isPresent && enabled) Refs.popEntity.invokeStatic()
inline fun leaves(renderer: WorldRenderer, enabled: Boolean = true, func: ()->Unit) {
if ((isPresent && enabled)) {
val vertexBuilder = Refs.sVertexBuilder.get(renderer)!!
Refs.pushEntity_num.invoke(vertexBuilder, leavesEntityData.toLong())
func()
Refs.popEntity.invoke(vertexBuilder)
} else {
func()
}
}
}

View File

@@ -1,37 +0,0 @@
package mods.betterfoliage.client.integration
import cpw.mods.fml.common.Loader
import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly
import mods.betterfoliage.client.Client
import mods.octarinecore.client.render.Axis
import net.minecraft.block.Block
import org.apache.logging.log4j.Level
/**
* Integration for TerraFirmaCraft
*/
@SideOnly(Side.CLIENT)
object TFCIntegration {
@JvmStatic val vanillaLogAxis = Client.logRenderer.axisFunc
init {
if (Loader.isModLoaded("terrafirmacraft")) {
Client.log(Level.INFO, "TerraFirmaCraft found - setting up compatibility")
// patch axis detection for log blocks to support TFC logs
Client.logRenderer.axisFunc = { block: Block, meta: Int ->
block.javaClass.name.let {
if (it.startsWith("com.bioxx.tfc")) {
if (it.contains("Horiz"))
if (meta shr 3 == 0) Axis.Z else Axis.X
else
Axis.Y
} else {
vanillaLogAxis(block, meta)
}
}
}
}
}
}

View File

@@ -1,11 +1,35 @@
package mods.betterfoliage.client.render
import mods.betterfoliage.client.config.BlockMatcher
import mods.betterfoliage.client.render.AbstractRenderColumn.BlockType.*
import mods.betterfoliage.client.render.AbstractRenderColumn.QuadrantType.*
import mods.octarinecore.client.render.*
import net.minecraft.block.Block
import net.minecraft.client.renderer.RenderBlocks
import net.minecraftforge.common.util.ForgeDirection.*
import mods.octarinecore.client.resource.BlockTextureInspector
import mods.octarinecore.common.Int3
import mods.octarinecore.common.Rotation
import mods.octarinecore.common.face
import mods.octarinecore.common.rot
import net.minecraft.block.state.IBlockState
import net.minecraft.client.renderer.BlockRendererDispatcher
import net.minecraft.client.renderer.WorldRenderer
import net.minecraft.client.renderer.texture.TextureAtlasSprite
import net.minecraft.client.renderer.texture.TextureMap
import net.minecraft.util.EnumFacing
import net.minecraft.util.EnumFacing.*
import net.minecraft.util.EnumWorldBlockLayer
data class ColumnInfo(val topTexture: TextureAtlasSprite,
val bottomTexture: TextureAtlasSprite,
val sideTexture: TextureAtlasSprite)
open class ColumnTextures(val matcher: BlockMatcher) : BlockTextureInspector<ColumnInfo>() {
init {
matchClassAndModel(matcher, "block/column_side", listOf("end", "end", "side"))
matchClassAndModel(matcher, "block/cube_column", listOf("end", "end", "side"))
}
override fun processTextures(textures: List<TextureAtlasSprite>, atlas: TextureMap) =
ColumnInfo(textures[0], textures[1], textures[2])
}
/** Index of SOUTH-EAST quadrant. */
const val SE = 0
@@ -30,7 +54,7 @@ abstract class AbstractRenderColumn(modId: String) : AbstractBlockRenderingHandl
// ============================
abstract val radiusSmall: Double
abstract val radiusLarge: Double
abstract val surroundPredicate: (Block) -> Boolean
abstract val surroundPredicate: (IBlockState) -> Boolean
abstract val connectPerpendicular: Boolean
abstract val connectSolids: Boolean
abstract val lenientConnect: Boolean
@@ -89,26 +113,26 @@ abstract class AbstractRenderColumn(modId: String) : AbstractBlockRenderingHandl
val transitionTop = model { mix(sideRoundLarge.model, sideRoundSmall.model) { it > 1 } }
val transitionBottom = model { mix(sideRoundSmall.model, sideRoundLarge.model) { it > 1 } }
val sideTexture = { ctx: ShadingContext, qi: Int, q: Quad -> if ((qi and 1) == 0) ctx.icon(SOUTH) else ctx.icon(EAST) }
val upTexture = { ctx: ShadingContext, qi: Int, q: Quad -> ctx.icon(UP) }
val downTexture = { ctx: ShadingContext, qi: Int, q: Quad -> ctx.icon(DOWN) }
inline fun continous(q1: QuadrantType, q2: QuadrantType) =
q1 == q2 || ((q1 == SQUARE || q1 == INVISIBLE) && (q2 == SQUARE || q2 == INVISIBLE))
abstract val axisFunc: (Block, Int)->Axis
abstract val blockPredicate: (Block, Int)->Boolean
abstract val axisFunc: (IBlockState)->EnumFacing.Axis
abstract val blockPredicate: (IBlockState)->Boolean
abstract val sideTexture: (ShadingContext, Int, Quad)->TextureAtlasSprite?
abstract val upTexture: (ShadingContext, Int, Quad)->TextureAtlasSprite?
abstract val downTexture: (ShadingContext, Int, Quad)->TextureAtlasSprite?
@Suppress("NON_EXHAUSTIVE_WHEN")
override fun render(ctx: BlockContext, parent: RenderBlocks): Boolean {
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean {
if (ctx.isSurroundedBy(surroundPredicate) ) return false
// get AO data
if (renderWorldBlockBase(parent, face = neverRender)) return true
modelRenderer.updateShading(Int3.zero, allFaces)
// check log neighborhood
val logAxis = ctx.blockAxis
val baseRotation = rotationFromUp[(logAxis to Dir.P).face.ordinal]
val baseRotation = rotationFromUp[(logAxis to AxisDirection.POSITIVE).face.ordinal]
val upType = ctx.blockType(baseRotation, logAxis, Int3(0, 1, 0))
val downType = ctx.blockType(baseRotation, logAxis, Int3(0, -1, 0))
@@ -141,6 +165,7 @@ abstract class AbstractRenderColumn(modId: String) : AbstractBlockRenderingHandl
}
if (sideModel != null) modelRenderer.render(
renderer,
sideModel,
rotation,
blockContext.blockCenter,
@@ -192,6 +217,7 @@ abstract class AbstractRenderColumn(modId: String) : AbstractBlockRenderingHandl
}
if (upModel != null) modelRenderer.render(
renderer,
upModel,
rotation,
blockContext.blockCenter,
@@ -200,6 +226,7 @@ abstract class AbstractRenderColumn(modId: String) : AbstractBlockRenderingHandl
postProcess = noPost
)
if (downModel != null) modelRenderer.render(
renderer,
downModel,
rotation,
blockContext.blockCenter,
@@ -283,19 +310,18 @@ abstract class AbstractRenderColumn(modId: String) : AbstractBlockRenderingHandl
}
/** Get the axis of the block */
val BlockContext.blockAxis: Axis get() = axisFunc(block(Int3.zero), meta(Int3.zero))
val BlockContext.blockAxis: Axis get() = axisFunc(blockState(Int3.zero))
/**
* Get the type of the block at the given offset in a rotated reference frame.
*/
fun BlockContext.blockType(rotation: Rotation, axis: Axis, offset: Int3): BlockType {
val offsetRot = offset.rotate(rotation)
val logBlock = block(offsetRot)
val logMeta = meta(offsetRot)
return if (!blockPredicate(logBlock, logMeta)) {
if (logBlock.isOpaqueCube) SOLID else NONSOLID
val state = blockState(offsetRot)
return if (!blockPredicate(state)) {
if (state.block.isOpaqueCube) SOLID else NONSOLID
} else {
if (axisFunc(logBlock, logMeta) == axis) PARALLEL else PERPENDICULAR
if (axisFunc(state) == axis) PARALLEL else PERPENDICULAR
}
}
}

View File

@@ -1,31 +1,31 @@
package mods.betterfoliage.client.render
import cpw.mods.fml.common.FMLCommonHandler
import cpw.mods.fml.common.eventhandler.SubscribeEvent
import cpw.mods.fml.common.gameevent.TickEvent
import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly
import mods.betterfoliage.client.config.Config
import mods.betterfoliage.client.texture.LeafRegistry
import mods.octarinecore.PI2
import mods.octarinecore.client.render.AbstractEntityFX
import mods.octarinecore.client.render.Double3
import mods.octarinecore.client.render.HSB
import mods.octarinecore.common.Double3
import mods.octarinecore.minmax
import mods.octarinecore.random
import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.Tessellator
import net.minecraft.client.renderer.WorldRenderer
import net.minecraft.util.BlockPos
import net.minecraft.util.MathHelper
import net.minecraft.world.World
import net.minecraftforge.common.MinecraftForge
import net.minecraftforge.common.util.ForgeDirection.DOWN
import net.minecraftforge.event.world.WorldEvent
import net.minecraftforge.fml.common.FMLCommonHandler
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import net.minecraftforge.fml.common.gameevent.TickEvent
import net.minecraftforge.fml.relauncher.Side
import net.minecraftforge.fml.relauncher.SideOnly
import org.lwjgl.opengl.GL11
import java.lang.Math.*
import java.util.*
class EntityFallingLeavesFX(world: World, x: Int, y: Int, z: Int) :
AbstractEntityFX(world, x.toDouble() + 0.5, y.toDouble(), z.toDouble() + 0.5) {
class EntityFallingLeavesFX(world: World, pos: BlockPos) :
AbstractEntityFX(world, pos.x.toDouble() + 0.5, pos.y.toDouble(), pos.z.toDouble() + 0.5) {
companion object {
@JvmStatic val biomeBrightnessMultiplier = 0.5f
@@ -41,10 +41,10 @@ AbstractEntityFX(world, x.toDouble() + 0.5, y.toDouble(), z.toDouble() + 0.5) {
motionY = -Config.fallingLeaves.speed
particleScale = Config.fallingLeaves.size.toFloat() * 0.1f
val block = world.getBlock(x, y, z)
LeafRegistry.leaves[block.getIcon(world, x, y, z, DOWN.ordinal)]?.let {
val state = world.getBlockState(pos)
LeafRegistry[world.getBlockState(pos)]?.let {
particleIcon = it.particleTextures[rand.nextInt(1024)]
calculateParticleColor(it.averageColor, block.colorMultiplier(world, x, y, z))
calculateParticleColor(it.averageColor, state.block.colorMultiplier(world, pos))
}
}
@@ -67,9 +67,9 @@ AbstractEntityFX(world, x.toDouble() + 0.5, y.toDouble(), z.toDouble() + 0.5) {
}
}
override fun render(tessellator: Tessellator, partialTickTime: Float) {
override fun render(worldRenderer: WorldRenderer, partialTickTime: Float) {
if (Config.fallingLeaves.opacityHack) GL11.glDepthMask(true)
renderParticleQuad(tessellator, partialTickTime, rotation = particleRot, isMirrored = isMirrored)
renderParticleQuad(worldRenderer, partialTickTime, rotation = particleRot, isMirrored = isMirrored)
}
fun calculateParticleColor(textureAvgColor: Int, blockColor: Int) {

View File

@@ -1,22 +1,23 @@
package mods.betterfoliage.client.render
import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly
import mods.betterfoliage.BetterFoliageMod
import mods.betterfoliage.client.Client
import mods.betterfoliage.client.config.Config
import mods.octarinecore.client.render.AbstractEntityFX
import mods.octarinecore.client.render.Double3
import mods.octarinecore.client.resource.ResourceHandler
import mods.octarinecore.common.Double3
import mods.octarinecore.forEachPairIndexed
import net.minecraft.client.renderer.Tessellator
import net.minecraft.client.renderer.WorldRenderer
import net.minecraft.util.BlockPos
import net.minecraft.util.MathHelper
import net.minecraft.world.World
import org.apache.logging.log4j.Level.*
import net.minecraftforge.fml.relauncher.Side
import net.minecraftforge.fml.relauncher.SideOnly
import org.apache.logging.log4j.Level.INFO
import java.util.*
class EntityRisingSoulFX(world: World, x: Int, y: Int, z: Int) :
AbstractEntityFX(world, x.toDouble() + 0.5, y.toDouble() + 1.0, z.toDouble() + 0.5) {
class EntityRisingSoulFX(world: World, pos: BlockPos) :
AbstractEntityFX(world, pos.x.toDouble() + 0.5, pos.y.toDouble() + 1.0, pos.z.toDouble() + 0.5) {
val particleTrail: Deque<Double3> = linkedListOf()
val initialPhase = rand.nextInt(64)
@@ -40,11 +41,11 @@ AbstractEntityFX(world, x.toDouble() + 0.5, y.toDouble() + 1.0, z.toDouble() + 0
if (!Config.enabled) setDead()
}
override fun render(tessellator: Tessellator, partialTickTime: Float) {
override fun render(worldRenderer: WorldRenderer, partialTickTime: Float) {
var alpha = Config.risingSoul.opacity
if (particleAge > particleMaxAge - 40) alpha *= (particleMaxAge - particleAge) / 40.0f
renderParticleQuad(tessellator, partialTickTime,
renderParticleQuad(worldRenderer, partialTickTime,
size = Config.risingSoul.headSize * 0.25,
alpha = alpha
)
@@ -53,7 +54,7 @@ AbstractEntityFX(world, x.toDouble() + 0.5, y.toDouble() + 1.0, z.toDouble() + 0
particleTrail.forEachPairIndexed { idx, current, previous ->
scale *= Config.risingSoul.sizeDecay
alpha *= Config.risingSoul.opacityDecay
if (idx % Config.risingSoul.trailDensity == 0) renderParticleQuad(tessellator, partialTickTime,
if (idx % Config.risingSoul.trailDensity == 0) renderParticleQuad(worldRenderer, partialTickTime,
currentPos = current,
prevPos = previous,
size = scale,
@@ -66,8 +67,8 @@ AbstractEntityFX(world, x.toDouble() + 0.5, y.toDouble() + 1.0, z.toDouble() + 0
@SideOnly(Side.CLIENT)
object RisingSoulTextures : ResourceHandler(BetterFoliageMod.MOD_ID) {
val headIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "rising_soul_%d")
val trackIcon = iconStatic(BetterFoliageMod.LEGACY_DOMAIN, "soul_track")
val headIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/rising_soul_%d")
val trackIcon = iconStatic(BetterFoliageMod.LEGACY_DOMAIN, "blocks/soul_track")
override fun afterStitch() {
Client.log(INFO, "Registered ${headIcons.num} soul particle textures")

View File

@@ -3,8 +3,9 @@ package mods.betterfoliage.client.render
import mods.betterfoliage.client.config.Config
import mods.octarinecore.client.render.*
import mods.octarinecore.common.Double3
import mods.octarinecore.exchange
import net.minecraftforge.common.util.ForgeDirection.*
import net.minecraft.util.EnumFacing.*
/** Weight of the same-side AO values on the outer edges of the 45deg chamfered column faces. */
const val chamferAffinity = 0.9f

View File

@@ -5,16 +5,19 @@ import mods.betterfoliage.client.Client
import mods.betterfoliage.client.config.Config
import mods.betterfoliage.client.integration.ShadersModIntegration
import mods.octarinecore.client.render.*
import mods.octarinecore.common.Int3
import mods.octarinecore.common.Rotation
import net.minecraft.block.material.Material
import net.minecraft.client.renderer.RenderBlocks
import net.minecraft.init.Blocks
import net.minecraft.client.renderer.BlockRendererDispatcher
import net.minecraft.client.renderer.WorldRenderer
import net.minecraft.util.EnumWorldBlockLayer
import org.apache.logging.log4j.Level.INFO
class RenderAlgae : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
val noise = simplexNoise()
val algaeIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "better_algae_%d")
val algaeIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_algae_%d")
val algaeModels = modelSet(64, RenderGrass.grassTopQuads)
override fun afterStitch() {
@@ -28,15 +31,17 @@ class RenderAlgae : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
ctx.block(up1).material == Material.water &&
Config.blocks.dirt.matchesID(ctx.block) &&
ctx.biomeId in Config.algae.biomes &&
noise[ctx.x, ctx.z] < Config.algae.population
noise[ctx.pos] < Config.algae.population
override fun render(ctx: BlockContext, parent: RenderBlocks): Boolean {
if (renderWorldBlockBase(parent, face = alwaysRender)) return true
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean {
renderWorldBlockBase(ctx, dispatcher, renderer, null)
modelRenderer.updateShading(Int3.zero, allFaces)
val rand = ctx.semiRandomArray(3)
ShadersModIntegration.grass(Config.algae.shaderWind) {
ShadersModIntegration.grass(renderer, Config.algae.shaderWind) {
modelRenderer.render(
renderer,
algaeModels[rand[2]],
Rotation.identity,
icon = { ctx, qi, q -> algaeIcons[rand[qi and 1]]!! },

View File

@@ -4,8 +4,13 @@ import mods.betterfoliage.BetterFoliageMod
import mods.betterfoliage.client.Client
import mods.betterfoliage.client.config.Config
import mods.octarinecore.client.render.*
import net.minecraft.client.renderer.RenderBlocks
import net.minecraftforge.common.util.ForgeDirection.*
import mods.octarinecore.client.resource.BlockTextureInspector
import mods.octarinecore.common.Int3
import mods.octarinecore.common.Rotation
import net.minecraft.client.renderer.BlockRendererDispatcher
import net.minecraft.client.renderer.WorldRenderer
import net.minecraft.util.EnumFacing.*
import net.minecraft.util.EnumWorldBlockLayer
import org.apache.logging.log4j.Level
class RenderCactus : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
@@ -13,8 +18,13 @@ class RenderCactus : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
val cactusStemRadius = 0.4375
val cactusArmRotation = listOf(NORTH, SOUTH, EAST, WEST).map { Rotation.rot90[it.ordinal] }
val iconCross = iconStatic(BetterFoliageMod.LEGACY_DOMAIN, "better_cactus")
val iconArm = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "better_cactus_arm_%d")
val iconCross = iconStatic(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_cactus")
val iconArm = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_cactus_arm_%d")
val iconBase = object : ColumnTextures(Config.blocks.cactus) {
init {
matchClassAndModel(matcher, "block/cactus", listOf("top", "bottom", "side"))
}
}
val modelStem = model {
horizontalRectangle(x1 = -cactusStemRadius, x2 = cactusStemRadius, z1 = -cactusStemRadius, z2 = cactusStemRadius, y = 0.5)
@@ -53,18 +63,23 @@ class RenderCactus : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
ctx.cameraDistance < Config.cactus.distance &&
Config.blocks.cactus.matchesID(ctx.block)
override fun render(ctx: BlockContext, parent: RenderBlocks): Boolean {
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean {
// get AO data
if (renderWorldBlockBase(parent, face = neverRender)) return true
modelRenderer.updateShading(Int3.zero, allFaces)
val icons = iconBase[ctx.blockState(Int3.zero)] ?: return renderWorldBlockBase(ctx, dispatcher, renderer, null)
modelRenderer.render(
renderer,
modelStem.model,
Rotation.identity,
icon = { ctx, qi, q -> ctx.icon(forgeDirs[qi])},
icon = { ctx, qi, q -> when(qi) {
0 -> icons.bottomTexture; 1 -> icons.topTexture; else -> icons.sideTexture
} },
rotateUV = { 0 },
postProcess = noPost
)
modelRenderer.render(
renderer,
modelCross[ctx.random(0)],
Rotation.identity,
icon = { ctx, qi, q -> iconCross.icon!!},
@@ -72,6 +87,7 @@ class RenderCactus : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
postProcess = noPost
)
modelRenderer.render(
renderer,
modelArm[ctx.random(1)],
cactusArmRotation[ctx.random(2) % 4],
icon = { ctx2, qi, q -> iconArm[ctx.random(3)]!!},

View File

@@ -2,9 +2,13 @@ package mods.betterfoliage.client.render
import mods.betterfoliage.BetterFoliageMod
import mods.betterfoliage.client.config.Config
import mods.octarinecore.client.render.*
import net.minecraft.block.material.Material
import net.minecraft.client.renderer.RenderBlocks
import mods.octarinecore.client.render.AbstractBlockRenderingHandler
import mods.octarinecore.client.render.BlockContext
import mods.octarinecore.client.render.withOffset
import mods.octarinecore.common.Int3
import net.minecraft.client.renderer.BlockRendererDispatcher
import net.minecraft.client.renderer.WorldRenderer
import net.minecraft.util.EnumWorldBlockLayer
class RenderConnectedGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
override fun isEligible(ctx: BlockContext) =
@@ -13,10 +17,10 @@ class RenderConnectedGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_
Config.blocks.grass.matchesID(ctx.block(up1)) &&
(Config.connectedGrass.snowEnabled || !ctx.block(up2).isSnow)
override fun render(ctx: BlockContext, parent: RenderBlocks): Boolean {
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean {
return ctx.withOffset(Int3.zero, up1) {
ctx.withOffset(up1, up2) {
renderWorldBlockBase(parent, face = alwaysRender)
renderWorldBlockBase(ctx, dispatcher, renderer, null)
}
}
}

View File

@@ -2,9 +2,15 @@ package mods.betterfoliage.client.render
import mods.betterfoliage.BetterFoliageMod
import mods.betterfoliage.client.config.Config
import mods.octarinecore.client.render.*
import net.minecraft.client.renderer.RenderBlocks
import net.minecraftforge.common.util.ForgeDirection.*
import mods.octarinecore.client.render.AbstractBlockRenderingHandler
import mods.octarinecore.client.render.BlockContext
import mods.octarinecore.client.render.withOffset
import mods.octarinecore.common.Int3
import mods.octarinecore.common.offset
import net.minecraft.client.renderer.BlockRendererDispatcher
import net.minecraft.client.renderer.WorldRenderer
import net.minecraft.util.EnumFacing.*
import net.minecraft.util.EnumWorldBlockLayer
class RenderConnectedGrassLog : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
@@ -15,17 +21,17 @@ class RenderConnectedGrassLog : AbstractBlockRenderingHandler(BetterFoliageMod.M
Config.blocks.dirt.matchesID(ctx.block) &&
Config.blocks.logs.matchesID(ctx.block(up1))
override fun render(ctx: BlockContext, parent: RenderBlocks): Boolean {
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean {
val grassDir = grassCheckDirs.find {
Config.blocks.grass.matchesID(ctx.block(it.offset))
}
return if (grassDir != null) {
ctx.withOffset(Int3.zero, grassDir.offset) {
renderWorldBlockBase(parent, face = alwaysRender)
renderWorldBlockBase(ctx, dispatcher, renderer, null)
}
} else {
renderWorldBlockBase(parent, face = alwaysRender)
renderWorldBlockBase(ctx, dispatcher, renderer, null)
}
}
}

View File

@@ -4,18 +4,24 @@ import mods.betterfoliage.BetterFoliageMod
import mods.betterfoliage.client.Client
import mods.betterfoliage.client.config.Config
import mods.octarinecore.client.render.*
import mods.octarinecore.common.Int3
import mods.octarinecore.common.forgeDirOffsets
import mods.octarinecore.common.forgeDirs
import mods.octarinecore.random
import net.minecraft.block.material.Material
import net.minecraft.client.renderer.RenderBlocks
import net.minecraftforge.common.util.ForgeDirection.UP
import net.minecraft.client.renderer.BlockRendererDispatcher
import net.minecraft.client.renderer.WorldRenderer
import net.minecraft.util.EnumFacing.Axis
import net.minecraft.util.EnumFacing.UP
import net.minecraft.util.EnumWorldBlockLayer
import org.apache.logging.log4j.Level.INFO
class RenderCoral : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
val noise = simplexNoise()
val coralIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "better_coral_%d")
val crustIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "better_crust_%d")
val coralIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_coral_%d")
val crustIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_crust_%d")
val coralModels = modelSet(64) { modelIdx ->
verticalRectangle(x1 = -0.5, z1 = 0.5, x2 = 0.5, z2 = -0.5, yBottom = 0.0, yTop = 1.0)
.scale(Config.coral.size).move(0.5 to UP)
@@ -32,7 +38,8 @@ class RenderCoral : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
}
override fun afterStitch() {
Client.log(INFO, "Registered ${coralIcons.num} algae textures")
Client.log(INFO, "Registered ${coralIcons.num} coral textures")
Client.log(INFO, "Registered ${crustIcons.num} coral crust textures")
}
override fun isEligible(ctx: BlockContext) =
@@ -42,15 +49,17 @@ class RenderCoral : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
ctx.block(up1).material == Material.water &&
Config.blocks.sand.matchesID(ctx.block) &&
ctx.biomeId in Config.coral.biomes &&
noise[ctx.x, ctx.z] < Config.coral.population
noise[ctx.pos] < Config.coral.population
override fun render(ctx: BlockContext, parent: RenderBlocks): Boolean {
if (renderWorldBlockBase(parent, face = alwaysRender)) return true
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean {
renderWorldBlockBase(ctx, dispatcher, renderer, null)
modelRenderer.updateShading(Int3.zero, allFaces)
forgeDirs.forEachIndexed { idx, face ->
if (!ctx.block(forgeDirOffsets[idx]).isOpaqueCube && blockContext.random(idx) < Config.coral.chance) {
var variation = blockContext.random(6)
modelRenderer.render(
renderer,
coralModels[variation++],
rotationFromUp[idx],
icon = { ctx, qi, q -> if (qi == 4) crustIcons[variation]!! else coralIcons[variation + (qi and 1)]!!},

View File

@@ -6,10 +6,16 @@ import mods.betterfoliage.client.config.Config
import mods.betterfoliage.client.integration.ShadersModIntegration
import mods.betterfoliage.client.texture.GrassRegistry
import mods.octarinecore.client.render.*
import mods.octarinecore.common.Double3
import mods.octarinecore.common.Int3
import mods.octarinecore.common.Rotation
import mods.octarinecore.random
import net.minecraft.block.material.Material
import net.minecraft.client.renderer.RenderBlocks
import net.minecraftforge.common.util.ForgeDirection.UP
import net.minecraft.client.renderer.BlockRendererDispatcher
import net.minecraft.client.renderer.WorldRenderer
import net.minecraft.util.EnumFacing.Axis
import net.minecraft.util.EnumFacing.UP
import net.minecraft.util.EnumWorldBlockLayer
import org.apache.logging.log4j.Level.INFO
class RenderGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
@@ -25,10 +31,10 @@ class RenderGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
}
}
val normalIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "better_grass_long_%d")
val snowedIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "better_grass_snowed_%d")
val normalGenIcon = iconStatic(Client.genGrass.generatedResource("minecraft:tallgrass", "snowed" to false))
val snowedGenIcon = iconStatic(Client.genGrass.generatedResource("minecraft:tallgrass", "snowed" to true))
val normalIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_grass_long_%d")
val snowedIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_grass_snowed_%d")
val normalGenIcon = iconStatic(Client.genGrass.generatedResource("minecraft:blocks/tallgrass", "snowed" to false))
val snowedGenIcon = iconStatic(Client.genGrass.generatedResource("minecraft:blocks/tallgrass", "snowed" to true))
val grassModels = modelSet(64, grassTopQuads)
@@ -43,61 +49,58 @@ class RenderGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
(Config.shortGrass.grassEnabled || Config.connectedGrass.enabled) &&
Config.blocks.grass.matchesID(ctx.block)
override fun render(ctx: BlockContext, parent: RenderBlocks): Boolean {
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean {
val isConnected = ctx.block(down1).let { Config.blocks.dirt.matchesID(it) || Config.blocks.grass.matchesID(it) }
val isSnowed = ctx.block(up1).isSnow
val connectedGrass = isConnected && Config.connectedGrass.enabled && (!isSnowed || Config.connectedGrass.snowEnabled)
val grassInfo = GrassRegistry.grass[ctx.icon(UP)]
if (grassInfo == null) {
renderWorldBlockBase(parent, face = alwaysRender)
return true
}
val cubeTexture = if (isSnowed) ctx.icon(up1, UP) else null ?: grassInfo.grassTopTexture
val blockColor = ctx.blockColor(Int3.zero)
val grassInfo = GrassRegistry[ctx.blockState(Int3.zero)] ?: return renderWorldBlockBase(ctx, dispatcher, renderer, layer)
val blockColor = ctx.blockData(Int3.zero, 0).color
if (connectedGrass) {
// get AO data
if (renderWorldBlockBase(parent, face = neverRender)) return true
// get full AO data
modelRenderer.updateShading(Int3.zero, allFaces)
// render full grass block
modelRenderer.render(
renderer,
fullCube,
Rotation.identity,
ctx.blockCenter,
icon = { ctx, qi, q -> cubeTexture },
icon = { ctx, qi, q -> grassInfo.grassTopTexture },
rotateUV = { 2 },
postProcess = { ctx, qi, q, vi, v ->
if (isSnowed) { if(!ctx.aoEnabled) setGrey(1.4f) }
else if (qi != UP.ordinal && ctx.aoEnabled) multiplyColor(blockColor)
else if (ctx.aoEnabled) multiplyColor(blockColor)
}
)
} else {
// render normally
if (renderWorldBlockBase(parent, face = alwaysRender)) return true
renderWorldBlockBase(ctx, dispatcher, renderer, null)
// get AO data only for block top
modelRenderer.updateShading(Int3.zero, topOnly)
}
if (!Config.shortGrass.grassEnabled) return true
if (isSnowed && !Config.shortGrass.snowEnabled) return true
if (ctx.block(up1).isOpaqueCube) return true
if (ctx.block(up1).material != Material.air) return true
// render grass quads
val iconset = if (isSnowed) snowedIcons else normalIcons
val iconGen = if (isSnowed) snowedGenIcon else normalGenIcon
val rand = ctx.semiRandomArray(2)
ShadersModIntegration.grass(Config.shortGrass.shaderWind) {
ShadersModIntegration.grass(renderer, Config.shortGrass.shaderWind) {
modelRenderer.render(
renderer,
grassModels[rand[0]],
Rotation.identity,
ctx.blockCenter + (if (isSnowed) snowOffset else Double3.zero),
icon = if (Config.shortGrass.useGenerated)
{ ctx: ShadingContext, qi: Int, q: Quad -> iconGen.icon!! }
else
{ ctx: ShadingContext, qi: Int, q: Quad -> iconset[rand[qi and 1]]!! },
icon = { ctx: ShadingContext, qi: Int, q: Quad ->
if (Config.shortGrass.useGenerated) iconGen.icon!! else iconset[rand[qi and 1]]!!
},
rotateUV = { 0 },
postProcess = if (isSnowed) whitewash else if (grassInfo.overrideColor == null) noPost else
{ ctx, qi, q, vi, v -> multiplyColor(grassInfo.overrideColor) }
postProcess = { ctx, qi, q, vi, v -> if (isSnowed) setGrey(1.4f) else multiplyColor(grassInfo.overrideColor ?: blockColor) }
)
}

View File

@@ -6,11 +6,16 @@ import mods.betterfoliage.client.integration.ShadersModIntegration
import mods.betterfoliage.client.texture.LeafRegistry
import mods.octarinecore.PI2
import mods.octarinecore.client.render.*
import mods.octarinecore.common.Double3
import mods.octarinecore.common.Int3
import mods.octarinecore.common.Rotation
import mods.octarinecore.common.vec
import mods.octarinecore.random
import net.minecraft.block.material.Material
import net.minecraft.client.renderer.RenderBlocks
import net.minecraftforge.common.util.ForgeDirection.DOWN
import net.minecraftforge.common.util.ForgeDirection.UP
import net.minecraft.client.renderer.BlockRendererDispatcher
import net.minecraft.client.renderer.WorldRenderer
import net.minecraft.util.EnumFacing.UP
import net.minecraft.util.EnumWorldBlockLayer
import java.lang.Math.cos
import java.lang.Math.sin
@@ -23,7 +28,7 @@ class RenderLeaves : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
.scale(Config.leaves.size)
.toCross(UP).addAll()
}
val snowedIcon = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "better_leaves_snowed_%d")
val snowedIcon = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_leaves_snowed_%d")
val perturbs = vectorSet(64) { idx ->
val angle = PI2 * idx / 64.0
@@ -37,27 +42,30 @@ class RenderLeaves : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
ctx.cameraDistance < Config.leaves.distance &&
Config.blocks.leaves.matchesID(ctx.block)
override fun render(ctx: BlockContext, parent: RenderBlocks): Boolean {
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean {
val isSnowed = ctx.block(up1).material.let {
it == Material.snow || it == Material.craftedSnow
}
renderWorldBlockBase(ctx, dispatcher, renderer, null)
val leafInfo = LeafRegistry[ctx.blockState(Int3.zero)] ?: return true
val blockColor = ctx.blockData(Int3.zero, 0).color
if (renderWorldBlockBase(parent, face = alwaysRender)) return true
val leafInfo = LeafRegistry.leaves[ctx.icon(DOWN)]
if (leafInfo != null) ShadersModIntegration.leaves {
modelRenderer.updateShading(Int3.zero, allFaces)
ShadersModIntegration.leaves(renderer) {
val rand = ctx.semiRandomArray(2)
(if (Config.leaves.dense) denseLeavesRot else normalLeavesRot).forEach { rotation ->
modelRenderer.render(
renderer,
leavesModel.model,
rotation,
ctx.blockCenter + perturbs[rand[0]],
icon = { ctx, qi, q -> leafInfo.roundLeafTexture },
rotateUV = { q -> rand[1] },
postProcess = noPost
postProcess = { ctx, qi, q, vi, v -> multiplyColor(blockColor) }
)
}
if (isSnowed) modelRenderer.render(
renderer,
leavesModel.model,
Rotation.identity,
ctx.blockCenter + perturbs[rand[0]],

View File

@@ -3,9 +3,15 @@ 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.ShadersModIntegration
import mods.octarinecore.client.render.*
import net.minecraft.client.renderer.RenderBlocks
import net.minecraftforge.common.util.ForgeDirection.*
import mods.octarinecore.common.Int3
import mods.octarinecore.common.Rotation
import net.minecraft.client.renderer.BlockRendererDispatcher
import net.minecraft.client.renderer.WorldRenderer
import net.minecraft.util.EnumFacing.DOWN
import net.minecraft.util.EnumFacing.UP
import net.minecraft.util.EnumWorldBlockLayer
import org.apache.logging.log4j.Level
class RenderLilypad : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
@@ -21,8 +27,8 @@ class RenderLilypad : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
.setFlatShader(FlatOffsetNoColor(Int3.zero))
.toCross(UP).addAll()
}
val rootIcon = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "better_lilypad_roots_%d")
val flowerIcon = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "better_lilypad_flower_%d")
val rootIcon = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_lilypad_roots_%d")
val flowerIcon = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_lilypad_flower_%d")
val perturbs = vectorSet(64) { modelIdx -> xzDisk(modelIdx) * Config.lilypad.hOffset }
override fun afterStitch() {
@@ -35,21 +41,27 @@ class RenderLilypad : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
ctx.cameraDistance < Config.lilypad.distance &&
Config.blocks.lilypad.matchesID(ctx.block)
override fun render(ctx: BlockContext, parent: RenderBlocks): Boolean {
if (renderWorldBlockBase(parent, face = alwaysRender)) return true
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean {
renderWorldBlockBase(ctx, dispatcher, renderer, null)
modelRenderer.updateShading(Int3.zero, allFaces)
val rand = ctx.semiRandomArray(5)
modelRenderer.render(
rootModel.model,
Rotation.identity,
ctx.blockCenter.add(perturbs[rand[2]]),
forceFlat = true,
icon = { ctx, qi, q -> rootIcon[rand[qi and 1]]!! },
rotateUV = { 0 },
postProcess = noPost
)
ShadersModIntegration.grass(renderer) {
modelRenderer.render(
renderer,
rootModel.model,
Rotation.identity,
ctx.blockCenter.add(perturbs[rand[2]]),
forceFlat = true,
icon = { ctx, qi, q -> rootIcon[rand[qi and 1]]!! },
rotateUV = { 0 },
postProcess = noPost
)
}
if (rand[3] < Config.lilypad.flowerChance) modelRenderer.render(
renderer,
flowerModel.model,
Rotation.identity,
ctx.blockCenter.add(perturbs[rand[4]]),

View File

@@ -2,9 +2,16 @@ package mods.betterfoliage.client.render
import mods.betterfoliage.BetterFoliageMod
import mods.betterfoliage.client.config.Config
import mods.octarinecore.client.render.Axis
import mods.octarinecore.client.render.BlockContext
import net.minecraft.block.Block
import mods.octarinecore.client.render.Quad
import mods.octarinecore.client.render.ShadingContext
import mods.octarinecore.client.resource.BlockTextureInspector
import mods.octarinecore.common.Int3
import net.minecraft.block.BlockLog
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.Axis
class RenderLog : AbstractRenderColumn(BetterFoliageMod.MOD_ID) {
@@ -13,18 +20,32 @@ class RenderLog : AbstractRenderColumn(BetterFoliageMod.MOD_ID) {
ctx.cameraDistance < Config.roundLogs.distance &&
Config.blocks.logs.matchesID(ctx.block)
override var axisFunc = { block: Block, meta: Int -> when ((meta shr 2) and 3) {
1 -> Axis.X
2 -> Axis.Z
else -> Axis.Y
} }
override var axisFunc = { state: IBlockState ->
when (state.getValue(BlockLog.LOG_AXIS).toString()) {
"x" -> Axis.X
"z" -> Axis.Z
else -> Axis.Y
}
}
override val blockPredicate = { block: Block, meta: Int -> Config.blocks.logs.matchesID(block) }
override val surroundPredicate = { block: Block -> block.isOpaqueCube && !Config.blocks.logs.matchesID(block) }
val columnTextures = ColumnTextures(Config.blocks.logs)
override val blockPredicate = { state: IBlockState -> Config.blocks.logs.matchesID(state.block) }
override val surroundPredicate = { state: IBlockState -> state.block.isOpaqueCube && !Config.blocks.logs.matchesID(state.block) }
override val connectPerpendicular: Boolean get() = Config.roundLogs.connectPerpendicular
override val connectSolids: Boolean get() = Config.roundLogs.connectSolids
override val lenientConnect: Boolean get() = Config.roundLogs.lenientConnect
override val radiusLarge: Double get() = Config.roundLogs.radiusLarge
override val radiusSmall: Double get() = Config.roundLogs.radiusSmall
override val downTexture = { ctx: ShadingContext, idx: Int, quad: Quad ->
columnTextures[ctx.blockData(Int3.zero).state]?.bottomTexture
}
override val sideTexture = { ctx: ShadingContext, idx: Int, quad: Quad ->
columnTextures[ctx.blockData(Int3.zero).state]?.sideTexture
}
override val upTexture = { ctx: ShadingContext, idx: Int, quad: Quad ->
columnTextures[ctx.blockData(Int3.zero).state]?.topTexture
}
}

View File

@@ -3,15 +3,22 @@ package mods.betterfoliage.client.render
import mods.betterfoliage.BetterFoliageMod
import mods.betterfoliage.client.Client
import mods.betterfoliage.client.config.Config
import mods.octarinecore.client.render.*
import mods.octarinecore.client.render.AbstractBlockRenderingHandler
import mods.octarinecore.client.render.BlockContext
import mods.octarinecore.client.render.modelRenderer
import mods.octarinecore.client.render.noPost
import mods.octarinecore.common.Double3
import mods.octarinecore.common.Rotation
import net.minecraft.block.material.Material
import net.minecraft.client.renderer.RenderBlocks
import net.minecraft.client.renderer.BlockRendererDispatcher
import net.minecraft.client.renderer.WorldRenderer
import net.minecraft.init.Blocks
import net.minecraft.util.EnumWorldBlockLayer
import org.apache.logging.log4j.Level.INFO
class RenderMycelium : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
val myceliumIcon = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "better_mycel_%d")
val myceliumIcon = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_mycel_%d")
val myceliumModel = modelSet(64, RenderGrass.grassTopQuads)
override fun afterStitch() {
@@ -24,17 +31,17 @@ class RenderMycelium : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
ctx.cameraDistance < Config.shortGrass.distance
}
override fun render(ctx: BlockContext, parent: RenderBlocks): Boolean {
val isSnowed = ctx.block(up1).material.let {
it == Material.snow || it == Material.craftedSnow
}
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean {
val isSnowed = ctx.block(up1).isSnow
renderWorldBlockBase(ctx, dispatcher, renderer, null)
if (renderWorldBlockBase(parent, face = alwaysRender)) return true
if (isSnowed && !Config.shortGrass.snowEnabled) return true
if (ctx.block(up1).isOpaqueCube) return true
val rand = ctx.semiRandomArray(2)
modelRenderer.render(
renderer,
myceliumModel[rand[0]],
Rotation.identity,
ctx.blockCenter + (if (isSnowed) snowOffset else Double3.zero),

View File

@@ -4,16 +4,19 @@ import mods.betterfoliage.BetterFoliageMod
import mods.betterfoliage.client.Client
import mods.betterfoliage.client.config.Config
import mods.octarinecore.client.render.*
import mods.octarinecore.common.Int3
import mods.octarinecore.common.Rotation
import mods.octarinecore.random
import net.minecraft.client.renderer.RenderBlocks
import net.minecraft.client.renderer.BlockRendererDispatcher
import net.minecraft.client.renderer.WorldRenderer
import net.minecraft.init.Blocks
import net.minecraftforge.common.util.ForgeDirection.DOWN
import net.minecraftforge.common.util.ForgeDirection.UP
import net.minecraft.util.EnumWorldBlockLayer
import net.minecraft.util.EnumFacing.*
import org.apache.logging.log4j.Level.INFO
class RenderNetherrack : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
val netherrackIcon = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "better_netherrack_%d")
val netherrackIcon = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_netherrack_%d")
val netherrackModel = modelSet(64) { modelIdx ->
verticalRectangle(x1 = -0.5, z1 = 0.5, x2 = 0.5, z2 = -0.5, yTop = -0.5,
yBottom = -0.5 - random(Config.netherrack.heightMin, Config.netherrack.heightMax))
@@ -33,12 +36,14 @@ class RenderNetherrack : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID)
ctx.cameraDistance < Config.netherrack.distance
}
override fun render(ctx: BlockContext, parent: RenderBlocks): Boolean {
if (renderWorldBlockBase(parent, face = alwaysRender)) return true
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean {
renderWorldBlockBase(ctx, dispatcher, renderer, null)
if (ctx.block(down1).isOpaqueCube) return true
modelRenderer.updateShading(Int3.zero, allFaces)
val rand = ctx.semiRandomArray(2)
modelRenderer.render(
renderer,
netherrackModel[rand[0]],
Rotation.identity,
icon = { ctx, qi, q -> netherrackIcon[rand[qi and 1]]!! },

View File

@@ -5,16 +5,20 @@ import mods.betterfoliage.client.Client
import mods.betterfoliage.client.config.Config
import mods.betterfoliage.client.integration.ShadersModIntegration
import mods.octarinecore.client.render.*
import mods.octarinecore.common.Int3
import mods.octarinecore.common.Rotation
import mods.octarinecore.random
import net.minecraft.block.material.Material
import net.minecraft.client.renderer.RenderBlocks
import net.minecraftforge.common.util.ForgeDirection.UP
import net.minecraft.client.renderer.BlockRendererDispatcher
import net.minecraft.client.renderer.WorldRenderer
import net.minecraft.util.EnumFacing.UP
import net.minecraft.util.EnumWorldBlockLayer
import org.apache.logging.log4j.Level
class RenderReeds : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
val noise = simplexNoise()
val reedIcons = iconSet(Client.genReeds.generatedResource("${BetterFoliageMod.LEGACY_DOMAIN}:better_reed_%d"))
val reedIcons = iconSet(Client.genReeds.generatedResource("${BetterFoliageMod.LEGACY_DOMAIN}:blocks/better_reed_%d"))
val reedModels = modelSet(64) { modelIdx ->
val height = random(Config.reed.heightMin, Config.reed.heightMax)
val waterline = 0.875f
@@ -44,14 +48,16 @@ class RenderReeds : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
ctx.block(up1).material == Material.water &&
Config.blocks.dirt.matchesID(ctx.block) &&
ctx.biomeId in Config.reed.biomes &&
noise[ctx.x, ctx.z] < Config.reed.population
noise[ctx.pos] < Config.reed.population
override fun render(ctx: BlockContext, parent: RenderBlocks): Boolean {
if (renderWorldBlockBase(parent, face = alwaysRender)) return true
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean {
renderWorldBlockBase(ctx, dispatcher, renderer, null)
modelRenderer.updateShading(Int3.zero, allFaces)
val iconVar = ctx.random(1)
ShadersModIntegration.grass(Config.reed.shaderWind) {
ShadersModIntegration.grass(renderer, Config.reed.shaderWind) {
modelRenderer.render(
renderer,
reedModels[ctx.random(0)],
Rotation.identity,
forceFlat = true,

View File

@@ -3,13 +3,14 @@ package mods.betterfoliage.client.render
import mods.octarinecore.PI2
import mods.octarinecore.client.render.*
import mods.octarinecore.common.Double3
import mods.octarinecore.common.Int3
import mods.octarinecore.common.Rotation
import mods.octarinecore.common.times
import net.minecraft.block.Block
import net.minecraft.block.material.Material
import net.minecraft.tileentity.TileEntity
import net.minecraft.world.IBlockAccess
import net.minecraft.world.biome.BiomeGenBase
import net.minecraftforge.common.util.ForgeDirection
import net.minecraftforge.common.util.ForgeDirection.*
import net.minecraft.util.EnumFacing
import net.minecraft.util.EnumFacing.*
val up1 = Int3(1 to UP)
val up2 = Int3(2 to UP)
@@ -24,11 +25,11 @@ val greywash: RenderVertex.(ShadingContext, Int, Quad, Int, Vertex)->Unit = { ct
val Block.isSnow: Boolean get() = material.let { it == Material.snow || it == Material.craftedSnow }
fun Quad.toCross(rotAxis: ForgeDirection, trans: (Quad)->Quad) =
fun Quad.toCross(rotAxis: EnumFacing, trans: (Quad)->Quad) =
(0..3).map { rotIdx ->
trans(rotate(Rotation.rot90[rotAxis.ordinal] * rotIdx).mirrorUV(rotIdx > 1, false))
}
fun Quad.toCross(rotAxis: ForgeDirection) = toCross(rotAxis) { it }
fun Quad.toCross(rotAxis: EnumFacing) = toCross(rotAxis) { it }
fun xzDisk(modelIdx: Int) = (PI2 * modelIdx / 64.0).let { Double3(Math.cos(it), 0.0, Math.sin(it)) }

View File

@@ -1,19 +1,19 @@
package mods.betterfoliage.client.texture
import cpw.mods.fml.common.eventhandler.SubscribeEvent
import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly
import mods.betterfoliage.client.Client
import mods.betterfoliage.client.config.Config
import mods.octarinecore.client.render.HSB
import mods.octarinecore.client.resource.averageColor
import net.minecraft.block.Block
import mods.octarinecore.client.resource.*
import net.minecraft.block.state.IBlockState
import net.minecraft.client.renderer.texture.TextureAtlasSprite
import net.minecraft.client.renderer.texture.TextureMap
import net.minecraft.util.IIcon
import net.minecraft.client.resources.model.ModelResourceLocation
import net.minecraftforge.client.event.TextureStitchEvent
import net.minecraftforge.client.model.IModel
import net.minecraftforge.common.MinecraftForge
import org.apache.logging.log4j.Level.DEBUG
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
const val defaultGrassColor = 0
@@ -34,36 +34,21 @@ class GrassInfo(
/** Collects and manages rendering-related information for grass blocks. */
@SideOnly(Side.CLIENT)
object GrassRegistry {
val grass: MutableMap<IIcon, GrassInfo> = hashMapOf()
object GrassRegistry : BlockTextureInspector<GrassInfo>() {
init {
MinecraftForge.EVENT_BUS.register(this)
matchClassAndModel(Config.blocks.grass, "block/grass", listOf("top"))
matchClassAndModel(Config.blocks.grass, "block/cube_bottom_top", listOf("top"))
}
@SubscribeEvent
fun handleTextureReload(event: TextureStitchEvent.Pre) {
if (event.map.textureType != 0) return
grass.clear()
override fun onAfterModelLoad() {
super.onAfterModelLoad()
Client.log(INFO, "Inspecting grass textures")
Block.blockRegistry.forEach { block ->
if (Config.blocks.grass.matchesClass(block as Block)) {
block.registerBlockIcons { location ->
val original = event.map.getTextureExtry(location)
Client.log(DEBUG, "Found grass texture: $location")
registerGrass(event.map, original)
return@registerBlockIcons original
}
}
}
}
fun registerGrass(atlas: TextureMap, icon: TextureAtlasSprite) {
val hsb = HSB.fromColor(icon.averageColor ?: defaultGrassColor)
override fun processTextures(textures: List<TextureAtlasSprite>, atlas: TextureMap): GrassInfo {
val hsb = HSB.fromColor(textures[0].averageColor ?: defaultGrassColor)
val overrideColor = if (hsb.saturation > Config.shortGrass.saturationThreshold) hsb.copy(brightness = 0.8f).asColor else null
grass.put(icon, GrassInfo(icon, overrideColor))
return GrassInfo(textures[0], overrideColor)
}
}

View File

@@ -1,21 +1,20 @@
package mods.betterfoliage.client.texture
import cpw.mods.fml.common.FMLCommonHandler
import cpw.mods.fml.common.eventhandler.SubscribeEvent
import cpw.mods.fml.relauncher.Side
import cpw.mods.fml.relauncher.SideOnly
import mods.betterfoliage.client.Client
import mods.betterfoliage.client.config.Config
import mods.octarinecore.client.resource.BlockTextureInspector
import mods.octarinecore.client.resource.IconSet
import mods.octarinecore.client.resource.averageColor
import net.minecraft.block.Block
import net.minecraft.client.renderer.texture.TextureAtlasSprite
import net.minecraft.client.renderer.texture.TextureMap
import net.minecraft.util.IIcon
import net.minecraft.util.ResourceLocation
import net.minecraftforge.client.event.TextureStitchEvent
import net.minecraftforge.common.MinecraftForge
import org.apache.logging.log4j.Level.*
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
const val defaultLeafColor = 0
@@ -36,49 +35,24 @@ class LeafInfo(
/** Collects and manages rendering-related information for leaf blocks. */
@SideOnly(Side.CLIENT)
object LeafRegistry {
object LeafRegistry : BlockTextureInspector<LeafInfo>() {
val leaves: MutableMap<IIcon, LeafInfo> = hashMapOf()
val particles: MutableMap<String, IconSet> = hashMapOf()
val typeMappings = TextureMatcher()
val typeMappings = TextureMatcher().apply { loadMappings(ResourceLocation("betterfoliage", "leafTypeMappings.cfg")) }
init {
MinecraftForge.EVENT_BUS.register(this)
matchClassAndModel(Config.blocks.leaves, "minecraft:block/leaves", listOf("all"))
}
@SubscribeEvent
fun handleTextureReload(event: TextureStitchEvent.Pre) {
if (event.map.textureType != 0) return
leaves.clear()
particles.clear()
typeMappings.loadMappings(ResourceLocation("betterfoliage", "leafTypeMappings.cfg"))
Client.log(INFO, "Generating leaf textures")
IconSet("betterfoliage", "falling_leaf_default_%d").let {
it.onStitch(event.map)
particles.put("default", it)
}
Block.blockRegistry.forEach { block ->
if (Config.blocks.leaves.matchesClass(block as Block)) {
block.registerBlockIcons { location ->
val original = event.map.getTextureExtry(location)
Client.log(DEBUG, "Found leaf texture: $location")
registerLeaf(event.map, original)
return@registerBlockIcons original
}
}
}
}
fun registerLeaf(atlas: TextureMap, icon: TextureAtlasSprite) {
var leafType = typeMappings.getType(icon) ?: "default"
val generated = atlas.registerIcon(
Client.genLeaves.generatedResource(icon.iconName, "type" to leafType).toString()
override fun processTextures(textures: List<TextureAtlasSprite>, atlas: TextureMap): LeafInfo {
val texture = textures[0]
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", "falling_leaf_${leafType}_%d")
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")
@@ -88,7 +62,6 @@ object LeafRegistry {
}
}
val leafInfo = LeafInfo(generated as TextureAtlasSprite, leafType)
leaves.put(icon, leafInfo)
return LeafInfo(generated as TextureAtlasSprite, leafType)
}
}

View File

@@ -1,69 +1,42 @@
package mods.betterfoliage.loader
import cpw.mods.fml.relauncher.FMLLaunchHandler
import cpw.mods.fml.relauncher.IFMLLoadingPlugin
import mods.octarinecore.metaprog.*
import mods.octarinecore.metaprog.ASMPlugin
import mods.octarinecore.metaprog.Transformer
import mods.octarinecore.metaprog.allAvailable
import net.minecraftforge.fml.relauncher.FMLLaunchHandler
import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin
import org.objectweb.asm.Opcodes.*
@IFMLLoadingPlugin.TransformerExclusions(
"mods.betterfoliage.loader",
"mods.octarinecore.metaprog",
"kotlin",
"mods.betterfoliage.kotlin"
"mods.octarinecore.kotlin"
)
class BetterFoliageLoader : ASMPlugin(BetterFoliageTransformer::class.java)
class BetterFoliageTransformer : Transformer() {
val isOptifinePresent = allAvailable(Refs.OptifineClassTransformer)
init {
if (FMLLaunchHandler.side().isClient) setupClient()
}
fun setupClient() {
// where: RenderBlocks.renderBlockByRenderType()
// what: invoke BF code to overrule the return value of Block.getRenderType()
// why: allows us to use custom block renderers for any block, without touching block code
transformMethod(Refs.renderBlockByRenderType) {
find(varinsn(ISTORE, 5))?.insertAfter {
log.info("Applying block render type override")
varinsn(ALOAD, 0)
getField(Refs.blockAccess)
varinsn(ILOAD, 2)
varinsn(ILOAD, 3)
varinsn(ILOAD, 4)
varinsn(ALOAD, 1)
varinsn(ILOAD, 5)
invokeStatic(Refs.getRenderTypeOverride)
varinsn(ISTORE, 5)
} ?: log.warn("Failed to apply block render type override!")
}
// where: WorldClient.doVoidFogParticles(), right before the end of the loop
// what: invoke BF code for every random display tick
// why: allows us to catch random display ticks, without touching block code
transformMethod(Refs.doVoidFogParticles) {
find(IINC)?.insertBefore {
log.info("Applying random display tick call hook")
varinsn(ALOAD, 10)
varinsn(ALOAD, 0)
varinsn(ILOAD, 7)
varinsn(ILOAD, 8)
varinsn(ILOAD, 9)
varinsn(ALOAD, 13)
varinsn(ALOAD, if (isOptifinePresent) 8 else 12)
invokeStatic(Refs.onRandomDisplayTick)
} ?: log.warn("Failed to apply random display tick call hook!")
}
// where: shadersmodcore.client.Shaders.pushEntity()
// what: invoke BF code to overrule block data
// why: allows us to change the block ID seen by shader programs
transformMethod(Refs.pushEntity) {
find(IASTORE)?.insertBefore {
log.info("Applying Shaders.pushEntity() block id override")
varinsn(ALOAD, 1)
invokeStatic(Refs.getBlockIdOverride)
} ?: log.warn("Failed to apply Shaders.pushEntity() block id override!")
}
// where: Block.getAmbientOcclusionLightValue()
// what: invoke BF code to overrule AO transparency value
// why: allows us to have light behave properly on non-solid log blocks without
@@ -95,12 +68,67 @@ class BetterFoliageTransformer : Transformer() {
find(IRETURN)?.insertBefore {
log.info("Applying Block.shouldSideBeRendered() override")
varinsn(ALOAD, 1)
varinsn(ILOAD, 2)
varinsn(ILOAD, 3)
varinsn(ILOAD, 4)
varinsn(ILOAD, 5)
varinsn(ALOAD, 2)
varinsn(ALOAD, 3)
invokeStatic(Refs.shouldRenderBlockSideOverride)
} ?: log.warn("Failed to apply Block.shouldSideBeRendered() override!")
}
// where: ModelLoader.setupModelRegistry(), right before the textures are loaded
// what: invoke handler code with ModelLoader instance
// why: allows us to iterate the unbaked models in ModelLoader in time to register textures
transformMethod(Refs.setupModelRegistry) {
find(invokeName("addAll"))?.insertAfter {
log.info("Applying ModelLoader lifecycle callback")
varinsn(ALOAD, 0)
invokeStatic(Refs.onAfterLoadModelDefinitions)
}
}
// where: RenderChunk.rebuildChunk()
// what: replace call to BlockRendererDispatcher.renderBlock()
// why: allows us to perform additional rendering for each block
// what: invoke code to overrule result of Block.canRenderInLayer()
// why: allows us to render transparent quads for blocks which are only on the SOLID layer
transformMethod(Refs.rebuildChunk) {
find(invokeRef(Refs.renderBlock))?.replace {
log.info("Applying RenderChunk block render override")
varinsn(ALOAD, if (isOptifinePresent) 21 else 18)
invokeStatic(Refs.renderWorldBlock)
}
if (isOptifinePresent) {
find(varinsn(ISTORE, 22))?.insertBefore {
log.info("Applying RenderChunk block layer override")
insn(POP)
varinsn(ALOAD, 17)
varinsn(ALOAD, 21)
invokeStatic(Refs.canRenderBlockInLayer)
}
} else {
find(invokeRef(Refs.canRenderInLayer))?.replace {
log.info("Applying RenderChunk block layer override")
invokeStatic(Refs.canRenderBlockInLayer)
}
}
}
// where: net.minecraft.client.renderer.BlockModelRenderer$AmbientOcclusionFace
// what: make constructor public
// why: use vanilla AO calculation at will without duplicating code
transformMethod(Refs.AOF_constructor) {
log.info("Setting AmbientOcclusionFace constructor public")
makePublic()
}
// where: shadersmod.client.SVertexBuilder.pushEntity()
// what: invoke code to overrule block data
// why: allows us to change the block ID seen by shader programs
transformMethod(Refs.pushEntity_state) {
find(invokeRef(Refs.pushEntity_num))?.insertBefore {
log.info("Applying SVertexBuilder.pushEntity() block ID override")
varinsn(ALOAD, 0)
invokeStatic(Refs.getBlockIdOverride)
} ?: log.warn("Failed to apply SVertexBuilder.pushEntity() block ID override!")
}
}
}

View File

@@ -1,9 +1,9 @@
package mods.betterfoliage.loader
import cpw.mods.fml.relauncher.FMLInjectionData
import mods.octarinecore.metaprog.ClassRef
import mods.octarinecore.metaprog.FieldRef
import mods.octarinecore.metaprog.MethodRef
import net.minecraftforge.fml.relauncher.FMLInjectionData
/** Singleton object holding references to foreign code elements. */
object Refs {
@@ -14,58 +14,76 @@ object Refs {
val List = ClassRef("java.util.List")
// Minecraft
val IBlockAccess = ClassRef("net.minecraft.world.IBlockAccess", "ahl")
val IBlockAccess = ClassRef("net.minecraft.world.IBlockAccess", "ard")
val IBlockState = ClassRef("net.minecraft.block.state.IBlockState", "bec")
val BlockPos = ClassRef("net.minecraft.util.BlockPos", "dt")
val EnumWorldBlockLayer = ClassRef("net.minecraft.util.EnumWorldBlockLayer", "aql")
val EnumFacing = ClassRef("net.minecraft.util.EnumFacing", "ej")
val Block = ClassRef("net.minecraft.block.Block", "aji")
val getAmbientOcclusionLightValue = MethodRef(Block, "getAmbientOcclusionLightValue", "func_149685_I", "I", ClassRef.float)
val getUseNeighborBrightness = MethodRef(Block, "getUseNeighborBrightness", "func_149710_n", "n", ClassRef.boolean)
val shouldSideBeRendered = MethodRef(Block, "shouldSideBeRendered", "func_149646_a", "a", ClassRef.boolean, IBlockAccess, ClassRef.int, ClassRef.int, ClassRef.int, ClassRef.int)
val Block = ClassRef("net.minecraft.block.Block", "atr")
val canRenderInLayer = MethodRef(Block, "canRenderInLayer", ClassRef.boolean, EnumWorldBlockLayer)
val getAmbientOcclusionLightValue = MethodRef(Block, "getAmbientOcclusionLightValue", "func_149685_I", "f", ClassRef.float)
val getUseNeighborBrightness = MethodRef(Block, "getUseNeighborBrightness", "func_149710_n", "q", ClassRef.boolean)
val shouldSideBeRendered = MethodRef(Block, "shouldSideBeRendered", "func_149646_a", "a", ClassRef.boolean, IBlockAccess, BlockPos, EnumFacing)
val RenderBlocks = ClassRef("net.minecraft.client.renderer.RenderBlocks", "blm")
val blockAccess = FieldRef(RenderBlocks, "blockAccess", null, "a", IBlockAccess)
val renderBlockByRenderType = MethodRef(RenderBlocks, "renderBlockByRenderType", null, "b", ClassRef.boolean, Block, ClassRef.int, ClassRef.int, ClassRef.int)
val BlockModelRenderer = ClassRef("net.minecraft.client.renderer.BlockModelRenderer", "cln")
val AmbientOcclusionFace = ClassRef("net.minecraft.client.renderer.BlockModelRenderer\$AmbientOcclusionFace", "clq")
val ChunkCompileTaskGenerator = ClassRef("net.minecraft.client.renderer.chunk.ChunkCompileTaskGenerator", "coa")
val WorldRenderer = ClassRef("net.minecraft.client.renderer.WorldRenderer", "civ")
val AOF_constructor = MethodRef(AmbientOcclusionFace, "<init>", ClassRef.void, BlockModelRenderer)
val WorldClient = ClassRef("net.minecraft.client.multiplayer.WorldClient", "bjf")
val doVoidFogParticles = MethodRef(WorldClient, "doVoidFogParticles", null, "C", ClassRef.void, ClassRef.int, ClassRef.int, ClassRef.int)
val RenderChunk = ClassRef("net.minecraft.client.renderer.chunk.RenderChunk", "cop")
val rebuildChunk = MethodRef(RenderChunk, "rebuildChunk", "func_178581_b", "b", ClassRef.void, ClassRef.float, ClassRef.float, ClassRef.float, ChunkCompileTaskGenerator)
val World = ClassRef("net.minecraft.world.World", "ahb")
val BlockRendererDispatcher = ClassRef("net.minecraft.client.renderer.BlockRendererDispatcher", "cll")
val renderBlock = MethodRef(BlockRendererDispatcher, "renderBlock", "func_175018_a", "a", ClassRef.boolean, IBlockState, BlockPos, IBlockAccess, WorldRenderer)
val TextureMap = ClassRef("net.minecraft.client.renderer.texture.TextureMap", "bpr")
val mapRegisteredSprites = FieldRef(TextureMap, "mapRegisteredSprites", "field_110574_e", "bpr", Map)
val World = ClassRef("net.minecraft.world.World", "aqu")
val WorldClient = ClassRef("net.minecraft.client.multiplayer.WorldClient", "cen")
val doVoidFogParticles = MethodRef(WorldClient, "doVoidFogParticles", "func_73029_E", "b", ClassRef.void, ClassRef.int, ClassRef.int, ClassRef.int)
val IMetadataSerializer = ClassRef("net.minecraft.client.resources.data.IMetadataSerializer", "brw")
val SimpleReloadableResourceManager = ClassRef("net.minecraft.client.resources.SimpleReloadableResourceManager", "brg")
val metadataSerializer = FieldRef(SimpleReloadableResourceManager, "rmMetadataSerializer", "field_110547_c", "f", IMetadataSerializer)
// val IMetadataSerializer = ClassRef("net.minecraft.client.resources.data.IMetadataSerializer", "brw")
// val SimpleReloadableResourceManager = ClassRef("net.minecraft.client.resources.SimpleReloadableResourceManager", "brg")
// val metadataSerializer = FieldRef(SimpleReloadableResourceManager, "rmMetadataSerializer", "field_110547_c", "f", IMetadataSerializer)
val IIcon = ClassRef("net.minecraft.util.IIcon", "rf")
val TextureAtlasSprite = ClassRef("net.minecraft.client.renderer.texture.TextureAtlasSprite", "bqd")
val IRegistry = ClassRef("net.minecraft.util.IRegistry", "ez")
val ModelLoader = ClassRef("net.minecraftforge.client.model.ModelLoader")
val stateModels = FieldRef(ModelLoader, "stateModels", Map)
val setupModelRegistry = MethodRef(ModelLoader, "setupModelRegistry", "func_177570_a", "a", IRegistry)
val IModel = ClassRef("net.minecraftforge.client.model.IModel", "")
val ModelBlock = ClassRef("net.minecraft.client.renderer.block.model.ModelBlock", "cmc")
val ModelResourceLocation = ClassRef("net.minecraft.client.renderer.block.model.ModelResourceLocation", "cmc")
val VanillaModelWrapper = ClassRef("net.minecraftforge.client.model.ModelLoader\$VanillaModelWrapper")
val model_VMW = FieldRef(VanillaModelWrapper, "model", ModelBlock)
val location_VMW = FieldRef(VanillaModelWrapper, "location", ModelBlock)
val WeightedPartWrapper = ClassRef("net.minecraftforge.client.model.ModelLoader\$WeightedPartWrapper")
val model_WPW = FieldRef(WeightedPartWrapper, "model", IModel)
val WeightedRandomModel = ClassRef("net.minecraftforge.client.model.ModelLoader\$WeightedRandomModel")
val models_WRM = FieldRef(WeightedRandomModel, "models", List)
// Better Foliage
val BetterFoliageHooks = ClassRef("mods.betterfoliage.client.Hooks")
val getAmbientOcclusionLightValueOverride = MethodRef(BetterFoliageHooks, "getAmbientOcclusionLightValueOverride", ClassRef.float, ClassRef.float, Block)
val getUseNeighborBrightnessOverride = MethodRef(BetterFoliageHooks, "getUseNeighborBrightnessOverride", ClassRef.boolean, ClassRef.boolean, Block)
val shouldRenderBlockSideOverride = MethodRef(BetterFoliageHooks, "shouldRenderBlockSideOverride", ClassRef.boolean, ClassRef.boolean, IBlockAccess, ClassRef.int, ClassRef.int, ClassRef.int, ClassRef.int)
val getRenderTypeOverride = MethodRef(BetterFoliageHooks, "getRenderTypeOverride", ClassRef.int, IBlockAccess, ClassRef.int, ClassRef.int, ClassRef.int, Block, ClassRef.int)
val onRandomDisplayTick = MethodRef(BetterFoliageHooks, "onRandomDisplayTick", ClassRef.void, Block, World, ClassRef.int, ClassRef.int, ClassRef.int)
// Shaders mod
val Shaders = ClassRef("shadersmodcore.client.Shaders")
val pushEntity = MethodRef(Shaders, "pushEntity", ClassRef.void, RenderBlocks, Block, ClassRef.int, ClassRef.int, ClassRef.int)
val pushEntity_I = MethodRef(Shaders, "pushEntity", ClassRef.void, ClassRef.int)
val popEntity = MethodRef(Shaders, "popEntity", ClassRef.void)
val ShadersModIntegration = ClassRef("mods.betterfoliage.client.integration.ShadersModIntegration")
val getBlockIdOverride = MethodRef(ShadersModIntegration, "getBlockIdOverride", ClassRef.int, ClassRef.int, Block)
val shouldRenderBlockSideOverride = MethodRef(BetterFoliageHooks, "shouldRenderBlockSideOverride", ClassRef.boolean, ClassRef.boolean, IBlockAccess, BlockPos, EnumFacing)
val onRandomDisplayTick = MethodRef(BetterFoliageHooks, "onRandomDisplayTick", ClassRef.void, World, IBlockState, BlockPos)
val onAfterLoadModelDefinitions = MethodRef(BetterFoliageHooks, "onAfterLoadModelDefinitions", ClassRef.void, ModelLoader)
val renderWorldBlock = MethodRef(BetterFoliageHooks, "renderWorldBlock", ClassRef.boolean, BlockRendererDispatcher, IBlockState, BlockPos, IBlockAccess, WorldRenderer, EnumWorldBlockLayer)
val canRenderBlockInLayer = MethodRef(BetterFoliageHooks, "canRenderBlockInLayer", ClassRef.boolean, Block, EnumWorldBlockLayer)
// Optifine
val ConnectedTextures = ClassRef("ConnectedTextures")
val getConnectedTexture = MethodRef(ConnectedTextures, "getConnectedTexture", IIcon, IBlockAccess, Block, ClassRef.int, ClassRef.int, ClassRef.int, ClassRef.int, IIcon)
val CTBlockProperties = FieldRef(ConnectedTextures, "blockProperties", null)
val CTTileProperties = FieldRef(ConnectedTextures, "tileProperties", null)
val OptifineClassTransformer = ClassRef("optifine.OptiFineClassTransformer")
val ConnectedProperties = ClassRef("ConnectedProperties")
val CPTileIcons = FieldRef(ConnectedProperties, "tileIcons", null)
// ShadersMod
val SVertexBuilder = ClassRef("shadersmod.client.SVertexBuilder")
val sVertexBuilder = FieldRef(WorldRenderer, "sVertexBuilder", SVertexBuilder)
val pushEntity_state = MethodRef(SVertexBuilder, "pushEntity", ClassRef.void, IBlockState, BlockPos, IBlockAccess, WorldRenderer)
val pushEntity_num = MethodRef(SVertexBuilder, "pushEntity", ClassRef.void, ClassRef.long)
val popEntity = MethodRef(SVertexBuilder, "popEntity", ClassRef.void)
// Colored Lights Core
val CLCLoadingPlugin = ClassRef("coloredlightscore.src.asm.ColoredLightsCoreLoadingPlugin")
val ShadersModIntegration = ClassRef("mods.betterfoliage.client.integration.ShadersModIntegration")
val getBlockIdOverride = MethodRef(ShadersModIntegration, "getBlockIdOverride", ClassRef.long, ClassRef.long, IBlockState)
}