diff --git a/build.gradle b/build.gradle index 9ba9703..2c606d4 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ dependencies { shade "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" } minecraft { - version = '1.10.2-12.18.1.2075' + version = '1.10.2-12.18.2.2121' mappings = 'snapshot_20160905' runDir = 'run' } diff --git a/src/main/kotlin/mods/betterfoliage/client/Client.kt b/src/main/kotlin/mods/betterfoliage/client/Client.kt index efd75f0..8510e74 100644 --- a/src/main/kotlin/mods/betterfoliage/client/Client.kt +++ b/src/main/kotlin/mods/betterfoliage/client/Client.kt @@ -2,9 +2,7 @@ package mods.betterfoliage.client import mods.betterfoliage.BetterFoliageMod import mods.betterfoliage.client.gui.ConfigGuiFactory -import mods.betterfoliage.client.integration.ForestryIntegration -import mods.betterfoliage.client.integration.OptifineCTM -import mods.betterfoliage.client.integration.ShadersModIntegration +import mods.betterfoliage.client.integration.* import mods.betterfoliage.client.render.* import mods.betterfoliage.client.texture.* import mods.octarinecore.client.KeyHandler @@ -63,12 +61,14 @@ object Client { val singletons = listOf( LeafRegistry, GrassRegistry, - LogRegistry, LeafWindTracker, RisingSoulTextures, ShadersModIntegration, OptifineCTM, - ForestryIntegration + ForestryIntegration, + IC2Integration, + TechRebornIntegration, + StandardLogSupport // add _after_ all other log registries ) fun log(level: Level, msg: String) { diff --git a/src/main/kotlin/mods/betterfoliage/client/integration/RubberIntegration.kt b/src/main/kotlin/mods/betterfoliage/client/integration/RubberIntegration.kt new file mode 100644 index 0000000..a663afb --- /dev/null +++ b/src/main/kotlin/mods/betterfoliage/client/integration/RubberIntegration.kt @@ -0,0 +1,217 @@ +package mods.betterfoliage.client.integration + +import mods.betterfoliage.BetterFoliageMod +import mods.betterfoliage.client.Client +import mods.betterfoliage.client.config.Config +import mods.betterfoliage.client.render.IColumnRegistry +import mods.betterfoliage.client.render.IColumnTextureInfo +import mods.betterfoliage.client.render.LogRegistry +import mods.betterfoliage.client.render.StaticColumnInfo +import mods.betterfoliage.client.texture.LeafRegistry +import mods.betterfoliage.client.texture.StandardLeafSupport +import mods.betterfoliage.loader.Refs +import mods.octarinecore.client.render.Quad +import mods.octarinecore.client.render.ShadingContext +import mods.octarinecore.client.render.blockContext +import mods.octarinecore.client.resource.ModelProcessor +import mods.octarinecore.client.resource.derivesFrom +import mods.octarinecore.client.resource.get +import mods.octarinecore.client.resource.modelBlockAndLoc +import mods.octarinecore.common.rotate +import mods.octarinecore.metaprog.ClassRef +import mods.octarinecore.metaprog.MethodRef +import mods.octarinecore.metaprog.allAvailable +import net.minecraft.block.properties.PropertyDirection +import net.minecraft.block.state.IBlockState +import net.minecraft.client.renderer.block.model.ModelResourceLocation +import net.minecraft.client.renderer.texture.TextureAtlasSprite +import net.minecraft.client.renderer.texture.TextureMap +import net.minecraft.util.EnumFacing +import net.minecraft.util.ResourceLocation +import net.minecraftforge.client.model.IModel +import net.minecraftforge.common.MinecraftForge +import net.minecraftforge.fml.common.Loader +import net.minecraftforge.fml.relauncher.Side +import net.minecraftforge.fml.relauncher.SideOnly +import org.apache.logging.log4j.Level +import org.apache.logging.log4j.Logger + +@SideOnly(Side.CLIENT) +object IC2Integration { + + val BlockRubWood = ClassRef("ic2.core.block.BlockRubWood") + + init { + if (Loader.isModLoaded("IC2") && allAvailable(BlockRubWood)) { + Client.log(Level.INFO, "IC2 support initialized") + LogRegistry.subRegistries.add(IC2LogSupport) + } + } +} + +@SideOnly(Side.CLIENT) +object TechRebornIntegration { + + val BlockRubberLog = ClassRef("techreborn.blocks.BlockRubberLog") + val ITexturedBlock = ClassRef("me.modmuss50.jsonDestroyer.api.ITexturedBlock") + val getTextureNameFromState = MethodRef(ITexturedBlock, "getTextureNameFromState", Refs.String, Refs.IBlockState, Refs.EnumFacing) + + val rubberLogTextureNames = listOf( + "techreborn:blocks/rubber_log_top", + "techreborn:blocks/rubber_log_top", + "techreborn:blocks/rubber_log_side", + "techreborn:blocks/rubber_log_sap" + ) + + init { + if (Loader.isModLoaded("techreborn") && allAvailable(BlockRubberLog, ITexturedBlock, getTextureNameFromState)) { + Client.log(Level.INFO, "TechReborn support initialized") + LogRegistry.subRegistries.add(TechRebornLogSupport) + + // initialize object but don't add to registry + TechRebornLeafSupport.toString() + } + } +} + +@SideOnly(Side.CLIENT) +data class RubberLogModelInfo( + val axis: EnumFacing.Axis?, + val spotDir: EnumFacing?, + val textures: List +) + +// TODO avoid copy-paste pattern with regards to StaticColumnInfo +@SideOnly(Side.CLIENT) +data class RubberLogColumnInfo(override val axis: EnumFacing.Axis?, + val spotDir: EnumFacing, + val topTexture: TextureAtlasSprite, + val bottomTexture: TextureAtlasSprite, + val sideTexture: TextureAtlasSprite, + val spotTexture: TextureAtlasSprite): IColumnTextureInfo { + override val top = { ctx: ShadingContext, idx: Int, quad: Quad -> + OptifineCTM.override(topTexture, blockContext, EnumFacing.UP.rotate(ctx.rotation)) + } + override val bottom = { ctx: ShadingContext, idx: Int, quad: Quad -> + OptifineCTM.override(bottomTexture, blockContext, EnumFacing.DOWN.rotate(ctx.rotation)) + } + override val side = { ctx: ShadingContext, idx: Int, quad: Quad -> + val worldRelativeSide = (if ((idx and 1) == 0) EnumFacing.SOUTH else EnumFacing.EAST).rotate(ctx.rotation) + val texture = if (worldRelativeSide == spotDir) spotTexture else sideTexture + OptifineCTM.override(texture, blockContext, worldRelativeSide) + } +} + +@SideOnly(Side.CLIENT) +abstract class RubberLogSupportBase : ModelProcessor, IColumnRegistry { + + override var stateToKey = mutableMapOf() + override var stateToValue = mapOf() + + override val logger = BetterFoliageMod.logDetail + + init { MinecraftForge.EVENT_BUS.register(this) } + + override fun processStitch(state: IBlockState, key: RubberLogModelInfo, atlas: TextureMap): IColumnTextureInfo? { + val topTex = atlas[key.textures[0]] ?: return null + val bottomTex = atlas[key.textures[1]] ?: return null + val sideTex = atlas[key.textures[2]] ?: return null + if (key.spotDir == null) + return StaticColumnInfo(key.axis, topTex, bottomTex, sideTex) + else { + val spotTex = atlas[key.textures[3]] ?: return null + return RubberLogColumnInfo(key.axis, key.spotDir, topTex, bottomTex, sideTex, spotTex) + } + } + + override fun get(state: IBlockState) = stateToValue[state] +} + +@SideOnly(Side.CLIENT) +object IC2LogSupport : RubberLogSupportBase() { + + override fun processModelLoad(state: IBlockState, modelLoc: ModelResourceLocation, model: IModel): RubberLogModelInfo? { + // check for proper block class, existence of ModelBlock, and "state" blockstate property + if (!IC2Integration.BlockRubWood.isInstance(state.block)) return null + val blockLoc = model.modelBlockAndLoc ?: return null + val type = state.properties.entries.find { it.key.getName() == "state" }?.value?.toString() ?: return null + + // logs with no rubber spot + if (blockLoc.derivesFrom(ResourceLocation("block/cube_column"))) { + val axis = when(type) { + "plain_y" -> EnumFacing.Axis.Y + "plain_x" -> EnumFacing.Axis.X + "plain_z" -> EnumFacing.Axis.Z + else -> null + } + val textureNames = listOf("end", "end", "side").map { blockLoc.first.resolveTextureName(it) } + logger.log(Level.DEBUG, "IC2LogSupport: block state ${state.toString()}") + logger.log(Level.DEBUG, "IC2LogSupport: axis=$axis, end=${textureNames[0]}, side=${textureNames[2]}") + return if (textureNames.all { it != "missingno" }) RubberLogModelInfo(axis, null, textureNames) else null + } + + // logs with rubber spot + val spotDir = when(type) { + "dry_north", "wet_north" -> EnumFacing.NORTH + "dry_south", "wet_south" -> EnumFacing.SOUTH + "dry_west", "wet_west" -> EnumFacing.WEST + "dry_east", "wet_east" -> EnumFacing.EAST + else -> null + } + val textureNames = listOf("up", "down", "south", "north").map { blockLoc.first.resolveTextureName(it) } + logger.log(Level.DEBUG, "IC2LogSupport: block state ${state.toString()}") + logger.log(Level.DEBUG, "IC2LogSupport: spotDir=$spotDir, up=${textureNames[0]}, down=${textureNames[1]}, side=${textureNames[2]}, spot=${textureNames[3]}") + return if (textureNames.all { it != "missingno" }) RubberLogModelInfo(EnumFacing.Axis.Y, spotDir, textureNames) else null + } +} + +@SideOnly(Side.CLIENT) +object TechRebornLogSupport : RubberLogSupportBase() { + + override fun processModelLoad(state: IBlockState, modelLoc: ModelResourceLocation, model: IModel): RubberLogModelInfo? { + // check for proper block class, existence of ModelBlock + if (!TechRebornIntegration.BlockRubberLog.isInstance(state.block)) return null + + val hasSap = state.properties.entries.find { it.key.getName() == "hassap" }?.value as? Boolean ?: return null + val sapSide = state.properties.entries.find { it.key.getName() == "sapside" }?.value as? EnumFacing ?: return null + + logger.log(Level.DEBUG, "TechRebornLogSupport: block state ${state.toString()}") + if (hasSap) { + val textureNames = listOf(EnumFacing.UP, EnumFacing.DOWN, sapSide.opposite, sapSide).map { + TechRebornIntegration.getTextureNameFromState.invoke(state.block, state, it) as String + } + logger.log(Level.DEBUG, "TechRebornLogSupport: spotDir=$sapSide, up=${textureNames[0]}, down=${textureNames[1]}, side=${textureNames[2]}, spot=${textureNames[3]}") + return if (textureNames.all { it != "missingno" }) RubberLogModelInfo(EnumFacing.Axis.Y, sapSide, textureNames) else null + } else { + val textureNames = listOf(EnumFacing.UP, EnumFacing.DOWN, sapSide).map { + TechRebornIntegration.getTextureNameFromState.invoke(state.block, state, it) as String + } + logger.log(Level.DEBUG, "TechRebornLogSupport: up=${textureNames[0]}, down=${textureNames[1]}, side=${textureNames[2]}") + return if (textureNames.all { it != "missingno" }) RubberLogModelInfo(EnumFacing.Axis.Y, null, textureNames) else null + } + } +} + +@SideOnly(Side.CLIENT) +object TechRebornLeafSupport : ModelProcessor { + + init { MinecraftForge.EVENT_BUS.register(this) } + + override var stateToKey = mutableMapOf() + override var stateToValue = mapOf() + override val logger: Logger get() = BetterFoliageMod.logDetail + + override fun processModelLoad(state: IBlockState, modelLoc: ModelResourceLocation, model: IModel): Nothing? { + if (Config.blocks.leavesClasses.matchesClass(state.block) && TechRebornIntegration.ITexturedBlock.isInstance(state.block)) { + val textureName = TechRebornIntegration.getTextureNameFromState.invoke(state.block, state, EnumFacing.UP) as String + logger.log(Level.DEBUG, "TechRebornLeafSupport: block state ${state.toString()}") + logger.log(Level.DEBUG, "TechRebornLeafSupport: texture=$textureName") + // register directly into StandardLeafSupport for the sake of simplicity + StandardLeafSupport.stateToKey[state] = listOf(textureName) + } + return null + } + + // no-op + override fun processStitch(state: IBlockState, key: Nothing, atlas: TextureMap) = null +} \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/client/render/RenderLog.kt b/src/main/kotlin/mods/betterfoliage/client/render/RenderLog.kt index ba2451e..3f9202b 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/RenderLog.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/RenderLog.kt @@ -24,7 +24,7 @@ import net.minecraftforge.fml.relauncher.SideOnly import org.apache.logging.log4j.Level import org.apache.logging.log4j.Logger -@SideOnly(Side.CLIENT) + class RenderLog : AbstractRenderColumn(BetterFoliageMod.MOD_ID) { override val moveToCutout: Boolean get() = false @@ -49,14 +49,17 @@ class RenderLog : AbstractRenderColumn(BetterFoliageMod.MOD_ID) { @SideOnly(Side.CLIENT) object LogRegistry : IColumnRegistry { - val subRegistries: MutableList = mutableListOf(StandardLogSupport) + val subRegistries: MutableList = mutableListOf() override fun get(state: IBlockState) = subRegistries.findFirst { it[state] } } @SideOnly(Side.CLIENT) object StandardLogSupport : TextureListModelProcessor, IColumnRegistry { - init { MinecraftForge.EVENT_BUS.register(this) } + init { + LogRegistry.subRegistries.add(this) + MinecraftForge.EVENT_BUS.register(this) + } override var stateToKey = mutableMapOf>() override var stateToValue = mapOf() diff --git a/src/main/kotlin/mods/octarinecore/client/resource/ModelProcessor.kt b/src/main/kotlin/mods/octarinecore/client/resource/ModelProcessor.kt index dfb700c..c575a8a 100644 --- a/src/main/kotlin/mods/octarinecore/client/resource/ModelProcessor.kt +++ b/src/main/kotlin/mods/octarinecore/client/resource/ModelProcessor.kt @@ -35,9 +35,13 @@ interface ModelProcessor { fun processModelLoad(state: IBlockState, modelLoc: ModelResourceLocation, model: IModel): T1? fun processStitch(state: IBlockState, key: T1, atlas: TextureMap): T2? + @SubscribeEvent(priority = EventPriority.HIGHEST) + fun clearBeforeLoadModelData(event: LoadModelDataEvent) { + stateToKey.clear() + } + @SubscribeEvent fun handleLoadModelData(event: LoadModelDataEvent) { - stateToKey.clear() onPostLoad() val stateMappings = Block.REGISTRY.flatMap { block -> @@ -96,7 +100,6 @@ interface TextureMediatedRegistry : ModelProcessor @Suppress("UNCHECKED_CAST") - // @SubscribeEvent(priority = EventPriority.LOW) override fun handlePreStitch(event: TextureStitchEvent.Pre) { textureToValue.clear() super.handlePreStitch(event) diff --git a/src/main/resources/assets/betterfoliage/LogBlocksDefault.cfg b/src/main/resources/assets/betterfoliage/LogBlocksDefault.cfg index 6babc83..53e5499 100644 --- a/src/main/resources/assets/betterfoliage/LogBlocksDefault.cfg +++ b/src/main/resources/assets/betterfoliage/LogBlocksDefault.cfg @@ -24,3 +24,9 @@ com.bioxx.tfc.Blocks.Flora.BlockLogNatural CookingPlus.blocks.CookingPlusPalmLog CookingPlus.blocks.CookingPlusTangleLog CookingPlus.blocks.CookingPlusTangleHeart + +// IC2 +ic2.core.block.BlockRubWood + +// TechReborn +techreborn.blocks.BlockRubberLog