From 9899816029a7e4697ceefbf81cdafb69865525e3 Mon Sep 17 00:00:00 2001 From: octarine-noise Date: Thu, 13 May 2021 00:44:45 +0200 Subject: [PATCH] [WIP] Cactus, netherrack, round logs work + lots more cleanup + Optifine x-ray fix --- .../mods/betterfoliage/mixin/MixinBlock.java | 3 + .../mixin/MixinOptifineBlockUtils.java | 13 ++ .../mixin/MixinOptifineChunkRender.java | 30 ---- src/main/kotlin/mods/betterfoliage/Client.kt | 46 +++-- src/main/kotlin/mods/betterfoliage/Hooks.kt | 39 ++-- .../mods/betterfoliage/chunk/BlockContext.kt | 5 +- .../mods/betterfoliage/config/Config.kt | 12 +- .../mods/betterfoliage/model/HalfBaked.kt | 26 +-- .../kotlin/mods/betterfoliage/model/Quads.kt | 2 + .../mods/betterfoliage/model/TuftMeshes.kt | 12 +- .../render/EntityRisingSoulFX.kt | 66 ------- .../render/block/vanilla/Cactus.kt | 93 ++++++++++ .../render/block/vanilla/Dirt.kt | 35 ++-- .../render/block/vanilla/Grass.kt | 28 ++- .../render/block/vanilla/Leaf.kt | 40 ++--- .../render/block/vanilla/Lilypad.kt | 20 +-- .../render/block/vanilla/Mycelium.kt | 25 +-- .../render/block/vanilla/Netherrack.kt | 82 +++++++++ .../render/block/vanilla/RoundLog.kt | 95 +++++++++- .../render/block/vanilla/Sand.kt | 28 ++- .../render/column/ColumnMeshSet.kt | 166 ++++++++++++++++++ .../render/column/ColumnModel.kt | 112 ++++++++++++ .../render/column/ColumnOverlayLayer.kt | 1 - .../render/lighting/VanillaVertexLighter.kt | 91 +++++++++- .../render/particle/FallingLeaves.kt | 3 - .../particle}/LeafParticleRegistry.kt | 20 ++- .../render/particle/RisingSouls.kt | 89 ++++++++++ .../resource/VeryEarlyReloadListener.kt | 27 +++ .../resource/discovery/BakingLifecycle.kt | 53 ++++-- .../resource/discovery/BlockTypeCache.kt | 12 +- .../discovery}/Matchers.kt | 9 +- .../resource/discovery/ModelDiscovery.kt | 78 +++----- .../discovery/SpecialRenderVariants.kt | 54 ++++++ .../generated/CenteringTextureGenerator.kt | 2 +- .../resource/generated/GeneratedGrass.kt | 4 +- .../resource/generated/GeneratedLeaf.kt | 2 +- .../mods/betterfoliage/texture/Utils.kt | 19 -- .../mods/betterfoliage/util/Geometry.kt | 3 +- .../betterfoliage/log_models_default.cfg | 14 +- .../betterfoliage.optifine.mixins.json | 1 + 40 files changed, 1059 insertions(+), 401 deletions(-) delete mode 100644 src/main/java/mods/betterfoliage/mixin/MixinOptifineChunkRender.java delete mode 100644 src/main/kotlin/mods/betterfoliage/render/EntityRisingSoulFX.kt create mode 100644 src/main/kotlin/mods/betterfoliage/render/block/vanilla/Cactus.kt create mode 100644 src/main/kotlin/mods/betterfoliage/render/block/vanilla/Netherrack.kt create mode 100644 src/main/kotlin/mods/betterfoliage/render/column/ColumnMeshSet.kt create mode 100644 src/main/kotlin/mods/betterfoliage/render/column/ColumnModel.kt rename src/main/kotlin/mods/betterfoliage/{texture => render/particle}/LeafParticleRegistry.kt (83%) create mode 100644 src/main/kotlin/mods/betterfoliage/render/particle/RisingSouls.kt create mode 100644 src/main/kotlin/mods/betterfoliage/resource/VeryEarlyReloadListener.kt rename src/main/kotlin/mods/betterfoliage/{config => resource/discovery}/Matchers.kt (89%) create mode 100644 src/main/kotlin/mods/betterfoliage/resource/discovery/SpecialRenderVariants.kt delete mode 100644 src/main/kotlin/mods/betterfoliage/texture/Utils.kt diff --git a/src/main/java/mods/betterfoliage/mixin/MixinBlock.java b/src/main/java/mods/betterfoliage/mixin/MixinBlock.java index 59c15fb..cd4c519 100644 --- a/src/main/java/mods/betterfoliage/mixin/MixinBlock.java +++ b/src/main/java/mods/betterfoliage/mixin/MixinBlock.java @@ -9,7 +9,9 @@ import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.world.IBlockReader; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; /** * Mixin overriding the {@link VoxelShape} used for the neighbor block in {@link Block}.shouldSideBeRendered(). @@ -22,6 +24,7 @@ public class MixinBlock { private static final String shouldSideBeRendered = "Lnet/minecraft/block/Block;shouldSideBeRendered(Lnet/minecraft/block/BlockState;Lnet/minecraft/world/IBlockReader;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/Direction;)Z"; private static final String getVoxelShape = "Lnet/minecraft/block/BlockState;func_215702_a(Lnet/minecraft/world/IBlockReader;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/Direction;)Lnet/minecraft/util/math/shapes/VoxelShape;"; private static final String getFaceOcclusionShape = "Lnet/minecraft/block/BlockState;getFaceOcclusionShape(Lnet/minecraft/world/IBlockReader;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/Direction;)Lnet/minecraft/util/math/shapes/VoxelShape;"; + private static final String isOpaqueCube = "Lnet/minecraft/block/Block;isOpaqueCube(Lnet/minecraft/block/BlockState;Lnet/minecraft/world/IBlockReader;Lnet/minecraft/util/math/BlockPos;)Z"; @Redirect(method = shouldSideBeRendered, at = @At(value = "INVOKE", target = getFaceOcclusionShape, ordinal = 1)) private static VoxelShape getVoxelShapeOverride(BlockState state, IBlockReader reader, BlockPos pos, Direction dir) { diff --git a/src/main/java/mods/betterfoliage/mixin/MixinOptifineBlockUtils.java b/src/main/java/mods/betterfoliage/mixin/MixinOptifineBlockUtils.java index bfdddbb..8393d97 100644 --- a/src/main/java/mods/betterfoliage/mixin/MixinOptifineBlockUtils.java +++ b/src/main/java/mods/betterfoliage/mixin/MixinOptifineBlockUtils.java @@ -9,11 +9,16 @@ import net.minecraft.world.IBlockReader; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Pseudo; import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Coerce; +import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Pseudo @Mixin(targets = "net.optifine.util.BlockUtils") public class MixinOptifineBlockUtils { + private static final String shouldSideBeRendered = "shouldSideBeRendered(Lnet/minecraft/block/BlockState;Lnet/minecraft/world/IBlockReader;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/Direction;Lnet/optifine/render/RenderEnv;)Z"; + private static final String shouldSideBeRenderedCached = "shouldSideBeRenderedCached(Lnet/minecraft/block/BlockState;Lnet/minecraft/world/IBlockReader;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/Direction;Lnet/optifine/render/RenderEnv;Lnet/minecraft/block/BlockState;Lnet/minecraft/util/math/BlockPos;)Z"; private static final String getFaceOcclusionShape = "Lnet/minecraft/block/BlockState;getFaceOcclusionShape(Lnet/minecraft/world/IBlockReader;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/Direction;)Lnet/minecraft/util/math/shapes/VoxelShape;"; @@ -22,4 +27,12 @@ public class MixinOptifineBlockUtils { private static VoxelShape getVoxelShapeOverride(BlockState state, IBlockReader reader, BlockPos pos, Direction dir) { return Hooks.getVoxelShapeOverride(state, reader, pos, dir); } + + @SuppressWarnings("UnresolvedMixinReference") + @Inject(method = shouldSideBeRendered, at = @At(value = "HEAD"), cancellable = true) + private static void shouldForceSideRender(BlockState state, IBlockReader reader, BlockPos pos, Direction face, @Coerce Object renderEnv, CallbackInfoReturnable cir) { + if (Hooks.shouldForceSideRenderOF(state, reader, pos, face)) { + cir.setReturnValue(true); + } + } } diff --git a/src/main/java/mods/betterfoliage/mixin/MixinOptifineChunkRender.java b/src/main/java/mods/betterfoliage/mixin/MixinOptifineChunkRender.java deleted file mode 100644 index b90e420..0000000 --- a/src/main/java/mods/betterfoliage/mixin/MixinOptifineChunkRender.java +++ /dev/null @@ -1,30 +0,0 @@ -package mods.betterfoliage.mixin; - -import mods.betterfoliage.Hooks; -import net.minecraft.block.BlockState; -import net.minecraft.client.renderer.RenderType; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Coerce; -import org.spongepowered.asm.mixin.injection.Redirect; -import org.spongepowered.asm.mixin.injection.Slice; - -@Mixin(targets = {"net.minecraft.client.renderer.chunk.ChunkRenderDispatcher$ChunkRender$RebuildTask"}) -public class MixinOptifineChunkRender { - - private static final String compile = "Lnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$ChunkRender$RebuildTask;compile(FFFLnet/minecraft/client/renderer/chunk/ChunkRenderDispatcher$CompiledChunk;Lnet/minecraft/client/renderer/RegionRenderCacheBuilder;)Ljava/util/Set;"; - private static final String invokeReflector = "Lnet/optifine/reflect/Reflector;callBoolean(Ljava/lang/Object;Lnet/optifine/reflect/ReflectorMethod;[Ljava/lang/Object;)Z"; - private static final String forgeBlockCanRender = "Lnet/minecraft/client/renderer/chunk/ChunkRender;FORGE_BLOCK_CAN_RENDER_IN_LAYER:Z"; - -// @Redirect( -// method = compile, -// at = @At(value = "INVOKE", target = invokeReflector), -// slice = @Slice( -// from = @At(value = "FIELD", target = forgeBlockCanRender) -// ) -// ) -// @SuppressWarnings("UnresolvedMixinReference") -// boolean canRenderInLayer(Object state, @Coerce Object reflector, Object[] layer) { -// return Hooks.canRenderInLayerOverride((BlockState) state, (RenderType) layer[0]); -// } -} diff --git a/src/main/kotlin/mods/betterfoliage/Client.kt b/src/main/kotlin/mods/betterfoliage/Client.kt index 0e75ecd..5caedb0 100644 --- a/src/main/kotlin/mods/betterfoliage/Client.kt +++ b/src/main/kotlin/mods/betterfoliage/Client.kt @@ -4,8 +4,10 @@ import mods.betterfoliage.chunk.ChunkOverlayManager import mods.betterfoliage.config.BlockConfig import mods.betterfoliage.integration.OptifineCustomColors import mods.betterfoliage.integration.ShadersModIntegration +import mods.betterfoliage.render.block.vanilla.RoundLogOverlayLayer +import mods.betterfoliage.render.block.vanilla.StandardCactusDiscovery +import mods.betterfoliage.render.block.vanilla.StandardCactusModel import mods.betterfoliage.render.block.vanilla.StandardDirtDiscovery -import mods.betterfoliage.render.block.vanilla.StandardDirtKey import mods.betterfoliage.render.block.vanilla.StandardDirtModel import mods.betterfoliage.render.block.vanilla.StandardGrassDiscovery import mods.betterfoliage.render.block.vanilla.StandardGrassModel @@ -13,43 +15,57 @@ import mods.betterfoliage.render.block.vanilla.StandardLeafDiscovery import mods.betterfoliage.render.block.vanilla.StandardLeafModel import mods.betterfoliage.render.block.vanilla.StandardLilypadDiscovery import mods.betterfoliage.render.block.vanilla.StandardLilypadModel +import mods.betterfoliage.render.block.vanilla.StandardLogDiscovery import mods.betterfoliage.render.block.vanilla.StandardMyceliumDiscovery import mods.betterfoliage.render.block.vanilla.StandardMyceliumModel +import mods.betterfoliage.render.block.vanilla.StandardNetherrackDiscovery +import mods.betterfoliage.render.block.vanilla.StandardNetherrackModel +import mods.betterfoliage.render.block.vanilla.StandardRoundLogModel import mods.betterfoliage.render.block.vanilla.StandardSandDiscovery import mods.betterfoliage.render.block.vanilla.StandardSandModel import mods.betterfoliage.render.lighting.AoSideHelper import mods.betterfoliage.render.particle.LeafWindTracker import mods.betterfoliage.resource.discovery.BakeWrapperManager import mods.betterfoliage.resource.discovery.BlockTypeCache +import mods.betterfoliage.resource.discovery.ModelDefinitionsLoadedEvent import mods.betterfoliage.resource.generated.GeneratedTexturePack -import mods.betterfoliage.texture.LeafParticleRegistry +import mods.betterfoliage.render.particle.LeafParticleRegistry +import mods.betterfoliage.render.particle.RisingSoulParticle import net.minecraft.block.BlockState -import net.minecraft.block.Blocks -import net.minecraft.client.renderer.RenderType -import net.minecraft.client.renderer.RenderTypeLookup -import net.minecraftforge.common.ForgeConfig +import net.minecraft.client.Minecraft +import net.minecraft.resources.IReloadableResourceManager +import net.minecraftforge.eventbus.api.SubscribeEvent /** * Object responsible for initializing (and holding a reference to) all the infrastructure of the mod * except for the call hooks. */ object Client { + /** Resource pack holding generated assets */ val generatedPack = GeneratedTexturePack("bf_gen", "Better Foliage generated assets") - var blockTypes = BlockTypeCache() - val suppressRenderErrors = mutableSetOf() + /** List of recognized [BlockState]s */ + var blockTypes = BlockTypeCache() fun init() { // discoverers BetterFoliageMod.bus.register(BakeWrapperManager) BetterFoliageMod.bus.register(LeafParticleRegistry) + BetterFoliageMod.bus.register(this) + (Minecraft.getInstance().resourceManager as IReloadableResourceManager).addReloadListener(LeafParticleRegistry) + + ChunkOverlayManager.layers.add(RoundLogOverlayLayer) + listOf( StandardLeafDiscovery, StandardGrassDiscovery, StandardDirtDiscovery, StandardMyceliumDiscovery, StandardSandDiscovery, - StandardLilypadDiscovery + StandardLilypadDiscovery, + StandardCactusDiscovery, + StandardNetherrackDiscovery, + StandardLogDiscovery ).forEach { BakeWrapperManager.discoverers.add(it) } @@ -68,7 +84,11 @@ object Client { StandardDirtModel.Companion, StandardMyceliumModel.Companion, StandardSandModel.Companion, - StandardLilypadModel.Companion + StandardLilypadModel.Companion, + StandardCactusModel.Companion, + StandardNetherrackModel.Companion, + StandardRoundLogModel.Companion, + RisingSoulParticle.Companion ) // init mod integrations @@ -77,5 +97,11 @@ object Client { OptifineCustomColors ) } + + @SubscribeEvent + fun handleModelLoad(event: ModelDefinitionsLoadedEvent) { + blockTypes = BlockTypeCache() + } + } diff --git a/src/main/kotlin/mods/betterfoliage/Hooks.kt b/src/main/kotlin/mods/betterfoliage/Hooks.kt index 76a91ee..dfc720e 100644 --- a/src/main/kotlin/mods/betterfoliage/Hooks.kt +++ b/src/main/kotlin/mods/betterfoliage/Hooks.kt @@ -1,44 +1,47 @@ @file:JvmName("Hooks") package mods.betterfoliage +import mods.betterfoliage.chunk.ChunkOverlayManager import mods.betterfoliage.config.Config import mods.betterfoliage.model.getActualRenderModel +import mods.betterfoliage.render.block.vanilla.RoundLogKey import mods.betterfoliage.render.particle.FallingLeafParticle -import mods.betterfoliage.texture.LeafBlockModel +import mods.betterfoliage.render.particle.LeafBlockModel +import mods.betterfoliage.render.particle.RisingSoulParticle +import mods.betterfoliage.util.plus import net.minecraft.block.Block import net.minecraft.block.BlockState +import net.minecraft.block.Blocks import net.minecraft.client.Minecraft import net.minecraft.client.world.ClientWorld import net.minecraft.util.Direction import net.minecraft.util.Direction.DOWN +import net.minecraft.util.Direction.UP import net.minecraft.util.math.BlockPos import net.minecraft.util.math.shapes.VoxelShape +import net.minecraft.util.math.shapes.VoxelShapes import net.minecraft.world.IBlockReader import net.minecraft.world.World import java.util.Random fun getAmbientOcclusionLightValueOverride(original: Float, state: BlockState): Float { -// if (Config.enabled && Config.roundLogs.enabled && BlockConfig.logBlocks.matchesClass(state.block)) return Config.roundLogs.dimming.toFloat(); - return original -} - -fun getUseNeighborBrightnessOverride(original: Boolean, state: BlockState): Boolean { -// return original || (Config.enabled && Config.roundLogs.enabled && BlockConfig.logBlocks.matchesClass(state.block)); + if (Config.enabled && Config.roundLogs.enabled && Client.blockTypes.stateKeys[state] is RoundLogKey) + return Config.roundLogs.dimming.toFloat() return original } fun onClientBlockChanged(worldClient: ClientWorld, pos: BlockPos, oldState: BlockState, newState: BlockState, flags: Int) { -// ChunkOverlayManager.onBlockChange(worldClient, pos) + ChunkOverlayManager.onBlockChange(worldClient, pos) } fun onRandomDisplayTick(block: Block, state: BlockState, world: World, pos: BlockPos, random: Random) { -// if (Config.enabled && -// Config.risingSoul.enabled && -// state.block == Blocks.SOUL_SAND && -// world.isAirBlock(pos + up1) && -// Math.random() < Config.risingSoul.chance) { -// EntityRisingSoulFX(world, pos).addIfValid() -// } + if (Config.enabled && + Config.risingSoul.enabled && + state.block == Blocks.SOUL_SAND && + world.isAirBlock(pos.offset(UP)) && + Math.random() < Config.risingSoul.chance) { + RisingSoulParticle(world, pos).addIfValid() + } if (Config.enabled && Config.fallingLeaves.enabled && @@ -53,6 +56,10 @@ fun onRandomDisplayTick(block: Block, state: BlockState, world: World, pos: Bloc } fun getVoxelShapeOverride(state: BlockState, reader: IBlockReader, pos: BlockPos, dir: Direction): VoxelShape { -// if (LogRegistry[state, reader, pos] != null) return VoxelShapes.empty() + if (Config.enabled && Config.roundLogs.enabled && Client.blockTypes.stateKeys[state] is RoundLogKey) + return VoxelShapes.empty() return state.getFaceOcclusionShape(reader, pos, dir) } + +fun shouldForceSideRenderOF(state: BlockState, world: IBlockReader, pos: BlockPos, face: Direction) = + world.getBlockState(pos.offset(face)).let { neighbor -> Client.blockTypes.stateKeys[neighbor] is RoundLogKey } \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/chunk/BlockContext.kt b/src/main/kotlin/mods/betterfoliage/chunk/BlockContext.kt index d99bc44..78140ef 100644 --- a/src/main/kotlin/mods/betterfoliage/chunk/BlockContext.kt +++ b/src/main/kotlin/mods/betterfoliage/chunk/BlockContext.kt @@ -27,8 +27,11 @@ interface BlockCtx { fun offset(offset: Int3): BlockCtx val state: BlockState get() = world.getBlockState(pos) - fun state(dir: Direction) = world.getBlockState(pos + dir.offset) fun state(offset: Int3) = world.getBlockState(pos + offset) + fun state(dir: Direction) = state(dir.offset) + + fun isAir(offset: Int3) = (pos + offset).let { world.getBlockState(it).isAir(world, it) } + fun isAir(dir: Direction) = isAir(dir.offset) val biome: Biome? get() = (world as? IWorldReader)?.getBiome(pos) ?: diff --git a/src/main/kotlin/mods/betterfoliage/config/Config.kt b/src/main/kotlin/mods/betterfoliage/config/Config.kt index 027d6b1..552127f 100644 --- a/src/main/kotlin/mods/betterfoliage/config/Config.kt +++ b/src/main/kotlin/mods/betterfoliage/config/Config.kt @@ -1,7 +1,8 @@ package mods.betterfoliage.config -import mods.betterfoliage.BetterFoliage import mods.betterfoliage.BetterFoliageMod +import mods.betterfoliage.resource.discovery.ConfigurableBlockMatcher +import mods.betterfoliage.resource.discovery.ModelTextureListConfiguration import net.minecraft.util.ResourceLocation import net.minecraftforge.eventbus.api.SubscribeEvent import net.minecraftforge.fml.config.ModConfig @@ -67,7 +68,7 @@ object Config : DelegatingConfig(BetterFoliageMod.MOD_ID, BetterFoliageMod.MOD_I object cactus : ConfigCategory(){ val enabled by featureEnable() - val size by double(min=0.5, max=1.5, default=0.8).lang("size") + val size by double(min=1.0, max=2.0, default=1.3).lang("size") val sizeVariation by double(max=0.5, default=0.1) val hOffset by double(max=0.5, default=0.1).lang("hOffset") } @@ -117,8 +118,8 @@ object Config : DelegatingConfig(BetterFoliageMod.MOD_ID, BetterFoliageMod.MOD_I object netherrack : ConfigCategory(){ val enabled by featureEnable() val hOffset by double(max=0.4, default=0.2).lang("hOffset") - val heightMin by double(min=0.1, max=1.5, default=0.6).lang("heightMin") - val heightMax by double(min=0.1, max=1.5, default=0.8).lang("heightMax") + val heightMin by double(min=0.1, max=1.5, default=0.2).lang("heightMin") + val heightMax by double(min=0.1, max=1.5, default=0.5).lang("heightMax") val size by double(min=0.5, max=1.5, default=1.0).lang("size") } @@ -147,6 +148,7 @@ object Config : DelegatingConfig(BetterFoliageMod.MOD_ID, BetterFoliageMod.MOD_I val trailLength by int(min=2, max=128, default=48) val trailDensity by int(min=1, max=16, default=3) } + } object BlockConfig { @@ -174,4 +176,4 @@ object BlockConfig { is ModelTextureListConfiguration -> it.readDefaults() } } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/mods/betterfoliage/model/HalfBaked.kt b/src/main/kotlin/mods/betterfoliage/model/HalfBaked.kt index fbac443..62c5482 100644 --- a/src/main/kotlin/mods/betterfoliage/model/HalfBaked.kt +++ b/src/main/kotlin/mods/betterfoliage/model/HalfBaked.kt @@ -1,24 +1,19 @@ package mods.betterfoliage.model import mods.betterfoliage.render.pipeline.RenderCtxBase +import mods.betterfoliage.resource.discovery.ModelBakingContext import mods.betterfoliage.resource.discovery.ModelBakingKey import mods.betterfoliage.util.Double3 import mods.betterfoliage.util.HasLogger import mods.betterfoliage.util.directionsAndNull +import mods.betterfoliage.util.mapArray import net.minecraft.client.renderer.model.BakedQuad import net.minecraft.client.renderer.model.IBakedModel -import net.minecraft.client.renderer.model.IModelTransform -import net.minecraft.client.renderer.model.IUnbakedModel -import net.minecraft.client.renderer.model.Material -import net.minecraft.client.renderer.model.ModelBakery import net.minecraft.client.renderer.model.SimpleBakedModel -import net.minecraft.client.renderer.texture.TextureAtlasSprite import net.minecraft.client.renderer.vertex.DefaultVertexFormats import net.minecraft.client.renderer.vertex.VertexFormatElement -import net.minecraft.util.ResourceLocation import net.minecraftforge.client.model.pipeline.BakedQuadBuilder import java.util.Random -import java.util.function.Function /** * Hybrid baked quad implementation, carrying both baked and unbaked information. @@ -47,23 +42,16 @@ open class HalfBakedSpecialWrapper(val baseModel: SpecialRenderModel): IBakedMod } abstract class HalfBakedWrapperKey : ModelBakingKey, HasLogger() { - override fun bake( - location: ResourceLocation, - unbaked: IUnbakedModel, - transform: IModelTransform, - bakery: ModelBakery, - spriteGetter: Function - ): IBakedModel? { - val baseModel = super.bake(location, unbaked, transform, bakery, spriteGetter) + override fun bake(ctx: ModelBakingContext): IBakedModel? { + val baseModel = super.bake(ctx) val halfBaked = when(baseModel) { is SimpleBakedModel -> HalfBakedSimpleModelWrapper(baseModel) else -> null } - return if (halfBaked == null) baseModel else replace(halfBaked) + return if (halfBaked == null) baseModel else bake(ctx, halfBaked) } - - abstract fun replace(wrapped: SpecialRenderModel): SpecialRenderModel + abstract fun bake(ctx: ModelBakingContext, wrapped: SpecialRenderModel): SpecialRenderModel } fun List.bake(applyDiffuseLighting: Boolean) = map { quad -> @@ -106,6 +94,8 @@ fun List.bake(applyDiffuseLighting: Boolean) = map { quad -> HalfBakedQuad(quad, builder.build()) } +fun Array>.bake(applyDiffuseLighting: Boolean) = mapArray { it.bake(applyDiffuseLighting) } + fun BakedQuad.unbake(): HalfBakedQuad { val size = DefaultVertexFormats.BLOCK.integerSize val verts = Array(4) { vIdx -> diff --git a/src/main/kotlin/mods/betterfoliage/model/Quads.kt b/src/main/kotlin/mods/betterfoliage/model/Quads.kt index bfe0446..0007b78 100644 --- a/src/main/kotlin/mods/betterfoliage/model/Quads.kt +++ b/src/main/kotlin/mods/betterfoliage/model/Quads.kt @@ -9,6 +9,7 @@ import mods.betterfoliage.util.nearestAngle import mods.betterfoliage.util.rotate import mods.betterfoliage.util.times import mods.betterfoliage.util.vec +import net.minecraft.client.renderer.texture.NativeImage import net.minecraft.client.renderer.texture.TextureAtlasSprite import net.minecraft.util.Direction import java.lang.Math.max @@ -83,6 +84,7 @@ data class Color(val alpha: Int, val red: Int, val green: Int, val blue: Int) { data class HSB(var hue: Float, var saturation: Float, var brightness: Float) { companion object { + /** Red is assumed to be LSB, see [NativeImage.PixelFormat.RGBA] */ fun fromColorRGBA(color: Int): HSB { val hsbVals = java.awt.Color.RGBtoHSB(color and 255, (color shr 8) and 255, (color shr 16) and 255, null) return HSB(hsbVals[0], hsbVals[1], hsbVals[2]) diff --git a/src/main/kotlin/mods/betterfoliage/model/TuftMeshes.kt b/src/main/kotlin/mods/betterfoliage/model/TuftMeshes.kt index 9805067..4e9f9e7 100644 --- a/src/main/kotlin/mods/betterfoliage/model/TuftMeshes.kt +++ b/src/main/kotlin/mods/betterfoliage/model/TuftMeshes.kt @@ -73,8 +73,8 @@ fun fullCubeTextured( .bake(true) } -fun crossModelsRaw(num: Int, size: Double, hOffset: Double, vOffset: Double): Array> { - return Array(num) { idx -> +fun crossModelsRaw(num: Int, size: Double, hOffset: Double, vOffset: Double): List> { + return (0 until num).map { idx -> listOf( Quad.verticalRectangle(x1 = -0.5, z1 = 0.5, x2 = 0.5, z2 = -0.5, yBottom = -0.5 * 1.41, yTop = 0.5 * 1.41), Quad.verticalRectangle(x1 = -0.5, z1 = 0.5, x2 = 0.5, z2 = -0.5, yBottom = -0.5 * 1.41, yTop = 0.5 * 1.41) @@ -93,7 +93,7 @@ fun crossModelSingle(base: List, sprite: TextureAtlasSprite, tintIndex: In .bake(false) fun crossModelsTextured( - leafBase: Array>, + leafBase: Iterable>, tintIndex: Int, scrambleUV: Boolean, spriteGetter: (Int) -> ResourceLocation @@ -101,8 +101,8 @@ fun crossModelsTextured( crossModelSingle(leaf, Atlas.BLOCKS[spriteGetter(idx)], tintIndex, scrambleUV) }.toTypedArray() -fun List.withOpposites() = flatMap { listOf(it, it.flipped) } -fun List>.buildTufts(applyDiffuseLighting: Boolean = false) = +fun Iterable.withOpposites() = flatMap { listOf(it, it.flipped) } +fun Iterable>.buildTufts(applyDiffuseLighting: Boolean = false) = map { it.withOpposites().bake(applyDiffuseLighting) }.toTypedArray() -fun List>.transform(trans: Quad.(Int)-> Quad) = mapIndexed { idx, qList -> qList.map { it.trans(idx) } } \ No newline at end of file +fun Iterable>.transform(trans: Quad.(Int)-> Quad) = mapIndexed { idx, qList -> qList.map { it.trans(idx) } } \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/render/EntityRisingSoulFX.kt b/src/main/kotlin/mods/betterfoliage/render/EntityRisingSoulFX.kt deleted file mode 100644 index fbbb563..0000000 --- a/src/main/kotlin/mods/betterfoliage/render/EntityRisingSoulFX.kt +++ /dev/null @@ -1,66 +0,0 @@ -package mods.betterfoliage.render - -import mods.betterfoliage.BetterFoliageMod -import mods.betterfoliage.config.Config -import mods.betterfoliage.render.old.AbstractEntityFX -import mods.betterfoliage.util.Atlas -import mods.betterfoliage.util.Double3 -import net.minecraft.client.renderer.BufferBuilder -import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.MathHelper -import net.minecraft.world.World -import java.util.* - -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 = LinkedList() - val initialPhase = rand.nextInt(64) - - init { - motionY = 0.1 - particleGravity = 0.0f -// sprite = RisingSoulTextures.headIcons[rand.nextInt(256)] - maxAge = MathHelper.floor((0.6 + 0.4 * rand.nextDouble()) * Config.risingSoul.lifetime * 20.0) - } - - override val isValid: Boolean get() = true - - override fun update() { - val phase = (initialPhase + age) % 64 - velocity.setTo(cos[phase] * Config.risingSoul.perturb, 0.1, sin[phase] * Config.risingSoul.perturb) - - particleTrail.addFirst(currentPos.copy()) - while (particleTrail.size > Config.risingSoul.trailLength) particleTrail.removeLast() - - if (!Config.enabled) setExpired() - } - - override fun render(worldRenderer: BufferBuilder, partialTickTime: Float) { -// var alpha = Config.risingSoul.opacity.toFloat() -// if (age > maxAge - 40) alpha *= (maxAge - age) / 40.0f -// -// renderParticleQuad(worldRenderer, partialTickTime, -// size = Config.risingSoul.headSize * 0.25, -// alpha = alpha -// ) -// -// var scale = Config.risingSoul.trailSize * 0.25 -// particleTrail.forEachPairIndexed { idx, current, previous -> -// scale *= Config.risingSoul.sizeDecay -// alpha *= Config.risingSoul.opacityDecay.toFloat() -// if (idx % Config.risingSoul.trailDensity == 0) renderParticleQuad(worldRenderer, partialTickTime, -// currentPos = current, -// prevPos = previous, -// size = scale, -// alpha = alpha, -// icon = RisingSoulTextures.trackIcon -// ) -// } - } -} - -//object RisingSoulTextures : ResourceHandler(BetterFoliageMod.MOD_ID, BetterFoliageMod.bus, targetAtlas = Atlas.PARTICLES) { -// val headIcons = spriteSet { idx -> ResourceLocation(BetterFoliageMod.MOD_ID, "rising_soul_$idx") } -// val trackIcon by sprite(Identifier(BetterFoliageMod.MOD_ID, "soul_track")) -//} \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Cactus.kt b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Cactus.kt new file mode 100644 index 0000000..298be50 --- /dev/null +++ b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Cactus.kt @@ -0,0 +1,93 @@ +package mods.betterfoliage.render.block.vanilla + +import mods.betterfoliage.BetterFoliageMod +import mods.betterfoliage.Client +import mods.betterfoliage.config.Config +import mods.betterfoliage.model.HalfBakedSpecialWrapper +import mods.betterfoliage.model.HalfBakedWrapperKey +import mods.betterfoliage.model.SpecialRenderModel +import mods.betterfoliage.model.SpriteDelegate +import mods.betterfoliage.model.SpriteSetDelegate +import mods.betterfoliage.model.buildTufts +import mods.betterfoliage.model.crossModelsRaw +import mods.betterfoliage.model.crossModelsTextured +import mods.betterfoliage.model.transform +import mods.betterfoliage.model.tuftModelSet +import mods.betterfoliage.model.tuftShapeSet +import mods.betterfoliage.render.lighting.LightingPreferredFace +import mods.betterfoliage.render.lighting.RoundLeafLighting +import mods.betterfoliage.render.pipeline.RenderCtxBase +import mods.betterfoliage.resource.discovery.AbstractModelDiscovery +import mods.betterfoliage.resource.discovery.BakeWrapperManager +import mods.betterfoliage.resource.discovery.ModelBakingContext +import mods.betterfoliage.resource.discovery.ModelDiscoveryContext +import mods.betterfoliage.util.Atlas +import mods.betterfoliage.util.LazyInvalidatable +import mods.betterfoliage.util.Rotation +import mods.betterfoliage.util.get +import mods.betterfoliage.util.horizontalDirections +import mods.betterfoliage.util.randomD +import mods.betterfoliage.util.randomI +import net.minecraft.block.Blocks +import net.minecraft.client.renderer.model.BlockModel +import net.minecraft.util.Direction.DOWN +import net.minecraft.util.ResourceLocation + +object StandardCactusDiscovery : AbstractModelDiscovery() { + val CACTUS_BLOCKS = listOf(Blocks.CACTUS) + + override fun processModel(ctx: ModelDiscoveryContext) { + val model = ctx.getUnbaked() + if (model is BlockModel && ctx.blockState.block in CACTUS_BLOCKS) { + Client.blockTypes.dirt.add(ctx.blockState) + ctx.addReplacement(StandardCactusKey) + } + super.processModel(ctx) + } +} + +object StandardCactusKey : HalfBakedWrapperKey() { + override fun bake(ctx: ModelBakingContext, wrapped: SpecialRenderModel) = StandardCactusModel(wrapped) +} + +class StandardCactusModel( + wrapped: SpecialRenderModel +) : HalfBakedSpecialWrapper(wrapped) { + + val armLighting = horizontalDirections.map { LightingPreferredFace(it) }.toTypedArray() + + override fun render(ctx: RenderCtxBase, noDecorations: Boolean) { + ctx.checkSides = false + super.render(ctx, noDecorations) + if (!Config.enabled || !Config.cactus.enabled) return + + val armSide = ctx.random.nextInt() and 3 + ctx.vertexLighter = armLighting[armSide] + ctx.renderQuads(cactusArmModels[armSide][ctx.random]) + ctx.vertexLighter = RoundLeafLighting + ctx.renderQuads(cactusCrossModels[ctx.random]) + } + + companion object { + val cactusCrossSprite by SpriteDelegate(Atlas.BLOCKS) { + ResourceLocation(BetterFoliageMod.MOD_ID, "blocks/better_cactus") + } + val cactusArmSprites by SpriteSetDelegate(Atlas.BLOCKS) { idx -> + ResourceLocation(BetterFoliageMod.MOD_ID, "blocks/better_cactus_arm_$idx") + } + val cactusArmModels by LazyInvalidatable(BakeWrapperManager) { + val shapes = Config.cactus.let { tuftShapeSet(0.8, 0.8, 0.8, 0.2) } + val models = tuftModelSet(shapes, -1) { cactusArmSprites[randomI()] } + horizontalDirections.map { side -> + models.transform { move(0.0625 to DOWN).rotate(Rotation.fromUp[side.ordinal]) }.buildTufts() + }.toTypedArray() + } + val cactusCrossModels by LazyInvalidatable(BakeWrapperManager) { + val models = Config.cactus.let { config -> + crossModelsRaw(64, config.size, 0.0, 0.0) + .transform { rotateZ(randomD(-config.sizeVariation, config.sizeVariation)) } + } + crossModelsTextured(models, -1, true) { cactusCrossSprite.name } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Dirt.kt b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Dirt.kt index a54acf2..dafba82 100644 --- a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Dirt.kt +++ b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Dirt.kt @@ -15,7 +15,8 @@ import mods.betterfoliage.render.pipeline.RenderCtxBase import mods.betterfoliage.render.pipeline.RenderCtxVanilla import mods.betterfoliage.resource.discovery.AbstractModelDiscovery import mods.betterfoliage.resource.discovery.BakeWrapperManager -import mods.betterfoliage.resource.discovery.ModelBakingKey +import mods.betterfoliage.resource.discovery.ModelBakingContext +import mods.betterfoliage.resource.discovery.ModelDiscoveryContext import mods.betterfoliage.resource.generated.CenteredSprite import mods.betterfoliage.util.Atlas import mods.betterfoliage.util.Int3 @@ -23,40 +24,36 @@ import mods.betterfoliage.util.LazyInvalidatable import mods.betterfoliage.util.get import mods.betterfoliage.util.offset import mods.betterfoliage.util.randomI -import net.minecraft.block.BlockState import net.minecraft.block.Blocks import net.minecraft.block.material.Material import net.minecraft.client.renderer.RenderType import net.minecraft.client.renderer.RenderTypeLookup import net.minecraft.client.renderer.model.BlockModel -import net.minecraft.client.renderer.model.ModelBakery import net.minecraft.util.Direction.UP import net.minecraft.util.ResourceLocation import net.minecraft.world.biome.Biome object StandardDirtDiscovery : AbstractModelDiscovery() { val DIRT_BLOCKS = listOf(Blocks.DIRT, Blocks.COARSE_DIRT, Blocks.PODZOL) - override fun processModel( - bakery: ModelBakery, - state: BlockState, - location: ResourceLocation, - sprites: MutableSet, - replacements: MutableMap - ): Boolean { - val model = bakery.getUnbakedModel(location) - if (model is BlockModel && state.block in DIRT_BLOCKS) { - Client.blockTypes.dirt.add(state) - replacements[location] = StandardDirtKey -// RenderTypeLookup.setRenderLayer(state.block, RenderType.getCutout()) - RenderTypeLookup.setRenderLayer(state.block, RenderType.getCutoutMipped()) - return true + + fun canRenderInLayer(layer: RenderType) = when { + !Config.enabled -> layer == RenderType.getSolid() + !Config.connectedGrass.enabled && !Config.algae.enabled && !Config.reed.enabled -> layer == RenderType.getSolid() + else -> layer == RenderType.getCutoutMipped() + } + + override fun processModel(ctx: ModelDiscoveryContext) { + if (ctx.getUnbaked() is BlockModel && ctx.blockState.block in DIRT_BLOCKS) { + Client.blockTypes.dirt.add(ctx.blockState) + ctx.addReplacement(StandardDirtKey) + RenderTypeLookup.setRenderLayer(ctx.blockState.block, ::canRenderInLayer) } - return super.processModel(bakery, state, location, sprites, replacements) + super.processModel(ctx) } } object StandardDirtKey : HalfBakedWrapperKey() { - override fun replace(wrapped: SpecialRenderModel) = StandardDirtModel(wrapped) + override fun bake(ctx: ModelBakingContext, wrapped: SpecialRenderModel) = StandardDirtModel(wrapped) } class StandardDirtModel( diff --git a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Grass.kt b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Grass.kt index 5a28a75..1bdca4a 100644 --- a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Grass.kt +++ b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Grass.kt @@ -4,8 +4,6 @@ import mods.betterfoliage.BetterFoliageMod import mods.betterfoliage.Client import mods.betterfoliage.config.BlockConfig import mods.betterfoliage.config.Config -import mods.betterfoliage.config.ConfigurableBlockMatcher -import mods.betterfoliage.config.ModelTextureList import mods.betterfoliage.integration.ShadersModIntegration import mods.betterfoliage.model.Color import mods.betterfoliage.model.HalfBakedSpecialWrapper @@ -19,8 +17,11 @@ import mods.betterfoliage.model.tuftShapeSet import mods.betterfoliage.render.lighting.LightingPreferredFace import mods.betterfoliage.render.pipeline.RenderCtxBase import mods.betterfoliage.resource.discovery.BakeWrapperManager +import mods.betterfoliage.resource.discovery.ConfigurableBlockMatcher import mods.betterfoliage.resource.discovery.ConfigurableModelDiscovery -import mods.betterfoliage.resource.discovery.ModelBakingKey +import mods.betterfoliage.resource.discovery.ModelBakingContext +import mods.betterfoliage.resource.discovery.ModelDiscoveryContext +import mods.betterfoliage.resource.discovery.ModelTextureList import mods.betterfoliage.util.Atlas import mods.betterfoliage.util.LazyInvalidatable import mods.betterfoliage.util.LazyMapInvalidatable @@ -28,7 +29,6 @@ import mods.betterfoliage.util.averageColor import mods.betterfoliage.util.get import mods.betterfoliage.util.isSnow import mods.betterfoliage.util.randomI -import net.minecraft.block.BlockState import net.minecraft.util.Direction.DOWN import net.minecraft.util.Direction.UP import net.minecraft.util.ResourceLocation @@ -37,17 +37,9 @@ object StandardGrassDiscovery : ConfigurableModelDiscovery() { override val matchClasses: ConfigurableBlockMatcher get() = BlockConfig.grassBlocks override val modelTextures: List get() = BlockConfig.grassModels.modelList - override fun processModel( - state: BlockState, - location: ResourceLocation, - textureMatch: List, - sprites: MutableSet, - replacements: MutableMap - ): Boolean { - replacements[location] = StandardGrassKey(textureMatch[0], null) - Client.blockTypes.grass.add(state) -// RenderTypeLookup.setRenderLayer(state.block, RenderType.getCutout()) - return true + override fun processModel(ctx: ModelDiscoveryContext, textureMatch: List) { + ctx.addReplacement(StandardGrassKey(textureMatch[0], null)) + Client.blockTypes.grass.add(ctx.blockState) } } @@ -57,7 +49,7 @@ data class StandardGrassKey( ) : HalfBakedWrapperKey() { val tintIndex: Int get() = if (overrideColor == null) 0 else -1 - override fun replace(wrapped: SpecialRenderModel): SpecialRenderModel { + override fun bake(ctx: ModelBakingContext, wrapped: SpecialRenderModel): SpecialRenderModel { val grassSpriteColor = Atlas.BLOCKS[grassLocation].averageColor.let { hsb -> logColorOverride(BetterFoliageMod.detailLogger(this), Config.shortGrass.saturationThreshold, hsb) hsb.colorOverride(Config.shortGrass.saturationThreshold) @@ -81,7 +73,7 @@ class StandardGrassModel( val stateBelow = ctx.state(DOWN) val stateAbove = ctx.state(UP) - + val isAir = ctx.isAir(UP) val isSnowed = stateAbove.isSnow val connected = Config.connectedGrass.enabled && (!isSnowed || Config.connectedGrass.snowEnabled) && @@ -93,7 +85,7 @@ class StandardGrassModel( super.render(ctx, noDecorations) } - if (Config.shortGrass.enabled(ctx.random) && !ctx.isNeighborSolid(UP)) { + if (Config.shortGrass.enabled(ctx.random) && (isAir || isSnowed)) { ctx.vertexLighter = tuftLighting ShadersModIntegration.grass(ctx, Config.shortGrass.shaderWind) { ctx.renderQuads(if (isSnowed) tuftSnowed[ctx.random] else tuftNormal[ctx.random]) diff --git a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Leaf.kt b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Leaf.kt index 5e28437..3c02c9e 100644 --- a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Leaf.kt +++ b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Leaf.kt @@ -4,8 +4,6 @@ import mods.betterfoliage.BetterFoliageMod import mods.betterfoliage.Client import mods.betterfoliage.config.BlockConfig import mods.betterfoliage.config.Config -import mods.betterfoliage.config.ConfigurableBlockMatcher -import mods.betterfoliage.config.ModelTextureList import mods.betterfoliage.model.Color import mods.betterfoliage.model.HSB import mods.betterfoliage.model.HalfBakedSpecialWrapper @@ -14,21 +12,22 @@ import mods.betterfoliage.model.SpecialRenderModel import mods.betterfoliage.model.SpriteSetDelegate import mods.betterfoliage.model.crossModelsRaw import mods.betterfoliage.model.crossModelsTextured -import mods.betterfoliage.render.lighting.RoundLeafLighting +import mods.betterfoliage.render.lighting.RoundLeafLightingPreferUp +import mods.betterfoliage.render.particle.LeafBlockModel +import mods.betterfoliage.render.particle.LeafParticleKey +import mods.betterfoliage.render.particle.LeafParticleRegistry import mods.betterfoliage.render.pipeline.RenderCtxBase -import mods.betterfoliage.render.pipeline.RenderCtxVanilla import mods.betterfoliage.resource.discovery.BakeWrapperManager +import mods.betterfoliage.resource.discovery.ConfigurableBlockMatcher import mods.betterfoliage.resource.discovery.ConfigurableModelDiscovery -import mods.betterfoliage.resource.discovery.ModelBakingKey +import mods.betterfoliage.resource.discovery.ModelBakingContext +import mods.betterfoliage.resource.discovery.ModelDiscoveryContext +import mods.betterfoliage.resource.discovery.ModelTextureList import mods.betterfoliage.resource.generated.GeneratedLeaf -import mods.betterfoliage.texture.LeafBlockModel -import mods.betterfoliage.texture.LeafParticleKey -import mods.betterfoliage.texture.LeafParticleRegistry import mods.betterfoliage.util.Atlas import mods.betterfoliage.util.LazyMapInvalidatable import mods.betterfoliage.util.averageColor import mods.betterfoliage.util.isSnow -import net.minecraft.block.BlockState import net.minecraft.util.Direction.UP import net.minecraft.util.ResourceLocation import org.apache.logging.log4j.Level.DEBUG @@ -39,21 +38,15 @@ object StandardLeafDiscovery : ConfigurableModelDiscovery() { override val matchClasses: ConfigurableBlockMatcher get() = BlockConfig.leafBlocks override val modelTextures: List get() = BlockConfig.leafModels.modelList - override fun processModel( - state: BlockState, - location: ResourceLocation, - textureMatch: List, - sprites: MutableSet, - replacements: MutableMap - ): Boolean { + + override fun processModel(ctx: ModelDiscoveryContext, textureMatch: List) { val leafType = LeafParticleRegistry.typeMappings.getType(textureMatch[0]) ?: "default" val generated = GeneratedLeaf(textureMatch[0], leafType) .register(Client.generatedPack) - .apply { sprites.add(this) } + .apply { ctx.sprites.add(this) } detailLogger.log(INFO, " particle $leafType") - replacements[location] = StandardLeafKey(generated, leafType, null) - return true + ctx.addReplacement(StandardLeafKey(generated, leafType, null)) } } @@ -76,7 +69,7 @@ data class StandardLeafKey( ) : HalfBakedWrapperKey(), LeafParticleKey { val tintIndex: Int get() = if (overrideColor == null) 0 else -1 - override fun replace(wrapped: SpecialRenderModel): SpecialRenderModel { + override fun bake(ctx: ModelBakingContext, wrapped: SpecialRenderModel): SpecialRenderModel { val leafSpriteColor = Atlas.BLOCKS[roundLeafTexture].averageColor.let { hsb -> logColorOverride(BetterFoliageMod.detailLogger(this), Config.leaves.saturationThreshold, hsb) hsb.colorOverride(Config.leaves.saturationThreshold) @@ -97,9 +90,10 @@ class StandardLeafModel( super.render(ctx, noDecorations) if (!Config.enabled || !Config.leaves.enabled || noDecorations) return - (ctx as? RenderCtxVanilla)?.let { it.vertexLighter = RoundLeafLighting } - ctx.renderQuads(leafNormal[ctx.random.nextInt(64)]) - if (ctx.state(UP).isSnow) ctx.renderQuads(leafSnowed[ctx.random.nextInt(64)]) + ctx.vertexLighter = RoundLeafLightingPreferUp + val leafIdx = ctx.random.nextInt(64) + ctx.renderQuads(leafNormal[leafIdx]) + if (ctx.state(UP).isSnow) ctx.renderQuads(leafSnowed[leafIdx]) } companion object { diff --git a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Lilypad.kt b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Lilypad.kt index bd22f9d..b284765 100644 --- a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Lilypad.kt +++ b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Lilypad.kt @@ -14,7 +14,9 @@ import mods.betterfoliage.model.tuftShapeSet import mods.betterfoliage.render.pipeline.RenderCtxBase import mods.betterfoliage.resource.discovery.AbstractModelDiscovery import mods.betterfoliage.resource.discovery.BakeWrapperManager +import mods.betterfoliage.resource.discovery.ModelBakingContext import mods.betterfoliage.resource.discovery.ModelBakingKey +import mods.betterfoliage.resource.discovery.ModelDiscoveryContext import mods.betterfoliage.util.Atlas import mods.betterfoliage.util.LazyInvalidatable import mods.betterfoliage.util.get @@ -27,23 +29,17 @@ import net.minecraft.util.ResourceLocation object StandardLilypadDiscovery : AbstractModelDiscovery() { val LILYPAD_BLOCKS = listOf(Blocks.LILY_PAD) - override fun processModel( - bakery: ModelBakery, - state: BlockState, - location: ResourceLocation, - sprites: MutableSet, - replacements: MutableMap - ): Boolean { - val model = bakery.getUnbakedModel(location) - if (model is BlockModel && state.block in LILYPAD_BLOCKS) { - replacements[location] = StandardLilypadKey + + override fun processModel(ctx: ModelDiscoveryContext) { + if (ctx.getUnbaked() is BlockModel && ctx.blockState.block in LILYPAD_BLOCKS) { + ctx.addReplacement(StandardLilypadKey) } - return super.processModel(bakery, state, location, sprites, replacements) + super.processModel(ctx) } } object StandardLilypadKey : HalfBakedWrapperKey() { - override fun replace(wrapped: SpecialRenderModel) = StandardLilypadModel(wrapped) + override fun bake(ctx: ModelBakingContext, wrapped: SpecialRenderModel) = StandardLilypadModel(wrapped) } class StandardLilypadModel( diff --git a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Mycelium.kt b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Mycelium.kt index e81024e..fd748d6 100644 --- a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Mycelium.kt +++ b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Mycelium.kt @@ -13,42 +13,33 @@ import mods.betterfoliage.render.lighting.LightingPreferredFace import mods.betterfoliage.render.pipeline.RenderCtxBase import mods.betterfoliage.resource.discovery.AbstractModelDiscovery import mods.betterfoliage.resource.discovery.BakeWrapperManager -import mods.betterfoliage.resource.discovery.ModelBakingKey +import mods.betterfoliage.resource.discovery.ModelBakingContext +import mods.betterfoliage.resource.discovery.ModelDiscoveryContext import mods.betterfoliage.util.Atlas import mods.betterfoliage.util.LazyInvalidatable import mods.betterfoliage.util.get import mods.betterfoliage.util.randomI -import net.minecraft.block.BlockState import net.minecraft.block.Blocks import net.minecraft.client.renderer.RenderType import net.minecraft.client.renderer.RenderTypeLookup import net.minecraft.client.renderer.model.BlockModel -import net.minecraft.client.renderer.model.ModelBakery import net.minecraft.util.Direction import net.minecraft.util.ResourceLocation object StandardMyceliumDiscovery : AbstractModelDiscovery() { val MYCELIUM_BLOCKS = listOf(Blocks.MYCELIUM) - override fun processModel( - bakery: ModelBakery, - state: BlockState, - location: ResourceLocation, - sprites: MutableSet, - replacements: MutableMap - ): Boolean { - val model = bakery.getUnbakedModel(location) - if (model is BlockModel && state.block in MYCELIUM_BLOCKS) { - replacements[location] = StandardMyceliumKey - RenderTypeLookup.setRenderLayer(state.block, RenderType.getCutout()) - return true + override fun processModel(ctx: ModelDiscoveryContext) { + if (ctx.getUnbaked() is BlockModel && ctx.blockState.block in MYCELIUM_BLOCKS) { + ctx.addReplacement(StandardMyceliumKey) + RenderTypeLookup.setRenderLayer(ctx.blockState.block, RenderType.getCutout()) } - return super.processModel(bakery, state, location, sprites, replacements) + super.processModel(ctx) } } object StandardMyceliumKey : HalfBakedWrapperKey() { - override fun replace(wrapped: SpecialRenderModel) = StandardMyceliumModel(wrapped) + override fun bake(ctx: ModelBakingContext, wrapped: SpecialRenderModel) = StandardMyceliumModel(wrapped) } class StandardMyceliumModel( diff --git a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Netherrack.kt b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Netherrack.kt new file mode 100644 index 0000000..547605c --- /dev/null +++ b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Netherrack.kt @@ -0,0 +1,82 @@ +package mods.betterfoliage.render.block.vanilla + +import mods.betterfoliage.BetterFoliageMod +import mods.betterfoliage.Client +import mods.betterfoliage.config.Config +import mods.betterfoliage.model.HalfBakedSpecialWrapper +import mods.betterfoliage.model.HalfBakedWrapperKey +import mods.betterfoliage.model.SpecialRenderModel +import mods.betterfoliage.model.SpriteSetDelegate +import mods.betterfoliage.model.buildTufts +import mods.betterfoliage.model.transform +import mods.betterfoliage.model.tuftModelSet +import mods.betterfoliage.model.tuftShapeSet +import mods.betterfoliage.render.lighting.LightingPreferredFace +import mods.betterfoliage.render.pipeline.RenderCtxBase +import mods.betterfoliage.resource.discovery.AbstractModelDiscovery +import mods.betterfoliage.resource.discovery.BakeWrapperManager +import mods.betterfoliage.resource.discovery.ModelBakingContext +import mods.betterfoliage.resource.discovery.ModelDiscoveryContext +import mods.betterfoliage.util.Atlas +import mods.betterfoliage.util.LazyInvalidatable +import mods.betterfoliage.util.Rotation +import mods.betterfoliage.util.get +import mods.betterfoliage.util.randomI +import net.minecraft.block.Blocks +import net.minecraft.client.renderer.RenderType +import net.minecraft.client.renderer.RenderTypeLookup +import net.minecraft.client.renderer.model.BlockModel +import net.minecraft.util.Direction.DOWN +import net.minecraft.util.ResourceLocation + +object StandardNetherrackDiscovery : AbstractModelDiscovery() { + val NETHERRACK_BLOCKS = listOf(Blocks.NETHERRACK) + + fun canRenderInLayer(layer: RenderType) = when { + !Config.enabled -> layer == RenderType.getSolid() + !Config.netherrack.enabled -> layer == RenderType.getSolid() + else -> layer == RenderType.getCutoutMipped() + } + + override fun processModel(ctx: ModelDiscoveryContext) { + if (ctx.getUnbaked() is BlockModel && ctx.blockState.block in NETHERRACK_BLOCKS) { + Client.blockTypes.dirt.add(ctx.blockState) + ctx.addReplacement(StandardNetherrackKey) + RenderTypeLookup.setRenderLayer(ctx.blockState.block, ::canRenderInLayer) + } + super.processModel(ctx) + } +} + +object StandardNetherrackKey : HalfBakedWrapperKey() { + override fun bake(ctx: ModelBakingContext, wrapped: SpecialRenderModel) = StandardNetherrackModel(wrapped) +} + +class StandardNetherrackModel( + wrapped: SpecialRenderModel +) : HalfBakedSpecialWrapper(wrapped) { + + val tuftLighting = LightingPreferredFace(DOWN) + + override fun render(ctx: RenderCtxBase, noDecorations: Boolean) { + super.render(ctx, noDecorations) + if (!Config.enabled || !Config.netherrack.enabled) return + + if (ctx.isAir(DOWN)) { + ctx.vertexLighter = tuftLighting + ctx.renderQuads(netherrackTuftModels[ctx.random]) + } + } + + companion object { + val netherrackTuftSprites by SpriteSetDelegate(Atlas.BLOCKS) { idx -> + ResourceLocation(BetterFoliageMod.MOD_ID, "blocks/better_netherrack_$idx") + } + val netherrackTuftModels by LazyInvalidatable(BakeWrapperManager) { + val shapes = Config.netherrack.let { tuftShapeSet(it.size, it.heightMin, it.heightMax, it.hOffset) } + tuftModelSet(shapes, -1) { netherrackTuftSprites[randomI()] } + .transform { rotate(Rotation.fromUp[DOWN.ordinal]).rotateUV(2) } + .buildTufts() + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/RoundLog.kt b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/RoundLog.kt index 018ad3b..7d13de8 100644 --- a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/RoundLog.kt +++ b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/RoundLog.kt @@ -1,13 +1,98 @@ package mods.betterfoliage.render.block.vanilla +import mods.betterfoliage.Client +import mods.betterfoliage.config.BlockConfig +import mods.betterfoliage.config.Config +import mods.betterfoliage.resource.discovery.ModelTextureList +import mods.betterfoliage.model.HalfBakedWrapperKey +import mods.betterfoliage.model.SpecialRenderModel import mods.betterfoliage.render.column.ColumnBlockKey +import mods.betterfoliage.render.column.ColumnMeshSet +import mods.betterfoliage.render.column.ColumnModelBase +import mods.betterfoliage.render.column.ColumnRenderLayer +import mods.betterfoliage.resource.discovery.BakeWrapperManager +import mods.betterfoliage.resource.discovery.ConfigurableBlockMatcher +import mods.betterfoliage.resource.discovery.ConfigurableModelDiscovery +import mods.betterfoliage.resource.discovery.ModelBakingContext import mods.betterfoliage.resource.discovery.ModelBakingKey -import net.minecraft.util.Direction +import mods.betterfoliage.resource.discovery.ModelDiscoveryContext +import mods.betterfoliage.util.Atlas +import mods.betterfoliage.util.LazyMapInvalidatable +import mods.betterfoliage.util.tryDefault +import net.minecraft.block.BlockState +import net.minecraft.block.LogBlock +import net.minecraft.util.Direction.Axis import net.minecraft.util.ResourceLocation +import org.apache.logging.log4j.Level.INFO -data class RoundLogKey( - override val axis: Direction.Axis?, - val barkSprite: ResourceLocation, +interface RoundLogKey : ColumnBlockKey, ModelBakingKey { + val barkSprite: ResourceLocation val endSprite: ResourceLocation -) : ColumnBlockKey, ModelBakingKey { +} + +object RoundLogOverlayLayer : ColumnRenderLayer() { + override fun getColumnKey(state: BlockState) = Client.blockTypes.getTyped(state) + override val connectSolids: Boolean get() = Config.roundLogs.connectSolids + override val lenientConnect: Boolean get() = Config.roundLogs.lenientConnect + override val defaultToY: Boolean get() = Config.roundLogs.defaultY +} + +object StandardLogDiscovery : ConfigurableModelDiscovery() { + override val matchClasses: ConfigurableBlockMatcher get() = BlockConfig.logBlocks + override val modelTextures: List get() = BlockConfig.logModels.modelList + + override fun processModel(ctx: ModelDiscoveryContext, textureMatch: List) { + val axis = getAxis(ctx.blockState) + detailLogger.log(INFO, " axis $axis") + StandardRoundLogKey(axis, textureMatch[0], textureMatch[1]).let { key -> + ctx.addReplacement(key) + Client.blockTypes.stateKeys[ctx.blockState] = key + } + } + + fun getAxis(state: BlockState): Axis? { + val axis = tryDefault(null) { state.get(LogBlock.AXIS).toString() } ?: + state.values.entries.find { it.key.getName().toLowerCase() == "axis" }?.value?.toString() + return when (axis) { + "x" -> Axis.X + "y" -> Axis.Y + "z" -> Axis.Z + else -> null + } + } +} + +data class StandardRoundLogKey( + override val axis: Axis?, + override val barkSprite: ResourceLocation, + override val endSprite: ResourceLocation +) : RoundLogKey, HalfBakedWrapperKey() { + override fun bake(ctx: ModelBakingContext, wrapped: SpecialRenderModel) = StandardRoundLogModel(this, wrapped) +} + +class StandardRoundLogModel( + val key: StandardRoundLogKey, + wrapped: SpecialRenderModel +) : ColumnModelBase(wrapped) { + override val enabled: Boolean get() = Config.enabled && Config.roundLogs.enabled + override val overlayLayer: ColumnRenderLayer get() = RoundLogOverlayLayer + override val connectPerpendicular: Boolean get() = Config.roundLogs.connectPerpendicular + + val modelSet by modelSets.delegate(key) + override fun getMeshSet(axis: Axis, quadrant: Int) = modelSet + + companion object { + val modelSets = LazyMapInvalidatable(BakeWrapperManager) { key: StandardRoundLogKey -> + val barkSprite = Atlas.BLOCKS[key.barkSprite] + val endSprite = Atlas.BLOCKS[key.endSprite] + Config.roundLogs.let { config -> + ColumnMeshSet( + config.radiusSmall, config.radiusLarge, config.zProtection, + key.axis ?: Axis.Y, + barkSprite, barkSprite, + endSprite, endSprite + ) + } + } + } } \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Sand.kt b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Sand.kt index a8fc4ca..8396082 100644 --- a/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Sand.kt +++ b/src/main/kotlin/mods/betterfoliage/render/block/vanilla/Sand.kt @@ -18,7 +18,8 @@ import mods.betterfoliage.render.lighting.LightingPreferredFace import mods.betterfoliage.render.pipeline.RenderCtxBase import mods.betterfoliage.resource.discovery.AbstractModelDiscovery import mods.betterfoliage.resource.discovery.BakeWrapperManager -import mods.betterfoliage.resource.discovery.ModelBakingKey +import mods.betterfoliage.resource.discovery.ModelBakingContext +import mods.betterfoliage.resource.discovery.ModelDiscoveryContext import mods.betterfoliage.util.Atlas import mods.betterfoliage.util.LazyInvalidatable import mods.betterfoliage.util.Rotation @@ -28,39 +29,30 @@ import mods.betterfoliage.util.mapArray import mods.betterfoliage.util.randomB import mods.betterfoliage.util.randomD import mods.betterfoliage.util.randomI -import net.minecraft.block.BlockState import net.minecraft.block.Blocks import net.minecraft.block.material.Material import net.minecraft.client.renderer.RenderType import net.minecraft.client.renderer.RenderTypeLookup import net.minecraft.client.renderer.model.BlockModel -import net.minecraft.client.renderer.model.ModelBakery import net.minecraft.util.Direction import net.minecraft.util.Direction.UP import net.minecraft.util.ResourceLocation object StandardSandDiscovery : AbstractModelDiscovery() { val SAND_BLOCKS = listOf(Blocks.SAND, Blocks.RED_SAND) - override fun processModel( - bakery: ModelBakery, - state: BlockState, - location: ResourceLocation, - sprites: MutableSet, - replacements: MutableMap - ): Boolean { - val model = bakery.getUnbakedModel(location) - if (model is BlockModel && state.block in SAND_BLOCKS) { - Client.blockTypes.dirt.add(state) - replacements[location] = StandardSandKey - RenderTypeLookup.setRenderLayer(state.block, RenderType.getCutoutMipped()) - return true + + override fun processModel(ctx: ModelDiscoveryContext) { + if (ctx.getUnbaked() is BlockModel && ctx.blockState.block in SAND_BLOCKS) { + Client.blockTypes.dirt.add(ctx.blockState) + ctx.addReplacement(StandardSandKey) + RenderTypeLookup.setRenderLayer(ctx.blockState.block, RenderType.getCutoutMipped()) } - return super.processModel(bakery, state, location, sprites, replacements) + super.processModel(ctx) } } object StandardSandKey : HalfBakedWrapperKey() { - override fun replace(wrapped: SpecialRenderModel) = StandardSandModel(wrapped) + override fun bake(ctx: ModelBakingContext, wrapped: SpecialRenderModel) = StandardSandModel(wrapped) } class StandardSandModel( diff --git a/src/main/kotlin/mods/betterfoliage/render/column/ColumnMeshSet.kt b/src/main/kotlin/mods/betterfoliage/render/column/ColumnMeshSet.kt new file mode 100644 index 0000000..caf4e8d --- /dev/null +++ b/src/main/kotlin/mods/betterfoliage/render/column/ColumnMeshSet.kt @@ -0,0 +1,166 @@ +package mods.betterfoliage.render.column + +import mods.betterfoliage.config.Config +import mods.betterfoliage.model.Quad +import mods.betterfoliage.model.UV +import mods.betterfoliage.model.Vertex +import mods.betterfoliage.model.bake +import mods.betterfoliage.render.column.ColumnLayerData.SpecialRender.QuadrantType +import mods.betterfoliage.render.column.ColumnLayerData.SpecialRender.QuadrantType.INVISIBLE +import mods.betterfoliage.render.column.ColumnLayerData.SpecialRender.QuadrantType.LARGE_RADIUS +import mods.betterfoliage.render.column.ColumnLayerData.SpecialRender.QuadrantType.SMALL_RADIUS +import mods.betterfoliage.render.column.ColumnLayerData.SpecialRender.QuadrantType.SQUARE +import mods.betterfoliage.util.Double3 +import mods.betterfoliage.util.Rotation +import net.minecraft.client.renderer.texture.TextureAtlasSprite +import net.minecraft.util.Direction.Axis +import net.minecraft.util.Direction.EAST +import net.minecraft.util.Direction.SOUTH +import net.minecraft.util.Direction.UP + +/** + * Collection of dynamically generated meshes used to render rounded columns. + */ +class ColumnMeshSet( + radiusSmall: Double, + radiusLarge: Double, + zProtection: Double, + val axis: Axis, + val spriteLeft: TextureAtlasSprite, + val spriteRight: TextureAtlasSprite, + val spriteTop: TextureAtlasSprite, + val spriteBottom: TextureAtlasSprite +) { + protected fun sideRounded(radius: Double, yBottom: Double, yTop: Double): List { + val halfRadius = radius * 0.5 + return listOf( + // left side of the diagonal + Quad.verticalRectangle(0.0, 0.5, 0.5 - radius, 0.5, yBottom, yTop).clampUV(minU = 0.0, maxU = 0.5 - radius), + Quad.verticalRectangle(0.5 - radius, 0.5, 0.5 - halfRadius, 0.5 - halfRadius, yBottom, yTop).clampUV(minU = 0.5 - radius), + // right side of the diagonal + Quad.verticalRectangle(0.5 - halfRadius, 0.5 - halfRadius, 0.5, 0.5 - radius, yBottom, yTop).clampUV(maxU = radius - 0.5), + Quad.verticalRectangle(0.5, 0.5 - radius, 0.5, 0.0, yBottom, yTop).clampUV(minU = radius - 0.5, maxU = 0.0) + ) + } + + protected fun sideRoundedTransition(radiusBottom: Double, radiusTop: Double, yBottom: Double, yTop: Double): List { + val ySplit = 0.5 * (yBottom + yTop) + val modelTop = sideRounded(radiusTop, yBottom, yTop) + val modelBottom = sideRounded(radiusBottom, yBottom, yTop) + return (modelBottom zip modelTop).map { (quadBottom, quadTop) -> + Quad.mix(quadBottom, quadTop) { vBottom, vTop -> if (vBottom.xyz.y < ySplit) vBottom.copy() else vTop.copy() } + } + } + + protected fun sideSquare(yBottom: Double, yTop: Double) = listOf( + Quad.verticalRectangle(0.0, 0.5, 0.5, 0.5, yBottom, yTop).clampUV(minU = 0.0), + Quad.verticalRectangle(0.5, 0.5, 0.5, 0.0, yBottom, yTop).clampUV(maxU = 0.0) + ) + + protected fun lidRounded(radius: Double, y: Double, isBottom: Boolean) = Array(4) { quadrant -> + val rotation = baseRotation(axis) + quadrantRotations[quadrant] + val v1 = Vertex(Double3(0.0, y, 0.0), UV(0.0, 0.0)) + val v2 = Vertex(Double3(0.0, y, 0.5), UV(0.0, 0.5)) + val v3 = Vertex(Double3(0.5 - radius, y, 0.5), UV(0.5 - radius, 0.5)) + val v4 = Vertex(Double3(0.5 - radius * 0.5, y, 0.5 - radius * 0.5), UV(0.5, 0.5)) + val v5 = Vertex(Double3(0.5, y, 0.5 - radius), UV(0.5, 0.5 - radius)) + val v6 = Vertex(Double3(0.5, y, 0.0), UV(0.5, 0.0)) + listOf(Quad(v1, v2, v3, v4), Quad(v1, v4, v5, v6)) + .map { it.cycleVertices(if (isBottom xor Config.nVidia) 0 else 1) } + .map { it.rotate(rotation).rotateUV(quadrant) } + .map { it.sprite(if (isBottom) spriteBottom else spriteTop) } + .map { if (isBottom) it.flipped else it } + } + + protected fun lidSquare(y: Double, isBottom: Boolean) = Array(4) { quadrant -> + val rotation = baseRotation(axis) + quadrantRotations[quadrant] + listOf( + Quad.horizontalRectangle(x1 = 0.0, x2 = 0.5, z1 = 0.0, z2 = 0.5, y = y).clampUV(minU = 0.0, minV = 0.0) + .rotate(rotation).rotateUV(quadrant) + .sprite(if (isBottom) spriteBottom else spriteTop) + .let { if (isBottom) it.flipped else it } + ) + } + + protected val zProtectionScale = zProtection.let { Double3(it, 1.0, it) } + + protected fun List.extendTop(size: Double) = map { q -> q.clampUV(minV = 0.5 - size).transformV { v -> + if (v.xyz.y > 0.501) v.copy(xyz = v.xyz * zProtectionScale) else v } + } + protected fun List.extendBottom(size: Double) = map { q -> q.clampUV(maxV = -0.5 + size).transformV { v -> + if (v.xyz.y < -0.501) v.copy(xyz = v.xyz * zProtectionScale) else v } + } + protected fun List.buildSides(quadsPerSprite: Int) = Array(4) { quadrant -> + val rotation = baseRotation(axis) + quadrantRotations[quadrant] + this.map { it.rotate(rotation) } + .mapIndexed { idx, q -> if (idx % (2 * quadsPerSprite) >= quadsPerSprite) q.sprite(spriteRight) else q.sprite(spriteLeft) } + .bake(false) + } + + companion object { + fun baseRotation(axis: Axis) = when(axis) { + Axis.X -> Rotation.fromUp[EAST.ordinal] + Axis.Y -> Rotation.fromUp[UP.ordinal] + Axis.Z -> Rotation.fromUp[SOUTH.ordinal] + } + val quadrantRotations = Array(4) { Rotation.rot90[UP.ordinal] * it } + } + + // + // Mesh definitions + // 4-element arrays hold prebuild meshes for each of the rotations around the axis + // + val sideSquare = sideSquare(-0.5, 0.5).buildSides(quadsPerSprite = 1) + val sideRoundSmall = sideRounded(radiusSmall, -0.5, 0.5).buildSides(quadsPerSprite = 2) + val sideRoundLarge = sideRounded(radiusLarge, -0.5, 0.5).buildSides(quadsPerSprite = 2) + + val sideExtendTopSquare = sideSquare(0.5, 0.5 + radiusLarge).extendTop(radiusLarge).buildSides(quadsPerSprite = 1) + val sideExtendTopRoundSmall = sideRounded(radiusSmall, 0.5, 0.5 + radiusLarge).extendTop(radiusLarge).buildSides(quadsPerSprite = 2) + val sideExtendTopRoundLarge = sideRounded(radiusLarge, 0.5, 0.5 + radiusLarge).extendTop(radiusLarge).buildSides(quadsPerSprite = 2) + + val sideExtendBottomSquare = sideSquare(-0.5 - radiusLarge, -0.5).extendBottom(radiusLarge).buildSides(quadsPerSprite = 1) + val sideExtendBottomRoundSmall = sideRounded(radiusSmall, -0.5 - radiusLarge, -0.5).extendBottom(radiusLarge).buildSides(quadsPerSprite = 2) + val sideExtendBottomRoundLarge = sideRounded(radiusLarge, -0.5 - radiusLarge, -0.5).extendBottom(radiusLarge).buildSides(quadsPerSprite = 2) + + val lidTopSquare = lidSquare(0.5, false).bake(false) + val lidTopRoundSmall = lidRounded(radiusSmall, 0.5, false).bake(false) + val lidTopRoundLarge = lidRounded(radiusLarge, 0.5, false).bake(false) + + val lidBottomSquare = lidSquare(-0.5, true).bake(false) + val lidBottomRoundSmall = lidRounded(radiusSmall, -0.5, true).bake(false) + val lidBottomRoundLarge = lidRounded(radiusLarge, -0.5, true).bake(false) + + val transitionTop = sideRoundedTransition(radiusLarge, radiusSmall, -0.5, 0.5).buildSides(quadsPerSprite = 2) + val transitionBottom = sideRoundedTransition(radiusSmall, radiusLarge, -0.5, 0.5).buildSides(quadsPerSprite = 2) + + // + // Helper fuctions for lids (block ends) + // + fun flatTop(quadrantTypes: Array, quadrant: Int) = when(quadrantTypes[quadrant]) { + SMALL_RADIUS -> lidTopRoundSmall[quadrant] + LARGE_RADIUS -> lidTopRoundLarge[quadrant] + SQUARE -> lidTopSquare[quadrant] + INVISIBLE -> lidTopSquare[quadrant] + } + + fun flatBottom(quadrantTypes: Array, quadrant: Int) = when(quadrantTypes[quadrant]) { + SMALL_RADIUS -> lidBottomRoundSmall[quadrant] + LARGE_RADIUS -> lidBottomRoundLarge[quadrant] + SQUARE -> lidBottomSquare[quadrant] + INVISIBLE -> lidBottomSquare[quadrant] + } + + fun extendTop(quadrantTypes: Array, quadrant: Int) = when(quadrantTypes[quadrant]) { + SMALL_RADIUS -> sideExtendTopRoundSmall[quadrant] + LARGE_RADIUS -> sideExtendTopRoundLarge[quadrant] + SQUARE -> sideExtendTopSquare[quadrant] + INVISIBLE -> sideExtendTopSquare[quadrant] + } + + fun extendBottom(quadrantTypes: Array, quadrant: Int) = when(quadrantTypes[quadrant]) { + SMALL_RADIUS -> sideExtendBottomRoundSmall[quadrant] + LARGE_RADIUS -> sideExtendBottomRoundLarge[quadrant] + SQUARE -> sideExtendBottomSquare[quadrant] + INVISIBLE -> sideExtendBottomSquare[quadrant] + } +} \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/render/column/ColumnModel.kt b/src/main/kotlin/mods/betterfoliage/render/column/ColumnModel.kt new file mode 100644 index 0000000..545f222 --- /dev/null +++ b/src/main/kotlin/mods/betterfoliage/render/column/ColumnModel.kt @@ -0,0 +1,112 @@ +package mods.betterfoliage.render.column + +import mods.betterfoliage.chunk.ChunkOverlayManager +import mods.betterfoliage.model.HalfBakedSpecialWrapper +import mods.betterfoliage.model.SpecialRenderModel +import mods.betterfoliage.render.column.ColumnLayerData.NormalRender +import mods.betterfoliage.render.column.ColumnLayerData.SpecialRender.BlockType.NONSOLID +import mods.betterfoliage.render.column.ColumnLayerData.SpecialRender.BlockType.PARALLEL +import mods.betterfoliage.render.column.ColumnLayerData.SpecialRender.BlockType.PERPENDICULAR +import mods.betterfoliage.render.column.ColumnLayerData.SpecialRender.QuadrantType.INVISIBLE +import mods.betterfoliage.render.column.ColumnLayerData.SpecialRender.QuadrantType.LARGE_RADIUS +import mods.betterfoliage.render.column.ColumnLayerData.SpecialRender.QuadrantType.SMALL_RADIUS +import mods.betterfoliage.render.column.ColumnLayerData.SpecialRender.QuadrantType.SQUARE +import mods.betterfoliage.render.lighting.ColumnLighting +import mods.betterfoliage.render.pipeline.RenderCtxBase +import net.minecraft.util.Direction.Axis + +abstract class ColumnModelBase( + wrapped: SpecialRenderModel +) : HalfBakedSpecialWrapper(wrapped) { + + abstract val enabled: Boolean + abstract val overlayLayer: ColumnRenderLayer + abstract val connectPerpendicular: Boolean + abstract fun getMeshSet(axis: Axis, quadrant: Int): ColumnMeshSet + + override fun render(ctx: RenderCtxBase, noDecorations: Boolean) { + val roundLog = ChunkOverlayManager.get(overlayLayer, ctx) + + when(roundLog) { + ColumnLayerData.SkipRender -> return + NormalRender -> return super.render(ctx, noDecorations) + ColumnLayerData.ResolveError, null -> { + return super.render(ctx, noDecorations) + } + } + + // if log axis is not defined and "Default to vertical" config option is not set, render normally + if ((roundLog as ColumnLayerData.SpecialRender).column.axis == null && !overlayLayer.defaultToY) { + return super.render(ctx, noDecorations) + } + + ctx.vertexLighter = ColumnLighting + + val axis = roundLog.column.axis ?: Axis.Y + val baseRotation = ColumnMeshSet.baseRotation(axis) + ColumnMeshSet.quadrantRotations.forEachIndexed { idx, quadrantRotation -> + // set rotation for the current quadrant + val rotation = baseRotation + quadrantRotation + val meshSet = getMeshSet(axis, idx) + + // disallow sharp discontinuities in the chamfer radius, or tapering-in where inappropriate + if (roundLog.quadrants[idx] == LARGE_RADIUS && + roundLog.upType == PARALLEL && roundLog.quadrantsTop[idx] != LARGE_RADIUS && + roundLog.downType == PARALLEL && roundLog.quadrantsBottom[idx] != LARGE_RADIUS) { + roundLog.quadrants[idx] = SMALL_RADIUS + } + + // select meshes for current quadrant based on connectivity rules + val sideMesh = when (roundLog.quadrants[idx]) { + SMALL_RADIUS -> meshSet.sideRoundSmall[idx] + LARGE_RADIUS -> if (roundLog.upType == PARALLEL && roundLog.quadrantsTop[idx] == SMALL_RADIUS) meshSet.transitionTop[idx] + else if (roundLog.downType == PARALLEL && roundLog.quadrantsBottom[idx] == SMALL_RADIUS) meshSet.transitionBottom[idx] + else meshSet.sideRoundLarge[idx] + SQUARE -> meshSet.sideSquare[idx] + else -> null + } + + val upMesh = when(roundLog.upType) { + NONSOLID -> meshSet.flatTop(roundLog.quadrants, idx) + PERPENDICULAR -> { + if (!connectPerpendicular) { + meshSet.flatTop(roundLog.quadrants, idx) + } else { + meshSet.extendTop(roundLog.quadrants, idx) + } + } + PARALLEL -> { + if (roundLog.quadrants[idx] discontinuousWith roundLog.quadrantsTop[idx] && + roundLog.quadrants[idx].let { it == SQUARE || it == INVISIBLE } ) + meshSet.flatTop(roundLog.quadrants, idx) + else null + } + else -> null + } + + val downMesh = when(roundLog.downType) { + NONSOLID -> meshSet.flatBottom(roundLog.quadrants, idx) + PERPENDICULAR -> { + if (!connectPerpendicular) { + meshSet.flatBottom(roundLog.quadrants, idx) + } else { + meshSet.extendBottom(roundLog.quadrants, idx) + } + } + PARALLEL -> { + if (roundLog.quadrants[idx] discontinuousWith roundLog.quadrantsBottom[idx] && + roundLog.quadrants[idx].let { it == SQUARE || it == INVISIBLE } ) + meshSet.flatBottom(roundLog.quadrants, idx) + else null + } + else -> null + } + + // render + sideMesh?.let { ctx.renderQuads(it) } + upMesh?.let { ctx.renderQuads(it) } + downMesh?.let { ctx.renderQuads(it) } + } + + } +} \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/render/column/ColumnOverlayLayer.kt b/src/main/kotlin/mods/betterfoliage/render/column/ColumnOverlayLayer.kt index 3831b1a..7344abb 100644 --- a/src/main/kotlin/mods/betterfoliage/render/column/ColumnOverlayLayer.kt +++ b/src/main/kotlin/mods/betterfoliage/render/column/ColumnOverlayLayer.kt @@ -90,7 +90,6 @@ abstract class ColumnRenderLayer : ChunkOverlayLayer { override fun calculate(ctx: BlockCtx): ColumnLayerData { // TODO detect round logs if (allDirections.all { dir -> ctx.offset(dir).let { it.isNormalCube } }) return ColumnLayerData.SkipRender -// val columnTextures = registry[ctx] ?: return ColumnLayerData.ResolveError val columnTextures = getColumnKey(ctx.state) ?: return ColumnLayerData.ResolveError // if log axis is not defined and "Default to vertical" config option is not set, render normally diff --git a/src/main/kotlin/mods/betterfoliage/render/lighting/VanillaVertexLighter.kt b/src/main/kotlin/mods/betterfoliage/render/lighting/VanillaVertexLighter.kt index a05e076..69435c4 100644 --- a/src/main/kotlin/mods/betterfoliage/render/lighting/VanillaVertexLighter.kt +++ b/src/main/kotlin/mods/betterfoliage/render/lighting/VanillaVertexLighter.kt @@ -2,7 +2,8 @@ package mods.betterfoliage.render.lighting import mods.betterfoliage.model.HalfBakedQuad import mods.betterfoliage.util.Double3 -import mods.betterfoliage.util.EPSILON +import mods.betterfoliage.util.EPSILON_ONE +import mods.betterfoliage.util.EPSILON_ZERO import mods.betterfoliage.util.minBy import net.minecraft.client.renderer.color.BlockColors import net.minecraft.util.Direction @@ -41,6 +42,12 @@ class VanillaQuadLighting { abstract class VanillaVertexLighter { abstract fun updateLightmapAndColor(quad: HalfBakedQuad, lighting: VanillaQuadLighting) + /** + * Update lighting for each vertex with AO values from one of the corners. + * Does not calculate missing AO values! + * @param quad the quad to shade + * @param func selector function from vertex position to directed corner index of desired AO values + */ inline fun VanillaQuadLighting.updateWithCornerAo(quad: HalfBakedQuad, func: (Double3)->Int?) { quad.raw.verts.forEachIndexed { idx, vertex -> func(vertex.xyz)?.let { @@ -51,9 +58,13 @@ abstract class VanillaVertexLighter { } } +/** + * Replicates vanilla shading for full blocks. Interpolation for non-full blocks + * is not implemented. + */ object VanillaFullBlockLighting : VanillaVertexLighter() { override fun updateLightmapAndColor(quad: HalfBakedQuad, lighting: VanillaQuadLighting) { - // TODO bounds checking + // TODO bounds checking & interpolation val face = quad.raw.face() lighting.calc.fillLightData(face, true) lighting.updateWithCornerAo(quad) { nearestCornerOnFace(it, face) } @@ -62,7 +73,7 @@ object VanillaFullBlockLighting : VanillaVertexLighter() { } } -object RoundLeafLighting : VanillaVertexLighter() { +object RoundLeafLightingPreferUp : VanillaVertexLighter() { override fun updateLightmapAndColor(quad: HalfBakedQuad, lighting: VanillaQuadLighting) { val angles = getAngles45(quad)?.let { normalFaces -> lighting.calc.fillLightData(normalFaces.first) @@ -79,6 +90,28 @@ object RoundLeafLighting : VanillaVertexLighter() { } } +/** + * Lights vertices with the AO values from the nearest corner on either of + * the 2 faces the quad normal points towards. + */ +object RoundLeafLighting : VanillaVertexLighter() { + override fun updateLightmapAndColor(quad: HalfBakedQuad, lighting: VanillaQuadLighting) { + val angles = getAngles45(quad)?.let { normalFaces -> + lighting.calc.fillLightData(normalFaces.first) + lighting.calc.fillLightData(normalFaces.second) + lighting.updateWithCornerAo(quad) { vertex -> + val cornerUndir = AoSideHelper.getCornerUndir(vertex.x, vertex.y, vertex.z) + val preferredFace = normalFaces.minBy { faceDistance(it, vertex) } + AoSideHelper.boxCornersDirFromUndir[preferredFace.ordinal][cornerUndir] + } + lighting.updateBlockTint(quad.baked.tintIndex) + } + } +} + +/** + * Lights vertices with the AO values from the nearest corner on the preferred face. + */ class LightingPreferredFace(val face: Direction) : VanillaVertexLighter() { override fun updateLightmapAndColor(quad: HalfBakedQuad, lighting: VanillaQuadLighting) { lighting.calc.fillLightData(face) @@ -87,6 +120,38 @@ class LightingPreferredFace(val face: Direction) : VanillaVertexLighter() { } } +object ColumnLighting : VanillaVertexLighter() { + override fun updateLightmapAndColor(quad: HalfBakedQuad, lighting: VanillaQuadLighting) { + // faces pointing in cardinal directions + getNormalFace(quad)?.let { face -> + lighting.calc.fillLightData(face) + lighting.updateWithCornerAo(quad) { nearestCornerOnFace(it, face) } + lighting.updateBlockTint(quad.baked.tintIndex) + return + } + // faces pointing at 45deg angles + getAngles45(quad)?.let { (face1, face2) -> + lighting.calc.fillLightData(face1) + lighting.calc.fillLightData(face2) + quad.raw.verts.forEachIndexed { idx, vertex -> + val cornerUndir = AoSideHelper.getCornerUndir(vertex.xyz.x, vertex.xyz.y, vertex.xyz.z) + val cornerDir1 = AoSideHelper.boxCornersDirFromUndir[face1.ordinal][cornerUndir] + val cornerDir2 = AoSideHelper.boxCornersDirFromUndir[face2.ordinal][cornerUndir] + if (cornerDir1 == null || cornerDir2 == null) return@let + val ao1 = lighting.calc.aoData[cornerDir1] + val ao2 = lighting.calc.aoData[cornerDir2] + lighting.packedLight[idx] = ((ao1.packedLight + ao2.packedLight) shr 1) and 0xFF00FF + lighting.colorMultiplier[idx] = (ao1.colorMultiplier + ao2.colorMultiplier) * 0.5f + } + lighting.updateBlockTint(quad.baked.tintIndex) + return + } + // something is wrong... + lighting.updateWithCornerAo(quad) { nearestCornerOnFace(it, quad.raw.face()) } + lighting.updateBlockTint(quad.baked.tintIndex) + } +} + /** * Return the directed box corner index for the corner nearest the given vertex, * which is on the given face. May return null if the vertex is closest to @@ -107,9 +172,9 @@ fun getAngles45(quad: HalfBakedQuad): Pair? { val normal = quad.raw.normal // one of the components must be close to zero val zeroAxis = when { - abs(normal.x) < EPSILON -> Axis.X - abs(normal.y) < EPSILON -> Axis.Y - abs(normal.z) < EPSILON -> Axis.Z + abs(normal.x) < EPSILON_ZERO -> Axis.X + abs(normal.y) < EPSILON_ZERO -> Axis.Y + abs(normal.z) < EPSILON_ZERO -> Axis.Z else -> return null } // the other two must be of similar magnitude @@ -118,7 +183,7 @@ fun getAngles45(quad: HalfBakedQuad): Pair? { Axis.Y -> abs(abs(normal.x) - abs(normal.z)) Axis.Z -> abs(abs(normal.x) - abs(normal.y)) } - if (diff > EPSILON) return null + if (diff > EPSILON_ZERO) return null return when(zeroAxis) { Axis.X -> Pair(if (normal.y > 0.0f) UP else DOWN, if (normal.z > 0.0f) SOUTH else NORTH) Axis.Y -> Pair(if (normal.x > 0.0f) EAST else WEST, if (normal.z > 0.0f) SOUTH else NORTH) @@ -126,6 +191,18 @@ fun getAngles45(quad: HalfBakedQuad): Pair? { } } +fun getNormalFace(quad: HalfBakedQuad) = quad.raw.normal.let { normal -> + when { + normal.x > EPSILON_ONE -> EAST + normal.x < -EPSILON_ONE -> WEST + normal.y > EPSILON_ONE -> UP + normal.y < -EPSILON_ONE -> DOWN + normal.z > EPSILON_ONE -> SOUTH + normal.z < -EPSILON_ONE -> NORTH + else -> null + } +} + fun faceDistance(face: Direction, pos: Double3) = when(face) { WEST -> pos.x; EAST -> 1.0 - pos.x DOWN -> pos.y; UP -> 1.0 - pos.y diff --git a/src/main/kotlin/mods/betterfoliage/render/particle/FallingLeaves.kt b/src/main/kotlin/mods/betterfoliage/render/particle/FallingLeaves.kt index d6447c9..4030397 100644 --- a/src/main/kotlin/mods/betterfoliage/render/particle/FallingLeaves.kt +++ b/src/main/kotlin/mods/betterfoliage/render/particle/FallingLeaves.kt @@ -1,9 +1,6 @@ package mods.betterfoliage.render.particle import mods.betterfoliage.config.Config -import mods.betterfoliage.model.HSB -import mods.betterfoliage.texture.LeafParticleKey -import mods.betterfoliage.texture.LeafParticleRegistry import mods.betterfoliage.util.Double3 import mods.betterfoliage.util.PI2 import mods.betterfoliage.util.minmax diff --git a/src/main/kotlin/mods/betterfoliage/texture/LeafParticleRegistry.kt b/src/main/kotlin/mods/betterfoliage/render/particle/LeafParticleRegistry.kt similarity index 83% rename from src/main/kotlin/mods/betterfoliage/texture/LeafParticleRegistry.kt rename to src/main/kotlin/mods/betterfoliage/render/particle/LeafParticleRegistry.kt index 4b0ebe3..06f527b 100644 --- a/src/main/kotlin/mods/betterfoliage/texture/LeafParticleRegistry.kt +++ b/src/main/kotlin/mods/betterfoliage/render/particle/LeafParticleRegistry.kt @@ -1,10 +1,10 @@ -package mods.betterfoliage.texture +package mods.betterfoliage.render.particle import mods.betterfoliage.BetterFoliageMod import mods.betterfoliage.model.Color import mods.betterfoliage.model.FixedSpriteSet import mods.betterfoliage.model.SpriteSet -import mods.betterfoliage.resource.discovery.ModelDefinitionsLoadedEvent +import mods.betterfoliage.resource.VeryEarlyReloadListener import mods.betterfoliage.util.Atlas import mods.betterfoliage.util.HasLogger import mods.betterfoliage.util.get @@ -15,7 +15,7 @@ import net.minecraft.client.renderer.texture.MissingTextureSprite import net.minecraft.util.ResourceLocation import net.minecraftforge.client.event.TextureStitchEvent import net.minecraftforge.eventbus.api.SubscribeEvent -import org.apache.logging.log4j.Level +import org.apache.logging.log4j.Level.INFO interface LeafBlockModel { val key: LeafParticleKey @@ -26,26 +26,28 @@ interface LeafParticleKey { val overrideColor: Color? } -object LeafParticleRegistry : HasLogger() { +object LeafParticleRegistry : HasLogger(), VeryEarlyReloadListener { val typeMappings = TextureMatcher() + val allTypes get() = (typeMappings.mappings.map { it.type } + "default").distinct() + val particles = hashMapOf() operator fun get(type: String) = particles[type] ?: particles["default"]!! - @SubscribeEvent - fun handleModelLoad(event: ModelDefinitionsLoadedEvent) { + override fun onReloadStarted() { typeMappings.loadMappings(ResourceLocation(BetterFoliageMod.MOD_ID, "leaf_texture_mappings.cfg")) + detailLogger.log(INFO, "Loaded leaf particle mappings, types = [${allTypes.joinToString(", ")}]") } @SubscribeEvent fun handlePreStitch(event: TextureStitchEvent.Pre) { if (event.map.textureLocation == Atlas.PARTICLES.resourceId) { - (typeMappings.mappings.map { it.type } + "default").distinct().forEach { leafType -> + allTypes.forEach { leafType -> val locations = (0 until 16).map { idx -> ResourceLocation(BetterFoliageMod.MOD_ID, "particle/falling_leaf_${leafType}_$idx") }.filter { resourceManager.hasResource(Atlas.PARTICLES.file(it)) } - detailLogger.log(Level.INFO, "Registering sprites for leaf particle type [$leafType], ${locations.size} sprites found") + detailLogger.log(INFO, "Registering sprites for leaf particle type [$leafType], ${locations.size} sprites found") locations.forEach { event.addSprite(it) } } } @@ -60,7 +62,7 @@ object LeafParticleRegistry : HasLogger() { } .map { event.map.getSprite(it) } .filter { it !is MissingTextureSprite } - detailLogger.log(Level.INFO, "Leaf particle type [$leafType], ${sprites.size} sprites in atlas") + detailLogger.log(INFO, "Leaf particle type [$leafType], ${sprites.size} sprites in atlas") particles[leafType] = FixedSpriteSet(sprites) } } diff --git a/src/main/kotlin/mods/betterfoliage/render/particle/RisingSouls.kt b/src/main/kotlin/mods/betterfoliage/render/particle/RisingSouls.kt new file mode 100644 index 0000000..96a1017 --- /dev/null +++ b/src/main/kotlin/mods/betterfoliage/render/particle/RisingSouls.kt @@ -0,0 +1,89 @@ +package mods.betterfoliage.render.particle + +import com.mojang.blaze3d.vertex.IVertexBuilder +import mods.betterfoliage.BetterFoliageMod +import mods.betterfoliage.config.Config +import mods.betterfoliage.model.SpriteDelegate +import mods.betterfoliage.model.SpriteSetDelegate +import mods.betterfoliage.util.Atlas +import mods.betterfoliage.util.Double3 +import mods.betterfoliage.util.PI2 +import mods.betterfoliage.util.forEachPairIndexed +import mods.betterfoliage.util.randomD +import mods.betterfoliage.util.randomI +import net.minecraft.client.particle.IParticleRenderType +import net.minecraft.client.renderer.ActiveRenderInfo +import net.minecraft.util.ResourceLocation +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.MathHelper +import net.minecraft.world.World +import java.util.Deque +import java.util.LinkedList +import kotlin.math.cos +import kotlin.math.sin + +class RisingSoulParticle( + world: World, pos: BlockPos +) : AbstractParticle( + world, pos.x.toDouble() + 0.5, pos.y.toDouble() + 1.0, pos.z.toDouble() + 0.5 +) { + + val particleTrail: Deque = LinkedList() + val initialPhase = randomD(max = PI2) + + init { + motionY = 0.1 + particleGravity = 0.0f + sprite = headIcons[randomI(max = 1024)] + maxAge = MathHelper.floor((0.6 + 0.4 * randomD()) * Config.risingSoul.lifetime * 20.0) + } + + override val isValid: Boolean get() = true + + override fun update() { + val phase = initialPhase + (age.toDouble() * PI2 / 64.0) + val cosPhase = cos(phase); + val sinPhase = sin(phase) + velocity.setTo(Config.risingSoul.perturb.let { Double3(cosPhase * it, 0.1, sinPhase * it) }) + + particleTrail.addFirst(currentPos.copy()) + while (particleTrail.size > Config.risingSoul.trailLength) particleTrail.removeLast() + + if (!Config.enabled) setExpired() + } + + override fun renderParticle(vertexBuilder: IVertexBuilder, camera: ActiveRenderInfo, tickDelta: Float) { + var alpha = Config.risingSoul.opacity.toFloat() + if (age > maxAge - 40) alpha *= (maxAge - age) / 40.0f + + renderParticleQuad( + vertexBuilder, camera, tickDelta, + size = Config.risingSoul.headSize * 0.25, + alpha = alpha + ) + + var scale = Config.risingSoul.trailSize * 0.25 + particleTrail.forEachPairIndexed { idx, current, previous -> + scale *= Config.risingSoul.sizeDecay + alpha *= Config.risingSoul.opacityDecay.toFloat() + if (idx % Config.risingSoul.trailDensity == 0) + renderParticleQuad( + vertexBuilder, camera, tickDelta, + currentPos = current, + prevPos = previous, + size = scale, + alpha = alpha, + sprite = trackIcon + ) + } + } + + override fun getRenderType(): IParticleRenderType = IParticleRenderType.PARTICLE_SHEET_TRANSLUCENT + + companion object { + val headIcons by SpriteSetDelegate(Atlas.PARTICLES) { idx -> + ResourceLocation(BetterFoliageMod.MOD_ID, "particle/rising_soul_$idx") + } + val trackIcon by SpriteDelegate(Atlas.PARTICLES) { ResourceLocation(BetterFoliageMod.MOD_ID, "particle/soul_track") } + } +} diff --git a/src/main/kotlin/mods/betterfoliage/resource/VeryEarlyReloadListener.kt b/src/main/kotlin/mods/betterfoliage/resource/VeryEarlyReloadListener.kt new file mode 100644 index 0000000..220d23d --- /dev/null +++ b/src/main/kotlin/mods/betterfoliage/resource/VeryEarlyReloadListener.kt @@ -0,0 +1,27 @@ +package mods.betterfoliage.resource + +import net.minecraft.profiler.IProfiler +import net.minecraft.resources.IFutureReloadListener +import net.minecraft.resources.IResourceManager +import java.util.concurrent.CompletableFuture +import java.util.concurrent.Executor + +/** + * Catch resource reload extremely early, before any of the reloaders + * have started working. + */ +interface VeryEarlyReloadListener : IFutureReloadListener { + override fun reload( + stage: IFutureReloadListener.IStage, + resourceManager: IResourceManager, + preparationsProfiler: IProfiler, + reloadProfiler: IProfiler, + backgroundExecutor: Executor, + gameExecutor: Executor + ): CompletableFuture { + onReloadStarted() + return stage.markCompleteAwaitingOthers(null) + } + + fun onReloadStarted() {} +} \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/resource/discovery/BakingLifecycle.kt b/src/main/kotlin/mods/betterfoliage/resource/discovery/BakingLifecycle.kt index 5f91d3d..66f2548 100644 --- a/src/main/kotlin/mods/betterfoliage/resource/discovery/BakingLifecycle.kt +++ b/src/main/kotlin/mods/betterfoliage/resource/discovery/BakingLifecycle.kt @@ -5,6 +5,7 @@ import mods.betterfoliage.util.Atlas import mods.betterfoliage.util.HasLogger import mods.betterfoliage.util.Invalidator import mods.betterfoliage.util.SimpleInvalidator +import net.minecraft.block.BlockState import net.minecraft.client.renderer.model.IBakedModel import net.minecraft.client.renderer.model.IModelTransform import net.minecraft.client.renderer.model.IUnbakedModel @@ -19,7 +20,9 @@ import net.minecraftforge.eventbus.api.Event import net.minecraftforge.eventbus.api.EventPriority import net.minecraftforge.eventbus.api.SubscribeEvent import net.minecraftforge.fml.loading.progress.StartupMessageManager +import org.apache.logging.log4j.Level.DEBUG import org.apache.logging.log4j.Level.INFO +import org.apache.logging.log4j.Logger import java.lang.ref.WeakReference import java.util.function.Function @@ -27,6 +30,21 @@ data class ModelDefinitionsLoadedEvent( val bakery: ModelBakery ) : Event() +data class ModelDiscoveryContext( + val bakery: ModelBakery, + val blockState: BlockState, + val modelLocation: ResourceLocation, + val sprites: MutableSet, + val replacements: MutableMap, + val logger: Logger +) { + fun getUnbaked(location: ResourceLocation = modelLocation) = bakery.getUnbakedModel(location) + fun addReplacement(key: ModelBakingKey) { + replacements[modelLocation] = key + logger.log(INFO, "Adding model replacement $modelLocation -> $key") + } +} + interface ModelDiscovery { fun onModelsLoaded( bakery: ModelBakery, @@ -35,14 +53,20 @@ interface ModelDiscovery { ) } +data class ModelBakingContext( + val bakery: ModelBakery, + val spriteGetter: Function, + val location: ResourceLocation, + val transform: IModelTransform, + val logger: Logger +) { + fun getUnbaked() = bakery.getUnbakedModel(location) + fun getBaked() = bakery.getBakedModel(location, transform, spriteGetter) +} + interface ModelBakingKey { - fun bake( - location: ResourceLocation, - unbaked: IUnbakedModel, - transform: IModelTransform, - bakery: ModelBakery, - spriteGetter: Function - ): IBakedModel? = unbaked.bakeModel(bakery, spriteGetter, transform, location) + fun bake(ctx: ModelBakingContext): IBakedModel? = + ctx.getUnbaked().bakeModel(ctx.bakery, ctx.spriteGetter, ctx.transform, ctx.location) } object BakeWrapperManager : Invalidator, HasLogger() { @@ -57,14 +81,16 @@ object BakeWrapperManager : Invalidator, HasLogger() { @SubscribeEvent(priority = EventPriority.LOWEST) fun handleModelLoad(event: ModelDefinitionsLoadedEvent) { + val startTime = System.currentTimeMillis() modelsValid.invalidate() StartupMessageManager.addModMessage("BetterFoliage: discovering models") logger.log(INFO, "starting model discovery (${discoverers.size} listeners)") discoverers.forEach { listener -> val replacementsLocal = mutableMapOf() - listener.onModelsLoaded(event.bakery, sprites, replacementsLocal) - replacements.putAll(replacementsLocal) + listener.onModelsLoaded(event.bakery, sprites, replacements) } + val elapsed = System.currentTimeMillis() - startTime + logger.log(INFO, "finished model discovery in $elapsed ms, ${replacements.size} top-level replacements") } @SubscribeEvent @@ -89,17 +115,12 @@ object BakeWrapperManager : Invalidator, HasLogger() { transform: IModelTransform, location: ResourceLocation ): IBakedModel? { + val ctx = ModelBakingContext(bakery, spriteGetter, location, transform, detailLogger) // bake replacement if available replacements[location]?.let { replacement -> detailLogger.log(INFO, "Baking replacement for [${unbaked::class.java.simpleName}] $location -> $replacement") - return replacement.bake(location, unbaked, transform, bakery, spriteGetter) + return replacement.bake(ctx) } - // container model support - if (unbaked is VariantList) SpecialRenderVariantList.bakeIfSpecial(location, unbaked, bakery, spriteGetter)?.let { - detailLogger.log(INFO, "Wrapping container [${unbaked::class.java.simpleName}] $location") - return it - } - return unbaked.bakeModel(bakery, spriteGetter, transform, location) } } diff --git a/src/main/kotlin/mods/betterfoliage/resource/discovery/BlockTypeCache.kt b/src/main/kotlin/mods/betterfoliage/resource/discovery/BlockTypeCache.kt index 05bacc6..bed73e0 100644 --- a/src/main/kotlin/mods/betterfoliage/resource/discovery/BlockTypeCache.kt +++ b/src/main/kotlin/mods/betterfoliage/resource/discovery/BlockTypeCache.kt @@ -1,19 +1,13 @@ package mods.betterfoliage.resource.discovery -import mods.betterfoliage.Client import net.minecraft.block.BlockState -import net.minecraft.client.renderer.model.ModelBakery -import net.minecraft.util.ResourceLocation class BlockTypeCache { val leaf = mutableSetOf() val grass = mutableSetOf() val dirt = mutableSetOf() - companion object : ModelDiscovery { - override fun onModelsLoaded(bakery: ModelBakery, sprites: MutableSet, replacements: MutableMap - ) { - Client.blockTypes = BlockTypeCache() - } - } + val stateKeys = mutableMapOf() + + inline fun getTyped(state: BlockState) = stateKeys[state] as? T } \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/config/Matchers.kt b/src/main/kotlin/mods/betterfoliage/resource/discovery/Matchers.kt similarity index 89% rename from src/main/kotlin/mods/betterfoliage/config/Matchers.kt rename to src/main/kotlin/mods/betterfoliage/resource/discovery/Matchers.kt index f58a1c6..9b59acc 100644 --- a/src/main/kotlin/mods/betterfoliage/config/Matchers.kt +++ b/src/main/kotlin/mods/betterfoliage/resource/discovery/Matchers.kt @@ -1,4 +1,4 @@ -package mods.betterfoliage.config +package mods.betterfoliage.resource.discovery import mods.betterfoliage.BetterFoliageMod import mods.betterfoliage.util.getJavaClass @@ -6,7 +6,7 @@ import mods.betterfoliage.util.getLines import mods.betterfoliage.util.resourceManager import net.minecraft.block.Block import net.minecraft.util.ResourceLocation -import org.apache.logging.log4j.Level.DEBUG +import org.apache.logging.log4j.Level.INFO interface IBlockMatcher { fun matchesClass(block: Block): Boolean @@ -28,7 +28,6 @@ class ConfigurableBlockMatcher(val location: ResourceLocation) : IBlockMatcher { val blackList = mutableListOf>() val whiteList = mutableListOf>() -// override fun convertValue(line: String) = getJavaClass(line) override fun matchesClass(block: Block): Boolean { val blockClass = block.javaClass @@ -48,7 +47,7 @@ class ConfigurableBlockMatcher(val location: ResourceLocation) : IBlockMatcher { blackList.clear() whiteList.clear() resourceManager.getAllResources(location).forEach { resource -> - logger.log(DEBUG, "Reading resource $location from pack ${resource.packName}") + logger.log(INFO, "Reading block class configuration $location from pack ${resource.packName}") resource.getLines().map{ it.trim() }.filter { !it.startsWith("//") && it.isNotEmpty() }.forEach { line -> if (line.startsWith("-")) getJavaClass(line.substring(1))?.let { blackList.add(it) } else getJavaClass(line)?.let { whiteList.add(it) } @@ -68,7 +67,7 @@ class ModelTextureListConfiguration(val location: ResourceLocation) { val modelList = mutableListOf() fun readDefaults() { resourceManager.getAllResources(location).forEach { resource -> - logger.log(DEBUG, "Reading resource $location from pack ${resource.packName}") + logger.log(INFO, "Reading model/texture configuration $location from pack ${resource.packName}") resource.getLines().map{ it.trim() }.filter { !it.startsWith("//") && it.isNotEmpty() }.forEach { line -> val elements = line.split(",") modelList.add(ModelTextureList(ResourceLocation(elements.first()), elements.drop(1))) diff --git a/src/main/kotlin/mods/betterfoliage/resource/discovery/ModelDiscovery.kt b/src/main/kotlin/mods/betterfoliage/resource/discovery/ModelDiscovery.kt index c518af8..2ef4680 100644 --- a/src/main/kotlin/mods/betterfoliage/resource/discovery/ModelDiscovery.kt +++ b/src/main/kotlin/mods/betterfoliage/resource/discovery/ModelDiscovery.kt @@ -1,15 +1,11 @@ package mods.betterfoliage.resource.discovery import com.google.common.base.Joiner -import mods.betterfoliage.config.IBlockMatcher -import mods.betterfoliage.config.ModelTextureList import mods.betterfoliage.util.HasLogger -import net.minecraft.block.BlockState import net.minecraft.client.renderer.BlockModelShapes import net.minecraft.client.renderer.model.BlockModel import net.minecraft.client.renderer.model.ModelBakery import net.minecraft.client.renderer.model.VariantList -import net.minecraft.client.renderer.model.multipart.Multipart import net.minecraft.client.renderer.texture.MissingTextureSprite import net.minecraft.util.ResourceLocation import net.minecraftforge.registries.ForgeRegistries @@ -25,36 +21,29 @@ abstract class AbstractModelDiscovery : HasLogger(), ModelDiscovery { .flatMap { block -> block.stateContainer.validStates } .forEach { state -> val location = BlockModelShapes.getModelLocation(state) + val ctx = ModelDiscoveryContext(bakery, state, location, sprites, replacements, detailLogger) try { - val hasReplaced = processModel(bakery, state, location, sprites, replacements) + processModel(ctx) } catch (e: Exception) { logger.log(Level.WARN, "Discovery error in $location", e) } } } - open fun processModel( - bakery: ModelBakery, - state: BlockState, - location: ResourceLocation, - sprites: MutableSet, - replacements: MutableMap - ): Boolean { + open fun processModel(ctx: ModelDiscoveryContext) { + val model = ctx.getUnbaked() + // built-in support for container models - return when (val model = bakery.getUnbakedModel(location)) { - is VariantList -> { - val hasReplaced = model.variantList.fold(false) { hasReplaced, variant -> - processModel(bakery, state, variant.modelLocation, sprites, replacements) || hasReplaced - } - if (hasReplaced) replacements[location] - hasReplaced + if (model is VariantList) { + // per-location replacements need to be scoped to the variant list, as replacement models + // may need information from the BlockState which is not available at baking time + val scopedReplacements = mutableMapOf() + model.variantList.forEach { variant -> + processModel(ctx.copy(modelLocation = variant.modelLocation, replacements = scopedReplacements)) } - is Multipart -> model.variants.fold(false) { hasReplaced, variantList -> - variantList.variantList.fold(false) { hasReplaced, variant -> - processModel(bakery, state, variant.modelLocation, sprites, replacements) || hasReplaced - } || hasReplaced + if (scopedReplacements.isNotEmpty()) { + ctx.addReplacement(SpecialRenderVariantList(scopedReplacements)) } - else -> false } } } @@ -64,37 +53,23 @@ abstract class ConfigurableModelDiscovery : AbstractModelDiscovery() { abstract val modelTextures: List abstract fun processModel( - state: BlockState, - location: ResourceLocation, - textureMatch: List, - sprites: MutableSet, - replacements: MutableMap - ): Boolean + ctx: ModelDiscoveryContext, + textureMatch: List + ) - override fun processModel( - bakery: ModelBakery, - state: BlockState, - location: ResourceLocation, - sprites: MutableSet, - replacements: MutableMap - ): Boolean { - val model = bakery.getUnbakedModel(location) + override fun processModel(ctx: ModelDiscoveryContext) { + val model = ctx.getUnbaked() if (model is BlockModel) { - val matchClass = matchClasses.matchingClass(state.block) ?: return false + val matchClass = matchClasses.matchingClass(ctx.blockState.block) ?: return - detailLogger.log(Level.INFO, "block state $state") - detailLogger.log(Level.INFO, " model $location") - replacements[location]?.let { existing -> - detailLogger.log(Level.INFO, " already processed as $existing") - return true - } - - detailLogger.log(Level.INFO, " class ${state.block.javaClass.name} matches ${matchClass.name}") + detailLogger.log(Level.INFO, "block state ${ctx.blockState}") + detailLogger.log(Level.INFO, " model ${ctx.modelLocation}") + detailLogger.log(Level.INFO, " class ${ctx.blockState.block.javaClass.name} matches ${matchClass.name}") modelTextures - .filter { matcher -> bakery.modelDerivesFrom(model, location, matcher.modelLocation) } + .filter { matcher -> ctx.bakery.modelDerivesFrom(model, ctx.modelLocation, matcher.modelLocation) } .forEach { match -> - detailLogger.log(Level.INFO, " model ${model} matches ${match.modelLocation}") + detailLogger.log(Level.INFO, " model $model matches ${match.modelLocation}") val materials = match.textureNames.map { it to model.resolveTextureName(it) } val texMapString = Joiner.on(", ").join(materials.map { "${it.first}=${it.second.textureLocation}" }) @@ -102,12 +77,11 @@ abstract class ConfigurableModelDiscovery : AbstractModelDiscovery() { if (materials.all { it.second.textureLocation != MissingTextureSprite.getLocation() }) { // found a valid model (all required textures exist) - if (processModel(state, location, materials.map { it.second.textureLocation }, sprites, replacements)) - return true + processModel(ctx, materials.map { it.second.textureLocation }) } } } - return super.processModel(bakery, state, location, sprites, replacements) + return super.processModel(ctx) } } diff --git a/src/main/kotlin/mods/betterfoliage/resource/discovery/SpecialRenderVariants.kt b/src/main/kotlin/mods/betterfoliage/resource/discovery/SpecialRenderVariants.kt new file mode 100644 index 0000000..0c16db2 --- /dev/null +++ b/src/main/kotlin/mods/betterfoliage/resource/discovery/SpecialRenderVariants.kt @@ -0,0 +1,54 @@ +package mods.betterfoliage.resource.discovery + +import mods.betterfoliage.model.HalfBakedSimpleModelWrapper +import mods.betterfoliage.model.SpecialRenderModel +import mods.betterfoliage.model.SpecialRenderVariantList +import net.minecraft.client.renderer.model.IBakedModel +import net.minecraft.client.renderer.model.SimpleBakedModel +import net.minecraft.client.renderer.model.VariantList +import net.minecraft.util.ResourceLocation +import org.apache.logging.log4j.Level +import org.apache.logging.log4j.Level.INFO +import org.apache.logging.log4j.Level.WARN + +class SpecialRenderVariantList( + val replacements: Map +) : ModelBakingKey { + + override fun bake(ctx: ModelBakingContext): IBakedModel? { + val unbaked = ctx.getUnbaked() + if (unbaked !is VariantList) return super.bake(ctx) + + // bake all variants, replace as needed + val bakedModels = unbaked.variantList.mapNotNull { + val variantCtx = ctx.copy(location = it.modelLocation, transform = it) + val replacement = replacements[it.modelLocation] + val baked = replacement?.let { replacement -> + ctx.logger.log(INFO, "Baking replacement for variant [${variantCtx.getUnbaked()::class.java.simpleName}] ${variantCtx.location} -> $replacement") + replacement.bake(variantCtx) + } ?: variantCtx.getBaked() + when(baked) { + is SpecialRenderModel -> it to baked + is SimpleBakedModel -> it to HalfBakedSimpleModelWrapper(baked) + else -> null + } + } + + // something fishy going on, possibly unknown model type + // let it through unchanged + if (bakedModels.isEmpty()) return super.bake(ctx) + + if (bakedModels.size < unbaked.variantList.size) { + SpecialRenderVariantList.detailLogger.log( + WARN, + "Dropped ${unbaked.variantList.size - bakedModels.size} variants from model ${ctx.location}" + ) + } + val weightedSpecials = bakedModels.map { (variant, model) -> + SpecialRenderVariantList.WeightedModel(model, variant.weight) + } + return SpecialRenderVariantList(weightedSpecials, weightedSpecials[0].model) + } + + override fun toString() = "[SpecialRenderVariantList, ${replacements.size} replacements]" +} \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/resource/generated/CenteringTextureGenerator.kt b/src/main/kotlin/mods/betterfoliage/resource/generated/CenteringTextureGenerator.kt index ea1e619..9f40d91 100644 --- a/src/main/kotlin/mods/betterfoliage/resource/generated/CenteringTextureGenerator.kt +++ b/src/main/kotlin/mods/betterfoliage/resource/generated/CenteringTextureGenerator.kt @@ -1,8 +1,8 @@ package mods.betterfoliage.resource.generated -import mods.betterfoliage.texture.loadSprite import mods.betterfoliage.util.Atlas import mods.betterfoliage.util.bytes +import mods.betterfoliage.util.loadSprite import net.minecraft.resources.IResourceManager import net.minecraft.util.ResourceLocation import java.awt.image.BufferedImage diff --git a/src/main/kotlin/mods/betterfoliage/resource/generated/GeneratedGrass.kt b/src/main/kotlin/mods/betterfoliage/resource/generated/GeneratedGrass.kt index 2cdb281..be81f66 100644 --- a/src/main/kotlin/mods/betterfoliage/resource/generated/GeneratedGrass.kt +++ b/src/main/kotlin/mods/betterfoliage/resource/generated/GeneratedGrass.kt @@ -1,10 +1,10 @@ package mods.betterfoliage.resource.generated -import mods.betterfoliage.texture.blendRGB -import mods.betterfoliage.texture.loadSprite import mods.betterfoliage.util.Atlas +import mods.betterfoliage.util.blendRGB import mods.betterfoliage.util.bytes import mods.betterfoliage.util.get +import mods.betterfoliage.util.loadSprite import mods.betterfoliage.util.set import net.minecraft.resources.IResourceManager import net.minecraft.util.ResourceLocation diff --git a/src/main/kotlin/mods/betterfoliage/resource/generated/GeneratedLeaf.kt b/src/main/kotlin/mods/betterfoliage/resource/generated/GeneratedLeaf.kt index 39f0bd9..b1abde6 100644 --- a/src/main/kotlin/mods/betterfoliage/resource/generated/GeneratedLeaf.kt +++ b/src/main/kotlin/mods/betterfoliage/resource/generated/GeneratedLeaf.kt @@ -1,11 +1,11 @@ package mods.betterfoliage.resource.generated import mods.betterfoliage.BetterFoliageMod -import mods.betterfoliage.texture.loadSprite import mods.betterfoliage.util.Atlas import mods.betterfoliage.util.bytes import mods.betterfoliage.util.get import mods.betterfoliage.util.loadImage +import mods.betterfoliage.util.loadSprite import mods.betterfoliage.util.resourceManager import mods.betterfoliage.util.set import net.minecraft.resources.IResource diff --git a/src/main/kotlin/mods/betterfoliage/texture/Utils.kt b/src/main/kotlin/mods/betterfoliage/texture/Utils.kt deleted file mode 100644 index d26568b..0000000 --- a/src/main/kotlin/mods/betterfoliage/texture/Utils.kt +++ /dev/null @@ -1,19 +0,0 @@ -@file:JvmName("Utils") -package mods.betterfoliage.texture - -import mods.betterfoliage.util.get -import mods.betterfoliage.util.loadImage -import net.minecraft.resources.IResourceManager -import net.minecraft.util.ResourceLocation -import java.io.IOException - -fun blendRGB(rgb1: Int, rgb2: Int, weight1: Int, weight2: Int): Int { - val r = (((rgb1 shr 16) and 255) * weight1 + ((rgb2 shr 16) and 255) * weight2) / (weight1 + weight2) - val g = (((rgb1 shr 8) and 255) * weight1 + ((rgb2 shr 8) and 255) * weight2) / (weight1 + weight2) - val b = ((rgb1 and 255) * weight1 + (rgb2 and 255) * weight2) / (weight1 + weight2) - val a = (rgb1 shr 24) and 255 - val result = ((a shl 24) or (r shl 16) or (g shl 8) or b) - return result -} - -fun IResourceManager.loadSprite(id: ResourceLocation) = this.get(id)?.loadImage() ?: throw IOException("Cannot load resource $id") \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/util/Geometry.kt b/src/main/kotlin/mods/betterfoliage/util/Geometry.kt index ff53b5e..0b73bc0 100644 --- a/src/main/kotlin/mods/betterfoliage/util/Geometry.kt +++ b/src/main/kotlin/mods/betterfoliage/util/Geometry.kt @@ -8,7 +8,8 @@ import net.minecraft.util.Direction.AxisDirection.NEGATIVE import net.minecraft.util.Direction.AxisDirection.POSITIVE import net.minecraft.util.math.BlockPos -val EPSILON = 0.05 +val EPSILON_ZERO = 0.05 +val EPSILON_ONE = 0.95 // ================================ // Axes and directions diff --git a/src/main/resources/assets/betterfoliage/log_models_default.cfg b/src/main/resources/assets/betterfoliage/log_models_default.cfg index ddccc01..a6ef581 100644 --- a/src/main/resources/assets/betterfoliage/log_models_default.cfg +++ b/src/main/resources/assets/betterfoliage/log_models_default.cfg @@ -1,12 +1,4 @@ // Vanilla -block/column_side,end,end,side -block/cube_column,end,end,side -block/cube_all,all,all,all - -// Agricultural Revolution -agriculturalrevolution:block/palmlog,top,top,texture - -// Lithos Core -block/column_top,end,end,side_a,side_b -block/column_side_x,end,end,side_a,side_b -block/column_side_z,end,end,side_a,side_b +block/column_side,side,end +block/cube_column,side,end +block/cube_all,all,all diff --git a/src/main/resources/betterfoliage.optifine.mixins.json b/src/main/resources/betterfoliage.optifine.mixins.json index 6972cc3..fd55290 100644 --- a/src/main/resources/betterfoliage.optifine.mixins.json +++ b/src/main/resources/betterfoliage.optifine.mixins.json @@ -7,6 +7,7 @@ "mixins": [ ], "client": [ + "MixinOptifineBlockUtils" ], "server": [ ],