diff --git a/build.gradle b/build.gradle index 35a385c..a1d5cde 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,12 @@ apply plugin: "forge" -apply plugin: "kotlin" +apply plugin: 'kotlin' group = 'com.github.octarine-noise' version = "2.0" -archivesBaseName = rootProject.name + '-MC1.7.10' +archivesBaseName = rootProject.name + '-MC1.8' buildscript { - ext.kotlin_version = '1.0.0-beta-4583' + ext.kotlin_version = '1.0.0-beta-4584' repositories { mavenCentral() maven { @@ -29,10 +29,12 @@ configurations { } dependencies { shade "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + } minecraft { - version = '1.7.10-10.13.4.1448-1.7.10' - srgExtra "PK: kotlin mods/betterfoliage/kotlin" + version = '1.8-11.14.3.1502' + mappings = 'stable_18' + srgExtra "PK: kotlin mods/octarinecore/kotlin" } processResources { @@ -55,6 +57,7 @@ jar { manifest { attributes "FMLCorePlugin": "mods.betterfoliage.loader.BetterFoliageLoader" attributes "FMLCorePluginContainsFMLMod": "mods.betterfoliage.BetterFoliageMod" + attributes "FMLAT": "BetterFoliage_at.cfg" } configurations.shade.each { dep -> from(project.zipTree(dep)){ diff --git a/src/main/java/net/minecraft/client/BFBlockModelRenderer.java b/src/main/java/net/minecraft/client/BFBlockModelRenderer.java new file mode 100644 index 0000000..8caef5a --- /dev/null +++ b/src/main/java/net/minecraft/client/BFBlockModelRenderer.java @@ -0,0 +1,25 @@ +package net.minecraft.client; + +import net.minecraft.block.Block; +import net.minecraft.client.renderer.BlockModelRenderer; +import net.minecraft.util.EnumFacing; + +import java.util.BitSet; + +/** + * FFS why isn't this public static... + */ +public class BFBlockModelRenderer extends BlockModelRenderer { + public class BFAmbientOcclusionFace extends BlockModelRenderer.AmbientOcclusionFace {} + + private static BFBlockModelRenderer INSTANCE = new BFBlockModelRenderer(); + + public static BFAmbientOcclusionFace getVanillaAoObject() { + return INSTANCE.new BFAmbientOcclusionFace(); + } + + public static void fillQuadBounds2(Block blockIn, int[] vertexData, EnumFacing facingIn, float[] quadBounds, BitSet boundsFlags) { + INSTANCE.fillQuadBounds(blockIn, vertexData, facingIn, quadBounds, boundsFlags); + } + +} diff --git a/src/main/kotlin/mods/betterfoliage/BetterFoliageMod.kt b/src/main/kotlin/mods/betterfoliage/BetterFoliageMod.kt index bf40168..1595fa6 100644 --- a/src/main/kotlin/mods/betterfoliage/BetterFoliageMod.kt +++ b/src/main/kotlin/mods/betterfoliage/BetterFoliageMod.kt @@ -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 diff --git a/src/main/kotlin/mods/betterfoliage/client/Client.kt b/src/main/kotlin/mods/betterfoliage/client/Client.kt index ad79fa4..c098c62 100644 --- a/src/main/kotlin/mods/betterfoliage/client/Client.kt +++ b/src/main/kotlin/mods/betterfoliage/client/Client.kt @@ -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) diff --git a/src/main/kotlin/mods/betterfoliage/client/Hooks.kt b/src/main/kotlin/mods/betterfoliage/client/Hooks.kt index a5ee1e7..3eb81c6 100644 --- a/src/main/kotlin/mods/betterfoliage/client/Hooks.kt +++ b/src/main/kotlin/mods/betterfoliage/client/Hooks.kt @@ -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) + } \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/client/config/BlockMatcher.kt b/src/main/kotlin/mods/betterfoliage/client/config/BlockMatcher.kt index 73bd8bf..c9811bd 100644 --- a/src/main/kotlin/mods/betterfoliage/client/config/BlockMatcher.kt +++ b/src/main/kotlin/mods/betterfoliage/client/config/BlockMatcher.kt @@ -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. diff --git a/src/main/kotlin/mods/betterfoliage/client/config/Config.kt b/src/main/kotlin/mods/betterfoliage/client/config/Config.kt index 79b15fe..8ea870c 100644 --- a/src/main/kotlin/mods/betterfoliage/client/config/Config.kt +++ b/src/main/kotlin/mods/betterfoliage/client/config/Config.kt @@ -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") diff --git a/src/main/kotlin/mods/betterfoliage/client/gui/BiomeListConfigEntry.kt b/src/main/kotlin/mods/betterfoliage/client/gui/BiomeListConfigEntry.kt index ef0a93e..62a1872 100644 --- a/src/main/kotlin/mods/betterfoliage/client/gui/BiomeListConfigEntry.kt +++ b/src/main/kotlin/mods/betterfoliage/client/gui/BiomeListConfigEntry.kt @@ -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(owningScreen, owningEntryList, configElement) { override val baseSet: List get() = BiomeGenBase.getBiomeGenArray().filterNotNull() diff --git a/src/main/kotlin/mods/betterfoliage/client/gui/ConfigGuiFactory.kt b/src/main/kotlin/mods/betterfoliage/client/gui/ConfigGuiFactory.kt index 655b75f..af1501a 100644 --- a/src/main/kotlin/mods/betterfoliage/client/gui/ConfigGuiFactory.kt +++ b/src/main/kotlin/mods/betterfoliage/client/gui/ConfigGuiFactory.kt @@ -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() - override fun getHandlerFor(element: RuntimeOptionCategoryElement?) = null + override fun runtimeGuiCategories() = hashSetOf() + override fun getHandlerFor(element: IModGuiFactory.RuntimeOptionCategoryElement?) = null override fun initialize(minecraftInstance: Minecraft?) { } class ConfigGuiBetterFoliage(parentScreen: GuiScreen?) : GuiConfig( diff --git a/src/main/kotlin/mods/betterfoliage/client/integration/CLCIntegration.kt b/src/main/kotlin/mods/betterfoliage/client/integration/CLCIntegration.kt deleted file mode 100644 index 90febdb..0000000 --- a/src/main/kotlin/mods/betterfoliage/client/integration/CLCIntegration.kt +++ /dev/null @@ -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) - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/client/integration/ShadersModIntegration.kt b/src/main/kotlin/mods/betterfoliage/client/integration/ShadersModIntegration.kt index 86c3395..1dda0f8 100644 --- a/src/main/kotlin/mods/betterfoliage/client/integration/ShadersModIntegration.kt +++ b/src/main/kotlin/mods/betterfoliage/client/integration/ShadersModIntegration.kt @@ -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() + } } } diff --git a/src/main/kotlin/mods/betterfoliage/client/integration/TFCIntegration.kt b/src/main/kotlin/mods/betterfoliage/client/integration/TFCIntegration.kt deleted file mode 100644 index eb6f189..0000000 --- a/src/main/kotlin/mods/betterfoliage/client/integration/TFCIntegration.kt +++ /dev/null @@ -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) - } - } - } - } - } -} diff --git a/src/main/kotlin/mods/betterfoliage/client/render/AbstractRenderColumn.kt b/src/main/kotlin/mods/betterfoliage/client/render/AbstractRenderColumn.kt index fba339d..70a42e6 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/AbstractRenderColumn.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/AbstractRenderColumn.kt @@ -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() { + init { + matchClassAndModel(matcher, "block/column_side", listOf("end", "end", "side")) + matchClassAndModel(matcher, "block/cube_column", listOf("end", "end", "side")) + } + override fun processTextures(textures: List, 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 } } } \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/client/render/EntityFallingLeavesFX.kt b/src/main/kotlin/mods/betterfoliage/client/render/EntityFallingLeavesFX.kt index da37ac3..aa9ceda 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/EntityFallingLeavesFX.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/EntityFallingLeavesFX.kt @@ -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) { diff --git a/src/main/kotlin/mods/betterfoliage/client/render/EntityRisingSoulFX.kt b/src/main/kotlin/mods/betterfoliage/client/render/EntityRisingSoulFX.kt index 624c924..70acb50 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/EntityRisingSoulFX.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/EntityRisingSoulFX.kt @@ -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 = 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") diff --git a/src/main/kotlin/mods/betterfoliage/client/render/ModelColumn.kt b/src/main/kotlin/mods/betterfoliage/client/render/ModelColumn.kt index 3a32d0f..4030e1c 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/ModelColumn.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/ModelColumn.kt @@ -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 diff --git a/src/main/kotlin/mods/betterfoliage/client/render/RenderAlgae.kt b/src/main/kotlin/mods/betterfoliage/client/render/RenderAlgae.kt index 03f3392..1d5506a 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/RenderAlgae.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/RenderAlgae.kt @@ -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]]!! }, diff --git a/src/main/kotlin/mods/betterfoliage/client/render/RenderCactus.kt b/src/main/kotlin/mods/betterfoliage/client/render/RenderCactus.kt index 9fbddeb..489ef51 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/RenderCactus.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/RenderCactus.kt @@ -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)]!!}, diff --git a/src/main/kotlin/mods/betterfoliage/client/render/RenderConnectedGrass.kt b/src/main/kotlin/mods/betterfoliage/client/render/RenderConnectedGrass.kt index f80eed6..cf3e8b6 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/RenderConnectedGrass.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/RenderConnectedGrass.kt @@ -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) } } } diff --git a/src/main/kotlin/mods/betterfoliage/client/render/RenderConnectedGrassLog.kt b/src/main/kotlin/mods/betterfoliage/client/render/RenderConnectedGrassLog.kt index 208ae65..370fbfa 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/RenderConnectedGrassLog.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/RenderConnectedGrassLog.kt @@ -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) } } } \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/client/render/RenderCoral.kt b/src/main/kotlin/mods/betterfoliage/client/render/RenderCoral.kt index 68383b1..1ed55a5 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/RenderCoral.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/RenderCoral.kt @@ -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)]!!}, diff --git a/src/main/kotlin/mods/betterfoliage/client/render/RenderGrass.kt b/src/main/kotlin/mods/betterfoliage/client/render/RenderGrass.kt index f4282c0..974440e 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/RenderGrass.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/RenderGrass.kt @@ -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) } ) } diff --git a/src/main/kotlin/mods/betterfoliage/client/render/RenderLeaves.kt b/src/main/kotlin/mods/betterfoliage/client/render/RenderLeaves.kt index 9cfad37..d4f9f72 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/RenderLeaves.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/RenderLeaves.kt @@ -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]], diff --git a/src/main/kotlin/mods/betterfoliage/client/render/RenderLilypad.kt b/src/main/kotlin/mods/betterfoliage/client/render/RenderLilypad.kt index 19cc6ac..2f57122 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/RenderLilypad.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/RenderLilypad.kt @@ -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]]), diff --git a/src/main/kotlin/mods/betterfoliage/client/render/RenderLog.kt b/src/main/kotlin/mods/betterfoliage/client/render/RenderLog.kt index 0a74550..2b6dc64 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/RenderLog.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/RenderLog.kt @@ -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 + } } \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/client/render/RenderMycelium.kt b/src/main/kotlin/mods/betterfoliage/client/render/RenderMycelium.kt index 84cc053..34ed242 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/RenderMycelium.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/RenderMycelium.kt @@ -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), diff --git a/src/main/kotlin/mods/betterfoliage/client/render/RenderNetherrack.kt b/src/main/kotlin/mods/betterfoliage/client/render/RenderNetherrack.kt index 67eaa68..8f5500c 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/RenderNetherrack.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/RenderNetherrack.kt @@ -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]]!! }, diff --git a/src/main/kotlin/mods/betterfoliage/client/render/RenderReeds.kt b/src/main/kotlin/mods/betterfoliage/client/render/RenderReeds.kt index 13cf9a8..933feb8 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/RenderReeds.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/RenderReeds.kt @@ -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, diff --git a/src/main/kotlin/mods/betterfoliage/client/render/Utils.kt b/src/main/kotlin/mods/betterfoliage/client/render/Utils.kt index 0982195..afe3379 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/Utils.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/Utils.kt @@ -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)) } diff --git a/src/main/kotlin/mods/betterfoliage/client/texture/GrassRegistry.kt b/src/main/kotlin/mods/betterfoliage/client/texture/GrassRegistry.kt index 3d72fc8..295420a 100644 --- a/src/main/kotlin/mods/betterfoliage/client/texture/GrassRegistry.kt +++ b/src/main/kotlin/mods/betterfoliage/client/texture/GrassRegistry.kt @@ -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 = hashMapOf() +object GrassRegistry : BlockTextureInspector() { 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, 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) } - } \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/client/texture/LeafRegistry.kt b/src/main/kotlin/mods/betterfoliage/client/texture/LeafRegistry.kt index 3da9dab..e35f390 100644 --- a/src/main/kotlin/mods/betterfoliage/client/texture/LeafRegistry.kt +++ b/src/main/kotlin/mods/betterfoliage/client/texture/LeafRegistry.kt @@ -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() { - val leaves: MutableMap = hashMapOf() val particles: MutableMap = 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, 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) } } \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/loader/BetterFoliageCore.kt b/src/main/kotlin/mods/betterfoliage/loader/BetterFoliageCore.kt index 0e897d9..a4c14f7 100644 --- a/src/main/kotlin/mods/betterfoliage/loader/BetterFoliageCore.kt +++ b/src/main/kotlin/mods/betterfoliage/loader/BetterFoliageCore.kt @@ -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!") + } } } \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/loader/Refs.kt b/src/main/kotlin/mods/betterfoliage/loader/Refs.kt index 6b91abd..4a9e138 100644 --- a/src/main/kotlin/mods/betterfoliage/loader/Refs.kt +++ b/src/main/kotlin/mods/betterfoliage/loader/Refs.kt @@ -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, "", 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) } \ No newline at end of file diff --git a/src/main/kotlin/mods/octarinecore/Utils.kt b/src/main/kotlin/mods/octarinecore/Utils.kt index c4fda09..b24f067 100644 --- a/src/main/kotlin/mods/octarinecore/Utils.kt +++ b/src/main/kotlin/mods/octarinecore/Utils.kt @@ -24,6 +24,15 @@ inline fun MutableList.exchange(idx1: Int, idx2: Int) { /** Cross product of this [Iterable] with the parameter. */ fun Iterable.cross(other: Iterable) = flatMap { a -> other.map { b -> a to b } } +inline fun Iterable.mapAs(transform: (C) -> R) = map { transform(it as C) } + +inline fun forEachNested(list1: Iterable, list2: Iterable, func: (T1, T2)-> Unit) = + list1.forEach { e1 -> + list2.forEach { e2 -> + func(e1, e2) + } + } + /** * Property-level delegate backed by a [ThreadLocal]. * diff --git a/src/main/kotlin/mods/octarinecore/client/KeyHandler.kt b/src/main/kotlin/mods/octarinecore/client/KeyHandler.kt index 0c6748d..a386678 100644 --- a/src/main/kotlin/mods/octarinecore/client/KeyHandler.kt +++ b/src/main/kotlin/mods/octarinecore/client/KeyHandler.kt @@ -1,10 +1,10 @@ package mods.octarinecore.client -import cpw.mods.fml.client.registry.ClientRegistry -import cpw.mods.fml.common.FMLCommonHandler -import cpw.mods.fml.common.eventhandler.SubscribeEvent -import cpw.mods.fml.common.gameevent.InputEvent import net.minecraft.client.settings.KeyBinding +import net.minecraftforge.fml.client.registry.ClientRegistry +import net.minecraftforge.fml.common.FMLCommonHandler +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.fml.common.gameevent.InputEvent class KeyHandler(val modId: String, val defaultKey: Int, val lang: String, val action: (InputEvent.KeyInputEvent)->Unit) { diff --git a/src/main/kotlin/mods/octarinecore/client/gui/IdListConfigEntry.kt b/src/main/kotlin/mods/octarinecore/client/gui/IdListConfigEntry.kt index 9f722ee..9fe1a86 100644 --- a/src/main/kotlin/mods/octarinecore/client/gui/IdListConfigEntry.kt +++ b/src/main/kotlin/mods/octarinecore/client/gui/IdListConfigEntry.kt @@ -1,10 +1,10 @@ package mods.octarinecore.client.gui -import cpw.mods.fml.client.config.* import net.minecraft.client.gui.GuiScreen import net.minecraft.client.resources.I18n import net.minecraft.util.EnumChatFormatting.GOLD import net.minecraft.util.EnumChatFormatting.YELLOW +import net.minecraftforge.fml.client.config.* /** * Base class for a config GUI element. @@ -12,9 +12,9 @@ import net.minecraft.util.EnumChatFormatting.YELLOW * The config representation is an integer list of the selected objects' IDs. */ abstract class IdListConfigEntry( - owningScreen: GuiConfig, - owningEntryList: GuiConfigEntries, - configElement: IConfigElement<*> + owningScreen: GuiConfig, + owningEntryList: GuiConfigEntries, + configElement: IConfigElement ) : GuiConfigEntries.CategoryEntry(owningScreen, owningEntryList, configElement) { /** Create the child GUI elements. */ @@ -25,10 +25,14 @@ abstract class IdListConfigEntry( init { stripTooltipDefaultText(toolTip as MutableList) } override fun buildChildScreen(): GuiScreen { - return GuiConfig(this.owningScreen, createChildren(), this.owningScreen.modID, - owningScreen.allRequireWorldRestart || this.configElement.requiresWorldRestart(), - owningScreen.allRequireMcRestart || this.configElement.requiresMcRestart(), this.owningScreen.title, - ((if (this.owningScreen.titleLine2 == null) "" else this.owningScreen.titleLine2) + " > " + this.name)) + return GuiConfig( + this.owningScreen, + createChildren(), + this.owningScreen.modID, + owningScreen.allRequireWorldRestart || this.configElement.requiresWorldRestart(), + owningScreen.allRequireMcRestart || this.configElement.requiresMcRestart(), + this.owningScreen.title, + (if (this.owningScreen.titleLine2 == null) "" else this.owningScreen.titleLine2) + " > " + this.name) } override fun saveConfigElement(): Boolean { @@ -45,14 +49,14 @@ abstract class IdListConfigEntry( /** Child config GUI element of a single toggleable object. */ inner class ItemWrapperElement(val item: T, value: Boolean, val default: Boolean) : - DummyConfigElement(item.itemName, default, ConfigGuiType.BOOLEAN, item.itemName) { - init { set(value) } + DummyConfigElement(item.itemName, default, ConfigGuiType.BOOLEAN, item.itemName) { + + init { + this.value = value + this.defaultValue = default + } override fun getComment() = I18n.format("${configElement.languageKey}.tooltip.element", "${GOLD}${item.itemName}${YELLOW}") - override fun set(value: Boolean) { this.value = value } - fun setDefault(value: Boolean) { this.defaultValue = value } val booleanValue: Boolean get() = value as Boolean } - - } \ No newline at end of file diff --git a/src/main/kotlin/mods/octarinecore/client/gui/NonVerboseArrayEntry.kt b/src/main/kotlin/mods/octarinecore/client/gui/NonVerboseArrayEntry.kt index 89f97f3..445bdf3 100644 --- a/src/main/kotlin/mods/octarinecore/client/gui/NonVerboseArrayEntry.kt +++ b/src/main/kotlin/mods/octarinecore/client/gui/NonVerboseArrayEntry.kt @@ -1,21 +1,21 @@ package mods.octarinecore.client.gui -import cpw.mods.fml.client.config.GuiConfig -import cpw.mods.fml.client.config.GuiConfigEntries -import cpw.mods.fml.client.config.IConfigElement import net.minecraft.client.resources.I18n -import net.minecraft.util.EnumChatFormatting.* +import net.minecraft.util.EnumChatFormatting.AQUA +import net.minecraftforge.fml.client.config.GuiConfig +import net.minecraftforge.fml.client.config.GuiConfigEntries +import net.minecraftforge.fml.client.config.IConfigElement class NonVerboseArrayEntry( - owningScreen: GuiConfig, - owningEntryList: GuiConfigEntries, - configElement: IConfigElement<*> + owningScreen: GuiConfig, + owningEntryList: GuiConfigEntries, + configElement: IConfigElement ) : GuiConfigEntries.ArrayEntry(owningScreen, owningEntryList, configElement) { init { stripTooltipDefaultText(toolTip as MutableList) val shortDefaults = I18n.format("${configElement.languageKey}.arrayEntry", configElement.defaults.size) - toolTip.addAll(mc.fontRenderer.listFormattedStringToWidth("$AQUA${I18n.format("fml.configgui.tooltip.default", shortDefaults)}", 300)) + toolTip.addAll(mc.fontRendererObj.listFormattedStringToWidth("$AQUA${I18n.format("fml.configgui.tooltip.default", shortDefaults)}", 300)) } override fun updateValueButtonText() { diff --git a/src/main/kotlin/mods/octarinecore/client/render/AbstractBlockRenderingHandler.kt b/src/main/kotlin/mods/octarinecore/client/render/AbstractBlockRenderingHandler.kt index d92703d..b235964 100644 --- a/src/main/kotlin/mods/octarinecore/client/render/AbstractBlockRenderingHandler.kt +++ b/src/main/kotlin/mods/octarinecore/client/render/AbstractBlockRenderingHandler.kt @@ -1,23 +1,21 @@ @file:JvmName("RendererHolder") package mods.octarinecore.client.render -import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler -import cpw.mods.fml.client.registry.RenderingRegistry import mods.octarinecore.ThreadLocalDelegate import mods.octarinecore.client.resource.ResourceHandler +import mods.octarinecore.common.Double3 +import mods.octarinecore.common.Int3 +import mods.octarinecore.common.forgeDirOffsets +import mods.octarinecore.common.plus import net.minecraft.block.Block +import net.minecraft.block.state.IBlockState import net.minecraft.client.Minecraft -import net.minecraft.client.renderer.RenderBlocks -import net.minecraft.util.IIcon +import net.minecraft.client.renderer.BlockRendererDispatcher +import net.minecraft.client.renderer.WorldRenderer +import net.minecraft.util.BlockPos +import net.minecraft.util.EnumWorldBlockLayer import net.minecraft.util.MathHelper import net.minecraft.world.IBlockAccess -import net.minecraftforge.common.util.ForgeDirection - -/** - * [ThreadLocal] instance of [ExtendedRenderBlocks] used instead of the vanilla [RenderBlocks] to get the - * AO values and textures used in rendering without duplicating vanilla code. - */ -val renderBlocks by ThreadLocalDelegate { ExtendedRenderBlocks() } /** * [ThreadLocal] instance of [BlockContext] representing the block being rendered. @@ -29,121 +27,77 @@ val blockContext by ThreadLocalDelegate { BlockContext() } */ val modelRenderer by ThreadLocalDelegate { ModelRenderer() } -abstract class AbstractBlockRenderingHandler(modId: String) : ResourceHandler(modId), ISimpleBlockRenderingHandler { +abstract class AbstractBlockRenderingHandler(modId: String) : ResourceHandler(modId) { - // ============================ - // Self-registration - // ============================ - val id = RenderingRegistry.getNextAvailableRenderId() - init { - RenderingRegistry.registerBlockHandler(this); - } + val moveToCutout: Boolean get() = true // ============================ // Custom rendering // ============================ abstract fun isEligible(ctx: BlockContext): Boolean - abstract fun render(ctx: BlockContext, parent: RenderBlocks): Boolean - - // ============================ - // Interface implementation - // ============================ - override fun renderWorldBlock(world: IBlockAccess?, x: Int, y: Int, z: Int, block: Block?, modelId: Int, parentRenderer: RenderBlocks?): Boolean { - renderBlocks.blockAccess = world - return render(blockContext, parentRenderer!!) - } - override fun renderInventoryBlock(block: Block?, metadata: Int, modelId: Int, renderer: RenderBlocks?) {} - override fun shouldRender3DInInventory(modelId: Int) = true - override fun getRenderId(): Int = id + abstract fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean // ============================ // Vanilla rendering wrapper // ============================ /** * Render the block in the current [BlockContext], and capture shading and texture data. - * - * @param[parentRenderer] parent renderer passed in by rendering pipeline, used only for block breaking overlay - * @param[targetPass] which render pass to save shading and texture data from - * @param[block] lambda to use to render the block if it does not have a custom renderer - * @param[face] lambda to determine which faces of the block to render */ - fun renderWorldBlockBase( - parentRenderer: RenderBlocks = renderBlocks, - targetPass: Int = 1, - block: () -> Unit = { blockContext.let { ctx -> renderBlocks.renderStandardBlock(ctx.block, ctx.x, ctx.y, ctx.z) } }, - face: (ShadingCapture, ForgeDirection, Int, IIcon?) -> Boolean - ): Boolean { - val ctx = blockContext - val renderBlocks = renderBlocks - - // use original renderer for block breaking overlay - if (parentRenderer.hasOverrideBlockTexture()) { - parentRenderer.setRenderBoundsFromBlock(ctx.block); - parentRenderer.renderStandardBlock(ctx.block, ctx.x, ctx.y, ctx.z); - return true; + fun renderWorldBlockBase(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer?): Boolean { + ctx.blockState(Int3.zero).let { + if (layer == null || it.block.canRenderInLayer(layer)) + return dispatcher.renderBlock(it, ctx.pos, ctx.world, renderer) } - - // render block - renderBlocks.capture.reset(targetPass) - renderBlocks.capture.renderCallback = face - renderBlocks.setRenderBoundsFromBlock(ctx.block); - val handler = renderingHandlers[ctx.block.renderType]; - if (handler != null && ctx.block.renderType != 0) { - handler.renderWorldBlock(ctx.world, ctx.x, ctx.y, ctx.z, ctx.block, ctx.block.renderType, renderBlocks); - } else { - block() - } - return false; + return false } } +data class BlockData(val state: IBlockState, val color: Int, val brightness: Int) + /** * Represents the block being rendered. Has properties and methods to query the neighborhood of the block in * block-relative coordinates. */ class BlockContext() { var world: IBlockAccess? = null - var x: Int = 0 - var y: Int = 0 - var z: Int = 0 + var pos = BlockPos.ORIGIN - fun set(world: IBlockAccess, x: Int, y: Int, z: Int) { this.world = world; this.x = x; this.y = y; this.z = z; } + fun set(world: IBlockAccess, pos: BlockPos) { this.world = world; this.pos = pos; } - /** Get the [Block] at the given offset. */ - val block: Block get() = world!!.getBlock(x, y, z) - fun block(offset: Int3) = world!!.getBlock(x + offset.x, y + offset.y, z + offset.z) - - /** Get the metadata at the given offset. */ - val meta: Int get() = world!!.getBlockMetadata(x, y, z) - fun meta(offset: Int3) = world!!.getBlockMetadata(x + offset.x, y + offset.y, z + offset.z) - - /** Get the block color multiplier at the given offset. */ - val blockColor: Int get() = block.colorMultiplier(world, x, y, z) - fun blockColor(offset: Int3) = block(offset).colorMultiplier(world, x + offset.x, y + offset.y, z + offset.z) - - /** Get the block brightness at the given offset. */ - val blockBrightness: Int get() = block.getMixedBrightnessForBlock(world, x, y, z) - fun blockBrightness(offset: Int3) = block(offset).getMixedBrightnessForBlock(world, x + offset.x, y + offset.y, z + offset.z) + val block: Block get() = block(Int3.zero) + fun block(offset: Int3) = blockState(offset).block + fun blockState(offset: Int3) = (pos + offset).let { world!!.getBlockState(it) } + fun blockData(offset: Int3, pass: Int) = (pos + offset).let { pos -> + world!!.getBlockState(pos).let { state -> + BlockData( + state, + state.block.colorMultiplier(world!!, pos, pass), + state.block.getMixedBrightnessForBlock(world!!, pos) + ) + } + } /** Get the biome ID at the block position. */ - val biomeId: Int get() = world!!.getBiomeGenForCoords(x, z).biomeID - - /** Get the texture on a given face of the block being rendered. */ - fun icon(face: ForgeDirection) = block(Int3.zero).getIcon(face.ordinal, meta(Int3.zero)) - /** Get the texture on a given face of the block at the given offset. */ - fun icon(offset: Int3, face: ForgeDirection) = block(offset).getIcon(face.ordinal, meta(offset)) + val biomeId: Int get() = world!!.getBiomeGenForCoords(pos).biomeID /** Get the centerpoint of the block being rendered. */ - val blockCenter: Double3 get() = Double3(x + 0.5, y + 0.5, z + 0.5) + val blockCenter: Double3 get() = Double3(pos.x + 0.5, pos.y + 0.5, pos.z + 0.5) + + val chunkBase: Double3 get() { + val cX = if (pos.x >= 0) pos.x / 16 else (pos.x + 1) / 16 - 1 + val cY = pos.y / 16 + val cZ = if (pos.z >= 0) pos.z / 16 else (pos.z + 1) / 16 - 1 + return Double3(cX * 16.0, cY * 16.0, cZ * 16.0) + } /** Is the block surrounded by other blocks that satisfy the predicate on all sides? */ - fun isSurroundedBy(predicate: (Block)->Boolean) = forgeDirOffsets.all { predicate(block(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. */ fun random(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 + 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 } @@ -153,8 +107,8 @@ class BlockContext() { /** Get the distance of the block from the camera (player). */ val cameraDistance: Int get() { val camera = Minecraft.getMinecraft().renderViewEntity ?: return 0 - return Math.abs(x - MathHelper.floor_double(camera.posX)) + - Math.abs(y - MathHelper.floor_double(camera.posY)) + - Math.abs(z - MathHelper.floor_double(camera.posZ)) + return Math.abs(pos.x - MathHelper.floor_double(camera.posX)) + + Math.abs(pos.y - MathHelper.floor_double(camera.posY)) + + Math.abs(pos.z - MathHelper.floor_double(camera.posZ)) } } \ No newline at end of file diff --git a/src/main/kotlin/mods/octarinecore/client/render/AbstractEntityFX.kt b/src/main/kotlin/mods/octarinecore/client/render/AbstractEntityFX.kt index 348159f..d054dd5 100644 --- a/src/main/kotlin/mods/octarinecore/client/render/AbstractEntityFX.kt +++ b/src/main/kotlin/mods/octarinecore/client/render/AbstractEntityFX.kt @@ -1,10 +1,12 @@ package mods.octarinecore.client.render import mods.octarinecore.PI2 +import mods.octarinecore.common.Double3 import net.minecraft.client.Minecraft import net.minecraft.client.particle.EntityFX -import net.minecraft.client.renderer.Tessellator -import net.minecraft.util.IIcon +import net.minecraft.client.renderer.WorldRenderer +import net.minecraft.client.renderer.texture.TextureAtlasSprite +import net.minecraft.entity.Entity import net.minecraft.world.World abstract class AbstractEntityFX(world: World, x: Double, y: Double, z: Double) : EntityFX(world, x, y, z) { @@ -30,7 +32,7 @@ abstract class AbstractEntityFX(world: World, x: Double, y: Double, z: Double) : } /** Render the particle. */ - abstract fun render(tessellator: Tessellator, partialTickTime: Float) + abstract fun render(worldRenderer: WorldRenderer, partialTickTime: Float) /** Update particle on world tick. */ abstract fun update() @@ -41,12 +43,11 @@ abstract class AbstractEntityFX(world: World, x: Double, y: Double, z: Double) : /** Add the particle to the effect renderer if it is valid. */ fun addIfValid() { if (isValid) Minecraft.getMinecraft().effectRenderer.addEffect(this) } - override fun renderParticle(tessellator: Tessellator, partialTickTime: Float, rotX: Float, rotZ: Float, rotYZ: Float, rotXY: Float, rotXZ: Float) { + override fun renderParticle(worldRenderer: WorldRenderer, entity: Entity, partialTickTime: Float, rotX: Float, rotZ: Float, rotYZ: Float, rotXY: Float, rotXZ: Float) { billboardRot.first.setTo(rotX + rotXY, rotZ, rotYZ + rotXZ) billboardRot.second.setTo(rotX - rotXY, -rotZ, rotYZ - rotXZ) - render(tessellator, partialTickTime) + render(worldRenderer, partialTickTime) } - /** * Render a particle quad. * @@ -60,13 +61,13 @@ abstract class AbstractEntityFX(world: World, x: Double, y: Double, z: Double) : * @param[isMirrored] mirror particle texture along V-axis * @param[alpha] aplha blending */ - fun renderParticleQuad(tessellator: Tessellator, + fun renderParticleQuad(worldRenderer: WorldRenderer, partialTickTime: Float, currentPos: Double3 = this.currentPos, prevPos: Double3 = this.prevPos, size: Double = particleScale.toDouble(), rotation: Int = 0, - icon: IIcon = particleIcon, + icon: TextureAtlasSprite = particleIcon, isMirrored: Boolean = false, alpha: Float = this.particleAlpha) { @@ -81,11 +82,11 @@ abstract class AbstractEntityFX(world: World, x: Double, y: Double, z: Double) : val v2 = if (rotation == 0) billboardRot.second * size else Double3.weight(billboardRot.first, -sin[rotation and 63] * size, billboardRot.second, cos[rotation and 63] * size) - tessellator.setColorRGBA_F(this.particleRed, this.particleGreen, this.particleBlue, alpha) - tessellator.addVertexWithUV(center.x - v1.x, center.y - v1.y, center.z - v1.z, maxU, maxV) - tessellator.addVertexWithUV(center.x - v2.x, center.y - v2.y, center.z - v2.z, maxU, minV) - tessellator.addVertexWithUV(center.x + v1.x, center.y + v1.y, center.z + v1.z, minU, minV) - tessellator.addVertexWithUV(center.x + v2.x, center.y + v2.y, center.z + v2.z, minU, maxV) + worldRenderer.setColorRGBA_F(this.particleRed, this.particleGreen, this.particleBlue, alpha) + worldRenderer.addVertexWithUV(center.x - v1.x, center.y - v1.y, center.z - v1.z, maxU, maxV) + worldRenderer.addVertexWithUV(center.x - v2.x, center.y - v2.y, center.z - v2.z, maxU, minV) + worldRenderer.addVertexWithUV(center.x + v1.x, center.y + v1.y, center.z + v1.z, minU, minV) + worldRenderer.addVertexWithUV(center.x + v2.x, center.y + v2.y, center.z + v2.z, minU, maxV) } override fun getFXLayer() = 1 diff --git a/src/main/kotlin/mods/octarinecore/client/render/Model.kt b/src/main/kotlin/mods/octarinecore/client/render/Model.kt index 7a07377..70ce98c 100644 --- a/src/main/kotlin/mods/octarinecore/client/render/Model.kt +++ b/src/main/kotlin/mods/octarinecore/client/render/Model.kt @@ -1,9 +1,11 @@ package mods.octarinecore.client.render +import mods.octarinecore.common.* import mods.octarinecore.minmax import mods.octarinecore.replace -import net.minecraftforge.common.util.ForgeDirection -import java.lang.Math.* +import net.minecraft.util.EnumFacing +import java.lang.Math.max +import java.lang.Math.min /** * Vertex UV coordinates @@ -57,7 +59,7 @@ data class Quad(val v1: Vertex, val v2: Vertex, val v3: Vertex, val v4: Vertex) val normal: Double3 get() = (v2.xyz - v1.xyz).cross(v4.xyz - v1.xyz).normalize fun move(trans: Double3) = transformV { it.copy(xyz = it.xyz + trans) } - fun move(trans: Pair) = move(Double3(trans.second) * trans.first) + fun move(trans: Pair) = move(Double3(trans.second) * trans.first) fun scale (scale: Double) = transformV { it.copy(xyz = it.xyz * scale) } fun scale (scale: Double3) = transformV { it.copy(xyz = Double3(it.xyz.x * scale.x, it.xyz.y * scale.y, it.xyz.z * scale.z)) } fun scaleUV (scale: Double) = transformV { it.copy(uv = UV(it.uv.u * scale, it.uv.v * scale)) } @@ -115,7 +117,7 @@ class Model() { ) } - fun faceQuad(face: ForgeDirection): Quad { + fun faceQuad(face: EnumFacing): Quad { val base = face.vec * 0.5 val top = faceCorners[face.ordinal].topLeft.first.vec * 0.5 val left = faceCorners[face.ordinal].topLeft.second.vec * 0.5 diff --git a/src/main/kotlin/mods/octarinecore/client/render/ModelRenderer.kt b/src/main/kotlin/mods/octarinecore/client/render/ModelRenderer.kt index 509030f..ec30e54 100644 --- a/src/main/kotlin/mods/octarinecore/client/render/ModelRenderer.kt +++ b/src/main/kotlin/mods/octarinecore/client/render/ModelRenderer.kt @@ -1,10 +1,12 @@ package mods.octarinecore.client.render +import mods.octarinecore.client.resource.resourceManager +import mods.octarinecore.common.* import net.minecraft.client.Minecraft -import net.minecraft.client.renderer.Tessellator -import net.minecraft.util.IIcon -import net.minecraftforge.common.util.ForgeDirection -import net.minecraftforge.common.util.ForgeDirection.* +import net.minecraft.client.renderer.WorldRenderer +import net.minecraft.client.renderer.texture.TextureAtlasSprite +import net.minecraft.util.EnumFacing +import net.minecraft.util.EnumFacing.* class ModelRenderer() : ShadingContext() { @@ -25,11 +27,12 @@ class ModelRenderer() : ShadingContext() { * @param[postProcess] lambda to perform arbitrary modifications on the [RenderVertex] just before it goes to the [Tessellator] */ inline fun render( + worldRenderer: WorldRenderer, model: Model, rot: Rotation, trans: Double3 = blockContext.blockCenter, forceFlat: Boolean = false, - icon: (ShadingContext, Int, Quad) -> IIcon, + icon: (ShadingContext, Int, Quad) -> TextureAtlasSprite?, rotateUV: (Quad) -> Int, postProcess: RenderVertex.(ShadingContext, Int, Quad, Int, Vertex) -> Unit ) { @@ -38,17 +41,19 @@ class ModelRenderer() : ShadingContext() { model.quads.forEachIndexed { quadIdx, quad -> val drawIcon = icon(this, quadIdx, quad) - val uvRot = rotateUV(quad) - quad.verts.forEachIndexed { vertIdx, vert -> - temp.init(vert) - temp.rotate(rotation).translate(trans).rotateUV(uvRot).setIcon(drawIcon) - val shader = if (aoEnabled && !forceFlat) vert.aoShader else vert.flatShader - shader.shade(this, temp) - temp.postProcess(this, quadIdx, quad, vertIdx, vert) - Tessellator.instance.apply { - setBrightness(temp.brightness) - setColorOpaque_F(temp.red, temp.green, temp.blue) - addVertexWithUV(temp.x, temp.y, temp.z, temp.u, temp.v) + if (drawIcon != null) { + val uvRot = rotateUV(quad) + quad.verts.forEachIndexed { vertIdx, vert -> + temp.init(vert) + temp.rotate(rotation).translate(trans).rotateUV(uvRot).setIcon(drawIcon) + val shader = if (aoEnabled && !forceFlat) vert.aoShader else vert.flatShader + shader.shade(this, temp) + temp.postProcess(this, quadIdx, quad, vertIdx, vert) + worldRenderer.setTextureUV(temp.u, temp.v) + worldRenderer.setBrightness(temp.brightness) + worldRenderer.setColorOpaque_F(temp.red, temp.green, temp.blue) + worldRenderer.addVertex(temp.x, temp.y, temp.z) + } } } @@ -61,13 +66,16 @@ class ModelRenderer() : ShadingContext() { open class ShadingContext { var rotation = Rotation.identity var aoEnabled = Minecraft.isAmbientOcclusionEnabled() + val aoFaces = Array(6) { AoFaceData(forgeDirs[it]) } - fun aoShading(face: ForgeDirection, corner1: ForgeDirection, corner2: ForgeDirection) = - renderBlocks.capture.aoShading(face.rotate(rotation), corner1.rotate(rotation), corner2.rotate(rotation)) + fun updateShading(offset: Int3, predicate: (EnumFacing) -> Boolean = { true }) { + forgeDirs.forEach { if (predicate(it)) aoFaces[it.ordinal].update(offset) } + } - fun blockColor(offset: Int3) = blockContext.blockColor(offset.rotate(rotation)) - fun blockBrightness(offset: Int3) = blockContext.blockBrightness(offset.rotate(rotation)) - fun icon(face: ForgeDirection) = blockContext.icon(face.rotate(rotation)) + fun aoShading(face: EnumFacing, corner1: EnumFacing, corner2: EnumFacing) = + aoFaces[face.rotate(rotation).ordinal][corner1.rotate(rotation), corner2.rotate(rotation)] + + fun blockData(offset: Int3) = blockContext.blockData(offset.rotate(rotation), 0) } /** @@ -112,7 +120,7 @@ class RenderVertex() { else -> { return this } } } - inline fun setIcon(icon: IIcon): RenderVertex { + inline fun setIcon(icon: TextureAtlasSprite): RenderVertex { u = (icon.maxU - icon.minU) * (u + 0.5) + icon.minU v = (icon.maxV - icon.minV) * (v + 0.5) + icon.minV return this @@ -134,5 +142,8 @@ class RenderVertex() { } } +val allFaces: (EnumFacing) -> Boolean = { true } +val topOnly: (EnumFacing) -> Boolean = { it == UP } + /** Perform no post-processing */ val noPost: RenderVertex.(ShadingContext, Int, Quad, Int, Vertex) -> Unit = { ctx, qi, q, vi, v -> } \ No newline at end of file diff --git a/src/main/kotlin/mods/octarinecore/client/render/OffsetBlockAccess.kt b/src/main/kotlin/mods/octarinecore/client/render/OffsetBlockAccess.kt index c0581aa..7707837 100644 --- a/src/main/kotlin/mods/octarinecore/client/render/OffsetBlockAccess.kt +++ b/src/main/kotlin/mods/octarinecore/client/render/OffsetBlockAccess.kt @@ -1,54 +1,33 @@ package mods.octarinecore.client.render -import mods.octarinecore.minmax +import mods.octarinecore.common.Int3 +import mods.octarinecore.common.plus +import net.minecraft.util.BlockPos +import net.minecraft.util.EnumFacing import net.minecraft.world.IBlockAccess -import net.minecraftforge.common.util.ForgeDirection /** * Delegating [IBlockAccess] that fakes a _modified_ location to return values from a _target_ location. * All other locations are handled normally. * * @param[original] the [IBlockAccess] that is delegated to - * @param[xModded] x coordinate of the _modified_ location - * @param[yModded] y coordinate of the _modified_ location - * @param[zModded] z coordinate of the _modified_ location - * @param[xTarget] x coordinate of the _target_ location - * @param[yTarget] y coordinate of the _target_ location - * @param[zTarget] z coordinate of the _target_ location */ -class OffsetBlockAccess(val original: IBlockAccess, - @JvmField val xModded: Int, @JvmField val yModded: Int, @JvmField val zModded: Int, - @JvmField val xTarget: Int, @JvmField val yTarget: Int, @JvmField val zTarget: Int) : IBlockAccess { +@Suppress("NOTHING_TO_INLINE") +class OffsetBlockAccess(val original: IBlockAccess, val modded: BlockPos, val target: BlockPos) : IBlockAccess { - inline fun withOffset(x: Int, y: Int, z: Int, func: (Int,Int,Int)->T): T { - if (x == xModded && y == yModded && z == zModded) { - return func(xTarget, yTarget, zTarget) - } else { - return func(x, y, z) - } - } + inline fun actualPos(pos: BlockPos?) = + if (pos != null && pos.x == modded.x && pos.y == modded.y && pos.z == modded.z) target else pos - override fun getBlock(x: Int, y: Int, z: Int) = withOffset(x, y, z) - { xAct, yAct, zAct -> original.getBlock(xAct, yAct, zAct) } - override fun getBlockMetadata(x: Int, y: Int, z: Int) = withOffset(x, y, z) - { xAct, yAct, zAct -> original.getBlockMetadata(xAct, yAct, zAct) } - override fun getTileEntity(x: Int, y: Int, z: Int) = withOffset(x, y, z) - { xAct, yAct, zAct -> original.getTileEntity(xAct, yAct, zAct) } - override fun isSideSolid(x: Int, y: Int, z: Int, side: ForgeDirection?, _default: Boolean) = withOffset(x, y, z) - { xAct, yAct, zAct -> original.isSideSolid(xAct, yAct, zAct, side, _default) } - override fun isAirBlock(x: Int, y: Int, z: Int) = withOffset(x, y, z) - { xAct, yAct, zAct -> original.isAirBlock(xAct, yAct, zAct) } - override fun getLightBrightnessForSkyBlocks(x: Int, y: Int, z: Int, side: Int) = withOffset(x, y, z) - { xAct, yAct, zAct -> original.getLightBrightnessForSkyBlocks(xAct, yAct, zAct, side) } - override fun isBlockProvidingPowerTo(x: Int, y: Int, z: Int, side: Int) = withOffset(x, y, z) - { xAct, yAct, zAct -> original.isBlockProvidingPowerTo(xAct, yAct, zAct, side) } - override fun getBiomeGenForCoords(x: Int, z: Int) = withOffset(x, 0, z) - { xAct, yAct, zAct -> original.getBiomeGenForCoords(xAct, zAct) } - - override fun getHeight() = original.height override fun extendedLevelsInChunkCache() = original.extendedLevelsInChunkCache() + override fun getBiomeGenForCoords(pos: BlockPos?) = original.getBiomeGenForCoords(actualPos(pos)) + override fun getBlockState(pos: BlockPos?) = original.getBlockState(actualPos(pos)) + override fun getCombinedLight(pos: BlockPos?, lightValue: Int) = original.getCombinedLight(actualPos(pos), lightValue) + override fun getStrongPower(pos: BlockPos?, direction: EnumFacing?) = original.getStrongPower(actualPos(pos), direction) + override fun getTileEntity(pos: BlockPos?) = original.getTileEntity(actualPos(pos)) + override fun getWorldType() = original.worldType + override fun isAirBlock(pos: BlockPos?) = original.isAirBlock(actualPos(pos)) + override fun isSideSolid(pos: BlockPos?, side: EnumFacing?, _default: Boolean) = original.isSideSolid(actualPos(pos), side, _default) } - /** * Temporarily replaces the [IBlockAccess] used by this [BlockContext] and the corresponding [ExtendedRenderBlocks] * to use an [OffsetBlockAccess] while executing this lambda. @@ -59,10 +38,8 @@ class OffsetBlockAccess(val original: IBlockAccess, */ inline fun BlockContext.withOffset(modded: Int3, target: Int3, func: () -> T): T { val original = world!! - world = OffsetBlockAccess(original, x + modded.x, y + modded.y, z + modded.z, x + target.x, y + target.y, z + target.z) - renderBlocks.blockAccess = world + world = OffsetBlockAccess(original, pos + modded, pos + target) val result = func() world = original - renderBlocks.blockAccess = original return result } \ No newline at end of file diff --git a/src/main/kotlin/mods/octarinecore/client/render/RenderBlocks.kt b/src/main/kotlin/mods/octarinecore/client/render/RenderBlocks.kt deleted file mode 100644 index 22cfb43..0000000 --- a/src/main/kotlin/mods/octarinecore/client/render/RenderBlocks.kt +++ /dev/null @@ -1,147 +0,0 @@ -package mods.octarinecore.client.render - -import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler -import cpw.mods.fml.client.registry.RenderingRegistry -import mods.octarinecore.metaprog.reflectField -import mods.octarinecore.metaprog.reflectStaticField -import net.minecraft.block.Block -import net.minecraft.client.renderer.RenderBlocks -import net.minecraft.util.IIcon -import net.minecraftforge.common.util.ForgeDirection -import net.minecraftforge.common.util.ForgeDirection.* - -/** Reference to the handler list in Forge [RenderingRegistry]. */ -val renderingHandlers: Map = RenderingRegistry::class.java - .reflectStaticField("INSTANCE")!! - .reflectField>("blockRenderers")!! - -/** - * Used instead of the vanilla [RenderBlocks] to get to the AO values and textures used in rendering - * without duplicating vanilla code. - */ -class ExtendedRenderBlocks : RenderBlocks() { - - /** Captures the AO values and textures used in a specific rendering pass when rendering a block. */ - val capture = ShadingCapture() - - override fun renderFaceXPos(block: Block?, x: Double, y: Double, z: Double, icon: IIcon?) = renderFace(EAST, block, x, y, z, icon) - override fun renderFaceXNeg(block: Block?, x: Double, y: Double, z: Double, icon: IIcon?) = renderFace(WEST, block, x, y, z, icon) - override fun renderFaceYPos(block: Block?, x: Double, y: Double, z: Double, icon: IIcon?) = renderFace(UP, block, x, y, z, icon) - override fun renderFaceYNeg(block: Block?, x: Double, y: Double, z: Double, icon: IIcon?) = renderFace(DOWN, block, x, y, z, icon) - override fun renderFaceZPos(block: Block?, x: Double, y: Double, z: Double, icon: IIcon?) = renderFace(SOUTH, block, x, y, z, icon) - override fun renderFaceZNeg(block: Block?, x: Double, y: Double, z: Double, icon: IIcon?) = renderFace(NORTH, block, x, y, z, icon) - - /** - * Render a block face, saving relevant data if appropriate. - */ - @Suppress("NON_EXHAUSTIVE_WHEN") - fun renderFace(face: ForgeDirection, block: Block?, x: Double, y: Double, z: Double, icon: IIcon?) { - if (capture.isCorrectPass(face)) { - saveAllShading(face); capture.icons[face.ordinal] = icon - } - if (capture.renderCallback(capture, face, capture.passes[face.ordinal], icon)) when (face) { - EAST -> super.renderFaceXPos(block, x, y, z, icon) - WEST -> super.renderFaceXNeg(block, x, y, z, icon) - UP -> super.renderFaceYPos(block, x, y, z, icon) - DOWN -> super.renderFaceYNeg(block, x, y, z, icon) - SOUTH -> super.renderFaceZPos(block, x, y, z, icon) - NORTH -> super.renderFaceZNeg(block, x, y, z, icon) - } - } - - fun saveTopLeft(face: ForgeDirection, corner: Pair) = - capture.aoShading(face, corner.first, corner.second) - .set(brightnessTopLeft, colorRedTopLeft, colorGreenTopLeft, colorBlueTopLeft) - - fun saveTopRight(face: ForgeDirection, corner: Pair) = - capture.aoShading(face, corner.first, corner.second) - .set(brightnessTopRight, colorRedTopRight, colorGreenTopRight, colorBlueTopRight) - - fun saveBottomLeft(face: ForgeDirection, corner: Pair) = - capture.aoShading(face, corner.first, corner.second) - .set(brightnessBottomLeft, colorRedBottomLeft, colorGreenBottomLeft, colorBlueBottomLeft) - - fun saveBottomRight(face: ForgeDirection, corner: Pair) = - capture.aoShading(face, corner.first, corner.second) - .set(brightnessBottomRight, colorRedBottomRight, colorGreenBottomRight, colorBlueBottomRight) - - fun saveAllShading(face: ForgeDirection) { - saveTopLeft(face, faceCorners[face.ordinal].topLeft) - saveTopRight(face, faceCorners[face.ordinal].topRight) - saveBottomLeft(face, faceCorners[face.ordinal].bottomLeft) - saveBottomRight(face, faceCorners[face.ordinal].bottomRight) - } -} - -/** - * Captures the AO values and textures used in a specific rendering pass when rendering a block. - */ -class ShadingCapture { - /** Sparse array of stored AO data. */ - val aoShadings = arrayOfNulls(6 * 6 * 6) - - /** List of stored AO data (only valid instances). */ - var shadingsList = listOf() - - /** List of stored texture data. */ - val icons = arrayOfNulls(6) - - /** Number of passes to go on a given face. */ - val passes = Array(6) { 0 } - - /** lambda to determine which faces to render. */ - var renderCallback = alwaysRender - - init { - (0..5).forEach { i1 -> - (0..5).forEach { i2 -> - (i2..5).forEach { i3 -> - aoShadings[cornerId(i1, i2, i3)] = AoData() - } - } - } - shadingsList = aoShadings.filterNotNull() - } - - /** - * Get the AO data of a specific corner. - * - * The two corner directions are interchangeable. All 3 parameters must lie on different axes. - * - * @param[face] block face - * @param[corner1] first direction of corner on face - * @param[corner2] second direction of corner on face - */ - fun aoShading(face: ForgeDirection, corner1: ForgeDirection, corner2: ForgeDirection) = - aoShadings[cornerId(face, corner1, corner2)]!! - - /** Returns true if the AO and texture data should be saved. Mutates state. */ - fun isCorrectPass(face: ForgeDirection) = (passes[face.ordinal]-- > 0) - - /** - * Reset all data and pass counters. - * - * @param[targetPass] which render pass to save - */ - fun reset(targetPass: Int) { - shadingsList.forEach { it.reset() } - (0..5).forEach { idx -> icons[idx] = null; passes[idx] = targetPass } - } - - /** One-dimensional index of a specific corner. */ - protected fun cornerId(face: Int, corner1: Int, corner2: Int) = when (corner2 > corner1) { - true -> 36 * face + 6 * corner1 + corner2 - false -> 36 * face + 6 * corner2 + corner1 - } - - /** One-dimensional index of a specific corner. */ - protected fun cornerId(face: ForgeDirection, corner1: ForgeDirection, corner2: ForgeDirection) = - cornerId(face.ordinal, corner1.ordinal, corner2.ordinal) -} - -/** Lambda to render all faces of a block */ -val alwaysRender: (ShadingCapture, ForgeDirection, Int, IIcon?) -> Boolean = { ctx, face, pass, icon -> true } - -/** Lambda to render no faces of a block */ -val neverRender: (ShadingCapture, ForgeDirection, Int, IIcon?) -> Boolean = { ctx, face, pass, icon -> false } - diff --git a/src/main/kotlin/mods/octarinecore/client/render/Shaders.kt b/src/main/kotlin/mods/octarinecore/client/render/Shaders.kt index d08eea9..a287a37 100644 --- a/src/main/kotlin/mods/octarinecore/client/render/Shaders.kt +++ b/src/main/kotlin/mods/octarinecore/client/render/Shaders.kt @@ -1,24 +1,26 @@ package mods.octarinecore.client.render -import net.minecraftforge.common.util.ForgeDirection +import mods.octarinecore.common.* +import net.minecraft.util.EnumFacing + const val defaultCornerDimming = 0.5f const val defaultEdgeDimming = 0.8f // ================================ -// Resolvers for automatic shading +// Shader instantiation lambdas // ================================ -fun cornerAo(fallbackAxis: Axis): (ForgeDirection, ForgeDirection, ForgeDirection)->Shader = { face, dir1, dir2 -> +fun cornerAo(fallbackAxis: EnumFacing.Axis): (EnumFacing, EnumFacing, EnumFacing)->Shader = { face, dir1, dir2 -> val fallbackDir = listOf(face, dir1, dir2).find { it.axis == fallbackAxis }!! CornerSingleFallback(face, dir1, dir2, fallbackDir) } -val cornerFlat = { face: ForgeDirection, dir1: ForgeDirection, dir2: ForgeDirection -> FaceFlat(face) } -fun cornerAoTri(func: (AoData, AoData)-> AoData) = { face: ForgeDirection, dir1: ForgeDirection, dir2: ForgeDirection -> +val cornerFlat = { face: EnumFacing, dir1: EnumFacing, dir2: EnumFacing -> FaceFlat(face) } +fun cornerAoTri(func: (AoData, AoData)-> AoData) = { face: EnumFacing, dir1: EnumFacing, dir2: EnumFacing -> CornerTri(face, dir1, dir2, func) } val cornerAoMaxGreen = cornerAoTri { s1, s2 -> if (s1.green > s2.green) s1 else s2 } -fun cornerInterpolate(edgeAxis: Axis, weight: Float, dimming: Float): (ForgeDirection, ForgeDirection, ForgeDirection)->Shader = { dir1, dir2, dir3 -> +fun cornerInterpolate(edgeAxis: EnumFacing.Axis, weight: Float, dimming: Float): (EnumFacing, EnumFacing, EnumFacing)->Shader = { dir1, dir2, dir3 -> val edgeDir = listOf(dir1, dir2, dir3).find { it.axis == edgeAxis }!! val faceDirs = listOf(dir1, dir2, dir3).filter { it.axis != edgeAxis } CornerInterpolateDimming(faceDirs[0], faceDirs[1], edgeDir, weight, dimming) @@ -32,14 +34,15 @@ object NoShader : Shader { override fun rotate(rot: Rotation) = this } -class CornerSingleFallback(val face: ForgeDirection, val dir1: ForgeDirection, val dir2: ForgeDirection, val fallbackDir: ForgeDirection, val fallbackDimming: Float = defaultCornerDimming) : Shader { +class CornerSingleFallback(val face: EnumFacing, val dir1: EnumFacing, val dir2: EnumFacing, val fallbackDir: EnumFacing, val fallbackDimming: Float = defaultCornerDimming) : Shader { val offset = Int3(fallbackDir) override fun shade(context: ShadingContext, vertex: RenderVertex) { val shading = context.aoShading(face, dir1, dir2) if (shading.valid) vertex.shade(shading) - else - vertex.shade(context.blockBrightness(offset) brMul fallbackDimming, context.blockColor(offset) colorMul fallbackDimming) + else context.blockData(offset).let { + vertex.shade(it.brightness brMul fallbackDimming, it.color colorMul fallbackDimming) + } } override fun rotate(rot: Rotation) = CornerSingleFallback(face.rotate(rot), dir1.rotate(rot), dir2.rotate(rot), fallbackDir.rotate(rot), fallbackDimming) } @@ -53,7 +56,7 @@ inline fun accumulate(v1: AoData?, v2: AoData?, func: ((AoData, AoData)-> AoData return null } -class CornerTri(val face: ForgeDirection, val dir1: ForgeDirection, val dir2: ForgeDirection, +class CornerTri(val face: EnumFacing, val dir1: EnumFacing, val dir2: EnumFacing, val func: ((AoData, AoData)-> AoData)) : Shader { override fun shade(context: ShadingContext, vertex: RenderVertex) { var acc = accumulate( @@ -69,17 +72,18 @@ class CornerTri(val face: ForgeDirection, val dir1: ForgeDirection, val dir2: Fo override fun rotate(rot: Rotation) = CornerTri(face.rotate(rot), dir1.rotate(rot), dir2.rotate(rot), func) } -class EdgeInterpolateFallback(val face: ForgeDirection, val edgeDir: ForgeDirection, val pos: Double, val fallbackDimming: Float = defaultEdgeDimming): Shader { +class EdgeInterpolateFallback(val face: EnumFacing, val edgeDir: EnumFacing, val pos: Double, val fallbackDimming: Float = defaultEdgeDimming): Shader { val offset = Int3(edgeDir) val edgeAxis = axes.find { it != face.axis && it != edgeDir.axis }!! val weightN = (0.5 - pos).toFloat() val weightP = (0.5 + pos).toFloat() override fun shade(context: ShadingContext, vertex: RenderVertex) { - val shadingP = context.aoShading(face, edgeDir, (edgeAxis to Dir.P).face) - val shadingN = context.aoShading(face, edgeDir, (edgeAxis to Dir.N).face) - if (!shadingP.valid && !shadingN.valid) - return vertex.shade(context.blockBrightness(offset) brMul fallbackDimming, context.blockColor(offset) colorMul fallbackDimming) + val shadingP = context.aoShading(face, edgeDir, (edgeAxis to EnumFacing.AxisDirection.POSITIVE).face) + val shadingN = context.aoShading(face, edgeDir, (edgeAxis to EnumFacing.AxisDirection.NEGATIVE).face) + if (!shadingP.valid && !shadingN.valid) context.blockData(offset).let { + return vertex.shade(it.brightness brMul fallbackDimming, it.color colorMul fallbackDimming) + } if (!shadingP.valid) return vertex.shade(shadingN) if (!shadingN.valid) return vertex.shade(shadingP) vertex.shade(shadingP, shadingN, weightP, weightN) @@ -87,7 +91,7 @@ class EdgeInterpolateFallback(val face: ForgeDirection, val edgeDir: ForgeDirect override fun rotate(rot: Rotation) = EdgeInterpolateFallback(face.rotate(rot), edgeDir.rotate(rot), pos) } -class CornerInterpolateDimming(val face1: ForgeDirection, val face2: ForgeDirection, val edgeDir: ForgeDirection, +class CornerInterpolateDimming(val face1: EnumFacing, val face2: EnumFacing, val edgeDir: EnumFacing, val weight: Float, val dimming: Float, val fallbackDimming: Float = defaultCornerDimming) : Shader { val offset = Int3(edgeDir) override fun shade(context: ShadingContext, vertex: RenderVertex) { @@ -95,8 +99,9 @@ class CornerInterpolateDimming(val face1: ForgeDirection, val face2: ForgeDirect var shading2 = context.aoShading(face2, edgeDir, face1) var weight1 = weight var weight2 = 1.0f - weight - if (!shading1.valid && !shading2.valid) - return vertex.shade(context.blockBrightness(offset) brMul fallbackDimming, context.blockColor(offset) colorMul fallbackDimming) + if (!shading1.valid && !shading2.valid) context.blockData(offset).let { + return vertex.shade(it.brightness brMul fallbackDimming, it.color colorMul fallbackDimming) + } if (!shading1.valid) { shading1 = shading2; weight1 *= dimming } if (!shading2.valid) { shading2 = shading1; weight2 *= dimming } vertex.shade(shading1, shading2, weight1, weight2) @@ -106,7 +111,7 @@ class CornerInterpolateDimming(val face1: ForgeDirection, val face2: ForgeDirect CornerInterpolateDimming(face1.rotate(rot), face2.rotate(rot), edgeDir.rotate(rot), weight, dimming, fallbackDimming) } -class FaceCenter(val face: ForgeDirection): Shader { +class FaceCenter(val face: EnumFacing): Shader { override fun shade(context: ShadingContext, vertex: RenderVertex) { vertex.red = 0.0f; vertex.green = 0.0f; vertex.blue = 0.0f; val b = IntArray(4) @@ -123,25 +128,27 @@ class FaceCenter(val face: ForgeDirection): Shader { override fun rotate(rot: Rotation) = FaceCenter(face.rotate(rot)) } -class FaceFlat(val face: ForgeDirection): Shader { +class FaceFlat(val face: EnumFacing): Shader { override fun shade(context: ShadingContext, vertex: RenderVertex) { - val color = context.blockColor(Int3.zero) - vertex.shade(context.blockBrightness(face.offset), color) + val color = context.blockData(Int3.zero).color + vertex.shade(context.blockData(face.offset).brightness, color) } override fun rotate(rot: Rotation): Shader = FaceFlat(face.rotate(rot)) } class FlatOffset(val offset: Int3): Shader { override fun shade(context: ShadingContext, vertex: RenderVertex) { - vertex.brightness = context.blockBrightness(offset) - vertex.setColor(context.blockColor(offset)) + context.blockData(offset).let { + vertex.brightness = it.brightness + vertex.setColor(it.color) + } } override fun rotate(rot: Rotation): Shader = this } class FlatOffsetNoColor(val offset: Int3): Shader { override fun shade(context: ShadingContext, vertex: RenderVertex) { - vertex.brightness = context.blockBrightness(offset) + vertex.brightness = context.blockData(offset).brightness vertex.red = 1.0f; vertex.green = 1.0f; vertex.blue = 1.0f } override fun rotate(rot: Rotation): Shader = this diff --git a/src/main/kotlin/mods/octarinecore/client/render/Shading.kt b/src/main/kotlin/mods/octarinecore/client/render/Shading.kt index 568bdf1..19c7a7f 100644 --- a/src/main/kotlin/mods/octarinecore/client/render/Shading.kt +++ b/src/main/kotlin/mods/octarinecore/client/render/Shading.kt @@ -1,7 +1,11 @@ package mods.octarinecore.client.render -import net.minecraftforge.common.util.ForgeDirection -import java.lang.Math.* +import mods.octarinecore.common.* +import net.minecraft.client.BFBlockModelRenderer +import net.minecraft.util.EnumFacing +import net.minecraft.util.EnumFacing.* +import java.lang.Math.min +import java.util.* /** Holds shading values for block corners as calculated by vanilla Minecraft rendering. */ class AoData() { @@ -22,11 +26,58 @@ class AoData() { this.blue = blue } + fun set(brightness: Int, colorMultiplier: Float) { + this.valid = true + this.brightness = brightness + this.red = colorMultiplier + this.green = colorMultiplier + this.blue = colorMultiplier + } + companion object { val black = AoData(); } } +class AoFaceData(val face: EnumFacing) { + val ao = BFBlockModelRenderer.getVanillaAoObject() + val top = faceCorners[face.ordinal].topLeft.first + val left = faceCorners[face.ordinal].topLeft.second + + val topLeft = AoData() + val topRight = AoData() + val bottomLeft = AoData() + val bottomRight = AoData() + val ordered = when(face) { + DOWN -> listOf(topLeft, bottomLeft, bottomRight, topRight) + UP -> listOf(bottomRight, topRight, topLeft, bottomLeft) + NORTH -> listOf(bottomLeft, bottomRight, topRight, topLeft) + SOUTH -> listOf(topLeft, bottomLeft, bottomRight, topRight) + WEST -> listOf(bottomLeft, bottomRight, topRight, topLeft) + EAST -> listOf(topRight, topLeft, bottomLeft, bottomRight) + } + + fun update(offset: Int3, useBounds: Boolean = false) { + val ctx = blockContext + val blockState = ctx.blockState(offset) + val quadBounds: FloatArray = FloatArray(12) + val flags = BitSet(3).apply { set(0) } + + ao.updateVertexBrightness(ctx.world, blockState.block, ctx.pos + offset, face, quadBounds, flags) + ordered.forEachIndexed { idx, aoData -> aoData.set(ao.vertexBrightness[idx], ao.vertexColorMultiplier[idx]) } + } + + operator fun get(dir1: EnumFacing, dir2: EnumFacing): AoData { + val isTop = top == dir1 || top == dir2 + val isLeft = left == dir1 || left == dir2 + return if (isTop) { + if (isLeft) topLeft else topRight + } else { + if (isLeft) bottomLeft else bottomRight + } + } +} + /** * Instances of this interface are associated with [Model] vertices, and used to apply brightness and color * values to a [RenderVertex]. @@ -81,9 +132,9 @@ interface Shader { * @param[corner] shader instantiation lambda for corner vertices * @param[edge] shader instantiation lambda for edge midpoint vertices */ -fun faceOrientedAuto(overrideFace: ForgeDirection? = null, - corner: ((ForgeDirection, ForgeDirection, ForgeDirection)->Shader)? = null, - edge: ((ForgeDirection, ForgeDirection)->Shader)? = null) = +fun faceOrientedAuto(overrideFace: EnumFacing? = null, + corner: ((EnumFacing, EnumFacing, EnumFacing)->Shader)? = null, + edge: ((EnumFacing, EnumFacing)->Shader)? = null) = fun(quad: Quad, vertex: Vertex): Shader { val quadFace = overrideFace ?: quad.normal.nearestCardinal val nearestCorner = nearestPosition(vertex.xyz, faceCorners[quadFace.ordinal].asList) { @@ -108,8 +159,8 @@ fun faceOrientedAuto(overrideFace: ForgeDirection? = null, * @param[overrideEdge] assume the given edge instead of going by the _quad_ normal * @param[corner] shader instantiation lambda */ -fun edgeOrientedAuto(overrideEdge: Pair? = null, - corner: (ForgeDirection, ForgeDirection, ForgeDirection)->Shader) = +fun edgeOrientedAuto(overrideEdge: Pair? = null, + corner: (EnumFacing, EnumFacing, EnumFacing)->Shader) = fun(quad: Quad, vertex: Vertex): Shader { val edgeDir = overrideEdge ?: nearestAngle(quad.normal, boxEdges) { it.first.vec + it.second.vec }.first val nearestFace = nearestPosition(vertex.xyz, edgeDir.toList()) { it.vec }.first @@ -119,11 +170,11 @@ fun edgeOrientedAuto(overrideEdge: Pair? = null, return corner(nearestFace, nearestCorner.first, nearestCorner.second) } -fun faceOrientedInterpolate(overrideFace: ForgeDirection? = null) = +fun faceOrientedInterpolate(overrideFace: EnumFacing? = null) = fun(quad: Quad, vertex: Vertex): Shader { val resolver = faceOrientedAuto(overrideFace, edge = { face, edgeDir -> val axis = axes.find { it != face.axis && it != edgeDir.axis }!! - val vec = Double3((axis to Dir.P).face) + val vec = Double3((axis to EnumFacing.AxisDirection.POSITIVE).face) val pos = vertex.xyz.dot(vec) EdgeInterpolateFallback(face, edgeDir, pos) }) diff --git a/src/main/kotlin/mods/octarinecore/client/resource/ModelDataInspector.kt b/src/main/kotlin/mods/octarinecore/client/resource/ModelDataInspector.kt new file mode 100644 index 0000000..7ec34ea --- /dev/null +++ b/src/main/kotlin/mods/octarinecore/client/resource/ModelDataInspector.kt @@ -0,0 +1,124 @@ +package mods.octarinecore.client.resource + +import mods.betterfoliage.client.config.BlockMatcher +import mods.betterfoliage.loader.Refs +import mods.octarinecore.stripStart +import net.minecraft.block.Block +import net.minecraft.block.state.IBlockState +import net.minecraft.client.renderer.block.model.ModelBlock +import net.minecraft.client.renderer.block.statemap.DefaultStateMapper +import net.minecraft.client.renderer.block.statemap.IStateMapper +import net.minecraft.client.renderer.texture.TextureAtlasSprite +import net.minecraft.client.renderer.texture.TextureMap +import net.minecraft.client.resources.model.ModelResourceLocation +import net.minecraft.util.ResourceLocation +import net.minecraftforge.client.event.TextureStitchEvent +import net.minecraftforge.client.model.IModel +import net.minecraftforge.client.model.ModelLoader +import net.minecraftforge.common.MinecraftForge +import net.minecraftforge.fml.common.eventhandler.Event +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +class LoadModelDataEvent(val loader: ModelLoader) : Event() + +abstract class ModelDataInspector { + + abstract fun onAfterModelLoad() + abstract fun processModelDefinition(state: IBlockState, location: ModelResourceLocation, model: IModel) + abstract fun onStitch(atlas: TextureMap) + + init { MinecraftForge.EVENT_BUS.register(this) } + + @Suppress("UNCHECKED_CAST") + @SubscribeEvent + fun handleLoadModelData(event: LoadModelDataEvent) { + val stateMappings = Block.blockRegistry.flatMap { block -> + ((event.loader.blockModelShapes.blockStateMapper.blockStateMap[block]as? IStateMapper ?: DefaultStateMapper()) + .putStateModelLocations(block as Block) as Map).entries + } + val stateModels = Refs.stateModels.get(event.loader) as Map + + onAfterModelLoad() + + stateMappings.forEach { mapping -> + val model = stateModels[mapping.value] + if (model != null) { + val result = processModelDefinition(mapping.key, mapping.value, model) + } + } + } + + @SubscribeEvent + fun handleTextureReload(event: TextureStitchEvent.Pre) { onStitch(event.map) } +} + +abstract class BlockTextureInspector : ModelDataInspector() { + + val state2Names = hashMapOf>() + val modelMappings = linkedListOfBoolean, Iterable>>() + val infoMap = hashMapOf() + + fun match(textureNames: Iterable, predicate: (IBlockState, IModel)->Boolean) = + modelMappings.add(predicate to textureNames) + fun matchClassAndModel(blockClass: BlockMatcher, modelLocation: String, textureNames: Iterable) = + match(textureNames) { state, model -> blockClass.matchesClass(state.block) && model.derivesFromModel(modelLocation) } + + operator fun get(state: IBlockState) = infoMap[state] + + override fun onAfterModelLoad() { + infoMap.clear() + } + + override fun processModelDefinition(state: IBlockState, modelDefLoc: ModelResourceLocation, model: IModel) { + modelMappings.forEach { mapping -> + if (mapping.first(state, model)) { + model.modelBlockAndLoc?.first?.let { modelBlock -> + val textures = mapping.second.map { modelBlock.resolveTextureName(it) } + if (textures.all { it != null && it != "missingno" }) { + state2Names.put(state, textures) + } + } + } + } + } + + override fun onStitch(atlas: TextureMap) { + val state2Texture = hashMapOf>() + val texture2Info = hashMapOf, T>() + state2Names.forEach { state, textureNames -> + val textures = textureNames.map { atlas.getTextureExtry(ResourceLocation(it).toString()) } + if (textures.all { it != null }) { + state2Texture.put(state, textures) + if (textures !in texture2Info) texture2Info.put(textures, processTextures(textures, atlas)) + } + } + state2Texture.forEach { state, texture -> infoMap.put(state, texture2Info[texture]!!) } + state2Names.clear() + } + + abstract fun processTextures(textures: List, atlas: TextureMap): T +} + +@Suppress("UNCHECKED_CAST") +val IModel.modelBlockAndLoc: Pair? get() { + if (Refs.VanillaModelWrapper.isInstance(this)) + return Pair(Refs.model_VMW.get(this) as ModelBlock, Refs.location_VMW.get(this) as ResourceLocation) + else if (Refs.WeightedPartWrapper.isInstance(this)) Refs.model_WPW.get(this)?.let { + return (it as IModel).modelBlockAndLoc + } + else if (Refs.WeightedRandomModel.isInstance(this)) Refs.models_WRM.get(this)?.let { + (it as List).forEach { + it.modelBlockAndLoc.let { if (it != null) return it } + } + } + return null +} + +fun Pair.derivesFrom(targetLocation: String): Boolean { + if (second.stripStart("models/") == ResourceLocation(targetLocation)) return true + if (first.parent != null && first.parentLocation != null) + return Pair(first.parent, first.parentLocation).derivesFrom(targetLocation) + return false +} + +fun IModel.derivesFromModel(modelLocation: String) = modelBlockAndLoc?.derivesFrom(modelLocation) ?: false \ No newline at end of file diff --git a/src/main/kotlin/mods/octarinecore/client/resource/ResourceGeneration.kt b/src/main/kotlin/mods/octarinecore/client/resource/ResourceGeneration.kt index 8941669..10b2596 100644 --- a/src/main/kotlin/mods/octarinecore/client/resource/ResourceGeneration.kt +++ b/src/main/kotlin/mods/octarinecore/client/resource/ResourceGeneration.kt @@ -1,13 +1,12 @@ package mods.octarinecore.client.resource -import cpw.mods.fml.client.FMLClientHandler -import mods.betterfoliage.loader.Refs import mods.octarinecore.metaprog.reflectField import net.minecraft.client.resources.IResourcePack import net.minecraft.client.resources.data.IMetadataSerializer import net.minecraft.client.resources.data.PackMetadataSection import net.minecraft.util.ChatComponentText import net.minecraft.util.ResourceLocation +import net.minecraftforge.fml.client.FMLClientHandler import java.io.InputStream import java.util.* @@ -21,7 +20,6 @@ import java.util.* class GeneratorPack(val name: String, vararg val generators: GeneratorBase) : IResourcePack { init { - // add to the default resource packs FMLClientHandler.instance().reflectField>("resourcePackList")!!.add(this) } @@ -107,16 +105,8 @@ class ParameterList(val params: Map, val value: String?) { } } -/** - * [GeneratorBase] returning parametrized generated resources. - * - * @param[domain] Resource domain of generator. - */ abstract class ParameterBasedGenerator(domain: String) : GeneratorBase(domain) { - /** @see [IResourcePack.resourceExists] */ abstract fun resourceExists(params: ParameterList): Boolean - - /** @see [IResourcePack.getInputStream] */ abstract fun getInputStream(params: ParameterList): InputStream? override fun resourceExists(location: ResourceLocation?) = diff --git a/src/main/kotlin/mods/octarinecore/client/resource/ResourceHandler.kt b/src/main/kotlin/mods/octarinecore/client/resource/ResourceHandler.kt index 199ca5d..27b51ff 100644 --- a/src/main/kotlin/mods/octarinecore/client/resource/ResourceHandler.kt +++ b/src/main/kotlin/mods/octarinecore/client/resource/ResourceHandler.kt @@ -1,13 +1,11 @@ package mods.octarinecore.client.resource -import cpw.mods.fml.client.event.ConfigChangedEvent -import cpw.mods.fml.common.FMLCommonHandler -import cpw.mods.fml.common.eventhandler.SubscribeEvent -import mods.octarinecore.client.render.Double3 -import mods.octarinecore.client.render.Int3 import mods.octarinecore.client.render.Model -import net.minecraft.client.renderer.texture.IIconRegister -import net.minecraft.util.IIcon +import mods.octarinecore.common.Double3 +import mods.octarinecore.common.Int3 +import net.minecraft.client.renderer.texture.TextureAtlasSprite +import net.minecraft.client.renderer.texture.TextureMap +import net.minecraft.util.BlockPos import net.minecraft.util.MathHelper import net.minecraft.util.ResourceLocation import net.minecraft.world.World @@ -15,12 +13,15 @@ import net.minecraft.world.gen.NoiseGeneratorSimplex import net.minecraftforge.client.event.TextureStitchEvent import net.minecraftforge.common.MinecraftForge import net.minecraftforge.event.world.WorldEvent +import net.minecraftforge.fml.client.event.ConfigChangedEvent +import net.minecraftforge.fml.common.FMLCommonHandler +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import java.util.* // ============================ // Resource types // ============================ -interface IStitchListener { fun onStitch(atlas: IIconRegister) } +interface IStitchListener { fun onStitch(atlas: TextureMap) } interface IConfigChangeListener { fun onConfigChange() } interface IWorldLoadListener { fun onWorldLoad(world: World) } @@ -61,10 +62,8 @@ open class ResourceHandler(val modId: String) { // ============================ @SubscribeEvent fun onStitch(event: TextureStitchEvent.Pre) { - if (event.map.textureType == 0) { - resources.forEach { (it as? IStitchListener)?.onStitch(event.map) } - afterStitch() - } + resources.forEach { (it as? IStitchListener)?.onStitch(event.map) } + afterStitch() } @SubscribeEvent @@ -81,8 +80,8 @@ open class ResourceHandler(val modId: String) { // Resource container classes // ============================ class IconHolder(val domain: String, val name: String) : IStitchListener { - var icon: IIcon? = null - override fun onStitch(atlas: IIconRegister) { icon = atlas.registerIcon("$domain:$name") } + var icon: TextureAtlasSprite? = null + override fun onStitch(atlas: TextureMap) { icon = atlas.registerSprite(ResourceLocation(domain, name)) } } class ModelHolder(val init: Model.()->Unit): IConfigChangeListener { @@ -91,14 +90,14 @@ class ModelHolder(val init: Model.()->Unit): IConfigChangeListener { } class IconSet(val domain: String, val namePattern: String) : IStitchListener { - val icons = arrayOfNulls(16) + val icons = arrayOfNulls(16) var num = 0 - override fun onStitch(atlas: IIconRegister) { + override fun onStitch(atlas: TextureMap) { num = 0; (0..15).forEach { idx -> - val locReal = ResourceLocation(domain, "textures/blocks/${namePattern.format(idx)}.png") - if (resourceManager[locReal] != null) icons[num++] = atlas.registerIcon("$domain:${namePattern.format(idx)}") + val locReal = ResourceLocation(domain, "textures/${namePattern.format(idx)}.png") + if (resourceManager[locReal] != null) icons[num++] = atlas.registerSprite(ResourceLocation(domain, namePattern.format(idx))) } } @@ -123,4 +122,5 @@ class SimplexNoise() : IWorldLoadListener { } operator fun get(x: Int, z: Int) = MathHelper.floor_double((noise.func_151605_a(x.toDouble(), z.toDouble()) + 1.0) * 32.0) operator fun get(pos: Int3) = get(pos.x, pos.z) + operator fun get(pos: BlockPos) = get(pos.x, pos.z) } \ No newline at end of file diff --git a/src/main/kotlin/mods/octarinecore/client/resource/TextureGenerator.kt b/src/main/kotlin/mods/octarinecore/client/resource/TextureGenerator.kt index b4c9ef3..308139d 100644 --- a/src/main/kotlin/mods/octarinecore/client/resource/TextureGenerator.kt +++ b/src/main/kotlin/mods/octarinecore/client/resource/TextureGenerator.kt @@ -39,9 +39,7 @@ abstract class TextureGenerator(domain: String) : ParameterBasedGenerator(domain } ) - /** - * Get the type and location of the texture resource encoded by the given [ParameterList]. - */ + /** Get the type and location of the texture resource encoded by the given [ParameterList]. */ fun targetResource(params: ParameterList): Pair? { val baseTexture = if (listOf("dom", "path").all { it in params }) ResourceLocation(params["dom"]!!, params["path"]!!) diff --git a/src/main/kotlin/mods/octarinecore/client/resource/Utils.kt b/src/main/kotlin/mods/octarinecore/client/resource/Utils.kt index 97ca2d5..a0bf44f 100644 --- a/src/main/kotlin/mods/octarinecore/client/resource/Utils.kt +++ b/src/main/kotlin/mods/octarinecore/client/resource/Utils.kt @@ -18,7 +18,8 @@ import java.lang.Math.* import javax.imageio.ImageIO /** Concise getter for the Minecraft resource manager. */ -val resourceManager: SimpleReloadableResourceManager get() = Minecraft.getMinecraft().resourceManager as SimpleReloadableResourceManager +val resourceManager: SimpleReloadableResourceManager get() = + Minecraft.getMinecraft().resourceManager as SimpleReloadableResourceManager /** Append a string to the [ResourceLocation]'s path. */ operator fun ResourceLocation.plus(str: String) = ResourceLocation(resourceDomain, resourcePath + str) @@ -86,5 +87,5 @@ val TextureAtlasSprite.averageColor: Int? get() { * Get the actual location of a texture from the name of its [TextureAtlasSprite]. */ fun textureLocation(iconName: String) = ResourceLocation(iconName).let { - ResourceLocation(it.resourceDomain, "textures/blocks/${it.resourcePath}") + ResourceLocation(it.resourceDomain, "textures/${it.resourcePath}") } \ No newline at end of file diff --git a/src/main/kotlin/mods/octarinecore/client/render/Geometry.kt b/src/main/kotlin/mods/octarinecore/common/Geometry.kt similarity index 70% rename from src/main/kotlin/mods/octarinecore/client/render/Geometry.kt rename to src/main/kotlin/mods/octarinecore/common/Geometry.kt index ccddb10..9afc975 100644 --- a/src/main/kotlin/mods/octarinecore/client/render/Geometry.kt +++ b/src/main/kotlin/mods/octarinecore/common/Geometry.kt @@ -1,41 +1,52 @@ -package mods.octarinecore.client.render +package mods.octarinecore.common -import mods.octarinecore.client.render.Axis.* -import mods.octarinecore.client.render.Dir.N -import mods.octarinecore.client.render.Dir.P import mods.octarinecore.cross -import net.minecraftforge.common.util.ForgeDirection -import net.minecraftforge.common.util.ForgeDirection.* +import net.minecraft.util.BlockPos +import net.minecraft.util.EnumFacing +import net.minecraft.util.EnumFacing.* +import net.minecraft.util.EnumFacing.Axis.* +import net.minecraft.util.EnumFacing.AxisDirection.* // ================================ // Axes and directions // ================================ -enum class Axis { X, Y, Z } -enum class Dir { P, N } val axes = listOf(X, Y, Z) -val axisDirs = listOf(P, N) -val forgeDirs = ForgeDirection.VALID_DIRECTIONS +val axisDirs = listOf(POSITIVE, NEGATIVE) +val EnumFacing.dir: AxisDirection get() = axisDirection +val AxisDirection.sign: String get() = when(this) { POSITIVE -> "+"; NEGATIVE -> "-" } +val forgeDirs = EnumFacing.values() val forgeDirOffsets = forgeDirs.map { Int3(it) } -val ForgeDirection.axis: Axis get() = when(this) {EAST, WEST -> X; UP, DOWN -> Y; else -> Z } -val ForgeDirection.dir: Dir get() = when(this) {UP, SOUTH, EAST -> P; else -> N } -val Pair.face: ForgeDirection get() = when(this) { - X to P -> EAST; X to N -> WEST; Y to P -> UP; Y to N -> DOWN; Z to P -> SOUTH; Z to N -> NORTH; else -> UNKNOWN +val Pair.face: EnumFacing get() = when(this) { + X to POSITIVE -> EAST; X to NEGATIVE -> WEST; + Y to POSITIVE -> UP; Y to NEGATIVE -> DOWN; + Z to POSITIVE -> SOUTH; else -> NORTH; } -val ForgeDirection.perpendiculars: List get() = +val EnumFacing.perpendiculars: List get() = axes.filter { it != this.axis }.cross(axisDirs).map { it.face } -val ForgeDirection.offset: Int3 get() = forgeDirOffsets[ordinal] +val EnumFacing.offset: Int3 get() = forgeDirOffsets[ordinal] + +/** Old ForgeDirection rotation matrix yanked from 1.7.10 */ +val ROTATION_MATRIX: Array get() = arrayOf( + intArrayOf(0, 1, 4, 5, 3, 2, 6), + intArrayOf(0, 1, 5, 4, 2, 3, 6), + intArrayOf(5, 4, 2, 3, 0, 1, 6), + intArrayOf(4, 5, 2, 3, 1, 0, 6), + intArrayOf(2, 3, 1, 0, 4, 5, 6), + intArrayOf(3, 2, 0, 1, 4, 5, 6) +) // ================================ // Vectors // ================================ -operator fun ForgeDirection.times(scale: Double) = - Double3(offsetX.toDouble() * scale, offsetY.toDouble() * scale, offsetZ.toDouble() * scale) -val ForgeDirection.vec: Double3 get() = Double3(offsetX.toDouble(), offsetY.toDouble(), offsetZ.toDouble()) +operator fun EnumFacing.times(scale: Double) = + Double3(directionVec.x.toDouble() * scale, directionVec.y.toDouble() * scale, directionVec.z.toDouble() * scale) +val EnumFacing.vec: Double3 get() = Double3(directionVec.x.toDouble(), directionVec.y.toDouble(), directionVec.z.toDouble()) +operator fun BlockPos.plus(other: Int3) = BlockPos(x + other.x, y + other.y, z + other.z) /** 3D vector of [Double]s. Offers both mutable operations, and immutable operations in operator notation. */ data class Double3(var x: Double, var y: Double, var z: Double) { constructor(x: Float, y: Float, z: Float) : this(x.toDouble(), y.toDouble(), z.toDouble()) - constructor(dir: ForgeDirection) : this(dir.offsetX.toDouble(), dir.offsetY.toDouble(), dir.offsetZ.toDouble()) + constructor(dir: EnumFacing) : this(dir.directionVec.x.toDouble(), dir.directionVec.y.toDouble(), dir.directionVec.z.toDouble()) companion object { val zero: Double3 get() = Double3(0.0, 0.0, 0.0) fun weight(v1: Double3, weight1: Double, v2: Double3, weight2: Double) = @@ -79,16 +90,16 @@ data class Double3(var x: Double, var y: Double, var z: Double) { infix fun cross(o: Double3) = Double3(y * o.z - z * o.y, z * o.x - x * o.z, x * o.y - y * o.x) val length: Double get() = Math.sqrt(x * x + y * y + z * z) val normalize: Double3 get() = (1.0 / length).let { Double3(x * it, y * it, z * it) } - val nearestCardinal: ForgeDirection get() = nearestAngle(this, forgeDirs.asIterable()) { it.vec }.first + val nearestCardinal: EnumFacing get() = nearestAngle(this, forgeDirs.asIterable()) { it.vec }.first } /** 3D vector of [Int]s. Offers both mutable operations, and immutable operations in operator notation. */ data class Int3(var x: Int, var y: Int, var z: Int) { - constructor(dir: ForgeDirection) : this(dir.offsetX, dir.offsetY, dir.offsetZ) - constructor(offset: Pair) : this( - offset.first * offset.second.offsetX, - offset.first * offset.second.offsetY, - offset.first * offset.second.offsetZ + constructor(dir: EnumFacing) : this(dir.directionVec.x, dir.directionVec.y, dir.directionVec.z) + constructor(offset: Pair) : this( + offset.first * offset.second.directionVec.x, + offset.first * offset.second.directionVec.y, + offset.first * offset.second.directionVec.z ) companion object { val zero = Int3(0, 0, 0) @@ -96,10 +107,10 @@ data class Int3(var x: Int, var y: Int, var z: Int) { // immutable operations operator fun plus(other: Int3) = Int3(x + other.x, y + other.y, z + other.z) - operator fun plus(other: Pair) = Int3( - x + other.first * other.second.offsetX, - y + other.first * other.second.offsetY, - z + other.first * other.second.offsetZ + operator fun plus(other: Pair) = Int3( + x + other.first * other.second.directionVec.x, + y + other.first * other.second.directionVec.y, + z + other.first * other.second.directionVec.z ) operator fun unaryMinus() = Int3(-x, -y, -z) operator fun minus(other: Int3) = Int3(x - other.x, y - other.y, z - other.z) @@ -132,17 +143,17 @@ data class Int3(var x: Int, var y: Int, var z: Int) { // ================================ // Rotation // ================================ -val ForgeDirection.rotations: Array get() = - Array(6) { idx -> ForgeDirection.values()[ForgeDirection.ROTATION_MATRIX[ordinal][idx]] } -fun ForgeDirection.rotate(rot: Rotation) = rot.forward[ordinal] -fun rot(axis: ForgeDirection) = Rotation.rot90[axis.ordinal] +val EnumFacing.rotations: Array get() = + Array(6) { idx -> EnumFacing.values()[ROTATION_MATRIX[ordinal][idx]] } +fun EnumFacing.rotate(rot: Rotation) = rot.forward[ordinal] +fun rot(axis: EnumFacing) = Rotation.rot90[axis.ordinal] /** * Class representing an arbitrary rotation (or combination of rotations) around cardinal axes by 90 degrees. * In effect, a permutation of [ForgeDirection]s. */ @Suppress("NOTHING_TO_INLINE") -class Rotation(val forward: Array, val reverse: Array) { +class Rotation(val forward: Array, val reverse: Array) { operator fun plus(other: Rotation) = Rotation( Array(6) { idx -> forward[other.forward[idx].ordinal] }, Array(6) { idx -> other.reverse[reverse[idx].ordinal] } @@ -150,9 +161,9 @@ class Rotation(val forward: Array, val reverse: Array this; 2 -> this + this; 3 -> -this; else -> identity } - inline fun rotatedComponent(dir: ForgeDirection, x: Int, y: Int, z: Int) = + inline fun rotatedComponent(dir: EnumFacing, x: Int, y: Int, z: Int) = when(reverse[dir.ordinal]) { EAST -> x; WEST -> -x; UP -> y; DOWN -> -y; SOUTH -> z; NORTH -> -z; else -> 0 } - inline fun rotatedComponent(dir: ForgeDirection, x: Double, y: Double, z: Double) = + inline fun rotatedComponent(dir: EnumFacing, x: Double, y: Double, z: Double) = when(reverse[dir.ordinal]) { EAST -> x; WEST -> -x; UP -> y; DOWN -> -y; SOUTH -> z; NORTH -> -z; else -> 0.0 } companion object { @@ -177,7 +188,7 @@ val boxEdges = forgeDirs.flatMap { face1 -> forgeDirs.filter { it.axis > face1.a * @param[objPos] lambda to calculate the position of an object * @return [Pair] of (object, distance) */ -fun nearestPosition(vertex: Double3, objs: Iterable, objPos: (T)->Double3): Pair = +fun nearestPosition(vertex: Double3, objs: Iterable, objPos: (T)-> Double3): Pair = objs.map { it to (objPos(it) - vertex).length }.minBy { it.second }!! /** @@ -188,14 +199,14 @@ fun nearestPosition(vertex: Double3, objs: Iterable, objPos: (T)->Double3 * @param[objAngle] lambda to calculate the orientation of an object * @return [Pair] of (object, normalized dot product) */ -fun nearestAngle(vector: Double3, objs: Iterable, objAngle: (T)->Double3): Pair = +fun nearestAngle(vector: Double3, objs: Iterable, objAngle: (T)-> Double3): Pair = objs.map { it to objAngle(it).dot(vector) }.maxBy { it.second }!! -data class FaceCorners(val topLeft: Pair, - val topRight: Pair, - val bottomLeft: Pair, - val bottomRight: Pair) { - constructor(top: ForgeDirection, left: ForgeDirection) : +data class FaceCorners(val topLeft: Pair, + val topRight: Pair, + val bottomLeft: Pair, + val bottomRight: Pair) { + constructor(top: EnumFacing, left: EnumFacing) : this(top to left, top to left.opposite, top.opposite to left, top.opposite to left.opposite) val asArray = arrayOf(topLeft, topRight, bottomLeft, bottomRight) @@ -208,7 +219,5 @@ val faceCorners = forgeDirs.map { when(it) { NORTH -> FaceCorners(WEST, UP) SOUTH -> FaceCorners(UP, WEST) WEST -> FaceCorners(SOUTH, UP) - EAST ->FaceCorners(SOUTH, DOWN) - else -> FaceCorners(UNKNOWN, UNKNOWN) + EAST -> FaceCorners(SOUTH, DOWN) }} - diff --git a/src/main/kotlin/mods/octarinecore/config/DelegatingConfig.kt b/src/main/kotlin/mods/octarinecore/common/config/DelegatingConfig.kt similarity index 94% rename from src/main/kotlin/mods/octarinecore/config/DelegatingConfig.kt rename to src/main/kotlin/mods/octarinecore/common/config/DelegatingConfig.kt index ab6f89a..9987197 100644 --- a/src/main/kotlin/mods/octarinecore/config/DelegatingConfig.kt +++ b/src/main/kotlin/mods/octarinecore/common/config/DelegatingConfig.kt @@ -1,17 +1,17 @@ -package mods.octarinecore.config +package mods.octarinecore.common.config import com.google.common.collect.LinkedListMultimap -import cpw.mods.fml.client.config.GuiConfigEntries -import cpw.mods.fml.client.config.IConfigElement -import cpw.mods.fml.client.event.ConfigChangedEvent -import cpw.mods.fml.common.FMLCommonHandler -import cpw.mods.fml.common.eventhandler.SubscribeEvent import mods.octarinecore.metaprog.reflectField import mods.octarinecore.metaprog.reflectFieldsOfType import mods.octarinecore.metaprog.reflectNestedObjects import net.minecraftforge.common.config.ConfigElement import net.minecraftforge.common.config.Configuration import net.minecraftforge.common.config.Property +import net.minecraftforge.fml.client.config.GuiConfigEntries +import net.minecraftforge.fml.client.config.IConfigElement +import net.minecraftforge.fml.client.event.ConfigChangedEvent +import net.minecraftforge.fml.common.FMLCommonHandler +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import kotlin.reflect.KProperty // ============================ @@ -37,7 +37,7 @@ abstract class DelegatingConfig(val modId: String, val langPrefix: String) { /** The [Configuration] backing this config object. */ var config: Configuration? = null - val rootGuiElements = linkedListOf>() + val rootGuiElements = linkedListOf() /** Attach this config object to the given [Configuration] and update all properties. */ fun attach(config: Configuration) { @@ -50,7 +50,7 @@ abstract class DelegatingConfig(val modId: String, val langPrefix: String) { property.attach(config, langPrefix, category, name) property.guiProperties.forEach { guiProperty -> property.guiClass?.let { guiProperty.setConfigEntryClass(it) } - if (category == "global") rootGuiElements.add(ConfigElement.getTypedElement(guiProperty)) + if (category == "global") rootGuiElements.add(ConfigElement(guiProperty)) else subProperties.put(category, guiProperty.name) } } @@ -58,7 +58,7 @@ abstract class DelegatingConfig(val modId: String, val langPrefix: String) { val configCategory = config.getCategory(category) configCategory.setLanguageKey("$langPrefix.$category") configCategory.setPropertyOrder(subProperties[category]) - rootGuiElements.add(ConfigElement(configCategory)) + rootGuiElements.add(ConfigElement(configCategory)) } save() } @@ -118,7 +118,7 @@ abstract class ConfigPropertyBase { var lang: String? = null /** GUI class to use. */ - var guiClass: Class>? = null + var guiClass: Class? = null /** @return true if the property has changed. */ abstract val hasChanged: Boolean diff --git a/src/main/kotlin/mods/octarinecore/metaprog/Reflection.kt b/src/main/kotlin/mods/octarinecore/metaprog/Reflection.kt index 3cf4e85..293306b 100644 --- a/src/main/kotlin/mods/octarinecore/metaprog/Reflection.kt +++ b/src/main/kotlin/mods/octarinecore/metaprog/Reflection.kt @@ -64,6 +64,7 @@ open class ClassRef(val mcpName: String, val obfName: String) : ResolvableUnit>> = arrayListOf() + var methodTransformers: MutableListUnit>> = arrayListOf() /** Add a transformation to perform. Call this during instance initialization. * * @param[method] the target method of the transformation * @param[trans] method transformation lambda */ - fun transformMethod(method: MethodRef, trans: MethodTransformContext.()->Unit) = transformers.add(method to trans) + fun transformMethod(method: MethodRef, trans: MethodTransformContext.()->Unit) = methodTransformers.add(method to trans) override fun transform(name: String?, transformedName: String?, classData: ByteArray?): ByteArray? { if (classData == null) return null @@ -48,7 +49,7 @@ open class Transformer : IClassTransformer { val classNode = ClassNode().apply { val reader = ClassReader(classData); reader.accept(this, 0) } var workDone = false - val transformations: ListUnit, MethodNode?>> = transformers.map { transformer -> + val transformations: ListUnit, MethodNode?>> = methodTransformers.map { transformer -> if (transformedName != transformer.first.parentClass.mcpName) return@map transformer.second to null log.debug("Found class: $name -> $transformedName") log.debug(" searching: ${transformer.first.name(OBF)} ${transformer.first.asmDescriptor(OBF)} -> ${transformer.first.name(MCP)} ${transformer.first.asmDescriptor(MCP)}") @@ -72,7 +73,7 @@ open class Transformer : IClassTransformer { } } - return if (!workDone) classData else ClassWriter(0).apply { classNode.accept(this) }.toByteArray() + return if (!workDone) classData else ClassWriter(3).apply { classNode.accept(this) }.toByteArray() } } @@ -84,6 +85,11 @@ open class Transformer : IClassTransformer { * @param[environment] the type of environment we are in */ class MethodTransformContext(val method: MethodNode, val environment: Namespace) { + + fun makePublic() { + method.access = (method.access or Opcodes.ACC_PUBLIC) and (Opcodes.ACC_PRIVATE or Opcodes.ACC_PROTECTED).inv() + } + /** * Find the first instruction that matches a predicate. * @@ -117,9 +123,14 @@ class MethodTransformContext(val method: MethodNode, val environment: Namespace) * @param[init] builder-style lambda to assemble instruction list */ fun AbstractInsnNode.insertBefore(init: InstructionList.()->Unit) = InstructionList(environment).apply{ - this.init(); list.forEach { method.instructions.insertBefore(this@insertBefore, it) } + val insertBeforeNode = this@insertBefore //.let { if (it.previous is FrameNode) it.previous else it } + this.init(); list.forEach { method.instructions.insertBefore(insertBeforeNode, it) } } + fun AbstractInsnNode.replace(init: InstructionList.()->Unit) = InstructionList(environment).apply { + insertAfter(init) + method.instructions.remove(this@replace) + } /** Remove all isntructiuons between the given two (inclusive). */ fun Pair.remove() { var current: AbstractInsnNode? = first @@ -151,6 +162,16 @@ class MethodTransformContext(val method: MethodNode, val environment: Namespace) fun varinsn(opcode: Int, idx: Int): (AbstractInsnNode)->Boolean = { insn -> insn.opcode == opcode && insn is VarInsnNode && insn.`var` == idx } + + fun invokeName(name: String): (AbstractInsnNode)->Boolean = { insn -> + (insn as? MethodInsnNode)?.name == name + } + + fun invokeRef(ref: MethodRef): (AbstractInsnNode)->Boolean = { insn -> + (insn as? MethodInsnNode)?.let { + it.name == ref.name(environment) && it.owner == ref.parentClass.name(environment).replace(".", "/") + } ?: false + } } /** @@ -160,6 +181,8 @@ class MethodTransformContext(val method: MethodNode, val environment: Namespace) */ class InstructionList(val environment: Namespace) { + fun insn(opcode: Int) = list.add(InsnNode(opcode)) + /** The instruction list being assembled. */ val list: MutableList = arrayListOf() diff --git a/src/main/resources/META-INF/BetterFoliage_at.cfg b/src/main/resources/META-INF/BetterFoliage_at.cfg new file mode 100644 index 0000000..bf3d22b --- /dev/null +++ b/src/main/resources/META-INF/BetterFoliage_at.cfg @@ -0,0 +1,28 @@ +public net.minecraft.client.renderer.BlockModelRenderer func_178261_a(Lnet/minecraft/block/Block;[ILnet/minecraft/util/EnumFacing;[FLjava/util/BitSet;)V + +public net.minecraft.client.renderer.BlockModelRenderer$AmbientOcclusionFace +public net.minecraft.client.renderer.BlockModelRenderer$AmbientOcclusionFace field_178206_b # vertexColorMultiplier +public net.minecraft.client.renderer.BlockModelRenderer$AmbientOcclusionFace field_178207_c # vertexBrightness + +public net.minecraft.client.renderer.BlockModelRenderer$VertexTranslations field_178191_g +public net.minecraft.client.renderer.BlockModelRenderer$VertexTranslations field_178200_h +public net.minecraft.client.renderer.BlockModelRenderer$VertexTranslations field_178201_i +public net.minecraft.client.renderer.BlockModelRenderer$VertexTranslations field_178198_j + +public net.minecraft.client.renderer.WorldRenderer field_179008_i # rawBufferIndex +public net.minecraft.client.renderer.WorldRenderer field_179009_s # bufferSize +public net.minecraft.client.renderer.WorldRenderer field_179011_q # vertexFormat +public net.minecraft.client.renderer.WorldRenderer func_178983_e(I)V # growBuffer() + +public net.minecraft.client.resources.model.ModelBakery field_177612_i # variants +public net.minecraft.client.resources.model.ModelBakery field_177611_h # models +public net.minecraft.client.resources.model.ModelBakery field_177609_j # textureMap +public net.minecraft.client.resources.model.ModelBakery field_177610_k # blockModelShapes + +public net.minecraftforge.client.model.ModelLoader stateModels + +public net.minecraft.client.resources.model.WeightedBakedModel field_177565_b # models + +public net.minecraft.client.renderer.block.statemap.BlockStateMapper field_178450_a # blockStateMap + +public net.minecraft.client.resources.SimpleReloadableResourceManager field_110548_a # domainResourceManagers \ No newline at end of file diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_algae_0.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_algae_0.png index 3703b07..ccdf7fe 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_algae_0.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_algae_0.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_algae_1.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_algae_1.png index 2601579..d9f56e1 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_algae_1.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_algae_1.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_algae_2.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_algae_2.png index 5377e8b..920f063 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_algae_2.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_algae_2.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_algae_3.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_algae_3.png index af1145c..7df8800 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_algae_3.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_algae_3.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_cactus.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_cactus.png index cfbf609..0945b8e 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_cactus.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_cactus.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_crust_0.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_crust_0.png index f1c6ab9..c16acec 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_crust_0.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_crust_0.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_crust_1.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_crust_1.png index 27f09fc..d6a68bd 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_crust_1.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_crust_1.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_crust_2.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_crust_2.png index a54af00..b7e6143 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_crust_2.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_crust_2.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_crust_3.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_crust_3.png index 5f383bf..8601161 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_crust_3.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_crust_3.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_long_0.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_long_0.png index 314e900..a45f67f 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_long_0.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_long_0.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_long_1.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_long_1.png index 76b92ea..f1ed5de 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_long_1.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_long_1.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_long_2.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_long_2.png index ac9aaf1..7313aaf 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_long_2.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_long_2.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_long_3.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_long_3.png index e8f46df..915f85b 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_long_3.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_long_3.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_long_4.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_long_4.png index 386e5db..c5d9d31 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_long_4.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_long_4.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_short_0.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_short_0.png index 5372504..8471b48 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_short_0.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_short_0.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_short_1.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_short_1.png index cda1e73..e2994e2 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_short_1.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_short_1.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_short_2.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_short_2.png index a82a97e..787c01a 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_short_2.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_short_2.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_side_0.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_side_0.png index 978d6c3..2dff2a4 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_side_0.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_side_0.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_side_1.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_side_1.png index 0af29c9..d82ae52 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_side_1.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_side_1.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_snowed_0.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_snowed_0.png index 00ffe89..4384561 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_snowed_0.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_snowed_0.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_snowed_1.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_snowed_1.png index 68d2f8f..a417071 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_snowed_1.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_grass_snowed_1.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_mycel_0.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_mycel_0.png index 936902e..5a1b3d7 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_mycel_0.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_mycel_0.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_mycel_1.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_mycel_1.png index a4291e3..021b648 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_mycel_1.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_mycel_1.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_mycel_2.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_mycel_2.png index 82172c2..7d8f7d3 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_mycel_2.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_mycel_2.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_mycel_3.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_mycel_3.png index a658ec1..dd76fc4 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_mycel_3.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_mycel_3.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_netherrack_0.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_netherrack_0.png index 8c19a4d..37f23cd 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_netherrack_0.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_netherrack_0.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_netherrack_1.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_netherrack_1.png index 03f03c1..19e5221 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_netherrack_1.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_netherrack_1.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_netherrack_2.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_netherrack_2.png index 72a676f..9076238 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_netherrack_2.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_netherrack_2.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_reed_0.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_reed_0.png index f7f107c..470c53f 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_reed_0.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_reed_0.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_reed_1.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_reed_1.png index e75e52c..feeb0d1 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_reed_1.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_reed_1.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_reed_2.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_reed_2.png index ff22ae9..8cb69c7 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_reed_2.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_reed_2.png differ diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_reed_3.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_reed_3.png index 96dcb2e..c1570eb 100644 Binary files a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_reed_3.png and b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_reed_3.png differ