From 46cbe643284960e9e05b0ad663f51fe04b507177 Mon Sep 17 00:00:00 2001 From: octarine-noise Date: Wed, 1 Jan 2020 16:57:47 +0100 Subject: [PATCH] [WIP] 1.14.4 port --- build.gradle | 97 ++++-- gradle.properties | 16 +- .../mods/betterfoliage/MixinConnector.java | 20 ++ .../loader/BetterFoliageLoader.java | 38 --- .../mods/betterfoliage/mixin/BlockMixin.java | 29 ++ .../betterfoliage/mixin/BlockStateMixin.java | 26 ++ .../betterfoliage/mixin/ChunkRenderMixin.java | 29 ++ .../mixin/ChunkRenderOptifineMixin.java | 31 ++ .../mixin/ChunkRenderVanillaMixin.java | 29 ++ .../betterfoliage/mixin/ClientWorldMixin.java | 44 +++ .../betterfoliage/mixin/ModelBakeryMixin.java | 21 ++ .../OptifineTransformerDevWrapper.java | 65 ---- .../optifine/OptifineTweakerDevWrapper.java | 28 -- .../mods/betterfoliage/BetterFoliage.kt | 57 ++++ .../mods/betterfoliage/BetterFoliageMod.kt | 78 ----- .../mods/betterfoliage/client/Client.kt | 66 ++-- .../kotlin/mods/betterfoliage/client/Hooks.kt | 79 ++--- .../betterfoliage/client/chunk/Overlay.kt | 96 +++--- .../betterfoliage/client/config/Config.kt | 108 ++++--- .../client/gui/BiomeListConfigEntry.kt | 19 -- .../client/gui/ConfigGuiFactory.kt | 29 -- .../client/integration/ForestryIntegration.kt | 41 ++- .../integration/OptifineCustomColors.kt | 24 +- .../client/integration/RubberIntegration.kt | 94 +++--- .../integration/ShadersModIntegration.kt | 31 +- .../client/render/EntityFallingLeavesFX.kt | 45 +-- .../client/render/EntityRisingSoulFX.kt | 30 +- .../client/render/ModelColumn.kt | 11 +- .../client/render/RenderAlgae.kt | 30 +- .../client/render/RenderCactus.kt | 40 +-- .../client/render/RenderConnectedGrass.kt | 30 +- .../client/render/RenderConnectedGrassLog.kt | 31 +- .../client/render/RenderCoral.kt | 38 +-- .../client/render/RenderGrass.kt | 49 ++- .../client/render/RenderLeaves.kt | 27 +- .../client/render/RenderLilypad.kt | 31 +- .../betterfoliage/client/render/RenderLog.kt | 40 +-- .../client/render/RenderMycelium.kt | 27 +- .../client/render/RenderNetherrack.kt | 28 +- .../client/render/RenderReeds.kt | 29 +- .../mods/betterfoliage/client/render/Utils.kt | 25 +- .../client/render/column/AbstractRenderer.kt | 34 +-- .../client/render/column/OverlayLayer.kt | 39 ++- .../client/render/column/RenderData.kt | 25 +- .../client/texture/GrassGenerator.kt | 21 +- .../client/texture/GrassRegistry.kt | 31 +- .../client/texture/LeafGenerator.kt | 48 ++- .../client/texture/LeafParticleRegistry.kt | 26 +- .../client/texture/LeafRegistry.kt | 37 +-- .../betterfoliage/loader/BetterFoliageCore.kt | 36 +-- .../kotlin/mods/betterfoliage/loader/Refs.kt | 85 +----- src/main/kotlin/mods/octarinecore/Utils.kt | 23 +- .../mods/octarinecore/client/KeyHandler.kt | 8 +- .../client/gui/IdListConfigEntry.kt | 61 ---- .../client/gui/NonVerboseArrayEntry.kt | 25 -- .../mods/octarinecore/client/gui/Utils.kt | 6 +- .../render/AbstractBlockRenderingHandler.kt | 72 +++-- .../client/render/AbstractEntityFX.kt | 20 +- .../mods/octarinecore/client/render/Model.kt | 6 +- .../client/render/ModelRenderer.kt | 24 +- .../client/render/OffsetBlockAccess.kt | 44 --- .../client/render/OffsetBlockReader.kt | 54 ++++ .../octarinecore/client/render/Shaders.kt | 26 +- .../octarinecore/client/render/Shading.kt | 36 ++- .../resource/CenteringTextureGenerator.kt | 20 +- .../client/resource/ModelProcessor.kt | 97 +++--- .../client/resource/ResourceGeneration.kt | 126 +++++--- .../client/resource/ResourceHandler.kt | 86 ++++-- .../client/resource/TextureGenerator.kt | 9 +- .../octarinecore/client/resource/Utils.kt | 58 ++-- .../mods/octarinecore/common/Geometry.kt | 58 ++-- .../config/BlackWhiteListConfigOption.kt | 56 ---- .../common/config/DelegatingConfig.kt | 282 ++++-------------- .../octarinecore/common/config/Matchers.kt | 38 ++- .../common/config/StringListConfigOption.kt | 43 --- .../mods/octarinecore/metaprog/Reflection.kt | 8 + .../octarinecore/metaprog/Transformation.kt | 212 ------------- .../resources/META-INF/BetterFoliage_at.cfg | 15 - src/main/resources/META-INF/MANIFEST.MF | 6 + .../resources/META-INF/accesstransformer.cfg | 20 ++ src/main/resources/META-INF/mods.toml | 14 + .../assets/betterfoliage/cactus_default.cfg | 5 +- .../assets/betterfoliage/crop_default.cfg | 33 +- .../assets/betterfoliage/dirt_default.cfg | 18 +- .../betterfoliage/grass_blocks_default.cfg | 18 +- .../betterfoliage/grass_models_default.cfg | 5 +- .../betterfoliage/leaves_blocks_default.cfg | 8 +- .../betterfoliage/log_blocks_default.cfg | 35 +-- .../betterfoliage/mycelium_blocks_default.cfg | 5 +- .../netherrack_blocks_default.cfg | 5 +- .../textures/blocks/better_algae_0.png | Bin .../textures/blocks/better_algae_1.png | Bin .../textures/blocks/better_algae_2.png | Bin .../textures/blocks/better_algae_3.png | Bin .../textures/blocks/better_cactus.png | Bin 0 -> 1659 bytes .../textures/blocks/better_cactus_arm_0.png | Bin 0 -> 2923 bytes .../textures/blocks/better_cactus_arm_1.png | Bin 0 -> 2955 bytes .../textures/blocks/better_coral_0.png | Bin .../textures/blocks/better_coral_1.png | Bin .../textures/blocks/better_coral_2.png | Bin .../textures/blocks/better_coral_3.png | Bin .../textures/blocks/better_coral_4.png | Bin .../textures/blocks/better_coral_5.png | Bin .../textures/blocks/better_crust_0.png | Bin .../textures/blocks/better_crust_1.png | Bin .../textures/blocks/better_crust_2.png | Bin .../textures/blocks/better_crust_3.png | Bin .../textures/blocks/better_grass_long_0.png | Bin .../textures/blocks/better_grass_long_1.png | Bin .../textures/blocks/better_grass_long_2.png | Bin .../textures/blocks/better_grass_long_3.png | Bin .../textures/blocks/better_grass_long_4.png | Bin .../textures/blocks/better_grass_short_0.png | Bin .../textures/blocks/better_grass_short_1.png | Bin .../textures/blocks/better_grass_short_2.png | Bin .../textures/blocks/better_grass_side_0.png | Bin .../textures/blocks/better_grass_side_1.png | Bin .../textures/blocks/better_grass_snowed_0.png | Bin .../textures/blocks/better_grass_snowed_1.png | Bin .../blocks/better_leaves_snowed_0.png | Bin .../blocks/better_leaves_snowed_1.png | Bin .../blocks/better_leaves_snowed_2.png | Bin .../blocks/better_lilypad_flower_0.png | Bin .../blocks/better_lilypad_flower_1.png | Bin .../blocks/better_lilypad_roots_0.png | Bin .../blocks/better_lilypad_roots_1.png | Bin .../blocks/better_lilypad_roots_2.png | Bin .../textures/blocks/better_mycel_0.png | Bin .../textures/blocks/better_mycel_1.png | Bin .../textures/blocks/better_mycel_2.png | Bin .../textures/blocks/better_mycel_3.png | Bin .../textures/blocks/better_mycel_side_0.png | Bin .../textures/blocks/better_mycel_side_1.png | Bin .../textures/blocks/better_netherrack_0.png | Bin .../textures/blocks/better_netherrack_1.png | Bin .../textures/blocks/better_netherrack_2.png | Bin .../textures/blocks/better_reed_0.png | Bin .../textures/blocks/better_reed_1.png | Bin .../textures/blocks/better_reed_2.png | Bin .../textures/blocks/better_reed_3.png | Bin .../textures/blocks/soul_track.png.mcmeta | 0 .../falling_leaf_default_0.png | Bin .../falling_leaf_default_1.png | Bin .../falling_leaf_default_2.png | Bin .../falling_leaf_default_3.png | Bin .../falling_leaf_jungle_0.png | Bin .../falling_leaf_jungle_1.png | Bin .../falling_leaf_jungle_2.png | Bin .../falling_leaf_jungle_3.png | Bin .../falling_leaf_spruce_0.png | Bin .../falling_leaf_spruce_1.png | Bin .../falling_leaf_spruce_2.png | Bin .../falling_leaf_spruce_3.png | Bin .../textures/particle}/rising_soul_0.png | Bin .../textures/particle}/rising_soul_1.png | Bin .../textures/particle}/soul_track.png | Bin .../textures/blocks/better_cactus.png | Bin 1238 -> 0 bytes .../textures/blocks/better_cactus_arm_0.png | Bin 2963 -> 0 bytes .../textures/blocks/better_cactus_arm_1.png | Bin 3011 -> 0 bytes .../betterfoliage.common.mixins.json | 21 ++ .../betterfoliage.optifine.mixins.json | 17 ++ .../betterfoliage.vanilla.mixins.json | 17 ++ src/main/resources/bf_generated_pack.png | Bin 0 -> 682 bytes src/main/resources/pack.mcmeta | 2 +- 164 files changed, 1715 insertions(+), 2115 deletions(-) create mode 100644 src/main/java/mods/betterfoliage/MixinConnector.java delete mode 100644 src/main/java/mods/betterfoliage/loader/BetterFoliageLoader.java create mode 100644 src/main/java/mods/betterfoliage/mixin/BlockMixin.java create mode 100644 src/main/java/mods/betterfoliage/mixin/BlockStateMixin.java create mode 100644 src/main/java/mods/betterfoliage/mixin/ChunkRenderMixin.java create mode 100644 src/main/java/mods/betterfoliage/mixin/ChunkRenderOptifineMixin.java create mode 100644 src/main/java/mods/betterfoliage/mixin/ChunkRenderVanillaMixin.java create mode 100644 src/main/java/mods/betterfoliage/mixin/ClientWorldMixin.java create mode 100644 src/main/java/mods/betterfoliage/mixin/ModelBakeryMixin.java delete mode 100644 src/main/java/optifine/OptifineTransformerDevWrapper.java delete mode 100644 src/main/java/optifine/OptifineTweakerDevWrapper.java create mode 100644 src/main/kotlin/mods/betterfoliage/BetterFoliage.kt delete mode 100644 src/main/kotlin/mods/betterfoliage/BetterFoliageMod.kt delete mode 100644 src/main/kotlin/mods/betterfoliage/client/gui/BiomeListConfigEntry.kt delete mode 100644 src/main/kotlin/mods/betterfoliage/client/gui/ConfigGuiFactory.kt delete mode 100644 src/main/kotlin/mods/octarinecore/client/gui/IdListConfigEntry.kt delete mode 100644 src/main/kotlin/mods/octarinecore/client/gui/NonVerboseArrayEntry.kt delete mode 100644 src/main/kotlin/mods/octarinecore/client/render/OffsetBlockAccess.kt create mode 100644 src/main/kotlin/mods/octarinecore/client/render/OffsetBlockReader.kt delete mode 100644 src/main/kotlin/mods/octarinecore/common/config/BlackWhiteListConfigOption.kt delete mode 100644 src/main/kotlin/mods/octarinecore/common/config/StringListConfigOption.kt delete mode 100644 src/main/kotlin/mods/octarinecore/metaprog/Transformation.kt delete mode 100644 src/main/resources/META-INF/BetterFoliage_at.cfg create mode 100644 src/main/resources/META-INF/MANIFEST.MF create mode 100644 src/main/resources/META-INF/accesstransformer.cfg create mode 100644 src/main/resources/META-INF/mods.toml rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_algae_0.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_algae_1.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_algae_2.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_algae_3.png (100%) create mode 100644 src/main/resources/assets/betterfoliage/textures/blocks/better_cactus.png create mode 100644 src/main/resources/assets/betterfoliage/textures/blocks/better_cactus_arm_0.png create mode 100644 src/main/resources/assets/betterfoliage/textures/blocks/better_cactus_arm_1.png rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_coral_0.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_coral_1.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_coral_2.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_coral_3.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_coral_4.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_coral_5.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_crust_0.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_crust_1.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_crust_2.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_crust_3.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_grass_long_0.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_grass_long_1.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_grass_long_2.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_grass_long_3.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_grass_long_4.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_grass_short_0.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_grass_short_1.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_grass_short_2.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_grass_side_0.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_grass_side_1.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_grass_snowed_0.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_grass_snowed_1.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_leaves_snowed_0.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_leaves_snowed_1.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_leaves_snowed_2.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_lilypad_flower_0.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_lilypad_flower_1.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_lilypad_roots_0.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_lilypad_roots_1.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_lilypad_roots_2.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_mycel_0.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_mycel_1.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_mycel_2.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_mycel_3.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_mycel_side_0.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_mycel_side_1.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_netherrack_0.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_netherrack_1.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_netherrack_2.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_reed_0.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_reed_1.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_reed_2.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/better_reed_3.png (100%) rename src/main/resources/assets/{bettergrassandleaves => betterfoliage}/textures/blocks/soul_track.png.mcmeta (100%) rename src/main/resources/assets/betterfoliage/textures/{blocks => particle}/falling_leaf_default_0.png (100%) rename src/main/resources/assets/betterfoliage/textures/{blocks => particle}/falling_leaf_default_1.png (100%) rename src/main/resources/assets/betterfoliage/textures/{blocks => particle}/falling_leaf_default_2.png (100%) rename src/main/resources/assets/betterfoliage/textures/{blocks => particle}/falling_leaf_default_3.png (100%) rename src/main/resources/assets/betterfoliage/textures/{blocks => particle}/falling_leaf_jungle_0.png (100%) rename src/main/resources/assets/betterfoliage/textures/{blocks => particle}/falling_leaf_jungle_1.png (100%) rename src/main/resources/assets/betterfoliage/textures/{blocks => particle}/falling_leaf_jungle_2.png (100%) rename src/main/resources/assets/betterfoliage/textures/{blocks => particle}/falling_leaf_jungle_3.png (100%) rename src/main/resources/assets/betterfoliage/textures/{blocks => particle}/falling_leaf_spruce_0.png (100%) rename src/main/resources/assets/betterfoliage/textures/{blocks => particle}/falling_leaf_spruce_1.png (100%) rename src/main/resources/assets/betterfoliage/textures/{blocks => particle}/falling_leaf_spruce_2.png (100%) rename src/main/resources/assets/betterfoliage/textures/{blocks => particle}/falling_leaf_spruce_3.png (100%) rename src/main/resources/assets/{bettergrassandleaves/textures/blocks => betterfoliage/textures/particle}/rising_soul_0.png (100%) rename src/main/resources/assets/{bettergrassandleaves/textures/blocks => betterfoliage/textures/particle}/rising_soul_1.png (100%) rename src/main/resources/assets/{bettergrassandleaves/textures/blocks => betterfoliage/textures/particle}/soul_track.png (100%) delete mode 100644 src/main/resources/assets/bettergrassandleaves/textures/blocks/better_cactus.png delete mode 100644 src/main/resources/assets/bettergrassandleaves/textures/blocks/better_cactus_arm_0.png delete mode 100644 src/main/resources/assets/bettergrassandleaves/textures/blocks/better_cactus_arm_1.png create mode 100644 src/main/resources/betterfoliage.common.mixins.json create mode 100644 src/main/resources/betterfoliage.optifine.mixins.json create mode 100644 src/main/resources/betterfoliage.vanilla.mixins.json create mode 100644 src/main/resources/bf_generated_pack.png diff --git a/build.gradle b/build.gradle index 0acbc5d..51fed21 100644 --- a/build.gradle +++ b/build.gradle @@ -1,62 +1,99 @@ -apply plugin: "net.minecraftforge.gradle.forge" -apply plugin: 'kotlin' - -archivesBaseName = jarName - buildscript { repositories { + mavenLocal() mavenCentral() + jcenter() maven { name = "forge" url = "http://files.minecraftforge.net/maven" } + maven { + name = 'sponge' + url = 'https://repo.spongepowered.org/maven' + } } dependencies { - classpath "net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT" + classpath(group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true) { + exclude group: 'trove', module: 'trove' + } + classpath 'org.spongepowered:mixingradle:0.7-SNAPSHOT' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } +apply plugin: "net.minecraftforge.gradle" +apply plugin: 'org.spongepowered.mixin' +apply plugin: 'kotlin' + +sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' repositories { mavenCentral() jcenter() maven { - name = "shadowfacts" - url = "https://maven.shadowfacts.net/" + name = "forge" + url = "http://files.minecraftforge.net/maven" + } + maven { + name = 'Curse' + url = 'https://minecraft.curseforge.com/api/maven/' + } + maven { + name = 'sponge' + url = 'https://repo.spongepowered.org/maven' } } dependencies { - compile "net.shadowfacts:Forgelin:$forgelin_version" + minecraft "net.minecraftforge:forge:$mc_version-$forge_version" + implementation "kottle:Kottle:$kottle_version" + implementation "org.spongepowered:mixin:0.8-SNAPSHOT" +} + +mixin { + add sourceSets.main, "betterfoliage.refmap.json" } minecraft { - version = mc_version + "-" + forge_version - mappings = mcp_mappings - runDir = 'run' -} -processResources { - from(sourceSets.main.resources) { exclude 'mcmod.info' } - from(sourceSets.main.resources) { include 'mcmod.info' expand 'version':version, 'mcversion':minecraft.version } + mappings channel: "$mcp_mappings_channel", version: "$mcp_mappings_version" + accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') - into "${buildDir}/classes/main" + runs { + client { + workingDirectory project.file('run') + property 'forge.logging.markers', 'CORE' + property 'forge.logging.console.level', 'debug' + mods { + betterfoliage { + source sourceSets.main + } + } + } + + server { + workingDirectory project.file('run') + property 'forge.logging.markers', 'CORE' + property 'forge.logging.console.level', 'debug' + mods { + betterfoliage { + source sourceSets.main + } + } + } + } } -def manifestCfg = { - attributes "FMLCorePlugin": "mods.betterfoliage.loader.BetterFoliageLoader" - attributes "FMLCorePluginContainsFMLMod": "mods.betterfoliage.BetterFoliageMod" - attributes "FMLAT": "BetterFoliage_at.cfg" +compileKotlin { + kotlinOptions { + freeCompilerArgs += ("-Xno-param-assertions") + freeCompilerArgs += ("-Xno-call-assertions") + } } jar { - manifest manifestCfg - exclude "optifine" -} + archiveName = "BetterFoliage-${version}-Forge-${mc_version}.jar" -task sourcesJar(type: Jar, dependsOn: classes) { - classifier = 'sources' - manifest manifestCfg - from(sourceSets.main.kotlin) - from(sourceSets.main.resources) { exclude 'mcmod.info' } - from(sourceSets.main.resources) { include 'mcmod.info' expand 'version':version, 'mcversion':minecraft.version } + manifest { + from "src/main/resources/META-INF/MANIFEST.MF" + attributes "Implementation-Version": "${version}" + } } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index dee74d6..3af4c08 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,11 +1,15 @@ +org.gradle.jvmargs=-Xmx2G + group = com.github.octarine-noise -jarName = BetterFoliage-MC1.12 +jarName = BetterFoliage-Forge version = 2.3.0 -mc_version = 1.12.2 -forge_version = 14.23.5.2847 -mcp_mappings = stable_39 +mc_version = 1.14.4 +forge_version = 28.1.109 +mcp_mappings_channel = snapshot +mcp_mappings_version = 20190719-1.14.3 -kotlin_version = 1.3.40 -forgelin_version = 1.8.4 \ No newline at end of file +kotlin_version = 1.3.61 +forgelin_version = 1.8.4 +kottle_version = 1.4.0 diff --git a/src/main/java/mods/betterfoliage/MixinConnector.java b/src/main/java/mods/betterfoliage/MixinConnector.java new file mode 100644 index 0000000..24743f0 --- /dev/null +++ b/src/main/java/mods/betterfoliage/MixinConnector.java @@ -0,0 +1,20 @@ +package mods.betterfoliage; + +import net.minecraftforge.fml.ModLoader; +import org.spongepowered.asm.mixin.Mixins; +import org.spongepowered.asm.mixin.connect.IMixinConnector; + +public class MixinConnector implements IMixinConnector { + @Override + public void connect() { + Mixins.addConfiguration("betterfoliage.common.mixins.json"); + + try { + Class.forName("optifine.OptiFineTransformationService"); + Mixins.addConfiguration("betterfoliage.optifine.mixins.json"); + } catch (ClassNotFoundException e) { + Mixins.addConfiguration("betterfoliage.vanilla.mixins.json"); + } + + } +} diff --git a/src/main/java/mods/betterfoliage/loader/BetterFoliageLoader.java b/src/main/java/mods/betterfoliage/loader/BetterFoliageLoader.java deleted file mode 100644 index 864f910..0000000 --- a/src/main/java/mods/betterfoliage/loader/BetterFoliageLoader.java +++ /dev/null @@ -1,38 +0,0 @@ -package mods.betterfoliage.loader; - -import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin; - -import java.util.Map; - -@IFMLLoadingPlugin.TransformerExclusions({ - "mods.betterfoliage.loader", - "mods.octarinecore.metaprog", - "kotlin" -}) -@IFMLLoadingPlugin.MCVersion("1.12.2") -@IFMLLoadingPlugin.SortingIndex(1400) -public class BetterFoliageLoader implements IFMLLoadingPlugin { - @Override - public String[] getASMTransformerClass() { - return new String[] { "mods.betterfoliage.loader.BetterFoliageTransformer" }; - } - - @Override - public String getModContainerClass() { - return null; - } - - @Override - public String getSetupClass() { - return null; - } - - @Override - public void injectData(Map data) { - } - - @Override - public String getAccessTransformerClass() { - return null; - } -} diff --git a/src/main/java/mods/betterfoliage/mixin/BlockMixin.java b/src/main/java/mods/betterfoliage/mixin/BlockMixin.java new file mode 100644 index 0000000..00e81f7 --- /dev/null +++ b/src/main/java/mods/betterfoliage/mixin/BlockMixin.java @@ -0,0 +1,29 @@ +package mods.betterfoliage.mixin; + +import mods.betterfoliage.client.Hooks; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +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.Redirect; + +/** + * Mixin overriding the {@link VoxelShape} used for the neighbor block in {@link Block}.shouldSideBeRendered(). + * + * This way log blocks can be made to not block rendering, without altering any {@link Block} or + * {@link BlockState} properties with potential gameplay ramifications. + */ +@Mixin(Block.class) +public class BlockMixin { + 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;"; + + @Redirect(method = shouldSideBeRendered, at = @At(value = "INVOKE", target = getVoxelShape, ordinal = 1)) + private static VoxelShape getVoxelShapeOverride(BlockState state, IBlockReader reader, BlockPos pos, Direction dir) { + return Hooks.getVoxelShapeOverride(state, reader, pos, dir); + } +} diff --git a/src/main/java/mods/betterfoliage/mixin/BlockStateMixin.java b/src/main/java/mods/betterfoliage/mixin/BlockStateMixin.java new file mode 100644 index 0000000..0d22a6c --- /dev/null +++ b/src/main/java/mods/betterfoliage/mixin/BlockStateMixin.java @@ -0,0 +1,26 @@ +package mods.betterfoliage.mixin; + +import mods.betterfoliage.client.Hooks; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockReader; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +/** + * Mixin to override the result of {@link BlockState}.getAmbientOcclusionLightValue(). + * + * Needed to avoid excessive darkening of Round Logs at the corners, now that they are not full blocks. + */ +@Mixin(BlockState.class) +public class BlockStateMixin { + private static final String callFrom = "Lnet/minecraft/block/BlockState;func_215703_d(Lnet/minecraft/world/IBlockReader;Lnet/minecraft/util/math/BlockPos;)F"; + private static final String callTo = "Lnet/minecraft/block/Block;func_220080_a(Lnet/minecraft/block/BlockState;Lnet/minecraft/world/IBlockReader;Lnet/minecraft/util/math/BlockPos;)F"; + + @Redirect(method = callFrom, at = @At(value = "INVOKE", target = callTo)) + float getAmbientOcclusionValue(Block block, BlockState state, IBlockReader reader, BlockPos pos) { + return Hooks.getAmbientOcclusionLightValueOverride(block.func_220080_a(state, reader, pos), state); + } +} diff --git a/src/main/java/mods/betterfoliage/mixin/ChunkRenderMixin.java b/src/main/java/mods/betterfoliage/mixin/ChunkRenderMixin.java new file mode 100644 index 0000000..69c1079 --- /dev/null +++ b/src/main/java/mods/betterfoliage/mixin/ChunkRenderMixin.java @@ -0,0 +1,29 @@ +package mods.betterfoliage.mixin; + +import mods.betterfoliage.client.Hooks; +import net.minecraft.block.BlockState; +import net.minecraft.client.renderer.BlockRendererDispatcher; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.chunk.ChunkRender; +import net.minecraft.util.BlockRenderLayer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IEnviromentBlockReader; +import net.minecraftforge.client.MinecraftForgeClient; +import net.minecraftforge.client.model.data.IModelData; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.Random; + +@Mixin(ChunkRender.class) +public class ChunkRenderMixin { + + private static final String rebuildChunk = "Lnet/minecraft/client/renderer/chunk/ChunkRender;rebuildChunk(FFFLnet/minecraft/client/renderer/chunk/ChunkRenderTask;)V"; + private static final String renderBlock = "Lnet/minecraft/client/renderer/BlockRendererDispatcher;renderBlock(Lnet/minecraft/block/BlockState;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/world/IEnviromentBlockReader;Lnet/minecraft/client/renderer/BufferBuilder;Ljava/util/Random;Lnet/minecraftforge/client/model/data/IModelData;)Z"; + + @Redirect(method = rebuildChunk, at = @At(value = "INVOKE", target = renderBlock)) + public boolean renderBlock(BlockRendererDispatcher dispatcher, BlockState state, BlockPos pos, IEnviromentBlockReader reader, BufferBuilder buffer, Random random, IModelData modelData) { + return Hooks.renderWorldBlock(dispatcher, state, pos, reader, buffer, random, modelData, MinecraftForgeClient.getRenderLayer()); + } +} diff --git a/src/main/java/mods/betterfoliage/mixin/ChunkRenderOptifineMixin.java b/src/main/java/mods/betterfoliage/mixin/ChunkRenderOptifineMixin.java new file mode 100644 index 0000000..f7bc0eb --- /dev/null +++ b/src/main/java/mods/betterfoliage/mixin/ChunkRenderOptifineMixin.java @@ -0,0 +1,31 @@ +package mods.betterfoliage.mixin; + +import mods.betterfoliage.client.Hooks; +import net.minecraft.block.BlockState; +import net.minecraft.client.renderer.chunk.ChunkRender; +import net.minecraft.util.BlockRenderLayer; +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(ChunkRender.class) +public class ChunkRenderOptifineMixin { + + private static final String rebuildChunk = "Lnet/minecraft/client/renderer/chunk/ChunkRender;rebuildChunk(FFFLnet/minecraft/client/renderer/chunk/ChunkRenderTask;)V"; + 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 = rebuildChunk, + 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, (BlockRenderLayer) layer[0]); + } +} diff --git a/src/main/java/mods/betterfoliage/mixin/ChunkRenderVanillaMixin.java b/src/main/java/mods/betterfoliage/mixin/ChunkRenderVanillaMixin.java new file mode 100644 index 0000000..e4d3f16 --- /dev/null +++ b/src/main/java/mods/betterfoliage/mixin/ChunkRenderVanillaMixin.java @@ -0,0 +1,29 @@ +package mods.betterfoliage.mixin; + +import mods.betterfoliage.client.Hooks; +import net.minecraft.block.BlockState; +import net.minecraft.client.renderer.BlockRendererDispatcher; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.chunk.ChunkRender; +import net.minecraft.util.BlockRenderLayer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IEnviromentBlockReader; +import net.minecraftforge.client.MinecraftForgeClient; +import net.minecraftforge.client.model.data.IModelData; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.Random; + +@Mixin(ChunkRender.class) +public class ChunkRenderVanillaMixin { + + private static final String rebuildChunk = "Lnet/minecraft/client/renderer/chunk/ChunkRender;rebuildChunk(FFFLnet/minecraft/client/renderer/chunk/ChunkRenderTask;)V"; + private static final String canRenderInLayer = "Lnet/minecraft/block/BlockState;canRenderInLayer(Lnet/minecraft/util/BlockRenderLayer;)Z"; + + @Redirect(method = rebuildChunk, at = @At(value = "INVOKE", target = canRenderInLayer)) + boolean canRenderInLayer(BlockState state, BlockRenderLayer layer) { + return Hooks.canRenderInLayerOverride(state, layer); + } +} diff --git a/src/main/java/mods/betterfoliage/mixin/ClientWorldMixin.java b/src/main/java/mods/betterfoliage/mixin/ClientWorldMixin.java new file mode 100644 index 0000000..c35131b --- /dev/null +++ b/src/main/java/mods/betterfoliage/mixin/ClientWorldMixin.java @@ -0,0 +1,44 @@ +package mods.betterfoliage.mixin; + +import mods.betterfoliage.client.Hooks; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.Random; + +@Mixin(ClientWorld.class) +public class ClientWorldMixin { + + private static final String worldAnimateTick = "Lnet/minecraft/client/world/ClientWorld;animateTick(IIIILjava/util/Random;ZLnet/minecraft/util/math/BlockPos$MutableBlockPos;)V"; + private static final String blockAnimateTick = "Lnet/minecraft/block/Block;animateTick(Lnet/minecraft/block/BlockState;Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Ljava/util/Random;)V"; + + private static final String worldNotify = "Lnet/minecraft/client/world/ClientWorld;notifyBlockUpdate(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;Lnet/minecraft/block/BlockState;I)V"; + private static final String rendererNotify = "Lnet/minecraft/client/renderer/WorldRenderer;notifyBlockUpdate(Lnet/minecraft/world/IBlockReader;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;Lnet/minecraft/block/BlockState;I)V"; + + /** + * Inject a callback to call for every random display tick. Used for adding custom particle effects to blocks. + */ + @Redirect(method = worldAnimateTick, at = @At(value = "INVOKE", target = blockAnimateTick)) + void onAnimateTick(Block block, BlockState state, World world, BlockPos pos, Random random) { + Hooks.onRandomDisplayTick(block, state, world, pos, random); + block.animateTick(state, world, pos, random); + } + + /** + * Inject callback to get notified of client-side blockstate changes. + * Used to invalidate caches in the {@link mods.betterfoliage.client.chunk.ChunkOverlayManager} + */ + @Redirect(method = worldNotify, at = @At(value = "INVOKE", target = rendererNotify)) + void onClientBlockChanged(WorldRenderer renderer, IBlockReader world, BlockPos pos, BlockState oldState, BlockState newState, int flags) { + Hooks.onClientBlockChanged((ClientWorld) world, pos, oldState, newState, flags); + renderer.notifyBlockUpdate(world, pos, oldState, newState, flags); + } +} diff --git a/src/main/java/mods/betterfoliage/mixin/ModelBakeryMixin.java b/src/main/java/mods/betterfoliage/mixin/ModelBakeryMixin.java new file mode 100644 index 0000000..0de8725 --- /dev/null +++ b/src/main/java/mods/betterfoliage/mixin/ModelBakeryMixin.java @@ -0,0 +1,21 @@ +package mods.betterfoliage.mixin; + +import mods.betterfoliage.client.Hooks; +import net.minecraft.client.renderer.model.ModelBakery; +import net.minecraft.profiler.IProfiler; +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.callback.CallbackInfo; + +@Mixin(ModelBakery.class) +public class ModelBakeryMixin { + + private static final String processLoading = "Lnet/minecraft/client/renderer/model/ModelBakery;processLoading(Lnet/minecraft/profiler/IProfiler;)V"; + private static final String endStartSection = "Lnet/minecraft/profiler/IProfiler;endStartSection(Ljava/lang/String;)V"; + + @Inject(method = processLoading, at = @At(value = "INVOKE_STRING", target = endStartSection, args = "ldc=stitching")) + void preStitchTextures(IProfiler profiler, CallbackInfo ci) { + Hooks.onLoadModelDefinitions(this); + } +} diff --git a/src/main/java/optifine/OptifineTransformerDevWrapper.java b/src/main/java/optifine/OptifineTransformerDevWrapper.java deleted file mode 100644 index 5ab9374..0000000 --- a/src/main/java/optifine/OptifineTransformerDevWrapper.java +++ /dev/null @@ -1,65 +0,0 @@ -package optifine; - -import net.minecraft.launchwrapper.IClassTransformer; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.Arrays; -import java.util.Optional; -import java.util.stream.Stream; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -public class OptifineTransformerDevWrapper implements IClassTransformer { - - public static String OPTIFINE_CLASSNAME = "optifine/OptiFineClassTransformer.class"; - private ZipFile ofZip = null; - - public OptifineTransformerDevWrapper() { - Stream loaderSources = Arrays.stream(((URLClassLoader) getClass().getClassLoader()).getURLs()); - Optional optifineURL = loaderSources.filter(this::isOptifineJar).findFirst(); - optifineURL.ifPresent(url -> ofZip = getZip(url)); - } - - private ZipFile getZip(URL url) { - try { - return new ZipFile(new File(url.toURI())); - } catch (Exception e) { - return null; - } - } - - private boolean isOptifineJar(URL url) { - ZipFile zip = getZip(url); - return zip != null && zip.getEntry(OPTIFINE_CLASSNAME) != null; - } - - @Override - public byte[] transform(String name, String transformedName, byte[] basicClass) { - if (ofZip == null) return basicClass; - ZipEntry replacement = ofZip.getEntry(name.replace(".", "/") + ".class"); - if (replacement == null) return basicClass; - - try { - return readAll(ofZip.getInputStream(replacement)); - } catch (IOException e) { - return basicClass; - } - } - - private byte[] readAll(InputStream is) throws IOException { - byte[] buf = new byte[4096]; - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - int len; - do { - len = is.read(buf, 0, 4096); - if (len > 0) bos.write(buf, 0, len); - } while (len > -1); - is.close(); - return bos.toByteArray(); - } -} diff --git a/src/main/java/optifine/OptifineTweakerDevWrapper.java b/src/main/java/optifine/OptifineTweakerDevWrapper.java deleted file mode 100644 index 65025cd..0000000 --- a/src/main/java/optifine/OptifineTweakerDevWrapper.java +++ /dev/null @@ -1,28 +0,0 @@ -package optifine; - -import net.minecraft.launchwrapper.ITweaker; -import net.minecraft.launchwrapper.LaunchClassLoader; - -import java.io.File; -import java.util.List; - -public class OptifineTweakerDevWrapper implements ITweaker { - @Override - public void acceptOptions(List args, File gameDir, File assetsDir, String profile) { - } - - @Override - public void injectIntoClassLoader(LaunchClassLoader classLoader) { - classLoader.registerTransformer("optifine.OptifineTransformerDevWrapper"); - } - - @Override - public String getLaunchTarget() { - return "net.minecraft.client.main.Main"; - } - - @Override - public String[] getLaunchArguments() { - return new String[0]; - } -} diff --git a/src/main/kotlin/mods/betterfoliage/BetterFoliage.kt b/src/main/kotlin/mods/betterfoliage/BetterFoliage.kt new file mode 100644 index 0000000..d36b378 --- /dev/null +++ b/src/main/kotlin/mods/betterfoliage/BetterFoliage.kt @@ -0,0 +1,57 @@ +package mods.betterfoliage + +import mods.betterfoliage.client.Client +import mods.betterfoliage.client.config.Config +import mods.betterfoliage.client.isAfterPostInit +import mods.octarinecore.client.resource.GeneratorPack +import net.alexwells.kottle.FMLKotlinModLoadingContext +import net.minecraft.client.Minecraft +import net.minecraftforge.eventbus.api.IEventBus +import net.minecraftforge.eventbus.api.SubscribeEvent +import net.minecraftforge.fml.ModLoadingContext +import net.minecraftforge.fml.common.Mod +import net.minecraftforge.fml.config.ModConfig +import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent +import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent +import org.apache.logging.log4j.Level.DEBUG +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.simple.SimpleLogger +import org.apache.logging.log4j.util.PropertiesUtil +import java.io.File +import java.io.PrintStream +import java.util.* + +@Mod(BetterFoliage.MOD_ID) +object BetterFoliage { + const val MOD_ID = "betterfoliage" + const val MOD_NAME = "Better Foliage" + + val modBus = FMLKotlinModLoadingContext.get().modEventBus + + var log = LogManager.getLogger("BetterFoliage") + var logDetail = SimpleLogger( + "BetterFoliage", + DEBUG, + false, false, true, false, + "yyyy-MM-dd HH:mm:ss", + null, + PropertiesUtil(Properties()), + PrintStream(File("logs/betterfoliage.log").apply { + parentFile.mkdirs() + if (!exists()) createNewFile() + }) + ) + + val genPack = GeneratorPack( + "bf_gen", + "Better Foliage generated assets", + "bf_generated_pack.png" + ) + + init { + log.log(DEBUG, "Constructing mod") + ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, Config.build()) + Minecraft.getInstance().resourcePackList.addPackFinder(genPack.packFinder) + Client.init() + } +} \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/BetterFoliageMod.kt b/src/main/kotlin/mods/betterfoliage/BetterFoliageMod.kt deleted file mode 100644 index 7ebae7b..0000000 --- a/src/main/kotlin/mods/betterfoliage/BetterFoliageMod.kt +++ /dev/null @@ -1,78 +0,0 @@ -package mods.betterfoliage - -import mods.betterfoliage.client.Client -import mods.betterfoliage.client.config.Config -import mods.betterfoliage.client.isAfterPostInit -import net.minecraftforge.common.config.Configuration -import net.minecraftforge.fml.common.FMLCommonHandler -import net.minecraftforge.fml.common.Mod -import net.minecraftforge.fml.common.event.FMLPostInitializationEvent -import net.minecraftforge.fml.common.event.FMLPreInitializationEvent -import net.minecraftforge.fml.common.network.NetworkCheckHandler -import net.minecraftforge.fml.relauncher.Side -import org.apache.logging.log4j.Level.DEBUG -import org.apache.logging.log4j.Level.INFO -import org.apache.logging.log4j.Logger -import org.apache.logging.log4j.simple.SimpleLogger -import org.apache.logging.log4j.util.PropertiesUtil -import java.io.File -import java.io.PrintStream -import java.util.* - -@Mod( - modid = BetterFoliageMod.MOD_ID, - name = BetterFoliageMod.MOD_NAME, - acceptedMinecraftVersions = BetterFoliageMod.MC_VERSIONS, - guiFactory = BetterFoliageMod.GUI_FACTORY, - dependencies = "after:forgelin", - modLanguageAdapter = "net.shadowfacts.forgelin.KotlinAdapter", - clientSideOnly = true -) -object BetterFoliageMod { - - const val MOD_ID = "betterfoliage" - const val MOD_NAME = "Better Foliage" - const val DOMAIN = "betterfoliage" - const val LEGACY_DOMAIN = "bettergrassandleaves" - const val MC_VERSIONS = "[1.12]" - const val GUI_FACTORY = "mods.betterfoliage.client.gui.ConfigGuiFactory" - - lateinit var log: Logger - lateinit var logDetail: Logger - - var config: Configuration? = null - - init { - // inject pack into default list at construction time to get domains enumerated - // there's no 2nd resource reload pass anymore - Client.generatorPack.inject() - } - - @Mod.EventHandler - fun preInit(event: FMLPreInitializationEvent) { - log = event.modLog - val logDetailFile = File(event.modConfigurationDirectory.parentFile, "logs/betterfoliage.log").apply { - parentFile.mkdirs() - if (!exists()) createNewFile() - } - logDetail = SimpleLogger( - "BetterFoliage", - DEBUG, - false, false, true, false, - "yyyy-MM-dd HH:mm:ss", - null, - PropertiesUtil(Properties()), - PrintStream(logDetailFile) - ) - config = Configuration(event.suggestedConfigurationFile, null, true) - - Config.attach(config!!) - Client.init() - Client.log(INFO, "BetterFoliage initialized") - isAfterPostInit = true - } - - /** Mod is cosmetic only, always allow connection. */ - @NetworkCheckHandler - fun checkVersion(mods: Map, side: Side) = true -} \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/client/Client.kt b/src/main/kotlin/mods/betterfoliage/client/Client.kt index 1cd18aa..eecfa31 100644 --- a/src/main/kotlin/mods/betterfoliage/client/Client.kt +++ b/src/main/kotlin/mods/betterfoliage/client/Client.kt @@ -1,53 +1,48 @@ package mods.betterfoliage.client -import mods.betterfoliage.BetterFoliageMod +import mods.betterfoliage.BetterFoliage import mods.betterfoliage.client.chunk.ChunkOverlayManager -import mods.betterfoliage.client.gui.ConfigGuiFactory -import mods.betterfoliage.client.integration.* +import mods.betterfoliage.client.config.BlockConfig +import mods.betterfoliage.client.integration.ForestryIntegration +import mods.betterfoliage.client.integration.IC2RubberIntegration +import mods.betterfoliage.client.integration.OptifineCustomColors +import mods.betterfoliage.client.integration.TechRebornRubberIntegration import mods.betterfoliage.client.render.* import mods.betterfoliage.client.texture.* -import mods.octarinecore.client.KeyHandler import mods.octarinecore.client.gui.textComponent import mods.octarinecore.client.render.AbstractBlockRenderingHandler import mods.octarinecore.client.resource.CenteringTextureGenerator import mods.octarinecore.client.resource.GeneratorPack -import net.minecraft.block.Block -import net.minecraft.block.state.IBlockState +import mods.octarinecore.client.resource.IConfigChangeListener +import net.minecraft.block.BlockState import net.minecraft.client.Minecraft import net.minecraft.util.math.BlockPos -import net.minecraft.util.text.TextComponentTranslation import net.minecraft.util.text.TextFormatting -import net.minecraftforge.fml.client.FMLClientHandler -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly +import net.minecraft.util.text.TranslationTextComponent +import net.minecraftforge.eventbus.api.SubscribeEvent +import net.minecraftforge.fml.config.ModConfig +import net.minecraftforge.registries.ForgeRegistries import org.apache.logging.log4j.Level /** * Object responsible for initializing (and holding a reference to) all the infrastructure of the mod * except for the call hooks. - * - * This and all other singletons are annotated [SideOnly] to avoid someone accidentally partially - * initializing the mod on a server environment. */ -@SideOnly(Side.CLIENT) object Client { + var renderers= emptyList() + var configListeners = emptyList() - lateinit var renderers: List - val suppressRenderErrors = mutableSetOf() + val suppressRenderErrors = mutableSetOf() - // texture generation stuff + // texture generators val genGrass = GrassGenerator("bf_gen_grass") val genLeaves = LeafGenerator("bf_gen_leaves") val genReeds = CenteringTextureGenerator("bf_gen_reeds", 1, 2) - val generatorPack = GeneratorPack( - "Better Foliage generated", - genGrass, - genLeaves, - genReeds - ) - fun init() { + // add resource generators to pack + listOf(genGrass, genLeaves, genReeds).forEach { BetterFoliage.genPack.generators.add(it) } + // init renderers renderers = listOf( RenderGrass(), @@ -66,6 +61,7 @@ object Client { // init other singletons val singletons = listOf( + BlockConfig, StandardCactusRegistry, LeafParticleRegistry, ChunkOverlayManager, @@ -75,7 +71,7 @@ object Client { // init mod integrations val integrations = listOf( - ShadersModIntegration, +// ShadersModIntegration, OptifineCustomColors, ForestryIntegration, IC2RubberIntegration, @@ -87,30 +83,26 @@ object Client { LeafRegistry.addRegistry(StandardLeafRegistry) LogRegistry.addRegistry(StandardLogRegistry) - // init config hotkey - val configKey = KeyHandler(BetterFoliageMod.MOD_NAME, 66, "key.betterfoliage.gui") { - FMLClientHandler.instance().showGuiScreen( - ConfigGuiFactory.createBFConfigGui(Minecraft.getMinecraft().currentScreen) - ) - } + configListeners = listOf(renderers, singletons, integrations).flatten().filterIsInstance() + configListeners.forEach { it.onConfigChange() } } fun log(level: Level, msg: String) { - BetterFoliageMod.log.log(level, "[BetterFoliage] $msg") - BetterFoliageMod.logDetail.log(level, msg) + BetterFoliage.log.log(level, "[BetterFoliage] $msg") + BetterFoliage.logDetail.log(level, msg) } fun logDetail(msg: String) { - BetterFoliageMod.logDetail.log(Level.DEBUG, msg) + BetterFoliage.logDetail.log(Level.DEBUG, msg) } - fun logRenderError(state: IBlockState, location: BlockPos) { + fun logRenderError(state: BlockState, location: BlockPos) { if (state in suppressRenderErrors) return suppressRenderErrors.add(state) - val blockName = Block.REGISTRY.getNameForObject(state.block).toString() + val blockName = ForgeRegistries.BLOCKS.getKey(state.block).toString() val blockLoc = "${location.x},${location.y},${location.z}" - Minecraft.getMinecraft().ingameGUI.chatGUI.printChatMessage(TextComponentTranslation( + Minecraft.getInstance().ingameGUI.chatGUI.printChatMessage(TranslationTextComponent( "betterfoliage.rendererror", textComponent(blockName, TextFormatting.GOLD), textComponent(blockLoc, TextFormatting.GOLD) diff --git a/src/main/kotlin/mods/betterfoliage/client/Hooks.kt b/src/main/kotlin/mods/betterfoliage/client/Hooks.kt index b37f53f..845da93 100644 --- a/src/main/kotlin/mods/betterfoliage/client/Hooks.kt +++ b/src/main/kotlin/mods/betterfoliage/client/Hooks.kt @@ -1,7 +1,9 @@ @file:JvmName("Hooks") -@file:SideOnly(Side.CLIENT) package mods.betterfoliage.client +import mods.betterfoliage.BetterFoliage +import mods.betterfoliage.client.chunk.ChunkOverlayManager +import mods.betterfoliage.client.config.BlockConfig import mods.betterfoliage.client.config.Config import mods.betterfoliage.client.render.* import mods.betterfoliage.loader.Refs @@ -10,46 +12,43 @@ import mods.octarinecore.client.resource.LoadModelDataEvent import mods.octarinecore.common.plus import mods.octarinecore.metaprog.allAvailable import net.minecraft.block.Block -import net.minecraft.block.state.IBlockState +import net.minecraft.block.BlockState +import net.minecraft.block.Blocks import net.minecraft.client.Minecraft import net.minecraft.client.renderer.BlockRendererDispatcher import net.minecraft.client.renderer.BufferBuilder -import net.minecraft.init.Blocks +import net.minecraft.client.renderer.model.ModelBakery +import net.minecraft.client.world.ClientWorld import net.minecraft.util.BlockRenderLayer import net.minecraft.util.BlockRenderLayer.CUTOUT import net.minecraft.util.BlockRenderLayer.CUTOUT_MIPPED -import net.minecraft.util.EnumFacing +import net.minecraft.util.Direction import net.minecraft.util.math.BlockPos -import net.minecraft.world.IBlockAccess +import net.minecraft.util.math.shapes.VoxelShape +import net.minecraft.util.math.shapes.VoxelShapes +import net.minecraft.world.IBlockReader +import net.minecraft.world.IEnviromentBlockReader import net.minecraft.world.World -import net.minecraftforge.client.model.ModelLoader -import net.minecraftforge.common.MinecraftForge -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly +import net.minecraftforge.client.model.data.IModelData +import java.util.* var isAfterPostInit = false val isOptifinePresent = allAvailable(Refs.OptifineClassTransformer) -fun doesSideBlockRenderingOverride(original: Boolean, blockAccess: IBlockAccess, pos: BlockPos, side: EnumFacing): Boolean { - return original && !(Config.enabled && Config.roundLogs.enabled && Config.blocks.logClasses.matchesClass(blockAccess.getBlockState(pos).block)); +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 isOpaqueCubeOverride(original: Boolean, state: IBlockState): Boolean { - // caution: blocks are initialized and the method called during startup - if (!isAfterPostInit) return original - return original && !(Config.enabled && Config.roundLogs.enabled && Config.blocks.logClasses.matchesClass(state.block)) +fun getUseNeighborBrightnessOverride(original: Boolean, state: BlockState): Boolean { + return original || (Config.enabled && Config.roundLogs.enabled && BlockConfig.logBlocks.matchesClass(state.block)); } -fun getAmbientOcclusionLightValueOverride(original: Float, state: IBlockState): Float { - if (Config.enabled && Config.roundLogs.enabled && Config.blocks.logClasses.matchesClass(state.block)) return Config.roundLogs.dimming; - return original; +fun onClientBlockChanged(worldClient: ClientWorld, pos: BlockPos, oldState: BlockState, newState: BlockState, flags: Int) { + ChunkOverlayManager.onBlockChange(worldClient, pos) } -fun getUseNeighborBrightnessOverride(original: Boolean, state: IBlockState): Boolean { - return original || (Config.enabled && Config.roundLogs.enabled && Config.blocks.logClasses.matchesClass(state.block)); -} - -fun onRandomDisplayTick(world: World, state: IBlockState, pos: BlockPos) { +fun onRandomDisplayTick(block: Block, state: BlockState, world: World, pos: BlockPos, random: Random) { if (Config.enabled && Config.risingSoul.enabled && state.block == Blocks.SOUL_SAND && @@ -60,42 +59,52 @@ fun onRandomDisplayTick(world: World, state: IBlockState, pos: BlockPos) { if (Config.enabled && Config.fallingLeaves.enabled && - Config.blocks.leavesClasses.matchesClass(state.block) && + BlockConfig.leafBlocks.matchesClass(state.block) && world.isAirBlock(pos + down1) && Math.random() < Config.fallingLeaves.chance) { EntityFallingLeavesFX(world, pos).addIfValid() } } -fun onAfterLoadModelDefinitions(loader: ModelLoader) { - MinecraftForge.EVENT_BUS.post(LoadModelDataEvent(loader)) +fun onLoadModelDefinitions(bakery: Any) { + BetterFoliage.modBus.post(LoadModelDataEvent(bakery as ModelBakery)) +} + +fun getVoxelShapeOverride(state: BlockState, reader: IBlockReader, pos: BlockPos, dir: Direction): VoxelShape { + if (LogRegistry[state, reader, pos] != null) return VoxelShapes.empty() + return state.func_215702_a(reader, pos, dir) } fun renderWorldBlock(dispatcher: BlockRendererDispatcher, - state: IBlockState, + state: BlockState, pos: BlockPos, - blockAccess: IBlockAccess, - worldRenderer: BufferBuilder, + reader: IEnviromentBlockReader, + buffer: BufferBuilder, + random: Random, + modelData: IModelData, layer: BlockRenderLayer ): Boolean { val doBaseRender = state.canRenderInLayer(layer) || (layer == targetCutoutLayer && state.canRenderInLayer(otherCutoutLayer)) blockContext.let { ctx -> - ctx.set(blockAccess, pos) + ctx.set(reader, pos) Client.renderers.forEach { renderer -> if (renderer.isEligible(ctx)) { // render on the block's default layer // also render on the cutout layer if the renderer requires it if (doBaseRender || (renderer.addToCutout && layer == targetCutoutLayer)) { - return renderer.render(ctx, dispatcher, worldRenderer, layer) + return renderer.render(ctx, dispatcher, buffer, random, modelData, layer) } } } } - return if (doBaseRender) dispatcher.renderBlock(state, pos, blockAccess, worldRenderer) else false + return if (doBaseRender) dispatcher.renderBlock(state, pos, reader, buffer, random, modelData) else false } -fun canRenderBlockInLayer(block: Block, state: IBlockState, layer: BlockRenderLayer) = block.canRenderInLayer(state, layer) || layer == targetCutoutLayer +fun canRenderInLayerOverride(state: BlockState, layer: BlockRenderLayer) = state.canRenderInLayer(layer) || layer == targetCutoutLayer -val targetCutoutLayer: BlockRenderLayer get() = if (Minecraft.getMinecraft().gameSettings.mipmapLevels > 0) CUTOUT_MIPPED else CUTOUT -val otherCutoutLayer: BlockRenderLayer get() = if (Minecraft.getMinecraft().gameSettings.mipmapLevels > 0) CUTOUT else CUTOUT_MIPPED +fun canRenderInLayerOverrideOptifine(state: BlockState, optifineReflector: Any?, layerArray: Array) = + canRenderInLayerOverride(state, layerArray[0] as BlockRenderLayer) + +val targetCutoutLayer: BlockRenderLayer get() = if (Minecraft.getInstance().gameSettings.mipmapLevels > 0) CUTOUT_MIPPED else CUTOUT +val otherCutoutLayer: BlockRenderLayer get() = if (Minecraft.getInstance().gameSettings.mipmapLevels > 0) CUTOUT else CUTOUT_MIPPED diff --git a/src/main/kotlin/mods/betterfoliage/client/chunk/Overlay.kt b/src/main/kotlin/mods/betterfoliage/client/chunk/Overlay.kt index 3ff6a17..2190088 100644 --- a/src/main/kotlin/mods/betterfoliage/client/chunk/Overlay.kt +++ b/src/main/kotlin/mods/betterfoliage/client/chunk/Overlay.kt @@ -1,56 +1,66 @@ package mods.betterfoliage.client.chunk +import mods.betterfoliage.BetterFoliage import mods.betterfoliage.client.Client -import net.minecraft.block.state.IBlockState -import net.minecraft.client.multiplayer.WorldClient -import net.minecraft.entity.Entity -import net.minecraft.entity.player.EntityPlayer -import net.minecraft.util.SoundCategory -import net.minecraft.util.SoundEvent +import mods.betterfoliage.loader.Refs +import net.minecraft.block.BlockState +import net.minecraft.client.renderer.chunk.ChunkRenderCache +import net.minecraft.client.world.ClientWorld import net.minecraft.util.math.BlockPos import net.minecraft.util.math.ChunkPos -import net.minecraft.world.IBlockAccess -import net.minecraft.world.IWorldEventListener -import net.minecraft.world.World -import net.minecraft.world.chunk.EmptyChunk +import net.minecraft.world.IBlockReader +import net.minecraft.world.IEnviromentBlockReader +import net.minecraft.world.IWorldReader +import net.minecraft.world.dimension.DimensionType import net.minecraftforge.common.MinecraftForge import net.minecraftforge.event.world.ChunkEvent import net.minecraftforge.event.world.WorldEvent -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.eventbus.api.SubscribeEvent import org.apache.logging.log4j.Level +import java.util.* + +val IEnviromentBlockReader.dimType: DimensionType get() = when { + this is IWorldReader -> dimension.type + this is ChunkRenderCache -> world.dimension.type + Refs.OptifineChunkCache.isInstance(this) -> (Refs.CCOFChunkCache.get(this) as ChunkRenderCache).world.dimension.type + else -> throw IllegalArgumentException("DimensionType of world with class ${this::class.qualifiedName} cannot be determined!") +} /** * Represents some form of arbitrary non-persistent data that can be calculated and cached for each block position */ interface ChunkOverlayLayer { - abstract fun calculate(world: IBlockAccess, pos: BlockPos): T - abstract fun onBlockUpdate(world: IBlockAccess, pos: BlockPos) + abstract fun calculate(reader: IEnviromentBlockReader, pos: BlockPos): T + abstract fun onBlockUpdate(reader: IEnviromentBlockReader, pos: BlockPos) } /** * Query, lazy calculation and lifecycle management of multiple layers of chunk overlay data. */ -object ChunkOverlayManager : IBlockUpdateListener { +object ChunkOverlayManager { + + var tempCounter = 0 + init { Client.log(Level.INFO, "Initializing client overlay manager") MinecraftForge.EVENT_BUS.register(this) } - val chunkData = mutableMapOf() + val chunkData = IdentityHashMap>() val layers = mutableListOf>() /** * Get the overlay data for a given layer and position * * @param layer Overlay layer to query - * @param world World to use if calculation of overlay value is necessary + * @param reader World to use if calculation of overlay value is necessary * @param pos Block position */ - fun get(layer: ChunkOverlayLayer, world: IBlockAccess, pos: BlockPos): T? { - val data = chunkData[ChunkPos(pos)] ?: return null + fun get(layer: ChunkOverlayLayer, reader: IEnviromentBlockReader, pos: BlockPos): T? { + val data = chunkData[reader.dimType]?.get(ChunkPos(pos)) ?: return null data.get(layer, pos).let { value -> if (value !== ChunkOverlayData.UNCALCULATED) return value - val newValue = layer.calculate(world, pos) + val newValue = layer.calculate(reader, pos) data.set(layer, pos, newValue) return newValue } @@ -62,32 +72,39 @@ object ChunkOverlayManager : IBlockUpdateListener { * @param layer Overlay layer to clear * @param pos Block position */ - fun clear(layer: ChunkOverlayLayer, pos: BlockPos) { - chunkData[ChunkPos(pos)]?.clear(layer, pos) + fun clear(dimension: DimensionType, layer: ChunkOverlayLayer, pos: BlockPos) { + chunkData[dimension]?.get(ChunkPos(pos))?.clear(layer, pos) } - override fun notifyBlockUpdate(world: World, pos: BlockPos, oldState: IBlockState, newState: IBlockState, flags: Int) { - if (chunkData.containsKey(ChunkPos(pos))) layers.forEach { layer -> layer.onBlockUpdate(world, pos) } - } - - @SubscribeEvent - fun handleLoadWorld(event: WorldEvent.Load) { - if (event.world is WorldClient) { - event.world.addEventListener(this) + fun onBlockChange(world: ClientWorld, pos: BlockPos) { + if (chunkData[world.dimType]?.containsKey(ChunkPos(pos)) == true) { + layers.forEach { layer -> layer.onBlockUpdate(world, pos) } } } @SubscribeEvent - fun handleLoadChunk(event: ChunkEvent.Load) { - if (event.world is WorldClient && event.chunk !is EmptyChunk) { - chunkData[event.chunk.pos] = ChunkOverlayData(layers) + fun handleLoadWorld(event: WorldEvent.Load) = (event.world as? ClientWorld)?.let { world -> + BetterFoliage.log.debug("Unloaded world: id=${world.dimType.id} name=${world.dimType.registryName}") + chunkData[world.dimType] = mutableMapOf() + } + + @SubscribeEvent + fun handleUnloadWorld(event: WorldEvent.Unload) = (event.world as? ClientWorld)?.let { world -> + BetterFoliage.log.debug("Unloaded world: id=${world.dimType.id} name=${world.dimType.registryName}") + chunkData.remove(world.dimType) + } + + @SubscribeEvent + fun handleLoadChunk(event: ChunkEvent.Load) = (event.world as? ClientWorld)?.let { world -> + chunkData[world.dimType]?.let { chunks -> + // check for existence first because Optifine fires a TON of these + if (event.chunk.pos !in chunks.keys) chunks[event.chunk.pos] = ChunkOverlayData(layers) } } + @SubscribeEvent - fun handleUnloadChunk(event: ChunkEvent.Unload) { - if (event.world is WorldClient) { - chunkData.remove(event.chunk.pos) - } + fun handleUnloadChunk(event: ChunkEvent.Unload) = (event.world as? ClientWorld)?.let { world -> + chunkData[world.dimType]?.remove(event.chunk.pos) } } @@ -107,6 +124,7 @@ class ChunkOverlayData(layers: List>) { * IWorldEventListener helper subclass * No-op for everything except notifyBlockUpdate() */ +/* interface IBlockUpdateListener : IWorldEventListener { override fun playSoundToAllNearExcept(player: EntityPlayer?, soundIn: SoundEvent, category: SoundCategory, x: Double, y: Double, z: Double, volume: Float, pitch: Float) {} override fun onEntityAdded(entityIn: Entity) {} @@ -119,4 +137,8 @@ interface IBlockUpdateListener : IWorldEventListener { override fun playRecord(soundIn: SoundEvent, pos: BlockPos) {} override fun sendBlockBreakProgress(breakerId: Int, pos: BlockPos, progress: Int) {} override fun markBlockRangeForRenderUpdate(x1: Int, y1: Int, z1: Int, x2: Int, y2: Int, z2: Int) {} -} \ No newline at end of file + override fun addParticle(p0: IParticleData, p1: Boolean, p2: Double, p3: Double, p4: Double, p5: Double, p6: Double, p7: Double) {} + override fun addParticle(p0: IParticleData, p1: Boolean, p2: Boolean, p3: Double, p4: Double, p5: Double, p6: Double, p7: Double, p8: Double) {} +} + + */ \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/client/config/Config.kt b/src/main/kotlin/mods/betterfoliage/client/config/Config.kt index 509f879..56bdaa0 100644 --- a/src/main/kotlin/mods/betterfoliage/client/config/Config.kt +++ b/src/main/kotlin/mods/betterfoliage/client/config/Config.kt @@ -1,18 +1,16 @@ package mods.betterfoliage.client.config -import mods.betterfoliage.BetterFoliageMod -import mods.betterfoliage.client.gui.BiomeListConfigEntry +import mods.betterfoliage.BetterFoliage +import mods.octarinecore.client.resource.LoadModelDataEvent import mods.octarinecore.common.config.* -import net.minecraft.client.Minecraft -import net.minecraft.world.biome.Biome -import net.minecraftforge.fml.client.event.ConfigChangedEvent -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly -import org.lwjgl.opengl.GL11 +import net.minecraft.util.ResourceLocation +import net.minecraftforge.common.MinecraftForge +import net.minecraftforge.eventbus.api.SubscribeEvent // BetterFoliage-specific property delegates -private val OBSOLETE = ObsoleteConfigProperty() +//private val OBSOLETE = ObsoleteConfigProperty() private fun featureEnable() = boolean(true).lang("enabled") +/* fun biomeList(defaults: (Biome) -> Boolean) = intList { Biome.REGISTRY .filter { it != null && defaults(it) } @@ -24,14 +22,15 @@ fun biomeList(defaults: (Biome) -> Boolean) = intList { private fun Biome.filterTemp(min: Float?, max: Float?) = (min == null || min <= defaultTemperature) && (max == null || max >= defaultTemperature) private fun Biome.filterRain(min: Float?, max: Float?) = (min == null || min <= rainfall) && (max == null || max >= rainfall) private fun Biome.filterClass(vararg name: String) = name.any { it in this.javaClass.name.toLowerCase() } +*/ // Config singleton -@SideOnly(Side.CLIENT) -object Config : DelegatingConfig(BetterFoliageMod.MOD_ID, BetterFoliageMod.DOMAIN) { +object Config : DelegatingConfig(BetterFoliage.MOD_ID, BetterFoliage.MOD_ID) { - var enabled by boolean(true) - var nVidia by boolean(GL11.glGetString(GL11.GL_VENDOR).toLowerCase().contains("nvidia")) + val enabled by boolean(true) + val nVidia by boolean(false) + /* object blocks { val leavesClasses = ConfigurableBlockMatcher(BetterFoliageMod.DOMAIN, "leaves_blocks_default.cfg") val leavesModels = ModelTextureListConfigOption(BetterFoliageMod.DOMAIN, "leaves_models_default.cfg", 1) @@ -54,8 +53,9 @@ object Config : DelegatingConfig(BetterFoliageMod.MOD_ID, BetterFoliageMod.DOMAI val logsWhitelist = OBSOLETE val logsBlacklist = OBSOLETE } +*/ - object leaves { + object leaves : ConfigCategory() { val enabled by featureEnable() val snowEnabled by boolean(true) val hOffset by double(max=0.4, default=0.2).lang("hOffset") @@ -65,7 +65,7 @@ object Config : DelegatingConfig(BetterFoliageMod.MOD_ID, BetterFoliageMod.DOMAI val hideInternal by boolean(true) } - object shortGrass { + object shortGrass : ConfigCategory(){ val grassEnabled by boolean(true) val myceliumEnabled by boolean(true) val snowEnabled by boolean(true) @@ -79,23 +79,16 @@ object Config : DelegatingConfig(BetterFoliageMod.MOD_ID, BetterFoliageMod.DOMAI val saturationThreshold by double(default=0.1) } -// object hangingGrass { -// var enabled by featureEnable() -// var distance by distanceLimit() -// var size by double(min=0.25, max=1.5, default=0.75).lang("size") -// var separation by double(max=0.5, default=0.25) -// } - - object connectedGrass { + object connectedGrass : ConfigCategory(){ val enabled by boolean(true) val snowEnabled by boolean(false) } - object roundLogs { + object roundLogs : ConfigCategory(){ val enabled by featureEnable() val radiusSmall by double(max=0.5, default=0.25) val radiusLarge by double(max=0.5, default=0.44) - val dimming by float(default = 0.7) + val dimming by double(default = 0.7) val connectSolids by boolean(false) val lenientConnect by boolean(true) val connectPerpendicular by boolean(true) @@ -104,41 +97,43 @@ object Config : DelegatingConfig(BetterFoliageMod.MOD_ID, BetterFoliageMod.DOMAI val zProtection by double(min = 0.9, default = 0.99) } - object cactus { + object cactus : ConfigCategory(){ val enabled by featureEnable() val size by double(min=0.5, max=1.5, default=0.8).lang("size") val sizeVariation by double(max=0.5, default=0.1) val hOffset by double(max=0.5, default=0.1).lang("hOffset") } - object lilypad { + object lilypad : ConfigCategory(){ val enabled by featureEnable() val hOffset by double(max=0.25, default=0.1).lang("hOffset") val flowerChance by int(max=64, default=16, min=0) } - object reed { + object reed : ConfigCategory(){ val enabled by featureEnable() val hOffset by double(max=0.4, default=0.2).lang("hOffset") val heightMin by double(min=1.5, max=3.5, default=1.7).lang("heightMin") val heightMax by double(min=1.5, max=3.5, default=2.2).lang("heightMax") val population by int(max=64, default=32).lang("population") - val biomes by biomeList { it.filterTemp(0.4f, null) && it.filterRain(0.4f, null) } + val minBiomeTemp by double(default=0.4) + val minBiomeRainfall by double(default=0.4) +// val biomes by biomeList { it.filterTemp(0.4f, null) && it.filterRain(0.4f, null) } val shaderWind by boolean(true).lang("shaderWind") } - object algae { + object algae : ConfigCategory(){ val enabled by featureEnable() val hOffset by double(max=0.25, default=0.1).lang("hOffset") val size by double(min=0.5, max=1.5, default=1.0).lang("size") val heightMin by double(min=0.1, max=1.5, default=0.5).lang("heightMin") val heightMax by double(min=0.1, max=1.5, default=1.0).lang("heightMax") val population by int(max=64, default=48).lang("population") - val biomes by biomeList { it.filterClass("river", "ocean") } +// val biomes by biomeList { it.filterClass("river", "ocean") } val shaderWind by boolean(true).lang("shaderWind") } - object coral { + object coral : ConfigCategory(){ val enabled by featureEnable() val shallowWater by boolean(false) val hOffset by double(max=0.4, default=0.2).lang("hOffset") @@ -147,10 +142,10 @@ object Config : DelegatingConfig(BetterFoliageMod.MOD_ID, BetterFoliageMod.DOMAI val crustSize by double(min=0.5, max=1.5, default=1.4) val chance by int(max=64, default=32) val population by int(max=64, default=48).lang("population") - val biomes by biomeList { it.filterClass("river", "ocean", "beach") } +// val biomes by biomeList { it.filterClass("river", "ocean", "beach") } } - object netherrack { + 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") @@ -158,7 +153,7 @@ object Config : DelegatingConfig(BetterFoliageMod.MOD_ID, BetterFoliageMod.DOMAI val size by double(min=0.5, max=1.5, default=1.0).lang("size") } - object fallingLeaves { + object fallingLeaves : ConfigCategory(){ val enabled by featureEnable() val speed by double(min=0.01, max=0.15, default=0.05) val windStrength by double(min=0.1, max=2.0, default=0.5) @@ -170,20 +165,20 @@ object Config : DelegatingConfig(BetterFoliageMod.MOD_ID, BetterFoliageMod.DOMAI val opacityHack by boolean(true) } - object risingSoul { + object risingSoul : ConfigCategory(){ val enabled by featureEnable() val chance by double(min=0.001, max=1.0, default=0.02) val perturb by double(min=0.01, max=0.25, default=0.05) val headSize by double(min=0.25, max=1.5, default=1.0) val trailSize by double(min=0.25, max=1.5, default=0.75) - val opacity by float(min=0.05, max=1.0, default=0.5) + val opacity by double(min=0.05, max=1.0, default=0.5) val sizeDecay by double(min=0.5, max=1.0, default=0.97) - val opacityDecay by float(min=0.5, max=1.0, default=0.97) + val opacityDecay by double(min=0.5, max=1.0, default=0.97) val lifetime by double(min=1.0, max=15.0, default=4.0) val trailLength by int(min=2, max=128, default=48) val trailDensity by int(min=1, max=16, default=3) } - +/* val forceReloadOptions = listOf( blocks.leavesClasses, blocks.leavesModels, @@ -194,8 +189,39 @@ object Config : DelegatingConfig(BetterFoliageMod.MOD_ID, BetterFoliageMod.DOMAI override fun onChange(event: ConfigChangedEvent.PostConfigChangedEvent) { if (hasChanged(forceReloadOptions)) - Minecraft.getMinecraft().refreshResources() + Minecraft.getInstance().refreshResources() else - Minecraft.getMinecraft().renderGlobal.loadRenderers() + Minecraft.getInstance().renderGlobal.loadRenderers() } +*/ } + +object BlockConfig { + private val list = mutableListOf() + + val leafBlocks = blocks("leaves_blocks_default.cfg") + val leafModels = models("leaves_models_default.cfg") + val grassBlocks = blocks("grass_blocks_default.cfg") + val grassModels = models("grass_models_default.cfg") + val mycelium = blocks("mycelium_blocks_default.cfg") +// val dirt = blocks("dirt_default.cfg") + val crops = blocks("crop_default.cfg") + val logBlocks = blocks("log_blocks_default.cfg") + val logModels = models("log_models_default.cfg") + val sand = blocks("sand_default.cfg") + val lilypad = blocks("lilypad_default.cfg") + val cactus = blocks("cactus_default.cfg") + val netherrack = blocks("netherrack_blocks_default.cfg") + + init { BetterFoliage.modBus.register(this) } + private fun blocks(cfgName: String) = ConfigurableBlockMatcher(BetterFoliage.logDetail, ResourceLocation(BetterFoliage.MOD_ID, cfgName)).apply { list.add(this) } + private fun models(cfgName: String) = ModelTextureListConfiguration(BetterFoliage.logDetail, ResourceLocation(BetterFoliage.MOD_ID, cfgName)).apply { list.add(this) } + + @SubscribeEvent + fun handleLoadModelData(event: LoadModelDataEvent) { + list.forEach { when(it) { + is ConfigurableBlockMatcher -> it.readDefaults() + is ModelTextureListConfiguration -> it.readDefaults() + } } + } +} \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/client/gui/BiomeListConfigEntry.kt b/src/main/kotlin/mods/betterfoliage/client/gui/BiomeListConfigEntry.kt deleted file mode 100644 index a2d791d..0000000 --- a/src/main/kotlin/mods/betterfoliage/client/gui/BiomeListConfigEntry.kt +++ /dev/null @@ -1,19 +0,0 @@ -package mods.betterfoliage.client.gui - -import mods.octarinecore.client.gui.IdListConfigEntry -import net.minecraft.world.biome.Biome -import net.minecraftforge.fml.client.config.GuiConfig -import net.minecraftforge.fml.client.config.GuiConfigEntries -import net.minecraftforge.fml.client.config.IConfigElement - -/** Toggleable list of all defined biomes. */ -class BiomeListConfigEntry( - owningScreen: GuiConfig, - owningEntryList: GuiConfigEntries, - configElement: IConfigElement) -: IdListConfigEntry(owningScreen, owningEntryList, configElement) { - - override val baseSet: List get() = Biome.REGISTRY.filterNotNull() - override val Biome.itemId: Int get() = Biome.REGISTRY.getIDForObject(this) - override val Biome.itemName: String get() = this.biomeName -} \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/client/gui/ConfigGuiFactory.kt b/src/main/kotlin/mods/betterfoliage/client/gui/ConfigGuiFactory.kt deleted file mode 100644 index 7775fbe..0000000 --- a/src/main/kotlin/mods/betterfoliage/client/gui/ConfigGuiFactory.kt +++ /dev/null @@ -1,29 +0,0 @@ -package mods.betterfoliage.client.gui - -import mods.betterfoliage.BetterFoliageMod -import mods.betterfoliage.client.config.Config -import net.minecraft.client.Minecraft -import net.minecraft.client.gui.GuiScreen -import net.minecraftforge.fml.client.IModGuiFactory -import net.minecraftforge.fml.client.config.GuiConfig - -class ConfigGuiFactory : IModGuiFactory { - - override fun initialize(minecraftInstance: Minecraft?) { } - override fun hasConfigGui() = true - override fun runtimeGuiCategories() = hashSetOf() - override fun createConfigGui(parentScreen: GuiScreen?) = createBFConfigGui(parentScreen) - - companion object { - @JvmStatic - fun createBFConfigGui(parentScreen: GuiScreen?) = GuiConfig( - parentScreen, - Config.rootGuiElements, - BetterFoliageMod.MOD_ID, - null, - false, - false, - BetterFoliageMod.MOD_NAME - ) - } -} diff --git a/src/main/kotlin/mods/betterfoliage/client/integration/ForestryIntegration.kt b/src/main/kotlin/mods/betterfoliage/client/integration/ForestryIntegration.kt index 4c9c565..49a69b5 100644 --- a/src/main/kotlin/mods/betterfoliage/client/integration/ForestryIntegration.kt +++ b/src/main/kotlin/mods/betterfoliage/client/integration/ForestryIntegration.kt @@ -1,8 +1,8 @@ package mods.betterfoliage.client.integration -import mods.betterfoliage.BetterFoliageMod +import mods.betterfoliage.BetterFoliage import mods.betterfoliage.client.Client -import mods.betterfoliage.client.config.Config +import mods.betterfoliage.client.config.BlockConfig import mods.betterfoliage.client.render.LogRegistry import mods.betterfoliage.client.render.StandardLogRegistry import mods.betterfoliage.client.render.column.ColumnTextureInfo @@ -19,19 +19,19 @@ import mods.octarinecore.metaprog.ClassRef import mods.octarinecore.metaprog.FieldRef import mods.octarinecore.metaprog.MethodRef import mods.octarinecore.metaprog.allAvailable -import net.minecraft.block.state.IBlockState +import net.minecraft.block.BlockState import net.minecraft.client.Minecraft -import net.minecraft.client.renderer.block.model.ModelResourceLocation +import net.minecraft.client.renderer.model.IUnbakedModel +import net.minecraft.client.renderer.model.ModelResourceLocation import net.minecraft.util.ResourceLocation import net.minecraft.util.math.BlockPos -import net.minecraft.world.IBlockAccess +import net.minecraft.world.IBlockReader +import net.minecraft.world.IWorldReader import net.minecraftforge.client.event.TextureStitchEvent import net.minecraftforge.client.model.IModel -import net.minecraftforge.fml.common.Loader -import net.minecraftforge.fml.common.eventhandler.EventPriority -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly +import net.minecraftforge.eventbus.api.EventPriority +import net.minecraftforge.eventbus.api.SubscribeEvent +import net.minecraftforge.fml.ModList import org.apache.logging.log4j.Level import kotlin.collections.Map import kotlin.collections.component1 @@ -45,7 +45,6 @@ import kotlin.collections.mapValues import kotlin.collections.mutableMapOf import kotlin.collections.set -@SideOnly(Side.CLIENT) object ForestryIntegration { val TextureLeaves = ClassRef("forestry.arboriculture.models.TextureLeaves") @@ -71,7 +70,7 @@ object ForestryIntegration { val getSprite = MethodRef(ILeafSpriteProvider, "getSprite", Refs.ResourceLocation, ClassRef.boolean, ClassRef.boolean) init { - if (Loader.isModLoaded("forestry") && allAvailable(TiLgetLeaveSprite, getLeafSpriteProvider, getSprite)) { + if (ModList.get().isLoaded("forestry") && allAvailable(TiLgetLeaveSprite, getLeafSpriteProvider, getSprite)) { Client.log(Level.INFO, "Forestry support initialized") LeafRegistry.addRegistry(ForestryLeafRegistry) LogRegistry.addRegistry(ForestryLogRegistry) @@ -80,13 +79,13 @@ object ForestryIntegration { } object ForestryLeafRegistry : ModelRenderRegistry { - val logger = BetterFoliageMod.logDetail + val logger = BetterFoliage.logDetail val textureToKey = mutableMapOf>() var textureToValue = emptyMap() - override fun get(state: IBlockState, world: IBlockAccess, pos: BlockPos): LeafInfo? { + override fun get(state: BlockState, world: IBlockReader, pos: BlockPos): LeafInfo? { // check variant property (used in decorative leaves) - state.properties.entries.find { + state.values.entries.find { ForestryIntegration.PropertyTreeType.isInstance(it.key) && ForestryIntegration.TreeDefinition.isInstance(it.value) } ?.let { val species = ForestryIntegration.TdSpecies.get(it.value) @@ -96,7 +95,7 @@ object ForestryLeafRegistry : ModelRenderRegistry { } // extract leaf texture information from TileEntity - val tile = world.getTileEntitySafe(pos) ?: return null + val tile = world.getTileEntity(pos) ?: return null if (!ForestryIntegration.TileLeaves.isInstance(tile)) return null val textureLoc = ForestryIntegration.TiLgetLeaveSprite.invoke(tile, Minecraft.isFancyGraphicsEnabled()) ?: return null return textureToValue[textureLoc] @@ -115,7 +114,7 @@ object ForestryLeafRegistry : ModelRenderRegistry { ForestryIntegration.TeLpollplain.get(it.value) as ResourceLocation, ForestryIntegration.TeLpollfancy.get(it.value) as ResourceLocation ).forEach { textureLocation -> - val key = StandardLeafKey(logger, textureLocation.toString()).apply { onPreStitch(event.map) } + val key = StandardLeafKey(logger, textureLocation.toString()).apply { onPreStitch(event) } textureToKey[textureLocation] = key } } @@ -129,14 +128,14 @@ object ForestryLeafRegistry : ModelRenderRegistry { } object ForestryLogRegistry : ModelRenderRegistryBase() { - override val logger = BetterFoliageMod.logDetail + override val logger = BetterFoliage.logDetail - override fun processModel(state: IBlockState, modelLoc: ModelResourceLocation, model: IModel): ModelRenderKey? { + override fun processModel(state: BlockState, modelLoc: ModelResourceLocation, models: List>): ModelRenderKey? { // respect class list to avoid triggering on fences, stairs, etc. - if (!Config.blocks.logClasses.matchesClass(state.block)) return null + if (!BlockConfig.logBlocks.matchesClass(state.block)) return null // find wood type property - val woodType = state.properties.entries.find { + val woodType = state.values.entries.find { ForestryIntegration.PropertyWoodType.isInstance(it.key) && ForestryIntegration.IWoodType.isInstance(it.value) } ?: return null diff --git a/src/main/kotlin/mods/betterfoliage/client/integration/OptifineCustomColors.kt b/src/main/kotlin/mods/betterfoliage/client/integration/OptifineCustomColors.kt index cbc1c80..3b6188d 100644 --- a/src/main/kotlin/mods/betterfoliage/client/integration/OptifineCustomColors.kt +++ b/src/main/kotlin/mods/betterfoliage/client/integration/OptifineCustomColors.kt @@ -7,22 +7,19 @@ import mods.octarinecore.client.render.BlockContext import mods.octarinecore.common.Int3 import mods.octarinecore.metaprog.allAvailable import mods.octarinecore.metaprog.reflectField -import net.minecraft.block.state.IBlockState +import net.minecraft.block.BlockState import net.minecraft.client.Minecraft -import net.minecraft.client.renderer.block.model.BakedQuad +import net.minecraft.client.renderer.model.BakedQuad import net.minecraft.client.renderer.vertex.DefaultVertexFormats -import net.minecraft.util.EnumFacing +import net.minecraft.util.Direction.UP import net.minecraft.util.math.BlockPos -import net.minecraft.world.IBlockAccess -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly +import net.minecraft.world.IBlockReader import org.apache.logging.log4j.Level /** * Integration for OptiFine custom block colors. */ @Suppress("UNCHECKED_CAST") -@SideOnly(Side.CLIENT) object OptifineCustomColors { val isColorAvailable = allAvailable( @@ -34,27 +31,26 @@ object OptifineCustomColors { } val renderEnv by ThreadLocalDelegate { OptifineRenderEnv() } - val fakeQuad = BakedQuad(IntArray(0), 1, EnumFacing.UP, null, true, DefaultVertexFormats.BLOCK) + val fakeQuad = BakedQuad(IntArray(0), 1, UP, null, true, DefaultVertexFormats.BLOCK) fun getBlockColor(ctx: BlockContext): Int { - val ofColor = if (isColorAvailable && Minecraft.getMinecraft().gameSettings.reflectField("ofCustomColors") == true) { - renderEnv.reset(ctx.world!!, ctx.blockState(Int3.zero), ctx.pos) - Refs.getColorMultiplier.invokeStatic(fakeQuad, ctx.blockState(Int3.zero), ctx.world!!, ctx.pos, renderEnv.wrapped) as? Int + val ofColor = if (isColorAvailable && Minecraft.getInstance().gameSettings.reflectField("ofCustomColors") == true) { + renderEnv.reset(ctx.reader!!, ctx.blockState(Int3.zero), ctx.pos) + Refs.getColorMultiplier.invokeStatic(fakeQuad, ctx.blockState(Int3.zero), ctx.reader!!, ctx.pos, renderEnv.wrapped) as? Int } else null return if (ofColor == null || ofColor == -1) ctx.blockData(Int3.zero).color else ofColor } } -@SideOnly(Side.CLIENT) class OptifineRenderEnv { val wrapped: Any = Refs.RenderEnv.element!!.getDeclaredConstructor( - Refs.IBlockAccess.element, Refs.IBlockState.element, Refs.BlockPos.element + Refs.IBlockReader.element, Refs.BlockState.element, Refs.BlockPos.element ).let { it.isAccessible = true it.newInstance(null, null, null) } - fun reset(blockAccess: IBlockAccess, state: IBlockState, pos: BlockPos) { + fun reset(blockAccess: IBlockReader, state: BlockState, pos: BlockPos) { Refs.RenderEnv_reset.invoke(wrapped, blockAccess, state, pos) } } \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/client/integration/RubberIntegration.kt b/src/main/kotlin/mods/betterfoliage/client/integration/RubberIntegration.kt index f792731..642a3d7 100644 --- a/src/main/kotlin/mods/betterfoliage/client/integration/RubberIntegration.kt +++ b/src/main/kotlin/mods/betterfoliage/client/integration/RubberIntegration.kt @@ -1,6 +1,6 @@ package mods.betterfoliage.client.integration -import mods.betterfoliage.BetterFoliageMod +import mods.betterfoliage.BetterFoliage import mods.betterfoliage.client.Client import mods.betterfoliage.client.render.LogRegistry import mods.betterfoliage.client.render.column.ColumnTextureInfo @@ -13,39 +13,39 @@ import mods.octarinecore.client.resource.* import mods.octarinecore.common.rotate import mods.octarinecore.metaprog.ClassRef import mods.octarinecore.metaprog.allAvailable -import net.minecraft.block.state.IBlockState -import net.minecraft.client.renderer.block.model.ModelResourceLocation +import net.minecraft.block.BlockState +import net.minecraft.client.renderer.model.BlockModel +import net.minecraft.client.renderer.model.IUnbakedModel +import net.minecraft.client.renderer.model.ModelResourceLocation +import net.minecraft.client.renderer.texture.AtlasTexture import net.minecraft.client.renderer.texture.TextureAtlasSprite -import net.minecraft.client.renderer.texture.TextureMap -import net.minecraft.util.EnumFacing +import net.minecraft.util.Direction +import net.minecraft.util.Direction.* import net.minecraft.util.ResourceLocation import net.minecraftforge.client.model.IModel -import net.minecraftforge.fml.common.Loader -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly +import net.minecraftforge.fml.ModList import org.apache.logging.log4j.Level +import org.apache.logging.log4j.Level.DEBUG import org.apache.logging.log4j.Logger -@SideOnly(Side.CLIENT) object IC2RubberIntegration { val BlockRubWood = ClassRef("ic2.core.block.BlockRubWood") init { - if (Loader.isModLoaded("ic2") && allAvailable(BlockRubWood)) { + if (ModList.get().isLoaded("ic2") && allAvailable(BlockRubWood)) { Client.log(Level.INFO, "IC2 rubber support initialized") LogRegistry.addRegistry(IC2LogSupport) } } } -@SideOnly(Side.CLIENT) object TechRebornRubberIntegration { val BlockRubberLog = ClassRef("techreborn.blocks.BlockRubberLog") init { - if (Loader.isModLoaded("techreborn") && allAvailable(BlockRubberLog)) { + if (ModList.get().isLoaded("techreborn") && allAvailable(BlockRubberLog)) { Client.log(Level.INFO, "TechReborn rubber support initialized") LogRegistry.addRegistry(TechRebornLogSupport) } @@ -53,8 +53,8 @@ object TechRebornRubberIntegration { } class RubberLogInfo( - axis: EnumFacing.Axis?, - val spotDir: EnumFacing, + axis: Axis?, + val spotDir: Direction, topTexture: TextureAtlasSprite, bottomTexture: TextureAtlasSprite, val spotTexture: TextureAtlasSprite, @@ -62,85 +62,85 @@ class RubberLogInfo( ) : SimpleColumnInfo(axis, topTexture, bottomTexture, sideTextures) { override val side: QuadIconResolver = { ctx: ShadingContext, idx: Int, quad: Quad -> - val worldFace = (if ((idx and 1) == 0) EnumFacing.SOUTH else EnumFacing.EAST).rotate(ctx.rotation) + val worldFace = (if ((idx and 1) == 0) SOUTH else EAST).rotate(ctx.rotation) if (worldFace == spotDir) spotTexture else { val sideIdx = if (this.sideTextures.size > 1) (blockContext.random(1) + dirToIdx[worldFace.ordinal]) % this.sideTextures.size else 0 this.sideTextures[sideIdx] } } - class Key(override val logger: Logger, val axis: EnumFacing.Axis?, val spotDir: EnumFacing, val textures: List): ModelRenderKey { - override fun resolveSprites(atlas: TextureMap) = RubberLogInfo( + class Key(override val logger: Logger, val axis: Axis?, val spotDir: Direction, val textures: List): ModelRenderKey { + override fun resolveSprites(atlas: AtlasTexture) = RubberLogInfo( axis, spotDir, - atlas[textures[0]] ?: atlas.missingSprite, - atlas[textures[1]] ?: atlas.missingSprite, - atlas[textures[2]] ?: atlas.missingSprite, - textures.drop(3).map { atlas[it] ?: atlas.missingSprite } + atlas[textures[0]] ?: missingSprite, + atlas[textures[1]] ?: missingSprite, + atlas[textures[2]] ?: missingSprite, + textures.drop(3).map { atlas[it] ?: missingSprite } ) } } object IC2LogSupport : ModelRenderRegistryBase() { - override val logger = BetterFoliageMod.logDetail + override val logger = BetterFoliage.logDetail - override fun processModel(state: IBlockState, modelLoc: ModelResourceLocation, model: IModel): ModelRenderKey? { + override fun processModel(state: BlockState, modelLoc: ModelResourceLocation, models: List>): ModelRenderKey? { // check for proper block class, existence of ModelBlock, and "state" blockstate property if (!IC2RubberIntegration.BlockRubWood.isInstance(state.block)) return null - val blockLoc = model.modelBlockAndLoc.firstOrNull() ?: return null - val type = state.properties.entries.find { it.key.getName() == "state" }?.value?.toString() ?: return null + val blockLoc = models.firstOrNull() as Pair ?: return null + val type = state.values.entries.find { it.key.getName() == "state" }?.value?.toString() ?: return null // logs with no rubber spot if (blockLoc.derivesFrom(ResourceLocation("block/cube_column"))) { val axis = when(type) { - "plain_y" -> EnumFacing.Axis.Y - "plain_x" -> EnumFacing.Axis.X - "plain_z" -> EnumFacing.Axis.Z + "plain_y" -> Axis.Y + "plain_x" -> Axis.X + "plain_z" -> Axis.Z else -> null } val textureNames = listOf("end", "end", "side").map { blockLoc.first.resolveTextureName(it) } if (textureNames.any { it == "missingno" }) return null - logger.log(Level.DEBUG, "IC2LogSupport: block state ${state.toString()}") - logger.log(Level.DEBUG, "IC2LogSupport: axis=$axis, end=${textureNames[0]}, side=${textureNames[2]}") + logger.log(DEBUG, "IC2LogSupport: block state ${state.toString()}") + logger.log(DEBUG, "IC2LogSupport: axis=$axis, end=${textureNames[0]}, side=${textureNames[2]}") return SimpleColumnInfo.Key(logger, axis, textureNames) } // logs with rubber spot val spotDir = when(type) { - "dry_north", "wet_north" -> EnumFacing.NORTH - "dry_south", "wet_south" -> EnumFacing.SOUTH - "dry_west", "wet_west" -> EnumFacing.WEST - "dry_east", "wet_east" -> EnumFacing.EAST + "dry_north", "wet_north" -> NORTH + "dry_south", "wet_south" -> SOUTH + "dry_west", "wet_west" -> WEST + "dry_east", "wet_east" -> EAST else -> null } val textureNames = listOf("up", "down", "north", "south").map { blockLoc.first.resolveTextureName(it) } if (textureNames.any { it == "missingno" }) return null - logger.log(Level.DEBUG, "IC2LogSupport: block state ${state.toString()}") - logger.log(Level.DEBUG, "IC2LogSupport: spotDir=$spotDir, up=${textureNames[0]}, down=${textureNames[1]}, side=${textureNames[2]}, spot=${textureNames[3]}") - return if (spotDir != null) RubberLogInfo.Key(logger, EnumFacing.Axis.Y, spotDir, textureNames) else SimpleColumnInfo.Key(logger, EnumFacing.Axis.Y, textureNames) + logger.log(DEBUG, "IC2LogSupport: block state ${state.toString()}") + logger.log(DEBUG, "IC2LogSupport: spotDir=$spotDir, up=${textureNames[0]}, down=${textureNames[1]}, side=${textureNames[2]}, spot=${textureNames[3]}") + return if (spotDir != null) RubberLogInfo.Key(logger, Axis.Y, spotDir, textureNames) else SimpleColumnInfo.Key(logger, Axis.Y, textureNames) } } object TechRebornLogSupport : ModelRenderRegistryBase() { - override val logger = BetterFoliageMod.logDetail + override val logger = BetterFoliage.logDetail - override fun processModel(state: IBlockState, modelLoc: ModelResourceLocation, model: IModel): ModelRenderKey? { + override fun processModel(state: BlockState, modelLoc: ModelResourceLocation, models: List>): ModelRenderKey? { // check for proper block class, existence of ModelBlock if (!TechRebornRubberIntegration.BlockRubberLog.isInstance(state.block)) return null - val blockLoc = model.modelBlockAndLoc.firstOrNull() ?: return null + val blockLoc = models.firstOrNull() as Pair ?: return null - val hasSap = state.properties.entries.find { it.key.getName() == "hassap" }?.value as? Boolean ?: return null - val sapSide = state.properties.entries.find { it.key.getName() == "sapside" }?.value as? EnumFacing ?: return null + val hasSap = state.values.entries.find { it.key.getName() == "hassap" }?.value as? Boolean ?: return null + val sapSide = state.values.entries.find { it.key.getName() == "sapside" }?.value as? Direction ?: return null - logger.log(Level.DEBUG, "$logName: block state $state") + logger.log(DEBUG, "$logName: block state $state") if (hasSap) { val textureNames = listOf("end", "end", "sapside", "side").map { blockLoc.first.resolveTextureName(it) } - logger.log(Level.DEBUG, "$logName: spotDir=$sapSide, end=${textureNames[0]}, side=${textureNames[2]}, spot=${textureNames[3]}") - if (textureNames.all { it != "missingno" }) return RubberLogInfo.Key(logger, EnumFacing.Axis.Y, sapSide, textureNames) + logger.log(DEBUG, "$logName: spotDir=$sapSide, end=${textureNames[0]}, side=${textureNames[2]}, spot=${textureNames[3]}") + if (textureNames.all { it != "missingno" }) return RubberLogInfo.Key(logger, Axis.Y, sapSide, textureNames) } else { val textureNames = listOf("end", "end", "side").map { blockLoc.first.resolveTextureName(it) } - logger.log(Level.DEBUG, "$logName: end=${textureNames[0]}, side=${textureNames[2]}") - if (textureNames.all { it != "missingno" })return SimpleColumnInfo.Key(logger, EnumFacing.Axis.Y, textureNames) + logger.log(DEBUG, "$logName: end=${textureNames[0]}, side=${textureNames[2]}") + if (textureNames.all { it != "missingno" })return SimpleColumnInfo.Key(logger, Axis.Y, textureNames) } return null } diff --git a/src/main/kotlin/mods/betterfoliage/client/integration/ShadersModIntegration.kt b/src/main/kotlin/mods/betterfoliage/client/integration/ShadersModIntegration.kt index 427c205..7f74fcb 100644 --- a/src/main/kotlin/mods/betterfoliage/client/integration/ShadersModIntegration.kt +++ b/src/main/kotlin/mods/betterfoliage/client/integration/ShadersModIntegration.kt @@ -1,41 +1,36 @@ package mods.betterfoliage.client.integration import mods.betterfoliage.client.Client -import mods.betterfoliage.client.config.Config +import mods.betterfoliage.client.config.BlockConfig import mods.betterfoliage.loader.Refs import mods.octarinecore.metaprog.allAvailable -import net.minecraft.block.Block -import net.minecraft.block.BlockTallGrass -import net.minecraft.block.state.IBlockState +import net.minecraft.block.BlockState +import net.minecraft.block.Blocks import net.minecraft.client.renderer.BufferBuilder -import net.minecraft.init.Blocks -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly import org.apache.logging.log4j.Level.INFO /** * Integration for ShadersMod. */ -@SideOnly(Side.CLIENT) object ShadersModIntegration { @JvmStatic var isAvailable = allAvailable(Refs.sVertexBuilder, Refs.pushEntity_state, Refs.pushEntity_num, Refs.popEntity) - @JvmStatic val tallGrassEntityData = entityDataFor(Blocks.TALLGRASS.defaultState.withProperty(BlockTallGrass.TYPE, BlockTallGrass.EnumType.GRASS)) - @JvmStatic val leavesEntityData = entityDataFor(Blocks.LEAVES.defaultState) + @JvmStatic val tallGrassEntityData = entityDataFor(Blocks.TALL_GRASS.defaultState) + @JvmStatic val leavesEntityData = entityDataFor(Blocks.OAK_LEAVES.defaultState) - fun entityDataFor(blockState: IBlockState) = - (Block.REGISTRY.getIDForObject(blockState.block).toLong() and 65535) or - ((blockState.renderType.ordinal.toLong() and 65535) shl 16) or - (blockState.block.getMetaFromState(blockState).toLong() shl 32) + fun entityDataFor(blockState: BlockState) = 0L +// (ForgeRegistries.BLOCKS.getIDForObject(blockState.block).toLong() and 65535) or +// ((blockState.renderType.ordinal.toLong() and 65535) shl 16) or +// (blockState.block.getMetaFromState(blockState).toLong() shl 32) /** * Called from transformed ShadersMod code. * @see mods.betterfoliage.loader.BetterFoliageTransformer */ - @JvmStatic fun getBlockIdOverride(original: Long, blockState: IBlockState): Long { - if (Config.blocks.leavesClasses.matchesClass(blockState.block)) return leavesEntityData - if (Config.blocks.crops.matchesClass(blockState.block)) return tallGrassEntityData + @JvmStatic fun getBlockIdOverride(original: Long, blockState: BlockState): Long { + if (BlockConfig.leafBlocks.matchesClass(blockState.block)) return leavesEntityData + if (BlockConfig.crops.matchesClass(blockState.block)) return tallGrassEntityData return original } @@ -56,7 +51,7 @@ object ShadersModIntegration { } /** Quads rendered inside this block will use the given block entity data in shader programs. */ - inline fun renderAs(state: IBlockState, renderer: BufferBuilder, enabled: Boolean = true, func: ()->Unit) = + inline fun renderAs(state: BlockState, renderer: BufferBuilder, enabled: Boolean = true, func: ()->Unit) = renderAs(entityDataFor(state), renderer, enabled, func) /** Quads rendered inside this block will behave as tallgrass blocks in shader programs. */ diff --git a/src/main/kotlin/mods/betterfoliage/client/render/EntityFallingLeavesFX.kt b/src/main/kotlin/mods/betterfoliage/client/render/EntityFallingLeavesFX.kt index 37cebc6..c883a7d 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/EntityFallingLeavesFX.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/EntityFallingLeavesFX.kt @@ -15,18 +15,22 @@ import net.minecraft.util.math.BlockPos import net.minecraft.util.math.MathHelper import net.minecraft.world.World import net.minecraftforge.common.MinecraftForge +import net.minecraftforge.event.TickEvent import net.minecraftforge.event.world.WorldEvent -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import net.minecraftforge.fml.common.gameevent.TickEvent -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly +import net.minecraftforge.eventbus.api.SubscribeEvent import org.lwjgl.opengl.GL11 -import java.lang.Math.* import java.util.* +import kotlin.math.abs +import kotlin.math.cos +import kotlin.math.sin -@SideOnly(Side.CLIENT) -class EntityFallingLeavesFX(world: World, pos: BlockPos) : -AbstractEntityFX(world, pos.x.toDouble() + 0.5, pos.y.toDouble(), pos.z.toDouble() + 0.5) { +const val rotationFactor = PI2.toFloat() / 64.0f + +class EntityFallingLeavesFX( + world: World, pos: BlockPos +) : AbstractEntityFX( + world, pos.x.toDouble() + 0.5, pos.y.toDouble(), pos.z.toDouble() + 0.5 +) { companion object { @JvmStatic val biomeBrightnessMultiplier = 0.5f @@ -38,38 +42,40 @@ AbstractEntityFX(world, pos.x.toDouble() + 0.5, pos.y.toDouble(), pos.z.toDouble var wasCollided = false init { - particleMaxAge = MathHelper.floor(random(0.6, 1.0) * Config.fallingLeaves.lifetime * 20.0) + maxAge = MathHelper.floor(random(0.6, 1.0) * Config.fallingLeaves.lifetime * 20.0) motionY = -Config.fallingLeaves.speed + particleScale = Config.fallingLeaves.size.toFloat() * 0.1f val state = world.getBlockState(pos) - val blockColor = Minecraft.getMinecraft().blockColors.colorMultiplier(state, world, pos, 0) val leafInfo = LeafRegistry[state, world, pos] + val blockColor = Minecraft.getInstance().blockColors.getColor(state, world, pos, 0) if (leafInfo != null) { - particleTexture = leafInfo.particleTextures[rand.nextInt(1024)] + sprite = leafInfo.particleTextures[rand.nextInt(1024)] calculateParticleColor(leafInfo.averageColor, blockColor) } else { - particleTexture = LeafParticleRegistry["default"][rand.nextInt(1024)] + sprite = LeafParticleRegistry["default"][rand.nextInt(1024)] setColor(blockColor) } } - override val isValid: Boolean get() = (particleTexture != null) + override val isValid: Boolean get() = (sprite != null) override fun update() { if (rand.nextFloat() > 0.95f) rotPositive = !rotPositive - if (particleAge > particleMaxAge - 20) particleAlpha = 0.05f * (particleMaxAge - particleAge) + if (age > maxAge - 20) particleAlpha = 0.05f * (maxAge - age) if (onGround || wasCollided) { velocity.setTo(0.0, 0.0, 0.0) if (!wasCollided) { - particleAge = Math.max(particleAge, particleMaxAge - 20) + age = Math.max(age, maxAge - 20) wasCollided = true } } else { velocity.setTo(cos[particleRot], 0.0, sin[particleRot]).mul(Config.fallingLeaves.perturb) .add(LeafWindTracker.current).add(0.0, -1.0, 0.0).mul(Config.fallingLeaves.speed) particleRot = (particleRot + (if (rotPositive) 1 else -1)) and 63 + particleAngle = rotationFactor * particleRot.toFloat() } } @@ -96,7 +102,6 @@ AbstractEntityFX(world, pos.x.toDouble() + 0.5, pos.y.toDouble(), pos.z.toDouble } } -@SideOnly(Side.CLIENT) object LeafWindTracker { var random = Random() val target = Double3.zero @@ -108,7 +113,7 @@ object LeafWindTracker { } fun changeWind(world: World) { - nextChange = world.worldInfo.worldTime + 120 + random.nextInt(80) + nextChange = world.worldInfo.gameTime + 120 + random.nextInt(80) val direction = PI2 * random.nextDouble() val speed = abs(random.nextGaussian()) * Config.fallingLeaves.windStrength + (if (!world.isRaining) 0.0 else abs(random.nextGaussian()) * Config.fallingLeaves.stormStrength) @@ -117,9 +122,9 @@ object LeafWindTracker { @SubscribeEvent fun handleWorldTick(event: TickEvent.ClientTickEvent) { - if (event.phase == TickEvent.Phase.START) Minecraft.getMinecraft().world?.let { world -> + if (event.phase == TickEvent.Phase.START) Minecraft.getInstance().world?.let { world -> // change target wind speed - if (world.worldInfo.worldTime >= nextChange) changeWind(world) + if (world.worldInfo.dayTime >= nextChange) changeWind(world) // change current wind speed val changeRate = if (world.isRaining) 0.015 else 0.005 @@ -132,5 +137,5 @@ object LeafWindTracker { } @SubscribeEvent - fun handleWorldLoad(event: WorldEvent.Load) { if (event.world.isRemote) changeWind(event.world) } + fun handleWorldLoad(event: WorldEvent.Load) { if (event.world.isRemote) changeWind(event.world.world) } } \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/client/render/EntityRisingSoulFX.kt b/src/main/kotlin/mods/betterfoliage/client/render/EntityRisingSoulFX.kt index 0950a9c..951f01f 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/EntityRisingSoulFX.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/EntityRisingSoulFX.kt @@ -1,22 +1,21 @@ package mods.betterfoliage.client.render -import mods.betterfoliage.BetterFoliageMod +import mods.betterfoliage.BetterFoliage import mods.betterfoliage.client.Client import mods.betterfoliage.client.config.Config import mods.octarinecore.client.render.AbstractEntityFX +import mods.octarinecore.client.resource.Atlas import mods.octarinecore.client.resource.ResourceHandler import mods.octarinecore.common.Double3 import mods.octarinecore.forEachPairIndexed import net.minecraft.client.renderer.BufferBuilder +import net.minecraft.util.ResourceLocation import net.minecraft.util.math.BlockPos import net.minecraft.util.math.MathHelper import net.minecraft.world.World -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly -import org.apache.logging.log4j.Level.INFO +import org.apache.logging.log4j.Level.DEBUG import java.util.* -@SideOnly(Side.CLIENT) class EntityRisingSoulFX(world: World, pos: BlockPos) : AbstractEntityFX(world, pos.x.toDouble() + 0.5, pos.y.toDouble() + 1.0, pos.z.toDouble() + 0.5) { @@ -26,14 +25,14 @@ AbstractEntityFX(world, pos.x.toDouble() + 0.5, pos.y.toDouble() + 1.0, pos.z.to init { motionY = 0.1 particleGravity = 0.0f - particleTexture = RisingSoulTextures.headIcons[rand.nextInt(256)] - particleMaxAge = MathHelper.floor((0.6 + 0.4 * rand.nextDouble()) * Config.risingSoul.lifetime * 20.0) + 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 + particleAge) % 64 + val phase = (initialPhase + age) % 64 velocity.setTo(cos[phase] * Config.risingSoul.perturb, 0.1, sin[phase] * Config.risingSoul.perturb) particleTrail.addFirst(currentPos.copy()) @@ -43,8 +42,8 @@ AbstractEntityFX(world, pos.x.toDouble() + 0.5, pos.y.toDouble() + 1.0, pos.z.to } override fun render(worldRenderer: BufferBuilder, partialTickTime: Float) { - var alpha = Config.risingSoul.opacity - if (particleAge > particleMaxAge - 40) alpha *= (particleMaxAge - particleAge) / 40.0f + var alpha = Config.risingSoul.opacity.toFloat() + if (age > maxAge - 40) alpha *= (maxAge - age) / 40.0f renderParticleQuad(worldRenderer, partialTickTime, size = Config.risingSoul.headSize * 0.25, @@ -54,7 +53,7 @@ AbstractEntityFX(world, pos.x.toDouble() + 0.5, pos.y.toDouble() + 1.0, pos.z.to var scale = Config.risingSoul.trailSize * 0.25 particleTrail.forEachPairIndexed { idx, current, previous -> scale *= Config.risingSoul.sizeDecay - alpha *= Config.risingSoul.opacityDecay + alpha *= Config.risingSoul.opacityDecay.toFloat() if (idx % Config.risingSoul.trailDensity == 0) renderParticleQuad(worldRenderer, partialTickTime, currentPos = current, prevPos = previous, @@ -66,12 +65,11 @@ AbstractEntityFX(world, pos.x.toDouble() + 0.5, pos.y.toDouble() + 1.0, pos.z.to } } -@SideOnly(Side.CLIENT) -object RisingSoulTextures : ResourceHandler(BetterFoliageMod.MOD_ID) { - val headIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/rising_soul_%d") - val trackIcon = iconStatic(BetterFoliageMod.LEGACY_DOMAIN, "blocks/soul_track") +object RisingSoulTextures : ResourceHandler(BetterFoliage.MOD_ID, BetterFoliage.modBus, targetAtlas = Atlas.PARTICLES) { + val headIcons = iconSet { idx -> ResourceLocation(BetterFoliage.MOD_ID, "rising_soul_$idx") } + val trackIcon = iconStatic(BetterFoliage.MOD_ID, "soul_track") override fun afterPreStitch() { - Client.log(INFO, "Registered ${headIcons.num} soul particle textures") + Client.log(DEBUG, "Registered ${headIcons.num} soul particle textures") } } \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/client/render/ModelColumn.kt b/src/main/kotlin/mods/betterfoliage/client/render/ModelColumn.kt index b3f2ea3..747efe3 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/ModelColumn.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/ModelColumn.kt @@ -5,7 +5,8 @@ import mods.betterfoliage.client.config.Config import mods.octarinecore.client.render.* import mods.octarinecore.common.Double3 import mods.octarinecore.exchange -import net.minecraft.util.EnumFacing.* +import net.minecraft.util.Direction +import net.minecraft.util.Direction.* import org.lwjgl.opengl.GL11 /** Weight of the same-side AO values on the outer edges of the 45deg chamfered column faces. */ @@ -25,10 +26,10 @@ fun Model.columnSide(radius: Double, yBottom: Double, yTop: Double, transform: ( verticalRectangle(x1 = 0.5 - radius, z1 = 0.5, x2 = 0.5 - halfRadius, z2 = 0.5 - halfRadius, yBottom = yBottom, yTop = yTop) .clampUV(minU = 0.5 - radius) .setAoShader( - faceOrientedAuto(overrideFace = SOUTH, corner = cornerInterpolate(Axis.Y, chamferAffinity, Config.roundLogs.dimming)) + faceOrientedAuto(overrideFace = SOUTH, corner = cornerInterpolate(Axis.Y, chamferAffinity, Config.roundLogs.dimming.toFloat())) ) .setAoShader( - faceOrientedAuto(overrideFace = SOUTH, corner = cornerInterpolate(Axis.Y, 0.5f, Config.roundLogs.dimming)), + faceOrientedAuto(overrideFace = SOUTH, corner = cornerInterpolate(Axis.Y, 0.5f, Config.roundLogs.dimming.toFloat())), predicate = { v, vi -> vi == 1 || vi == 2} ) ).forEach { transform(it.setFlatShader(FaceFlat(SOUTH))).add() } @@ -37,9 +38,9 @@ fun Model.columnSide(radius: Double, yBottom: Double, yTop: Double, transform: ( verticalRectangle(x1 = 0.5 - halfRadius, z1 = 0.5 - halfRadius, x2 = 0.5, z2 = 0.5 - radius, yBottom = yBottom, yTop = yTop) .clampUV(maxU = radius - 0.5) .setAoShader( - faceOrientedAuto(overrideFace = EAST, corner = cornerInterpolate(Axis.Y, chamferAffinity, Config.roundLogs.dimming))) + faceOrientedAuto(overrideFace = EAST, corner = cornerInterpolate(Axis.Y, chamferAffinity, Config.roundLogs.dimming.toFloat()))) .setAoShader( - faceOrientedAuto(overrideFace = EAST, corner = cornerInterpolate(Axis.Y, 0.5f, Config.roundLogs.dimming)), + faceOrientedAuto(overrideFace = EAST, corner = cornerInterpolate(Axis.Y, 0.5f, Config.roundLogs.dimming.toFloat())), predicate = { v, vi -> vi == 0 || vi == 3} ), diff --git a/src/main/kotlin/mods/betterfoliage/client/render/RenderAlgae.kt b/src/main/kotlin/mods/betterfoliage/client/render/RenderAlgae.kt index 4d4d49d..25b7f98 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/RenderAlgae.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/RenderAlgae.kt @@ -1,42 +1,46 @@ package mods.betterfoliage.client.render -import mods.betterfoliage.BetterFoliageMod +import mods.betterfoliage.BetterFoliage import mods.betterfoliage.client.Client +import mods.betterfoliage.client.config.BlockConfig import mods.betterfoliage.client.config.Config import mods.betterfoliage.client.integration.ShadersModIntegration import mods.octarinecore.client.render.* import mods.octarinecore.common.Int3 import mods.octarinecore.common.Rotation +import net.minecraft.block.Block import net.minecraft.block.material.Material import net.minecraft.client.renderer.BlockRendererDispatcher import net.minecraft.client.renderer.BufferBuilder +import net.minecraft.tags.BlockTags import net.minecraft.util.BlockRenderLayer -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly -import org.apache.logging.log4j.Level.INFO +import net.minecraft.util.ResourceLocation +import net.minecraft.world.biome.Biome +import net.minecraftforge.client.model.data.IModelData +import org.apache.logging.log4j.Level.DEBUG +import java.util.* -@SideOnly(Side.CLIENT) -class RenderAlgae : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) { +class RenderAlgae : AbstractBlockRenderingHandler(BetterFoliage.MOD_ID, BetterFoliage.modBus) { val noise = simplexNoise() - val algaeIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_algae_%d") - val algaeModels = modelSet(64, RenderGrass.grassTopQuads(Config.algae.heightMin, Config.algae.heightMax)) + val algaeIcons = iconSet { idx -> ResourceLocation(BetterFoliage.MOD_ID, "blocks/better_algae_$idx") } + val algaeModels = modelSet(64) { idx -> RenderGrass.grassTopQuads(Config.algae.heightMin, Config.algae.heightMax)(idx) } override fun afterPreStitch() { - Client.log(INFO, "Registered ${algaeIcons.num} algae textures") + Client.log(DEBUG, "Registered ${algaeIcons.num} algae textures") } override fun isEligible(ctx: BlockContext) = Config.enabled && Config.algae.enabled && ctx.blockState(up2).material == Material.WATER && ctx.blockState(up1).material == Material.WATER && - Config.blocks.dirt.matchesClass(ctx.block) && - ctx.biomeId in Config.algae.biomes && + BlockTags.DIRT_LIKE.contains(ctx.block) && + ctx.biome.category.let { it == Biome.Category.OCEAN || it == Biome.Category.BEACH || it == Biome.Category.RIVER } && noise[ctx.pos] < Config.algae.population - override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, layer: BlockRenderLayer): Boolean { - val baseRender = renderWorldBlockBase(ctx, dispatcher, renderer, layer) + override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, random: Random, modelData: IModelData, layer: BlockRenderLayer): Boolean { + val baseRender = renderWorldBlockBase(ctx, dispatcher, renderer, random, modelData, layer) if (!layer.isCutout) return baseRender modelRenderer.updateShading(Int3.zero, allFaces) diff --git a/src/main/kotlin/mods/betterfoliage/client/render/RenderCactus.kt b/src/main/kotlin/mods/betterfoliage/client/render/RenderCactus.kt index b0fd30a..78daf80 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/RenderCactus.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/RenderCactus.kt @@ -1,7 +1,8 @@ package mods.betterfoliage.client.render -import mods.betterfoliage.BetterFoliageMod +import mods.betterfoliage.BetterFoliage import mods.betterfoliage.client.Client +import mods.betterfoliage.client.config.BlockConfig import mods.betterfoliage.client.config.Config import mods.betterfoliage.client.render.column.ColumnTextureInfo import mods.betterfoliage.client.render.column.SimpleColumnInfo @@ -11,33 +12,32 @@ import mods.octarinecore.common.Int3 import mods.octarinecore.common.Rotation import mods.octarinecore.common.config.ModelTextureList import mods.octarinecore.common.config.SimpleBlockMatcher -import net.minecraft.block.BlockCactus -import net.minecraft.block.state.IBlockState +import net.minecraft.block.BlockState +import net.minecraft.block.CactusBlock import net.minecraft.client.renderer.BlockRendererDispatcher import net.minecraft.client.renderer.BufferBuilder import net.minecraft.util.BlockRenderLayer -import net.minecraft.util.EnumFacing.* -import net.minecraftforge.common.MinecraftForge -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly -import org.apache.logging.log4j.Level +import net.minecraft.util.Direction.* +import net.minecraft.util.ResourceLocation +import net.minecraftforge.client.model.data.IModelData +import org.apache.logging.log4j.Level.DEBUG +import java.util.* object StandardCactusRegistry : ModelRenderRegistryConfigurable() { - override val logger = BetterFoliageMod.logDetail - override val matchClasses = SimpleBlockMatcher(BlockCactus::class.java) + override val logger = BetterFoliage.logDetail + override val matchClasses = SimpleBlockMatcher(CactusBlock::class.java) override val modelTextures = listOf(ModelTextureList("block/cactus", "top", "bottom", "side")) - override fun processModel(state: IBlockState, textures: List) = SimpleColumnInfo.Key(logger, Axis.Y, textures) - init { MinecraftForge.EVENT_BUS.register(this) } + override fun processModel(state: BlockState, textures: List) = SimpleColumnInfo.Key(logger, Axis.Y, textures) + init { BetterFoliage.modBus.register(this) } } -@SideOnly(Side.CLIENT) -class RenderCactus : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) { +class RenderCactus : AbstractBlockRenderingHandler(BetterFoliage.MOD_ID, BetterFoliage.modBus) { val cactusStemRadius = 0.4375 val cactusArmRotation = listOf(NORTH, SOUTH, EAST, WEST).map { Rotation.rot90[it.ordinal] } - val iconCross = iconStatic(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_cactus") - val iconArm = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_cactus_arm_%d") + val iconCross = iconStatic(ResourceLocation(BetterFoliage.MOD_ID, "blocks/better_cactus")) + val iconArm = iconSet { idx -> ResourceLocation(BetterFoliage.MOD_ID, "blocks/better_cactus_arm_$idx") } val modelStem = model { horizontalRectangle(x1 = -cactusStemRadius, x2 = cactusStemRadius, z1 = -cactusStemRadius, z2 = cactusStemRadius, y = 0.5) @@ -68,20 +68,20 @@ class RenderCactus : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) { } override fun afterPreStitch() { - Client.log(Level.INFO, "Registered ${iconArm.num} cactus arm textures") + Client.log(DEBUG, "Registered ${iconArm.num} cactus arm textures") } override fun isEligible(ctx: BlockContext): Boolean = Config.enabled && Config.cactus.enabled && - Config.blocks.cactus.matchesClass(ctx.block) + StandardCactusRegistry[ctx] != null - override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, layer: BlockRenderLayer): Boolean { + override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, random: Random, modelData: IModelData, layer: BlockRenderLayer): Boolean { // render the whole block on the cutout layer if (!layer.isCutout) return false // get AO data modelRenderer.updateShading(Int3.zero, allFaces) - val icons = StandardCactusRegistry[ctx] ?: return renderWorldBlockBase(ctx, dispatcher, renderer, null) + val icons = StandardCactusRegistry[ctx] ?: return renderWorldBlockBase(ctx, dispatcher, renderer, random, modelData, null) modelRenderer.render( renderer, diff --git a/src/main/kotlin/mods/betterfoliage/client/render/RenderConnectedGrass.kt b/src/main/kotlin/mods/betterfoliage/client/render/RenderConnectedGrass.kt index 5484d36..a6586a0 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/RenderConnectedGrass.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/RenderConnectedGrass.kt @@ -1,36 +1,36 @@ package mods.betterfoliage.client.render -import mods.betterfoliage.BetterFoliageMod +import mods.betterfoliage.BetterFoliage +import mods.betterfoliage.client.config.BlockConfig import mods.betterfoliage.client.config.Config +import mods.betterfoliage.client.texture.GrassRegistry import mods.octarinecore.client.render.AbstractBlockRenderingHandler import mods.octarinecore.client.render.BlockContext -import mods.octarinecore.client.render.withOffset +import mods.octarinecore.client.render.offset import mods.octarinecore.common.Int3 import mods.octarinecore.common.forgeDirsHorizontal import mods.octarinecore.common.offset +import net.minecraft.block.Block import net.minecraft.client.renderer.BlockRendererDispatcher import net.minecraft.client.renderer.BufferBuilder +import net.minecraft.tags.BlockTags import net.minecraft.util.BlockRenderLayer -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly +import net.minecraftforge.client.model.data.IModelData +import java.util.* -@SideOnly(Side.CLIENT) -class RenderConnectedGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) { +class RenderConnectedGrass : AbstractBlockRenderingHandler(BetterFoliage.MOD_ID, BetterFoliage.modBus) { override fun isEligible(ctx: BlockContext) = Config.enabled && Config.connectedGrass.enabled && - Config.blocks.dirt.matchesClass(ctx.block) && - Config.blocks.grassClasses.matchesClass(ctx.block(up1)) && + BlockTags.DIRT_LIKE.contains(ctx.block) && + GrassRegistry[ctx, up1] != null && (Config.connectedGrass.snowEnabled || !ctx.blockState(up2).isSnow) - override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, layer: BlockRenderLayer): Boolean { + override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, random: Random, modelData: IModelData, layer: BlockRenderLayer): Boolean { // if the block sides are not visible anyway, render normally - if (forgeDirsHorizontal.all { ctx.blockState(it.offset).isOpaqueCube }) return renderWorldBlockBase(ctx, dispatcher, renderer, layer) + if (forgeDirsHorizontal.none { ctx.shouldSideBeRendered(it) }) return renderWorldBlockBase(ctx, dispatcher, renderer, random, modelData, layer) - if (ctx.isSurroundedBy { it.isOpaqueCube } ) return false - return ctx.withOffset(Int3.zero, up1) { - ctx.withOffset(up1, up2) { - renderWorldBlockBase(ctx, dispatcher, renderer, layer) - } + return ctx.offset(Int3.zero, up1).offset(up1, up2).let { offsetCtx -> + renderWorldBlockBase(offsetCtx, dispatcher, renderer, random, modelData, layer) } } } \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/client/render/RenderConnectedGrassLog.kt b/src/main/kotlin/mods/betterfoliage/client/render/RenderConnectedGrassLog.kt index ba0ef4e..4ca7650 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/RenderConnectedGrassLog.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/RenderConnectedGrassLog.kt @@ -1,36 +1,39 @@ package mods.betterfoliage.client.render -import mods.betterfoliage.BetterFoliageMod +import mods.betterfoliage.BetterFoliage +import mods.betterfoliage.client.config.BlockConfig import mods.betterfoliage.client.config.Config +import mods.betterfoliage.client.texture.GrassRegistry import mods.octarinecore.client.render.AbstractBlockRenderingHandler import mods.octarinecore.client.render.BlockContext -import mods.octarinecore.client.render.withOffset +import mods.octarinecore.client.render.offset import mods.octarinecore.common.Int3 import mods.octarinecore.common.offset +import net.minecraft.block.Block import net.minecraft.client.renderer.BlockRendererDispatcher import net.minecraft.client.renderer.BufferBuilder +import net.minecraft.tags.BlockTags import net.minecraft.util.BlockRenderLayer -import net.minecraft.util.EnumFacing.* -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly +import net.minecraft.util.Direction.* +import net.minecraftforge.client.model.data.IModelData +import java.util.* -@SideOnly(Side.CLIENT) -class RenderConnectedGrassLog : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) { +class RenderConnectedGrassLog : AbstractBlockRenderingHandler(BetterFoliage.MOD_ID, BetterFoliage.modBus) { val grassCheckDirs = listOf(EAST, WEST, NORTH, SOUTH) override fun isEligible(ctx: BlockContext) = Config.enabled && Config.roundLogs.enabled && Config.roundLogs.connectGrass && - Config.blocks.dirt.matchesClass(ctx.block) && - Config.blocks.logClasses.matchesClass(ctx.block(up1)) + BlockTags.DIRT_LIKE.contains(ctx.block) && + LogRegistry[ctx, up1] != null - override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, layer: BlockRenderLayer): Boolean { + override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, random: Random, modelData: IModelData, layer: BlockRenderLayer): Boolean { val grassDir = grassCheckDirs.find { - Config.blocks.grassClasses.matchesClass(ctx.block(it.offset)) - } ?: return renderWorldBlockBase(ctx, dispatcher, renderer, layer) + GrassRegistry[ctx, it.offset] != null + } ?: return renderWorldBlockBase(ctx, dispatcher, renderer, random, modelData, layer) - return ctx.withOffset(Int3.zero, grassDir.offset) { - renderWorldBlockBase(ctx, dispatcher, renderer, layer) + return ctx.offset(Int3.zero, grassDir.offset).let { offsetCtx -> + renderWorldBlockBase(offsetCtx, dispatcher, renderer, random, modelData, layer) } } } \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/client/render/RenderCoral.kt b/src/main/kotlin/mods/betterfoliage/client/render/RenderCoral.kt index 73758e6..0d9b60c 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/RenderCoral.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/RenderCoral.kt @@ -1,7 +1,8 @@ package mods.betterfoliage.client.render -import mods.betterfoliage.BetterFoliageMod +import mods.betterfoliage.BetterFoliage import mods.betterfoliage.client.Client +import mods.betterfoliage.client.config.BlockConfig import mods.betterfoliage.client.config.Config import mods.octarinecore.client.render.* import mods.octarinecore.common.Int3 @@ -12,19 +13,22 @@ import net.minecraft.block.material.Material import net.minecraft.client.renderer.BlockRendererDispatcher import net.minecraft.client.renderer.BufferBuilder import net.minecraft.util.BlockRenderLayer -import net.minecraft.util.EnumFacing.Axis -import net.minecraft.util.EnumFacing.UP -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly -import org.apache.logging.log4j.Level.INFO +import net.minecraft.util.Direction.Axis +import net.minecraft.util.Direction.UP +import net.minecraft.util.ResourceLocation +import net.minecraft.world.biome.Biome +import net.minecraftforge.api.distmarker.Dist +import net.minecraftforge.client.model.data.IModelData +import net.minecraftforge.fml.common.Mod +import org.apache.logging.log4j.Level.DEBUG +import java.util.* -@SideOnly(Side.CLIENT) -class RenderCoral : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) { +class RenderCoral : AbstractBlockRenderingHandler(BetterFoliage.MOD_ID, BetterFoliage.modBus) { val noise = simplexNoise() - val coralIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_coral_%d") - val crustIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_crust_%d") + val coralIcons = iconSet { idx -> ResourceLocation(BetterFoliage.MOD_ID, "blocks/better_coral_$idx") } + val crustIcons = iconSet { idx -> ResourceLocation(BetterFoliage.MOD_ID, "blocks/better_crust_$idx") } val coralModels = modelSet(64) { modelIdx -> verticalRectangle(x1 = -0.5, z1 = 0.5, x2 = 0.5, z2 = -0.5, yBottom = 0.0, yTop = 1.0) .scale(Config.coral.size).move(0.5 to UP) @@ -41,26 +45,26 @@ class RenderCoral : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) { } override fun afterPreStitch() { - Client.log(INFO, "Registered ${coralIcons.num} coral textures") - Client.log(INFO, "Registered ${crustIcons.num} coral crust textures") + Client.log(DEBUG, "Registered ${coralIcons.num} coral textures") + Client.log(DEBUG, "Registered ${crustIcons.num} coral crust textures") } override fun isEligible(ctx: BlockContext) = Config.enabled && Config.coral.enabled && (ctx.blockState(up2).material == Material.WATER || Config.coral.shallowWater) && ctx.blockState(up1).material == Material.WATER && - Config.blocks.sand.matchesClass(ctx.block) && - ctx.biomeId in Config.coral.biomes && + BlockConfig.sand.matchesClass(ctx.block) && + ctx.biome.category.let { it == Biome.Category.OCEAN || it == Biome.Category.BEACH } && noise[ctx.pos] < Config.coral.population - override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, layer: BlockRenderLayer): Boolean { - val baseRender = renderWorldBlockBase(ctx, dispatcher, renderer, layer) + override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, random: Random, modelData: IModelData, layer: BlockRenderLayer): Boolean { + val baseRender = renderWorldBlockBase(ctx, dispatcher, renderer, random, modelData, layer) if (!layer.isCutout) return baseRender modelRenderer.updateShading(Int3.zero, allFaces) forgeDirs.forEachIndexed { idx, face -> - if (!ctx.blockState(forgeDirOffsets[idx]).isOpaqueCube && blockContext.random(idx) < Config.coral.chance) { + if (!ctx.isNormalCube(forgeDirOffsets[idx]) && blockContext.random(idx) < Config.coral.chance) { var variation = blockContext.random(6) modelRenderer.render( renderer, diff --git a/src/main/kotlin/mods/betterfoliage/client/render/RenderGrass.kt b/src/main/kotlin/mods/betterfoliage/client/render/RenderGrass.kt index 218a206..ffcd88a 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/RenderGrass.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/RenderGrass.kt @@ -1,6 +1,6 @@ package mods.betterfoliage.client.render -import mods.betterfoliage.BetterFoliageMod +import mods.betterfoliage.BetterFoliage import mods.betterfoliage.client.Client import mods.betterfoliage.client.config.Config import mods.betterfoliage.client.integration.OptifineCustomColors @@ -9,17 +9,19 @@ import mods.betterfoliage.client.texture.GrassRegistry import mods.octarinecore.client.render.* import mods.octarinecore.common.* import mods.octarinecore.random +import net.minecraft.block.Block import net.minecraft.client.renderer.BlockRendererDispatcher import net.minecraft.client.renderer.BufferBuilder +import net.minecraft.tags.BlockTags import net.minecraft.util.BlockRenderLayer -import net.minecraft.util.EnumFacing.Axis -import net.minecraft.util.EnumFacing.UP -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly -import org.apache.logging.log4j.Level.INFO +import net.minecraft.util.Direction.Axis +import net.minecraft.util.Direction.* +import net.minecraft.util.ResourceLocation +import net.minecraftforge.client.model.data.IModelData +import org.apache.logging.log4j.Level.DEBUG +import java.util.* -@SideOnly(Side.CLIENT) -class RenderGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) { +class RenderGrass : AbstractBlockRenderingHandler(BetterFoliage.MOD_ID, BetterFoliage.modBus) { companion object { @JvmStatic fun grassTopQuads(heightMin: Double, heightMax: Double): Model.(Int)->Unit = { modelIdx -> @@ -34,16 +36,16 @@ class RenderGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) { val noise = simplexNoise() - val normalIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_grass_long_%d") - val snowedIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_grass_snowed_%d") - val normalGenIcon = iconStatic(Client.genGrass.generatedResource("minecraft:blocks/tallgrass", "snowed" to false)) - val snowedGenIcon = iconStatic(Client.genGrass.generatedResource("minecraft:blocks/tallgrass", "snowed" to true)) + val normalIcons = iconSet { idx -> ResourceLocation(BetterFoliage.MOD_ID, "blocks/better_grass_long_$idx") } + val snowedIcons = iconSet { idx -> ResourceLocation(BetterFoliage.MOD_ID, "blocks/better_grass_snowed_$idx") } + val normalGenIcon = iconStatic { Client.genGrass.register(texture = "minecraft:blocks/tallgrass", isSnowed = false) } + val snowedGenIcon = iconStatic { Client.genGrass.register(texture = "minecraft:blocks/tallgrass", isSnowed = true) } - val grassModels = modelSet(64, grassTopQuads(Config.shortGrass.heightMin, Config.shortGrass.heightMax)) + val grassModels = modelSet(64) { idx -> grassTopQuads(Config.shortGrass.heightMin, Config.shortGrass.heightMax)(idx) } override fun afterPreStitch() { - Client.log(INFO, "Registered ${normalIcons.num} grass textures") - Client.log(INFO, "Registered ${snowedIcons.num} snowed grass textures") + Client.log(DEBUG, "Registered ${normalIcons.num} grass textures") + Client.log(DEBUG, "Registered ${snowedIcons.num} snowed grass textures") } override fun isEligible(ctx: BlockContext) = @@ -51,14 +53,11 @@ class RenderGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) { (Config.shortGrass.grassEnabled || Config.connectedGrass.enabled) && GrassRegistry[ctx] != null - override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, layer: BlockRenderLayer): Boolean { + override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, random: Random, modelData: IModelData, layer: BlockRenderLayer): Boolean { // render the whole block on the cutout layer if (!layer.isCutout) return false - val isConnected = ctx.block(down1).let { - Config.blocks.dirt.matchesClass(it) || - Config.blocks.grassClasses.matchesClass(it) - } + val isConnected = BlockTags.DIRT_LIKE.contains(ctx.block(down1)) || GrassRegistry[ctx, down1] != null val isSnowed = ctx.blockState(up1).isSnow val connectedGrass = isConnected && Config.connectedGrass.enabled && (!isSnowed || Config.connectedGrass.snowEnabled) @@ -66,7 +65,7 @@ class RenderGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) { if (grass == null) { // shouldn't happen Client.logRenderError(ctx.blockState(Int3.zero), ctx.pos) - return renderWorldBlockBase(ctx, dispatcher, renderer, null) + return renderWorldBlockBase(ctx, dispatcher, renderer, random, modelData, null) } val blockColor = OptifineCustomColors.getBlockColor(ctx) @@ -75,14 +74,14 @@ class RenderGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) { modelRenderer.updateShading(Int3.zero, allFaces) // check occlusion - val isHidden = forgeDirs.map { ctx.blockState(it.offset).isOpaqueCube } + val isVisible = forgeDirs.map { ctx.shouldSideBeRendered(it) } // render full grass block ShadersModIntegration.renderAs(ctx.blockState(Int3.zero), renderer) { modelRenderer.render( renderer, fullCube, - quadFilter = { qi, _ -> !isHidden[qi] }, + quadFilter = { qi, _ -> isVisible[qi] }, icon = { _, _, _ -> grass.grassTopTexture }, postProcess = { ctx, _, _, _, _ -> rotateUV(2) @@ -93,7 +92,7 @@ class RenderGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) { ) } } else { - renderWorldBlockBase(ctx, dispatcher, renderer, null) + renderWorldBlockBase(ctx, dispatcher, renderer, random, modelData, null) // get AO data only for block top modelRenderer.updateShading(Int3.zero, topOnly) @@ -101,7 +100,7 @@ class RenderGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) { if (!Config.shortGrass.grassEnabled) return true if (isSnowed && !Config.shortGrass.snowEnabled) return true - if (ctx.blockState(up1).isOpaqueCube) return true + if (ctx.isNormalCube(up1)) return true if (Config.shortGrass.population < 64 && noise[ctx.pos] >= Config.shortGrass.population) return true // render grass quads diff --git a/src/main/kotlin/mods/betterfoliage/client/render/RenderLeaves.kt b/src/main/kotlin/mods/betterfoliage/client/render/RenderLeaves.kt index 0fcbc53..eeca63b 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/RenderLeaves.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/RenderLeaves.kt @@ -1,6 +1,6 @@ package mods.betterfoliage.client.render -import mods.betterfoliage.BetterFoliageMod +import mods.betterfoliage.BetterFoliage import mods.betterfoliage.client.Client import mods.betterfoliage.client.config.Config import mods.betterfoliage.client.integration.OptifineCustomColors @@ -17,15 +17,14 @@ import net.minecraft.block.material.Material import net.minecraft.client.renderer.BlockRendererDispatcher import net.minecraft.client.renderer.BufferBuilder import net.minecraft.util.BlockRenderLayer -import net.minecraft.util.EnumFacing.DOWN -import net.minecraft.util.EnumFacing.UP -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly +import net.minecraft.util.Direction.* +import net.minecraft.util.ResourceLocation +import net.minecraftforge.client.model.data.IModelData import java.lang.Math.cos import java.lang.Math.sin +import java.util.* -@SideOnly(Side.CLIENT) -class RenderLeaves : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) { +class RenderLeaves : AbstractBlockRenderingHandler(BetterFoliage.MOD_ID, BetterFoliage.modBus) { val leavesModel = model { verticalRectangle(x1 = -0.5, z1 = 0.5, x2 = 0.5, z2 = -0.5, yBottom = -0.5 * 1.41, yTop = 0.5 * 1.41) @@ -34,7 +33,7 @@ class RenderLeaves : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) { .scale(Config.leaves.size) .toCross(UP).addAll() } - val snowedIcon = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_leaves_snowed_%d") + val snowedIcon = iconSet { idx -> ResourceLocation(BetterFoliage.MOD_ID, "blocks/better_leaves_snowed_$idx") } val perturbs = vectorSet(64) { idx -> val angle = PI2 * idx / 64.0 @@ -46,21 +45,19 @@ class RenderLeaves : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) { Config.enabled && Config.leaves.enabled && LeafRegistry[ctx] != null && - !(Config.leaves.hideInternal && ctx.isSurroundedBy { it.isFullCube || it.material == Material.LEAVES } ) + !(Config.leaves.hideInternal && ctx.isSurroundedByNormal) - override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, layer: BlockRenderLayer): Boolean { - val isSnowed = ctx.blockState(up1).material.let { - it == Material.SNOW || it == Material.CRAFTED_SNOW - } + override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, random: Random, modelData: IModelData, layer: BlockRenderLayer): Boolean { + val isSnowed = ctx.blockState(up1).isSnow val leafInfo = LeafRegistry[ctx] if (leafInfo == null) { // shouldn't happen Client.logRenderError(ctx.blockState(Int3.zero), ctx.pos) - return renderWorldBlockBase(ctx, dispatcher, renderer, layer) + return renderWorldBlockBase(ctx, dispatcher, renderer, random, modelData, layer) } val blockColor = OptifineCustomColors.getBlockColor(ctx) - renderWorldBlockBase(ctx, dispatcher, renderer, layer) + renderWorldBlockBase(ctx, dispatcher, renderer, random, modelData, layer) if (!layer.isCutout) return true modelRenderer.updateShading(Int3.zero, allFaces) diff --git a/src/main/kotlin/mods/betterfoliage/client/render/RenderLilypad.kt b/src/main/kotlin/mods/betterfoliage/client/render/RenderLilypad.kt index 75bd24f..a74fa31 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/RenderLilypad.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/RenderLilypad.kt @@ -1,7 +1,8 @@ package mods.betterfoliage.client.render -import mods.betterfoliage.BetterFoliageMod +import mods.betterfoliage.BetterFoliage import mods.betterfoliage.client.Client +import mods.betterfoliage.client.config.BlockConfig import mods.betterfoliage.client.config.Config import mods.betterfoliage.client.integration.ShadersModIntegration import mods.octarinecore.client.render.* @@ -10,14 +11,14 @@ import mods.octarinecore.common.Rotation import net.minecraft.client.renderer.BlockRendererDispatcher import net.minecraft.client.renderer.BufferBuilder import net.minecraft.util.BlockRenderLayer -import net.minecraft.util.EnumFacing.DOWN -import net.minecraft.util.EnumFacing.UP -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly -import org.apache.logging.log4j.Level +import net.minecraft.util.Direction.DOWN +import net.minecraft.util.Direction.UP +import net.minecraft.util.ResourceLocation +import net.minecraftforge.client.model.data.IModelData +import org.apache.logging.log4j.Level.DEBUG +import java.util.* -@SideOnly(Side.CLIENT) -class RenderLilypad : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) { +class RenderLilypad : AbstractBlockRenderingHandler(BetterFoliage.MOD_ID, BetterFoliage.modBus) { val rootModel = model { verticalRectangle(x1 = -0.5, z1 = 0.5, x2 = 0.5, z2 = -0.5, yBottom = -1.5, yTop = -0.5) @@ -30,24 +31,24 @@ class RenderLilypad : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) { .setFlatShader(FlatOffsetNoColor(Int3.zero)) .toCross(UP).addAll() } - val rootIcon = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_lilypad_roots_%d") - val flowerIcon = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_lilypad_flower_%d") + val rootIcon = iconSet { idx -> ResourceLocation(BetterFoliage.MOD_ID, "blocks/better_lilypad_roots_$idx") } + val flowerIcon = iconSet { idx -> ResourceLocation(BetterFoliage.MOD_ID, "blocks/better_lilypad_flower_$idx") } val perturbs = vectorSet(64) { modelIdx -> xzDisk(modelIdx) * Config.lilypad.hOffset } override fun afterPreStitch() { - Client.log(Level.INFO, "Registered ${rootIcon.num} lilypad root textures") - Client.log(Level.INFO, "Registered ${flowerIcon.num} lilypad flower textures") + Client.log(DEBUG, "Registered ${rootIcon.num} lilypad root textures") + Client.log(DEBUG, "Registered ${flowerIcon.num} lilypad flower textures") } override fun isEligible(ctx: BlockContext): Boolean = Config.enabled && Config.lilypad.enabled && - Config.blocks.lilypad.matchesClass(ctx.block) + BlockConfig.lilypad.matchesClass(ctx.block) - override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, layer: BlockRenderLayer): Boolean { + override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, random: Random, modelData: IModelData, layer: BlockRenderLayer): Boolean { // render the whole block on the cutout layer if (!layer.isCutout) return false - renderWorldBlockBase(ctx, dispatcher, renderer, null) + renderWorldBlockBase(ctx, dispatcher, renderer, random, modelData, null) modelRenderer.updateShading(Int3.zero, allFaces) val rand = ctx.semiRandomArray(5) diff --git a/src/main/kotlin/mods/betterfoliage/client/render/RenderLog.kt b/src/main/kotlin/mods/betterfoliage/client/render/RenderLog.kt index 8e1fdc3..449079b 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/RenderLog.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/RenderLog.kt @@ -1,30 +1,32 @@ package mods.betterfoliage.client.render -import mods.betterfoliage.BetterFoliageMod +import mods.betterfoliage.BetterFoliage import mods.betterfoliage.client.chunk.ChunkOverlayManager +import mods.betterfoliage.client.config.BlockConfig import mods.betterfoliage.client.config.Config import mods.betterfoliage.client.render.column.AbstractRenderColumn import mods.betterfoliage.client.render.column.ColumnRenderLayer import mods.betterfoliage.client.render.column.ColumnTextureInfo import mods.betterfoliage.client.render.column.SimpleColumnInfo +import mods.betterfoliage.client.texture.GrassRegistry import mods.octarinecore.client.render.BlockContext -import mods.octarinecore.client.resource.* +import mods.octarinecore.client.resource.ModelRenderRegistry +import mods.octarinecore.client.resource.ModelRenderRegistryConfigurable +import mods.octarinecore.client.resource.ModelRenderRegistryRoot import mods.octarinecore.common.config.ConfigurableBlockMatcher import mods.octarinecore.common.config.ModelTextureList import mods.octarinecore.tryDefault -import net.minecraft.block.BlockLog -import net.minecraft.block.state.IBlockState -import net.minecraft.util.EnumFacing.Axis -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly +import net.minecraft.block.BlockState +import net.minecraft.block.LogBlock +import net.minecraft.util.Direction.Axis -class RenderLog : AbstractRenderColumn(BetterFoliageMod.MOD_ID) { +class RenderLog : AbstractRenderColumn(BetterFoliage.MOD_ID, BetterFoliage.modBus) { override val addToCutout: Boolean get() = false override fun isEligible(ctx: BlockContext) = Config.enabled && Config.roundLogs.enabled && - Config.blocks.logClasses.matchesClass(ctx.block) + LogRegistry[ctx] != null override val overlayLayer = RoundLogOverlayLayer() override val connectPerpendicular: Boolean get() = Config.roundLogs.connectPerpendicular @@ -37,26 +39,26 @@ class RenderLog : AbstractRenderColumn(BetterFoliageMod.MOD_ID) { class RoundLogOverlayLayer : ColumnRenderLayer() { override val registry: ModelRenderRegistry get() = LogRegistry - override val blockPredicate = { state: IBlockState -> Config.blocks.logClasses.matchesClass(state.block) } - override val surroundPredicate = { state: IBlockState -> state.isOpaqueCube && !Config.blocks.logClasses.matchesClass(state.block) } + override val blockPredicate = { state: BlockState -> BlockConfig.logBlocks.matchesClass(state.block) } + override val surroundPredicate = { state: BlockState -> !BlockConfig.logBlocks.matchesClass(state.block) } override val connectSolids: Boolean get() = Config.roundLogs.connectSolids override val lenientConnect: Boolean get() = Config.roundLogs.lenientConnect override val defaultToY: Boolean get() = Config.roundLogs.defaultY } -@SideOnly(Side.CLIENT) object LogRegistry : ModelRenderRegistryRoot() object StandardLogRegistry : ModelRenderRegistryConfigurable() { - override val logger = BetterFoliageMod.logDetail - override val matchClasses: ConfigurableBlockMatcher get() = Config.blocks.logClasses - override val modelTextures: List get() = Config.blocks.logModels.list - override fun processModel(state: IBlockState, textures: List) = SimpleColumnInfo.Key(logger, getAxis(state), textures) + override val logger = BetterFoliage.logDetail + override val matchClasses: ConfigurableBlockMatcher get() = BlockConfig.logBlocks + override val modelTextures: List get() = BlockConfig.logModels.modelList + override fun processModel(state: BlockState, textures: List) = SimpleColumnInfo.Key(logger, getAxis(state), textures) + init { BetterFoliage.modBus.register(this) } - fun getAxis(state: IBlockState): Axis? { - val axis = tryDefault(null) { state.getValue(BlockLog.LOG_AXIS).toString() } ?: - state.properties.entries.find { it.key.getName().toLowerCase() == "axis" }?.value?.toString() + 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 diff --git a/src/main/kotlin/mods/betterfoliage/client/render/RenderMycelium.kt b/src/main/kotlin/mods/betterfoliage/client/render/RenderMycelium.kt index 24b0d4a..89e2d7a 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/RenderMycelium.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/RenderMycelium.kt @@ -1,7 +1,8 @@ package mods.betterfoliage.client.render -import mods.betterfoliage.BetterFoliageMod +import mods.betterfoliage.BetterFoliage import mods.betterfoliage.client.Client +import mods.betterfoliage.client.config.BlockConfig import mods.betterfoliage.client.config.Config import mods.octarinecore.client.render.AbstractBlockRenderingHandler import mods.octarinecore.client.render.BlockContext @@ -12,35 +13,35 @@ import mods.octarinecore.common.Rotation import net.minecraft.client.renderer.BlockRendererDispatcher import net.minecraft.client.renderer.BufferBuilder import net.minecraft.util.BlockRenderLayer -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly -import org.apache.logging.log4j.Level.INFO +import net.minecraft.util.ResourceLocation +import net.minecraftforge.client.model.data.IModelData +import org.apache.logging.log4j.Level.DEBUG +import java.util.* -@SideOnly(Side.CLIENT) -class RenderMycelium : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) { +class RenderMycelium : AbstractBlockRenderingHandler(BetterFoliage.MOD_ID, BetterFoliage.modBus) { - val myceliumIcon = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_mycel_%d") - val myceliumModel = modelSet(64, RenderGrass.grassTopQuads(Config.shortGrass.heightMin, Config.shortGrass.heightMax)) + val myceliumIcon = iconSet { idx -> ResourceLocation(BetterFoliage.MOD_ID, "blocks/better_mycel_$idx") } + val myceliumModel = modelSet(64) { idx -> RenderGrass.grassTopQuads(Config.shortGrass.heightMin, Config.shortGrass.heightMax)(idx) } override fun afterPreStitch() { - Client.log(INFO, "Registered ${myceliumIcon.num} mycelium textures") + Client.log(DEBUG, "Registered ${myceliumIcon.num} mycelium textures") } override fun isEligible(ctx: BlockContext): Boolean { if (!Config.enabled || !Config.shortGrass.myceliumEnabled) return false - return Config.blocks.mycelium.matchesClass(ctx.block) + return BlockConfig.mycelium.matchesClass(ctx.block) } - override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, layer: BlockRenderLayer): Boolean { + override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, random: Random, modelData: IModelData, layer: BlockRenderLayer): Boolean { // render the whole block on the cutout layer if (!layer.isCutout) return false val isSnowed = ctx.blockState(up1).isSnow - renderWorldBlockBase(ctx, dispatcher, renderer, null) + renderWorldBlockBase(ctx, dispatcher, renderer, random, modelData, null) if (isSnowed && !Config.shortGrass.snowEnabled) return true - if (ctx.blockState(up1).isOpaqueCube) return true + if (ctx.isNormalCube(up1)) return true val rand = ctx.semiRandomArray(2) modelRenderer.render( diff --git a/src/main/kotlin/mods/betterfoliage/client/render/RenderNetherrack.kt b/src/main/kotlin/mods/betterfoliage/client/render/RenderNetherrack.kt index 2ef9df1..8cbf528 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/RenderNetherrack.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/RenderNetherrack.kt @@ -1,7 +1,8 @@ package mods.betterfoliage.client.render -import mods.betterfoliage.BetterFoliageMod +import mods.betterfoliage.BetterFoliage import mods.betterfoliage.client.Client +import mods.betterfoliage.client.config.BlockConfig import mods.betterfoliage.client.config.Config import mods.octarinecore.client.render.* import mods.octarinecore.common.Int3 @@ -10,15 +11,16 @@ import mods.octarinecore.random import net.minecraft.client.renderer.BlockRendererDispatcher import net.minecraft.client.renderer.BufferBuilder import net.minecraft.util.BlockRenderLayer -import net.minecraft.util.EnumFacing.* -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly -import org.apache.logging.log4j.Level.INFO +import net.minecraft.util.Direction.Axis +import net.minecraft.util.Direction.* +import net.minecraft.util.ResourceLocation +import net.minecraftforge.client.model.data.IModelData +import org.apache.logging.log4j.Level.DEBUG +import java.util.* -@SideOnly(Side.CLIENT) -class RenderNetherrack : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) { +class RenderNetherrack : AbstractBlockRenderingHandler(BetterFoliage.MOD_ID, BetterFoliage.modBus) { - val netherrackIcon = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_netherrack_%d") + val netherrackIcon = iconSet { idx -> ResourceLocation(BetterFoliage.MOD_ID, "blocks/better_netherrack_$idx") } val netherrackModel = modelSet(64) { modelIdx -> verticalRectangle(x1 = -0.5, z1 = 0.5, x2 = 0.5, z2 = -0.5, yTop = -0.5, yBottom = -0.5 - random(Config.netherrack.heightMin, Config.netherrack.heightMax)) @@ -29,19 +31,19 @@ class RenderNetherrack : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) } override fun afterPreStitch() { - Client.log(INFO, "Registered ${netherrackIcon.num} netherrack textures") + Client.log(DEBUG, "Registered ${netherrackIcon.num} netherrack textures") } override fun isEligible(ctx: BlockContext): Boolean { if (!Config.enabled || !Config.netherrack.enabled) return false - return Config.blocks.netherrack.matchesClass(ctx.block) + return BlockConfig.netherrack.matchesClass(ctx.block) } - override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, layer: BlockRenderLayer): Boolean { - val baseRender = renderWorldBlockBase(ctx, dispatcher, renderer, layer) + override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, random: Random, modelData: IModelData, layer: BlockRenderLayer): Boolean { + val baseRender = renderWorldBlockBase(ctx, dispatcher, renderer, random, modelData, layer) if (!layer.isCutout) return baseRender - if (ctx.blockState(down1).isOpaqueCube) return baseRender + if (ctx.isNormalCube(down1)) return baseRender modelRenderer.updateShading(Int3.zero, allFaces) diff --git a/src/main/kotlin/mods/betterfoliage/client/render/RenderReeds.kt b/src/main/kotlin/mods/betterfoliage/client/render/RenderReeds.kt index a810d65..e33288c 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/RenderReeds.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/RenderReeds.kt @@ -1,27 +1,30 @@ package mods.betterfoliage.client.render -import mods.betterfoliage.BetterFoliageMod +import mods.betterfoliage.BetterFoliage import mods.betterfoliage.client.Client +import mods.betterfoliage.client.config.BlockConfig import mods.betterfoliage.client.config.Config import mods.betterfoliage.client.integration.ShadersModIntegration import mods.octarinecore.client.render.* import mods.octarinecore.common.Int3 import mods.octarinecore.common.Rotation import mods.octarinecore.random +import net.minecraft.block.Block import net.minecraft.block.material.Material import net.minecraft.client.renderer.BlockRendererDispatcher import net.minecraft.client.renderer.BufferBuilder +import net.minecraft.tags.BlockTags import net.minecraft.util.BlockRenderLayer -import net.minecraft.util.EnumFacing.UP -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly -import org.apache.logging.log4j.Level +import net.minecraft.util.Direction.UP +import net.minecraft.util.ResourceLocation +import net.minecraftforge.client.model.data.IModelData +import org.apache.logging.log4j.Level.DEBUG +import java.util.* -@SideOnly(Side.CLIENT) -class RenderReeds : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) { +class RenderReeds : AbstractBlockRenderingHandler(BetterFoliage.MOD_ID, BetterFoliage.modBus) { val noise = simplexNoise() - val reedIcons = iconSet(Client.genReeds.generatedResource("${BetterFoliageMod.LEGACY_DOMAIN}:blocks/better_reed_%d")) + val reedIcons = iconSet { idx -> Client.genReeds.registerResource(ResourceLocation(BetterFoliage.MOD_ID, "blocks/better_reed_$idx")) } val reedModels = modelSet(64) { modelIdx -> val height = random(Config.reed.heightMin, Config.reed.heightMax) val waterline = 0.875f @@ -41,19 +44,19 @@ class RenderReeds : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) { } override fun afterPreStitch() { - Client.log(Level.INFO, "Registered ${reedIcons.num} reed textures") + Client.log(DEBUG, "Registered ${reedIcons.num} reed textures") } override fun isEligible(ctx: BlockContext) = Config.enabled && Config.reed.enabled && ctx.blockState(up2).material == Material.AIR && ctx.blockState(up1).material == Material.WATER && - Config.blocks.dirt.matchesClass(ctx.block) && - ctx.biomeId in Config.reed.biomes && + BlockTags.DIRT_LIKE.contains(ctx.block) && + ctx.biome.let { it.downfall > Config.reed.minBiomeRainfall && it.defaultTemperature >= Config.reed.minBiomeTemp } && noise[ctx.pos] < Config.reed.population - override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, layer: BlockRenderLayer): Boolean { - val baseRender = renderWorldBlockBase(ctx, dispatcher, renderer, layer) + override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, random: Random, modelData: IModelData, layer: BlockRenderLayer): Boolean { + val baseRender = renderWorldBlockBase(ctx, dispatcher, renderer, random, modelData, layer) if (!layer.isCutout) return baseRender modelRenderer.updateShading(Int3.zero, allFaces) diff --git a/src/main/kotlin/mods/betterfoliage/client/render/Utils.kt b/src/main/kotlin/mods/betterfoliage/client/render/Utils.kt index ae4ffd6..3490d29 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/Utils.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/Utils.kt @@ -2,17 +2,20 @@ package mods.betterfoliage.client.render import mods.octarinecore.PI2 -import mods.octarinecore.client.render.* +import mods.octarinecore.client.render.Model +import mods.octarinecore.client.render.PostProcessLambda +import mods.octarinecore.client.render.Quad import mods.octarinecore.common.Double3 import mods.octarinecore.common.Int3 import mods.octarinecore.common.Rotation import mods.octarinecore.common.times -import net.minecraft.block.Block +import net.minecraft.block.BlockState import net.minecraft.block.material.Material -import net.minecraft.block.state.IBlockState import net.minecraft.util.BlockRenderLayer -import net.minecraft.util.EnumFacing -import net.minecraft.util.EnumFacing.* +import net.minecraft.util.Direction +import net.minecraft.util.Direction.* +import kotlin.math.cos +import kotlin.math.sin val up1 = Int3(1 to UP) val up2 = Int3(2 to UP) @@ -25,15 +28,15 @@ val denseLeavesRot = arrayOf(Rotation.identity, Rotation.rot90[EAST.ordinal], Ro val whitewash: PostProcessLambda = { _, _, _, _, _ -> setGrey(1.4f) } val greywash: PostProcessLambda = { _, _, _, _, _ -> setGrey(1.0f) } -val IBlockState.isSnow: Boolean get() = material.let { it == Material.SNOW || it == Material.CRAFTED_SNOW } +val BlockState.isSnow: Boolean get() = material.let { it == Material.SNOW } -fun Quad.toCross(rotAxis: EnumFacing, trans: (Quad)->Quad) = +fun Quad.toCross(rotAxis: Direction, trans: (Quad)->Quad) = (0..3).map { rotIdx -> trans(rotate(Rotation.rot90[rotAxis.ordinal] * rotIdx).mirrorUV(rotIdx > 1, false)) } -fun Quad.toCross(rotAxis: EnumFacing) = toCross(rotAxis) { it } +fun Quad.toCross(rotAxis: Direction) = toCross(rotAxis) { it } -fun xzDisk(modelIdx: Int) = (PI2 * modelIdx / 64.0).let { Double3(Math.cos(it), 0.0, Math.sin(it)) } +fun xzDisk(modelIdx: Int) = (PI2 * modelIdx / 64.0).let { Double3(cos(it), 0.0, sin(it)) } val rotationFromUp = arrayOf( Rotation.rot90[EAST.ordinal] * 2, @@ -58,5 +61,5 @@ fun Model.mix(first: Model, second: Model, predicate: (Int)->Boolean) { val BlockRenderLayer.isCutout: Boolean get() = (this == BlockRenderLayer.CUTOUT) || (this == BlockRenderLayer.CUTOUT_MIPPED) -fun IBlockState.canRenderInLayer(layer: BlockRenderLayer) = this.block.canRenderInLayer(this, layer) -fun IBlockState.canRenderInCutout() = this.block.canRenderInLayer(this, BlockRenderLayer.CUTOUT) || this.block.canRenderInLayer(this, BlockRenderLayer.CUTOUT_MIPPED) \ No newline at end of file +fun BlockState.canRenderInLayer(layer: BlockRenderLayer) = this.block.canRenderInLayer(this, layer) +fun BlockState.canRenderInCutout() = this.block.canRenderInLayer(this, BlockRenderLayer.CUTOUT) || this.block.canRenderInLayer(this, BlockRenderLayer.CUTOUT_MIPPED) \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/client/render/column/AbstractRenderer.kt b/src/main/kotlin/mods/betterfoliage/client/render/column/AbstractRenderer.kt index cd2bfc0..420caff 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/column/AbstractRenderer.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/column/AbstractRenderer.kt @@ -1,31 +1,29 @@ package mods.betterfoliage.client.render.column import mods.betterfoliage.client.Client -import mods.betterfoliage.client.chunk.ChunkOverlayLayer import mods.betterfoliage.client.chunk.ChunkOverlayManager -import mods.betterfoliage.client.config.Config import mods.betterfoliage.client.integration.ShadersModIntegration.renderAs import mods.betterfoliage.client.render.* import mods.betterfoliage.client.render.column.ColumnLayerData.SpecialRender.BlockType.* import mods.betterfoliage.client.render.column.ColumnLayerData.SpecialRender.QuadrantType import mods.betterfoliage.client.render.column.ColumnLayerData.SpecialRender.QuadrantType.* import mods.octarinecore.client.render.* -import mods.octarinecore.client.resource.ModelRenderRegistry -import mods.octarinecore.common.* -import net.minecraft.block.state.IBlockState +import mods.octarinecore.common.Int3 +import mods.octarinecore.common.Rotation +import mods.octarinecore.common.face +import mods.octarinecore.common.rot import net.minecraft.client.renderer.BlockRendererDispatcher import net.minecraft.client.renderer.BufferBuilder -import net.minecraft.client.renderer.texture.TextureAtlasSprite +import net.minecraft.client.renderer.chunk.ChunkRenderCache +import net.minecraft.client.world.ClientWorld import net.minecraft.util.BlockRenderLayer -import net.minecraft.util.EnumFacing.* -import net.minecraft.util.math.BlockPos -import net.minecraft.world.IBlockAccess -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly +import net.minecraft.util.Direction.* +import net.minecraftforge.client.model.data.IModelData +import net.minecraftforge.eventbus.api.IEventBus +import java.util.* -@SideOnly(Side.CLIENT) @Suppress("NOTHING_TO_INLINE") -abstract class AbstractRenderColumn(modId: String) : AbstractBlockRenderingHandler(modId) { +abstract class AbstractRenderColumn(modId: String, modBus: IEventBus) : AbstractBlockRenderingHandler(modId, modBus) { /** The rotations necessary to bring the models in position for the 4 quadrants */ val quadrantRotations = Array(4) { Rotation.rot90[UP.ordinal] * it } @@ -96,21 +94,21 @@ abstract class AbstractRenderColumn(modId: String) : AbstractBlockRenderingHandl q1 == q2 || ((q1 == SQUARE || q1 == INVISIBLE) && (q2 == SQUARE || q2 == INVISIBLE)) @Suppress("NON_EXHAUSTIVE_WHEN") - override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, layer: BlockRenderLayer): Boolean { + override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, random: Random, modelData: IModelData, layer: BlockRenderLayer): Boolean { - val roundLog = ChunkOverlayManager.get(overlayLayer, ctx.world!!, ctx.pos) + val roundLog = ChunkOverlayManager.get(overlayLayer, ctx.reader!!, ctx.pos) when(roundLog) { ColumnLayerData.SkipRender -> return true - ColumnLayerData.NormalRender -> return renderWorldBlockBase(ctx, dispatcher, renderer, null) + ColumnLayerData.NormalRender -> return renderWorldBlockBase(ctx, dispatcher, renderer, random, modelData, null) ColumnLayerData.ResolveError, null -> { Client.logRenderError(ctx.blockState(Int3.zero), ctx.pos) - return renderWorldBlockBase(ctx, dispatcher, renderer, null) + return renderWorldBlockBase(ctx, dispatcher, renderer, random, modelData, null) } } // 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 renderWorldBlockBase(ctx, dispatcher, renderer, null) + return renderWorldBlockBase(ctx, dispatcher, renderer, random, modelData, null) } // get AO data diff --git a/src/main/kotlin/mods/betterfoliage/client/render/column/OverlayLayer.kt b/src/main/kotlin/mods/betterfoliage/client/render/column/OverlayLayer.kt index a1a200e..778f1f7 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/column/OverlayLayer.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/column/OverlayLayer.kt @@ -2,6 +2,7 @@ package mods.betterfoliage.client.render.column import mods.betterfoliage.client.chunk.ChunkOverlayLayer import mods.betterfoliage.client.chunk.ChunkOverlayManager +import mods.betterfoliage.client.chunk.dimType import mods.betterfoliage.client.config.Config import mods.betterfoliage.client.render.column.ColumnLayerData.SpecialRender.BlockType.* import mods.betterfoliage.client.render.column.ColumnLayerData.SpecialRender.QuadrantType @@ -13,12 +14,11 @@ import mods.octarinecore.common.Int3 import mods.octarinecore.common.Rotation import mods.octarinecore.common.face import mods.octarinecore.common.plus -import net.minecraft.block.state.IBlockState -import net.minecraft.util.EnumFacing +import net.minecraft.block.BlockState +import net.minecraft.util.Direction.Axis +import net.minecraft.util.Direction.AxisDirection import net.minecraft.util.math.BlockPos -import net.minecraft.world.IBlockAccess -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly +import net.minecraft.world.IEnviromentBlockReader /** Index of SOUTH-EAST quadrant. */ const val SE = 0 @@ -32,13 +32,11 @@ const val SW = 3 /** * Sealed class hierarchy for all possible render outcomes */ -@SideOnly(Side.CLIENT) sealed class ColumnLayerData { /** * Data structure to cache texture and world neighborhood data relevant to column rendering */ @Suppress("ArrayInDataClass") // not used in comparisons anywhere - @SideOnly(Side.CLIENT) data class SpecialRender( val column: ColumnTextureInfo, val upType: BlockType, @@ -52,15 +50,12 @@ sealed class ColumnLayerData { } /** Column block should not be rendered at all */ - @SideOnly(Side.CLIENT) object SkipRender : ColumnLayerData() /** Column block must be rendered normally */ - @SideOnly(Side.CLIENT) object NormalRender : ColumnLayerData() /** Error while resolving render data, column block must be rendered normally */ - @SideOnly(Side.CLIENT) object ResolveError : ColumnLayerData() } @@ -68,29 +63,29 @@ sealed class ColumnLayerData { abstract class ColumnRenderLayer : ChunkOverlayLayer { abstract val registry: ModelRenderRegistry - abstract val blockPredicate: (IBlockState)->Boolean - abstract val surroundPredicate: (IBlockState) -> Boolean + abstract val blockPredicate: (BlockState)->Boolean + abstract val surroundPredicate: (BlockState) -> Boolean abstract val connectSolids: Boolean abstract val lenientConnect: Boolean abstract val defaultToY: Boolean val allNeighborOffsets = (-1..1).flatMap { offsetX -> (-1..1).flatMap { offsetY -> (-1..1).map { offsetZ -> Int3(offsetX, offsetY, offsetZ) }}} - override fun onBlockUpdate(world: IBlockAccess, pos: BlockPos) { - allNeighborOffsets.forEach { offset -> ChunkOverlayManager.clear(this, pos + offset) } + override fun onBlockUpdate(reader: IEnviromentBlockReader, pos: BlockPos) { + allNeighborOffsets.forEach { offset -> ChunkOverlayManager.clear(reader.dimType, this, pos + offset) } } - override fun calculate(world: IBlockAccess, pos: BlockPos) = calculate(BlockContext(world, pos)) + override fun calculate(reader: IEnviromentBlockReader, pos: BlockPos) = calculate(BlockContext(reader, pos)) fun calculate(ctx: BlockContext): ColumnLayerData { - if (ctx.isSurroundedBy(surroundPredicate)) return ColumnLayerData.SkipRender + if (ctx.isSurroundedBy(surroundPredicate) && ctx.isSurroundedByNormal) return ColumnLayerData.SkipRender val columnTextures = registry[ctx] ?: return ColumnLayerData.ResolveError // if log axis is not defined and "Default to vertical" config option is not set, render normally - val logAxis = columnTextures.axis ?: if (defaultToY) EnumFacing.Axis.Y else return ColumnLayerData.NormalRender + val logAxis = columnTextures.axis ?: if (defaultToY) Axis.Y else return ColumnLayerData.NormalRender // check log neighborhood - val baseRotation = rotationFromUp[(logAxis to EnumFacing.AxisDirection.POSITIVE).face.ordinal] + val baseRotation = rotationFromUp[(logAxis to AxisDirection.POSITIVE).face.ordinal] val upType = ctx.blockType(baseRotation, logAxis, Int3(0, 1, 0)) val downType = ctx.blockType(baseRotation, logAxis, Int3(0, -1, 0)) @@ -109,7 +104,7 @@ abstract class ColumnRenderLayer : ChunkOverlayLayer { } /** Fill the array of [QuadrantType]s based on the blocks to the sides of this one. */ - fun Array.checkNeighbors(ctx: BlockContext, rotation: Rotation, logAxis: EnumFacing.Axis, yOff: Int): Array { + fun Array.checkNeighbors(ctx: BlockContext, rotation: Rotation, logAxis: Axis, yOff: Int): Array { val blkS = ctx.blockType(rotation, logAxis, Int3(0, yOff, 1)) val blkE = ctx.blockType(rotation, logAxis, Int3(1, yOff, 0)) val blkN = ctx.blockType(rotation, logAxis, Int3(0, yOff, -1)) @@ -176,13 +171,13 @@ abstract class ColumnRenderLayer : ChunkOverlayLayer { /** * Get the type of the block at the given offset in a rotated reference frame. */ - fun BlockContext.blockType(rotation: Rotation, axis: EnumFacing.Axis, offset: Int3): ColumnLayerData.SpecialRender.BlockType { + fun BlockContext.blockType(rotation: Rotation, axis: Axis, offset: Int3): ColumnLayerData.SpecialRender.BlockType { val offsetRot = offset.rotate(rotation) val state = blockState(offsetRot) return if (!blockPredicate(state)) { - if (state.isOpaqueCube) SOLID else NONSOLID + if (isNormalCube(offsetRot)) SOLID else NONSOLID } else { - (registry[state, world!!, pos + offsetRot]?.axis ?: if (Config.roundLogs.defaultY) EnumFacing.Axis.Y else null)?.let { + (registry[state, reader!!, pos + offsetRot]?.axis ?: if (Config.roundLogs.defaultY) Axis.Y else null)?.let { if (it == axis) PARALLEL else PERPENDICULAR } ?: SOLID } diff --git a/src/main/kotlin/mods/betterfoliage/client/render/column/RenderData.kt b/src/main/kotlin/mods/betterfoliage/client/render/column/RenderData.kt index 6137182..3781c5f 100644 --- a/src/main/kotlin/mods/betterfoliage/client/render/column/RenderData.kt +++ b/src/main/kotlin/mods/betterfoliage/client/render/column/RenderData.kt @@ -4,25 +4,22 @@ import mods.octarinecore.client.render.QuadIconResolver import mods.octarinecore.client.render.blockContext import mods.octarinecore.client.resource.ModelRenderKey import mods.octarinecore.client.resource.get +import mods.octarinecore.client.resource.missingSprite import mods.octarinecore.common.rotate +import net.minecraft.client.renderer.texture.AtlasTexture import net.minecraft.client.renderer.texture.TextureAtlasSprite -import net.minecraft.client.renderer.texture.TextureMap -import net.minecraft.util.EnumFacing -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly +import net.minecraft.util.Direction.* import org.apache.logging.log4j.Logger -@SideOnly(Side.CLIENT) interface ColumnTextureInfo { - val axis: EnumFacing.Axis? + val axis: Axis? val top: QuadIconResolver val bottom: QuadIconResolver val side: QuadIconResolver } -@SideOnly(Side.CLIENT) open class SimpleColumnInfo( - override val axis: EnumFacing.Axis?, + override val axis: Axis?, val topTexture: TextureAtlasSprite, val bottomTexture: TextureAtlasSprite, val sideTextures: List @@ -34,17 +31,17 @@ open class SimpleColumnInfo( override val top: QuadIconResolver = { _, _, _ -> topTexture } override val bottom: QuadIconResolver = { _, _, _ -> bottomTexture } override val side: QuadIconResolver = { ctx, idx, _ -> - val worldFace = (if ((idx and 1) == 0) EnumFacing.SOUTH else EnumFacing.EAST).rotate(ctx.rotation) + val worldFace = (if ((idx and 1) == 0) SOUTH else EAST).rotate(ctx.rotation) val sideIdx = if (sideTextures.size > 1) (blockContext.random(1) + dirToIdx[worldFace.ordinal]) % sideTextures.size else 0 sideTextures[sideIdx] } - class Key(override val logger: Logger, val axis: EnumFacing.Axis?, val textures: List) : ModelRenderKey { - override fun resolveSprites(atlas: TextureMap) = SimpleColumnInfo( + class Key(override val logger: Logger, val axis: Axis?, val textures: List) : ModelRenderKey { + override fun resolveSprites(atlas: AtlasTexture) = SimpleColumnInfo( axis, - atlas[textures[0]] ?: atlas.missingSprite, - atlas[textures[1]] ?: atlas.missingSprite, - textures.drop(2).map { atlas[it] ?: atlas.missingSprite } + atlas[textures[0]] ?: missingSprite, + atlas[textures[1]] ?: missingSprite, + textures.drop(2).map { atlas[it] ?: missingSprite } ) } } \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/client/texture/GrassGenerator.kt b/src/main/kotlin/mods/betterfoliage/client/texture/GrassGenerator.kt index cbfd4b4..4eb6a27 100644 --- a/src/main/kotlin/mods/betterfoliage/client/texture/GrassGenerator.kt +++ b/src/main/kotlin/mods/betterfoliage/client/texture/GrassGenerator.kt @@ -2,7 +2,9 @@ package mods.betterfoliage.client.texture import mods.octarinecore.client.resource.* import net.minecraft.util.ResourceLocation +import net.minecraftforge.resource.VanillaResourceType.TEXTURES import java.awt.image.BufferedImage +import java.io.InputStream /** * Generate Short Grass textures from [Blocks.tallgrass] block textures. @@ -10,13 +12,16 @@ import java.awt.image.BufferedImage * * @param[domain] Resource domain of generator */ -class GrassGenerator(domain: String) : TextureGenerator(domain) { +class GrassGenerator(domain: String) : GeneratorBase(domain, TEXTURES) { - override fun generate(params: ParameterList): BufferedImage? { - val target = targetResource(params)!! - val isSnowed = params["snowed"]?.toBoolean() ?: false + override val locationMapper = Atlas.BLOCKS::unwrap - val baseTexture = resourceManager[target.second]?.loadImage() ?: return null + fun register(texture: String, isSnowed: Boolean) = registerResource(Key(ResourceLocation(texture), isSnowed)) + + override fun exists(key: Key) = resourceManager.hasResource(Atlas.BLOCKS.wrap(key.texture)) + + override fun get(key: Key): InputStream? { + val baseTexture = resourceManager[Atlas.BLOCKS.wrap(key.texture)]?.loadImage() ?: return null val result = BufferedImage(baseTexture.width, baseTexture.height, BufferedImage.TYPE_4BYTE_ABGR) val graphics = result.createGraphics() @@ -39,12 +44,14 @@ class GrassGenerator(domain: String) : TextureGenerator(domain) { } // blend with white if snowed - if (isSnowed && target.first == ResourceType.COLOR) { + if (key.isSnowed) { for (x in 0..result.width - 1) for (y in 0..result.height - 1) { result[x, y] = blendRGB(result[x, y], 16777215, 2, 3) } } - return result + return result.asStream } + + data class Key(val texture: ResourceLocation, val isSnowed: Boolean) } diff --git a/src/main/kotlin/mods/betterfoliage/client/texture/GrassRegistry.kt b/src/main/kotlin/mods/betterfoliage/client/texture/GrassRegistry.kt index 8c8ff50..c50051a 100644 --- a/src/main/kotlin/mods/betterfoliage/client/texture/GrassRegistry.kt +++ b/src/main/kotlin/mods/betterfoliage/client/texture/GrassRegistry.kt @@ -1,25 +1,15 @@ package mods.betterfoliage.client.texture -import mods.betterfoliage.BetterFoliageMod -import mods.betterfoliage.client.Client +import mods.betterfoliage.BetterFoliage +import mods.betterfoliage.client.config.BlockConfig import mods.betterfoliage.client.config.Config -import mods.octarinecore.client.render.BlockContext import mods.octarinecore.client.render.HSB import mods.octarinecore.client.resource.* -import mods.octarinecore.common.Int3 import mods.octarinecore.common.config.ConfigurableBlockMatcher -import mods.octarinecore.common.config.IBlockMatcher import mods.octarinecore.common.config.ModelTextureList -import mods.octarinecore.findFirst -import net.minecraft.block.state.IBlockState +import net.minecraft.block.BlockState +import net.minecraft.client.renderer.texture.AtlasTexture import net.minecraft.client.renderer.texture.TextureAtlasSprite -import net.minecraft.client.renderer.texture.TextureMap -import net.minecraft.util.EnumFacing -import net.minecraft.util.math.BlockPos -import net.minecraft.world.IBlockAccess -import net.minecraftforge.common.MinecraftForge -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly import org.apache.logging.log4j.Level import org.apache.logging.log4j.Logger import java.lang.Math.min @@ -43,16 +33,17 @@ class GrassInfo( object GrassRegistry : ModelRenderRegistryRoot() object StandardGrassRegistry : ModelRenderRegistryConfigurable() { - override val logger = BetterFoliageMod.logDetail - override val matchClasses: ConfigurableBlockMatcher get() = Config.blocks.grassClasses - override val modelTextures: List get() = Config.blocks.grassModels.list - override fun processModel(state: IBlockState, textures: List) = StandardGrassKey(logger, textures[0]) + override val logger = BetterFoliage.logDetail + override val matchClasses: ConfigurableBlockMatcher get() = BlockConfig.grassBlocks + override val modelTextures: List get() = BlockConfig.grassModels.modelList + override fun processModel(state: BlockState, textures: List) = StandardGrassKey(logger, textures[0]) + init { BetterFoliage.modBus.register(this) } } class StandardGrassKey(override val logger: Logger, val textureName: String) : ModelRenderKey { - override fun resolveSprites(atlas: TextureMap): GrassInfo { + override fun resolveSprites(atlas: AtlasTexture): GrassInfo { val logName = "StandardGrassKey" - val texture = atlas[textureName] ?: atlas.missingSprite + val texture = atlas[textureName] ?: missingSprite logger.log(Level.DEBUG, "$logName: texture $textureName") val hsb = HSB.fromColor(texture.averageColor ?: defaultGrassColor) val overrideColor = if (hsb.saturation >= Config.shortGrass.saturationThreshold) { diff --git a/src/main/kotlin/mods/betterfoliage/client/texture/LeafGenerator.kt b/src/main/kotlin/mods/betterfoliage/client/texture/LeafGenerator.kt index 2c94caa..394d30e 100644 --- a/src/main/kotlin/mods/betterfoliage/client/texture/LeafGenerator.kt +++ b/src/main/kotlin/mods/betterfoliage/client/texture/LeafGenerator.kt @@ -1,10 +1,13 @@ package mods.betterfoliage.client.texture -import mods.betterfoliage.BetterFoliageMod +import mods.betterfoliage.BetterFoliage import mods.octarinecore.client.resource.* import mods.octarinecore.stripStart +import net.minecraft.resources.IResource import net.minecraft.util.ResourceLocation +import net.minecraftforge.resource.VanillaResourceType.TEXTURES import java.awt.image.BufferedImage +import java.io.InputStream /** * Generate round leaf textures from leaf block textures. @@ -14,22 +17,24 @@ import java.awt.image.BufferedImage * * @param[domain] Resource domain of generator */ -class LeafGenerator(domain: String) : TextureGenerator(domain) { +class LeafGenerator(domain: String) : GeneratorBase(domain, TEXTURES) { - override fun generate(params: ParameterList): BufferedImage? { - val target = targetResource(params)!! - val leafType = params["type"] ?: "default" + override val locationMapper = Atlas.BLOCKS::unwrap - val handDrawnLoc = target.second.stripStart("textures/").stripStart("blocks/").let { - ResourceLocation(BetterFoliageMod.DOMAIN, "${it.namespace}/textures/blocks/${it.path}") - } - resourceManager[handDrawnLoc]?.loadImage()?.let { return it } + fun register(texture: ResourceLocation, leafType: String) = registerResource(Key(texture, leafType)) - val baseTexture = resourceManager[target.second]?.loadImage() ?: return null + override fun exists(key: Key) = resourceManager.hasResource(Atlas.BLOCKS.wrap(key.texture)) + + override fun get(key: Key): InputStream? { + +// val handDrawnLoc = Atlas.BLOCKS.wrap(key.texture) +// resourceManager[handDrawnLoc]?.loadImage()?.let { return it.asStream } + + val baseTexture = resourceManager[Atlas.BLOCKS.wrap(key.texture)]?.loadImage() ?: return null val size = baseTexture.width val frames = baseTexture.height / size - val maskTexture = (getLeafMask(leafType, size * 2) ?: getLeafMask("default", size * 2))?.loadImage() + val maskTexture = (getLeafMask(key.leafType, size * 2) ?: getLeafMask("default", size * 2))?.loadImage() fun scale(i: Int) = i * maskTexture!!.width / (size * 2) val leafTexture = BufferedImage(size * 2, size * 2 * frames, BufferedImage.TYPE_4BYTE_ABGR) @@ -49,7 +54,7 @@ class LeafGenerator(domain: String) : TextureGenerator(domain) { } // overlay alpha mask - if (target.first == ResourceType.COLOR && maskTexture != null) { + if (maskTexture != null) { for (x in 0 .. size * 2 - 1) for (y in 0 .. size * 2 - 1) { val basePixel = leafFrame[x, y].toLong() and 0xFFFFFFFFL val maskPixel = maskTexture[scale(x), scale(y)].toLong() and 0xFF000000L or 0xFFFFFFL @@ -61,7 +66,7 @@ class LeafGenerator(domain: String) : TextureGenerator(domain) { graphics.drawImage(leafFrame, 0, size * frame * 2, null) } - return leafTexture + return leafTexture.asStream } /** @@ -71,7 +76,22 @@ class LeafGenerator(domain: String) : TextureGenerator(domain) { * @param[maxSize] Preferred mask size. */ fun getLeafMask(type: String, maxSize: Int) = getMultisizeTexture(maxSize) { size -> - ResourceLocation(BetterFoliageMod.DOMAIN, "textures/blocks/leafmask_${size}_${type}.png") + ResourceLocation(BetterFoliage.MOD_ID, "textures/blocks/leafmask_${size}_${type}.png") } + /** + * Get a texture resource when multiple sizes may exist. + * + * @param[maxSize] Maximum size to consider. This value is progressively halved when searching for smaller versions. + * @param[maskPath] Location of the texture of the given size + * + */ + fun getMultisizeTexture(maxSize: Int, maskPath: (Int)->ResourceLocation): IResource? { + var size = maxSize + val sizes = mutableListOf() + while(size > 2) { sizes.add(size); size /= 2 } + return sizes.map { resourceManager[maskPath(it)] }.filterNotNull().firstOrNull() + } + + data class Key(val texture: ResourceLocation, val leafType: String) } \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/client/texture/LeafParticleRegistry.kt b/src/main/kotlin/mods/betterfoliage/client/texture/LeafParticleRegistry.kt index 223c877..3577e03 100644 --- a/src/main/kotlin/mods/betterfoliage/client/texture/LeafParticleRegistry.kt +++ b/src/main/kotlin/mods/betterfoliage/client/texture/LeafParticleRegistry.kt @@ -1,40 +1,42 @@ package mods.betterfoliage.client.texture -import mods.betterfoliage.BetterFoliageMod +import mods.betterfoliage.BetterFoliage import mods.octarinecore.client.resource.* import mods.octarinecore.stripStart -import net.minecraft.client.renderer.texture.TextureAtlasSprite import net.minecraft.util.ResourceLocation import net.minecraftforge.client.event.TextureStitchEvent import net.minecraftforge.common.MinecraftForge -import net.minecraftforge.fml.common.eventhandler.EventPriority -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.eventbus.api.EventPriority +import net.minecraftforge.eventbus.api.SubscribeEvent object LeafParticleRegistry { + val targetAtlas = Atlas.PARTICLES val typeMappings = TextureMatcher() val particles = hashMapOf() operator fun get(type: String) = particles[type] ?: particles["default"]!! - init { MinecraftForge.EVENT_BUS.register(this) } - - @SubscribeEvent(priority = EventPriority.HIGH) - fun handleLoadModelData(event: LoadModelDataEvent) { - particles.clear() - typeMappings.loadMappings(ResourceLocation(BetterFoliageMod.DOMAIN, "leaf_texture_mappings.cfg")) - } + init { BetterFoliage.modBus.register(this) } @SubscribeEvent fun handlePreStitch(event: TextureStitchEvent.Pre) { + if (!targetAtlas.matches(event)) return + + particles.clear() + typeMappings.loadMappings(ResourceLocation(BetterFoliage.MOD_ID, "leaf_texture_mappings.cfg")) + val allTypes = (typeMappings.mappings.map { it.type } + "default").distinct() allTypes.forEach { leafType -> - val particleSet = IconSet("betterfoliage", "blocks/falling_leaf_${leafType}_%d").apply { onPreStitch(event.map) } + val particleSet = IconSet(Atlas.PARTICLES) { + idx -> ResourceLocation(BetterFoliage.MOD_ID, "falling_leaf_${leafType}_$idx") + }.apply { onPreStitch(event) } if (leafType == "default" || particleSet.num > 0) particles[leafType] = particleSet } } @SubscribeEvent fun handlePostStitch(event: TextureStitchEvent.Post) { + if (!targetAtlas.matches(event)) return particles.forEach { (_, particleSet) -> particleSet.onPostStitch(event.map) } } } diff --git a/src/main/kotlin/mods/betterfoliage/client/texture/LeafRegistry.kt b/src/main/kotlin/mods/betterfoliage/client/texture/LeafRegistry.kt index 445c3c9..db84d49 100644 --- a/src/main/kotlin/mods/betterfoliage/client/texture/LeafRegistry.kt +++ b/src/main/kotlin/mods/betterfoliage/client/texture/LeafRegistry.kt @@ -1,28 +1,16 @@ package mods.betterfoliage.client.texture -import mods.betterfoliage.BetterFoliageMod +import mods.betterfoliage.BetterFoliage import mods.betterfoliage.client.Client -import mods.betterfoliage.client.config.Config -import mods.octarinecore.client.render.BlockContext +import mods.betterfoliage.client.config.BlockConfig import mods.octarinecore.client.resource.* -import mods.octarinecore.common.Int3 import mods.octarinecore.common.config.ConfigurableBlockMatcher -import mods.octarinecore.common.config.IBlockMatcher import mods.octarinecore.common.config.ModelTextureList -import mods.octarinecore.findFirst -import net.minecraft.block.state.IBlockState +import net.minecraft.block.BlockState import net.minecraft.client.renderer.texture.TextureAtlasSprite -import net.minecraft.client.renderer.texture.TextureMap -import net.minecraft.util.EnumFacing +import net.minecraft.client.renderer.texture.AtlasTexture import net.minecraft.util.ResourceLocation -import net.minecraft.util.math.BlockPos -import net.minecraft.world.IBlockAccess import net.minecraftforge.client.event.TextureStitchEvent -import net.minecraftforge.common.MinecraftForge -import net.minecraftforge.fml.common.eventhandler.EventPriority -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import net.minecraftforge.fml.relauncher.Side -import net.minecraftforge.fml.relauncher.SideOnly import org.apache.logging.log4j.Level import org.apache.logging.log4j.Logger @@ -46,25 +34,26 @@ class LeafInfo( object LeafRegistry : ModelRenderRegistryRoot() object StandardLeafRegistry : ModelRenderRegistryConfigurable() { - override val logger = BetterFoliageMod.logDetail - override val matchClasses: ConfigurableBlockMatcher get() = Config.blocks.leavesClasses - override val modelTextures: List get() = Config.blocks.leavesModels.list - override fun processModel(state: IBlockState, textures: List) = StandardLeafKey(logger, textures[0]) + override val logger = BetterFoliage.logDetail + override val matchClasses: ConfigurableBlockMatcher get() = BlockConfig.leafBlocks + override val modelTextures: List get() = BlockConfig.leafModels.modelList + override fun processModel(state: BlockState, textures: List) = StandardLeafKey(logger, textures[0]) + init { BetterFoliage.modBus.register(this) } } class StandardLeafKey(override val logger: Logger, val textureName: String) : ModelRenderKey { lateinit var leafType: String lateinit var generated: ResourceLocation - override fun onPreStitch(atlas: TextureMap) { + override fun onPreStitch(event: TextureStitchEvent.Pre) { val logName = "StandardLeafKey" leafType = LeafParticleRegistry.typeMappings.getType(textureName) ?: "default" - generated = Client.genLeaves.generatedResource(textureName, "type" to leafType) - atlas.registerSprite(generated) + generated = Client.genLeaves.register(ResourceLocation(textureName), leafType) + event.addSprite(generated) logger.log(Level.DEBUG, "$logName: leaf texture $textureName") logger.log(Level.DEBUG, "$logName: particle $leafType") } - override fun resolveSprites(atlas: TextureMap) = LeafInfo(atlas[generated] ?: atlas.missingSprite, leafType) + override fun resolveSprites(atlas: AtlasTexture) = LeafInfo(atlas[generated] ?: missingSprite, leafType) } \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/loader/BetterFoliageCore.kt b/src/main/kotlin/mods/betterfoliage/loader/BetterFoliageCore.kt index 77a31e1..efd8a45 100644 --- a/src/main/kotlin/mods/betterfoliage/loader/BetterFoliageCore.kt +++ b/src/main/kotlin/mods/betterfoliage/loader/BetterFoliageCore.kt @@ -1,31 +1,23 @@ package mods.betterfoliage.loader -import mods.octarinecore.metaprog.Transformer +//import mods.octarinecore.metaprog.Transformer import mods.octarinecore.metaprog.allAvailable -import net.minecraftforge.fml.relauncher.FMLLaunchHandler -import org.objectweb.asm.ClassWriter import org.objectweb.asm.ClassWriter.COMPUTE_FRAMES import org.objectweb.asm.ClassWriter.COMPUTE_MAXS import org.objectweb.asm.Opcodes.* +/* class BetterFoliageTransformer : Transformer() { val isOptifinePresent = allAvailable(Refs.OptifineClassTransformer) init { - if (FMLLaunchHandler.side().isClient) setupClient() - } - - fun setupClient() { - // where: WorldClient.showBarrierParticles(), right after invoking Block.randomDisplayTick + // where: WorldClient.animateTick(), replacing invocation to Block.animateTick // what: invoke BF code for every random display tick - // why: allows us to catch random display ticks, without touching block code - transformMethod(Refs.showBarrierParticles) { - find(invokeRef(Refs.randomDisplayTick))?.insertAfter { + // why: allows us to catch random display ticks + transformMethod(Refs.WC_animeteTick) { + find(invokeRef(Refs.B_animateTick))?.replace { log.info("[BetterFoliageLoader] Applying random display tick call hook") - varinsn(ALOAD, 0) - varinsn(ALOAD, 11) - varinsn(ALOAD, 7) invokeStatic(Refs.onRandomDisplayTick) } ?: log.warn("[BetterFoliageLoader] Failed to apply random display tick call hook!") } @@ -58,9 +50,7 @@ class BetterFoliageTransformer : Transformer() { transformMethod(Refs.doesSideBlockRendering) { find(IRETURN)?.insertBefore { log.info("[BetterFoliageLoader] Applying doesSideBlockRendering() override") - varinsn(ALOAD, 1) - varinsn(ALOAD, 2) - varinsn(ALOAD, 3) + varinsn(ALOAD, 0) invokeStatic(Refs.doesSideBlockRenderingOverride) } ?: log.warn("[BetterFoliageLoader] Failed to apply doesSideBlockRendering() override!") } @@ -76,11 +66,11 @@ class BetterFoliageTransformer : Transformer() { } ?: log.warn("[BetterFoliageLoader] Failed to apply isOpaqueCube() override!") } - // where: ModelLoader.setupModelRegistry(), right before the textures are loaded - // what: invoke handler code with ModelLoader instance - // why: allows us to iterate the unbaked models in ModelLoader in time to register textures + // where: ModelBakery.setupModelRegistry(), after all models are loaded + // what: invoke handler code with ModelBakery instance + // why: allows us to iterate the unbaked models in ModelBakery in time to register textures transformMethod(Refs.setupModelRegistry) { - find(invokeName("addAll"))?.insertAfter { + find(invokeName("newLinkedHashSet"))?.insertBefore { log.info("[BetterFoliageLoader] Applying ModelLoader lifecycle callback") varinsn(ALOAD, 0) invokeStatic(Refs.onAfterLoadModelDefinitions) @@ -135,4 +125,6 @@ class BetterFoliageTransformer : Transformer() { } ?: log.warn("[BetterFoliageLoader] Failed to apply SVertexBuilder.pushEntity() block ID override!") } } -} \ No newline at end of file +} + + */ \ No newline at end of file diff --git a/src/main/kotlin/mods/betterfoliage/loader/Refs.kt b/src/main/kotlin/mods/betterfoliage/loader/Refs.kt index a6fd6ca..8b31663 100644 --- a/src/main/kotlin/mods/betterfoliage/loader/Refs.kt +++ b/src/main/kotlin/mods/betterfoliage/loader/Refs.kt @@ -3,11 +3,10 @@ package mods.betterfoliage.loader import mods.octarinecore.metaprog.ClassRef import mods.octarinecore.metaprog.FieldRef import mods.octarinecore.metaprog.MethodRef -import net.minecraftforge.fml.relauncher.FMLInjectionData /** Singleton object holding references to foreign code elements. */ object Refs { - val mcVersion = FMLInjectionData.data()[4].toString() +// val mcVersion = FMLInjectionData.data()[4].toString() // Java val String = ClassRef("java.lang.String") @@ -16,102 +15,44 @@ object Refs { val Random = ClassRef("java.util.Random") // Minecraft - val IBlockAccess = ClassRef("net.minecraft.world.IBlockAccess") - val IBlockState = ClassRef("net.minecraft.block.state.IBlockState") - val BlockStateBase = ClassRef("net.minecraft.block.state.BlockStateBase") + val IBlockReader = ClassRef("net.minecraft.world.IBlockReader") + val IEnvironmentBlockReader = ClassRef("net.minecraft.world.IEnvironmentBlockReader") + val BlockState = ClassRef("net.minecraft.block.state.BlockState") val BlockPos = ClassRef("net.minecraft.util.math.BlockPos") - val MutableBlockPos = ClassRef("net.minecraft.util.math.BlockPos\$MutableBlockPos") val BlockRenderLayer = ClassRef("net.minecraft.util.BlockRenderLayer") - val EnumFacing = ClassRef("net.minecraft.util.EnumFacing") - - val World = ClassRef("net.minecraft.world.World") - val WorldClient = ClassRef("net.minecraft.client.multiplayer.WorldClient") - val ChunkCache = ClassRef("net.minecraft.world.ChunkCache") - val showBarrierParticles = MethodRef(WorldClient, "showBarrierParticles", "func_184153_a", ClassRef.void, ClassRef.int, ClassRef.int, ClassRef.int, ClassRef.int, Random, ClassRef.boolean, MutableBlockPos) - val Block = ClassRef("net.minecraft.block.Block") - val StateImplementation = ClassRef("net.minecraft.block.state.BlockStateContainer\$StateImplementation") - val canRenderInLayer = MethodRef(Block, "canRenderInLayer", ClassRef.boolean, IBlockState, BlockRenderLayer) - val getAmbientOcclusionLightValue = MethodRef(StateImplementation, "getAmbientOcclusionLightValue", "func_185892_j", ClassRef.float) - val useNeighborBrightness = MethodRef(StateImplementation, "useNeighborBrightness", "func_185916_f", ClassRef.boolean) - val doesSideBlockRendering = MethodRef(StateImplementation, "doesSideBlockRendering", ClassRef.boolean, IBlockAccess, BlockPos, EnumFacing) - val isOpaqueCube = MethodRef(StateImplementation, "isOpaqueCube", "func_185914_p", ClassRef.boolean) - val randomDisplayTick = MethodRef(Block, "randomDisplayTick", "func_180655_c", ClassRef.void, IBlockState, World, BlockPos, Random) - - val BlockModelRenderer = ClassRef("net.minecraft.client.renderer.BlockModelRenderer") - val AmbientOcclusionFace = ClassRef("net.minecraft.client.renderer.BlockModelRenderer\$AmbientOcclusionFace") - val ChunkCompileTaskGenerator = ClassRef("net.minecraft.client.renderer.chunk.ChunkCompileTaskGenerator") val BufferBuilder = ClassRef("net.minecraft.client.renderer.BufferBuilder") - val AOF_constructor = MethodRef(AmbientOcclusionFace, "", ClassRef.void, BlockModelRenderer) - - val RenderChunk = ClassRef("net.minecraft.client.renderer.chunk.RenderChunk") - val rebuildChunk = MethodRef(RenderChunk, "rebuildChunk", "func_178581_b", ClassRef.void, ClassRef.float, ClassRef.float, ClassRef.float, ChunkCompileTaskGenerator) - val BlockRendererDispatcher = ClassRef("net.minecraft.client.renderer.BlockRendererDispatcher") - val renderBlock = MethodRef(BlockRendererDispatcher, "renderBlock", "func_175018_a", ClassRef.boolean, IBlockState, BlockPos, IBlockAccess, BufferBuilder) - + val ChunkCache = ClassRef("net.minecraft.client.renderer.chunk.ChunkRenderCache") val TextureAtlasSprite = ClassRef("net.minecraft.client.renderer.texture.TextureAtlasSprite") - - val IRegistry = ClassRef("net.minecraft.util.registry.IRegistry") - val ModelLoader = ClassRef("net.minecraftforge.client.model.ModelLoader") - val stateModels = FieldRef(ModelLoader, "stateModels", Map) - val setupModelRegistry = MethodRef(ModelLoader, "setupModelRegistry", "func_177570_a", IRegistry) - - val IModel = ClassRef("net.minecraftforge.client.model.IModel") - val ModelBlock = ClassRef("net.minecraft.client.renderer.block.model.ModelBlock") val ResourceLocation = ClassRef("net.minecraft.util.ResourceLocation") - val ModelResourceLocation = ClassRef("net.minecraft.client.renderer.block.model.ModelResourceLocation") - val VanillaModelWrapper = ClassRef("net.minecraftforge.client.model.ModelLoader\$VanillaModelWrapper") - val model_VMW = FieldRef(VanillaModelWrapper, "model", ModelBlock) - val location_VMW = FieldRef(VanillaModelWrapper, "location", ModelBlock) - val WeightedRandomModel = ClassRef("net.minecraftforge.client.model.ModelLoader\$WeightedRandomModel") - val models_WRM = FieldRef(WeightedRandomModel, "models", List) - val MultiModel = ClassRef("net.minecraftforge.client.model.MultiModel") - val base_MM = FieldRef(MultiModel, "base", IModel) - val MultipartModel = ClassRef("net.minecraftforge.client.model.ModelLoader\$MultipartModel") - val partModels_MPM = FieldRef(MultipartModel, "partModels", List) - - val BakedQuad = ClassRef("net.minecraft.client.renderer.block.model.BakedQuad") - - val resetChangedState = MethodRef(ClassRef("net.minecraftforge.common.config.Configuration"), "resetChangedState", ClassRef.void) - - - // Better Foliage - val BetterFoliageHooks = ClassRef("mods.betterfoliage.client.Hooks") - val getAmbientOcclusionLightValueOverride = MethodRef(BetterFoliageHooks, "getAmbientOcclusionLightValueOverride", ClassRef.float, ClassRef.float, IBlockState) - val useNeighborBrightnessOverride = MethodRef(BetterFoliageHooks, "getUseNeighborBrightnessOverride", ClassRef.boolean, ClassRef.boolean, IBlockState) - val doesSideBlockRenderingOverride = MethodRef(BetterFoliageHooks, "doesSideBlockRenderingOverride", ClassRef.boolean, ClassRef.boolean, IBlockAccess, BlockPos, EnumFacing) - val isOpaqueCubeOverride = MethodRef(BetterFoliageHooks, "isOpaqueCubeOverride", ClassRef.boolean, ClassRef.boolean, IBlockState) - val onRandomDisplayTick = MethodRef(BetterFoliageHooks, "onRandomDisplayTick", ClassRef.void, World, IBlockState, BlockPos) - val onAfterLoadModelDefinitions = MethodRef(BetterFoliageHooks, "onAfterLoadModelDefinitions", ClassRef.void, ModelLoader) - val onAfterBakeModels = MethodRef(BetterFoliageHooks, "onAfterBakeModels", ClassRef.void, Map) - val renderWorldBlock = MethodRef(BetterFoliageHooks, "renderWorldBlock", ClassRef.boolean, BlockRendererDispatcher, IBlockState, BlockPos, IBlockAccess, BufferBuilder, BlockRenderLayer) - val canRenderBlockInLayer = MethodRef(BetterFoliageHooks, "canRenderBlockInLayer", ClassRef.boolean, Block, IBlockState, BlockRenderLayer) // Optifine val OptifineClassTransformer = ClassRef("optifine.OptiFineClassTransformer") val OptifineChunkCache = ClassRef("net.optifine.override.ChunkCacheOF") val CCOFChunkCache = FieldRef(OptifineChunkCache, "chunkCache", ChunkCache) - val getBlockId = MethodRef(BlockStateBase, "getBlockId", ClassRef.int); - val getMetadata = MethodRef(BlockStateBase, "getMetadata", ClassRef.int); + val getBlockId = MethodRef(BlockState, "getBlockId", ClassRef.int); + val getMetadata = MethodRef(BlockState, "getMetadata", ClassRef.int); // Optifine val RenderEnv = ClassRef("net.optifine.render.RenderEnv") - val RenderEnv_reset = MethodRef(RenderEnv, "reset", ClassRef.void, IBlockAccess, IBlockState, BlockPos) + val RenderEnv_reset = MethodRef(RenderEnv, "reset", ClassRef.void, IBlockReader, BlockState, BlockPos) val quadSprite = FieldRef(BufferBuilder, "quadSprite", TextureAtlasSprite) + val BlockPosM = ClassRef("net.optifine.BlockPosM") + val IColorizer = ClassRef("net.optifine.CustomColors\$IColorizer") // Optifine: custom colors val CustomColors = ClassRef("net.optifine.CustomColors") - val getColorMultiplier = MethodRef(CustomColors, "getColorMultiplier", ClassRef.int, BakedQuad, IBlockState, IBlockAccess, BlockPos, RenderEnv) + val getColorMultiplier = MethodRef(CustomColors, "getSmoothColorMultiplier", ClassRef.int, BlockState, IEnvironmentBlockReader, BlockPos, IColorizer, BlockPosM) // Optifine: shaders val SVertexBuilder = ClassRef("net.optifine.shaders.SVertexBuilder") val sVertexBuilder = FieldRef(BufferBuilder, "sVertexBuilder", SVertexBuilder) - val pushEntity_state = MethodRef(SVertexBuilder, "pushEntity", ClassRef.void, IBlockState, BlockPos, IBlockAccess, BufferBuilder) + val pushEntity_state = MethodRef(SVertexBuilder, "pushEntity", ClassRef.void, BlockState, BlockPos, IBlockReader, BufferBuilder) val pushEntity_num = MethodRef(SVertexBuilder, "pushEntity", ClassRef.void, ClassRef.long) val popEntity = MethodRef(SVertexBuilder, "popEntity", ClassRef.void) val ShadersModIntegration = ClassRef("mods.betterfoliage.client.integration.ShadersModIntegration") - val getBlockIdOverride = MethodRef(ShadersModIntegration, "getBlockIdOverride", ClassRef.long, ClassRef.long, IBlockState) + val getBlockIdOverride = MethodRef(ShadersModIntegration, "getBlockIdOverride", ClassRef.long, ClassRef.long, BlockState) } \ No newline at end of file diff --git a/src/main/kotlin/mods/octarinecore/Utils.kt b/src/main/kotlin/mods/octarinecore/Utils.kt index e21f15d..4075ca1 100644 --- a/src/main/kotlin/mods/octarinecore/Utils.kt +++ b/src/main/kotlin/mods/octarinecore/Utils.kt @@ -6,19 +6,19 @@ import mods.betterfoliage.loader.Refs import net.minecraft.tileentity.TileEntity import net.minecraft.util.ResourceLocation import net.minecraft.util.math.BlockPos -import net.minecraft.world.ChunkCache -import net.minecraft.world.IBlockAccess -import net.minecraft.world.World +import net.minecraft.world.* import kotlin.reflect.KProperty import java.lang.Math.* const val PI2 = 2.0 * PI /** Strip the given prefix off the start of the string, if present */ -inline fun String.stripStart(str: String) = if (startsWith(str)) substring(str.length) else this +inline fun String.stripStart(str: String, ignoreCase: Boolean = true) = if (startsWith(str, ignoreCase)) substring(str.length) else this +inline fun String.stripEnd(str: String, ignoreCase: Boolean = true) = if (endsWith(str, ignoreCase)) substring(0, length - str.length) else this /** Strip the given prefix off the start of the resource path, if present */ inline fun ResourceLocation.stripStart(str: String) = ResourceLocation(namespace, path.stripStart(str)) +inline fun ResourceLocation.stripEnd(str: String) = ResourceLocation(namespace, path.stripEnd(str)) /** Mutating version of _map_. Replace each element of the list with the result of the given transformation. */ inline fun MutableList.replace(transform: (T) -> T) = forEachIndexed { idx, value -> this[idx] = transform(value) } @@ -104,17 +104,18 @@ fun nextPowerOf2(x: Int): Int { * Check if the Chunk containing the given [BlockPos] is loaded. * Works for both [World] and [ChunkCache] (vanilla and OptiFine) instances. */ -fun IBlockAccess.isBlockLoaded(pos: BlockPos) = when { - this is World -> isBlockLoaded(pos, false) - this is ChunkCache -> world.isBlockLoaded(pos, false) - Refs.OptifineChunkCache.isInstance(this) -> (Refs.CCOFChunkCache.get(this) as ChunkCache).world.isBlockLoaded(pos, false) - else -> false -} +//fun IWorldReader.isBlockLoaded(pos: BlockPos) = when { +// this is World -> isBlockLoaded(pos, false) +// this is RenderChunkCache -> isworld.isBlockLoaded(pos, false) +// Refs.OptifineChunkCache.isInstance(this) -> (Refs.CCOFChunkCache.get(this) as ChunkCache).world.isBlockLoaded(pos, false) +// else -> false +//} + /** * Get the [TileEntity] at the given position, suppressing exceptions. * Also returns null if the chunk is unloaded, which can happen because of multithreaded rendering. */ -fun IBlockAccess.getTileEntitySafe(pos: BlockPos): TileEntity? = tryDefault(null as TileEntity?) { +fun IWorldReader.getTileEntitySafe(pos: BlockPos): TileEntity? = tryDefault(null as TileEntity?) { if (isBlockLoaded(pos)) getTileEntity(pos) else null } \ No newline at end of file diff --git a/src/main/kotlin/mods/octarinecore/client/KeyHandler.kt b/src/main/kotlin/mods/octarinecore/client/KeyHandler.kt index a386678..f6edbad 100644 --- a/src/main/kotlin/mods/octarinecore/client/KeyHandler.kt +++ b/src/main/kotlin/mods/octarinecore/client/KeyHandler.kt @@ -1,10 +1,10 @@ package mods.octarinecore.client import net.minecraft.client.settings.KeyBinding +import net.minecraftforge.client.event.InputEvent +import net.minecraftforge.common.MinecraftForge +import net.minecraftforge.eventbus.api.SubscribeEvent import net.minecraftforge.fml.client.registry.ClientRegistry -import net.minecraftforge.fml.common.FMLCommonHandler -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import net.minecraftforge.fml.common.gameevent.InputEvent class KeyHandler(val modId: String, val defaultKey: Int, val lang: String, val action: (InputEvent.KeyInputEvent)->Unit) { @@ -12,7 +12,7 @@ class KeyHandler(val modId: String, val defaultKey: Int, val lang: String, val a init { ClientRegistry.registerKeyBinding(keyBinding) - FMLCommonHandler.instance().bus().register(this) + MinecraftForge.EVENT_BUS.register(this) } @SubscribeEvent diff --git a/src/main/kotlin/mods/octarinecore/client/gui/IdListConfigEntry.kt b/src/main/kotlin/mods/octarinecore/client/gui/IdListConfigEntry.kt deleted file mode 100644 index 590fe80..0000000 --- a/src/main/kotlin/mods/octarinecore/client/gui/IdListConfigEntry.kt +++ /dev/null @@ -1,61 +0,0 @@ -package mods.octarinecore.client.gui - -import net.minecraft.client.gui.GuiScreen -import net.minecraft.client.resources.I18n -import net.minecraft.util.text.TextFormatting.* -import net.minecraftforge.fml.client.config.* - -/** - * Base class for a config GUI element. - * The GUI representation is a list of toggleable objects. - * The config representation is an integer list of the selected objects' IDs. - */ -abstract class IdListConfigEntry( - owningScreen: GuiConfig, - owningEntryList: GuiConfigEntries, - configElement: IConfigElement -) : GuiConfigEntries.CategoryEntry(owningScreen, owningEntryList, configElement) { - - /** Create the child GUI elements. */ - fun createChildren() = baseSet.map { - ItemWrapperElement(it, it.itemId in configElement.list, it.itemId in configElement.defaults) - } - - init { stripTooltipDefaultText(toolTip as MutableList) } - - override fun buildChildScreen(): GuiScreen { - return GuiConfig( - this.owningScreen, - createChildren(), - this.owningScreen.modID, - owningScreen.allRequireWorldRestart || this.configElement.requiresWorldRestart(), - owningScreen.allRequireMcRestart || this.configElement.requiresMcRestart(), - this.owningScreen.title, - (if (this.owningScreen.titleLine2 == null) "" else this.owningScreen.titleLine2) + " > " + this.name) - } - - override fun saveConfigElement(): Boolean { - val requiresRestart = (childScreen as GuiConfig).entryList.saveConfigElements() - val children = (childScreen as GuiConfig).configElements as List - val ids = children.filter { it.booleanValue == true }.map { it.item.itemId } - configElement.set(ids.sorted().toTypedArray()) - return requiresRestart - } - - abstract val baseSet: List - abstract val T.itemId: Int - abstract val T.itemName: String - - /** Child config GUI element of a single toggleable object. */ - inner class ItemWrapperElement(val item: T, value: Boolean, val default: Boolean) : - DummyConfigElement(item.itemName, default, ConfigGuiType.BOOLEAN, item.itemName) { - - init { - this.value = value - this.defaultValue = default - } - - override fun getComment() = I18n.format("${configElement.languageKey}.tooltip.element", "${GOLD}${item.itemName}${YELLOW}") - val booleanValue: Boolean get() = defaultValue as Boolean - } -} \ No newline at end of file diff --git a/src/main/kotlin/mods/octarinecore/client/gui/NonVerboseArrayEntry.kt b/src/main/kotlin/mods/octarinecore/client/gui/NonVerboseArrayEntry.kt deleted file mode 100644 index 3cddf60..0000000 --- a/src/main/kotlin/mods/octarinecore/client/gui/NonVerboseArrayEntry.kt +++ /dev/null @@ -1,25 +0,0 @@ -package mods.octarinecore.client.gui - -import net.minecraft.client.resources.I18n -import net.minecraft.util.text.TextFormatting.* -import net.minecraftforge.fml.client.config.GuiConfig -import net.minecraftforge.fml.client.config.GuiConfigEntries -import net.minecraftforge.fml.client.config.IConfigElement - -class NonVerboseArrayEntry( - owningScreen: GuiConfig, - owningEntryList: GuiConfigEntries, - configElement: IConfigElement -) : GuiConfigEntries.ArrayEntry(owningScreen, owningEntryList, configElement) { - - init { - stripTooltipDefaultText(toolTip as MutableList) - val shortDefaults = I18n.format("${configElement.languageKey}.arrayEntry", configElement.defaults.size) - toolTip.addAll(mc.fontRenderer.listFormattedStringToWidth("$AQUA${I18n.format("fml.configgui.tooltip.default", shortDefaults)}", 300)) - } - - override fun updateValueButtonText() { - btnValue.displayString = I18n.format("${configElement.languageKey}.arrayEntry", currentValues.size) - } - -} \ No newline at end of file diff --git a/src/main/kotlin/mods/octarinecore/client/gui/Utils.kt b/src/main/kotlin/mods/octarinecore/client/gui/Utils.kt index b001332..4cfedbd 100644 --- a/src/main/kotlin/mods/octarinecore/client/gui/Utils.kt +++ b/src/main/kotlin/mods/octarinecore/client/gui/Utils.kt @@ -1,8 +1,8 @@ @file:JvmName("Utils") package mods.octarinecore.client.gui +import net.minecraft.util.text.StringTextComponent import net.minecraft.util.text.Style -import net.minecraft.util.text.TextComponentString import net.minecraft.util.text.TextFormatting import net.minecraft.util.text.TextFormatting.AQUA import net.minecraft.util.text.TextFormatting.GRAY @@ -16,7 +16,7 @@ fun stripTooltipDefaultText(tooltip: MutableList) { } } -fun textComponent(msg: String, color: TextFormatting = GRAY): TextComponentString { +fun textComponent(msg: String, color: TextFormatting = GRAY): StringTextComponent { val style = Style().apply { this.color = color } - return TextComponentString(msg).apply { this.style = style } + return StringTextComponent(msg).apply { this.style = style } } \ No newline at end of file diff --git a/src/main/kotlin/mods/octarinecore/client/render/AbstractBlockRenderingHandler.kt b/src/main/kotlin/mods/octarinecore/client/render/AbstractBlockRenderingHandler.kt index c244484..461d9c5 100644 --- a/src/main/kotlin/mods/octarinecore/client/render/AbstractBlockRenderingHandler.kt +++ b/src/main/kotlin/mods/octarinecore/client/render/AbstractBlockRenderingHandler.kt @@ -2,7 +2,6 @@ package mods.octarinecore.client.render import mods.betterfoliage.client.render.canRenderInCutout -import mods.betterfoliage.client.render.canRenderInLayer import mods.betterfoliage.client.render.isCutout import mods.octarinecore.ThreadLocalDelegate import mods.octarinecore.client.resource.ResourceHandler @@ -12,16 +11,21 @@ import mods.octarinecore.common.forgeDirOffsets import mods.octarinecore.common.plus import mods.octarinecore.semiRandom import net.minecraft.block.Block -import net.minecraft.block.state.IBlockState +import net.minecraft.block.BlockState import net.minecraft.client.Minecraft import net.minecraft.client.renderer.BlockRendererDispatcher import net.minecraft.client.renderer.BufferBuilder import net.minecraft.client.renderer.color.BlockColors import net.minecraft.util.BlockRenderLayer +import net.minecraft.util.Direction import net.minecraft.util.math.BlockPos import net.minecraft.util.math.MathHelper -import net.minecraft.world.IBlockAccess +import net.minecraft.world.IBlockReader +import net.minecraft.world.IEnviromentBlockReader import net.minecraft.world.biome.Biome +import net.minecraftforge.client.model.data.IModelData +import net.minecraftforge.eventbus.api.IEventBus +import java.util.* import kotlin.math.abs /** @@ -36,7 +40,7 @@ val modelRenderer by ThreadLocalDelegate { ModelRenderer() } val blockColors = ThreadLocal() -abstract class AbstractBlockRenderingHandler(modId: String) : ResourceHandler(modId) { +abstract class AbstractBlockRenderingHandler(modId: String, modBus: IEventBus) : ResourceHandler(modId, modBus) { open val addToCutout: Boolean get() = true @@ -44,7 +48,7 @@ abstract class AbstractBlockRenderingHandler(modId: String) : ResourceHandler(mo // Custom rendering // ============================ abstract fun isEligible(ctx: BlockContext): Boolean - abstract fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, layer: BlockRenderLayer): Boolean + abstract fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, random: Random, modelData: IModelData, layer: BlockRenderLayer): Boolean // ============================ // Vanilla rendering wrapper @@ -52,12 +56,12 @@ abstract class AbstractBlockRenderingHandler(modId: String) : ResourceHandler(mo /** * Render the block in the current [BlockContext] */ - fun renderWorldBlockBase(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, layer: BlockRenderLayer?): Boolean { + fun renderWorldBlockBase(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: BufferBuilder, random: Random, modelData: IModelData, layer: BlockRenderLayer?): Boolean { ctx.blockState(Int3.zero).let { state -> if (layer == null || state.canRenderInLayer(layer) || (state.canRenderInCutout() && layer.isCutout)) { - return dispatcher.renderBlock(state, ctx.pos, ctx.world, renderer) + return dispatcher.renderBlock(state, ctx.pos, ctx.reader!!, renderer, random, modelData) } } return false @@ -65,33 +69,23 @@ abstract class AbstractBlockRenderingHandler(modId: String) : ResourceHandler(mo } -data class BlockData(val state: IBlockState, val color: Int, val brightness: Int) +data class BlockData(val state: BlockState, val color: Int, val brightness: Int) /** * Represents the block being rendered. Has properties and methods to query the neighborhood of the block in * block-relative coordinates. */ -class BlockContext( - var world: IBlockAccess? = null, - var pos: BlockPos = BlockPos.ORIGIN -) { - fun set(world: IBlockAccess, pos: BlockPos) { this.world = world; this.pos = pos; } +@Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS") +open class BlockContext( + var reader: IEnviromentBlockReader? = null, + open var pos: BlockPos = BlockPos.ZERO +) { + fun set(blockReader: IEnviromentBlockReader, pos: BlockPos) { this.reader = blockReader; this.pos = pos; } val block: Block get() = block(Int3.zero) fun block(offset: Int3) = blockState(offset).block - fun blockState(offset: Int3) = (pos + offset).let { world!!.getBlockState(it) } - fun blockData(offset: Int3) = (pos + offset).let { pos -> - world!!.getBlockState(pos).let { state -> - BlockData( - state, - Minecraft.getMinecraft().blockColors.colorMultiplier(state, world!!, pos, 0), - state.block.getPackedLightmapCoords(state, world!!, pos) - ) - } - } - - /** Get the biome ID at the block position. */ - val biomeId: Int get() = Biome.getIdForBiome(world!!.getBiome(pos)) + fun blockState(offset: Int3) = (pos + offset).let { reader!!.getBlockState(it) } + fun isNormalCube(offset: Int3) = (pos + offset).let { reader!!.getBlockState(it).isNormalCube(reader, it) } /** Get the centerpoint of the block being rendered. */ val blockCenter: Double3 get() = Double3(pos.x + 0.5, pos.y + 0.5, pos.z + 0.5) @@ -103,8 +97,24 @@ class BlockContext( return Double3(cX * 16.0, cY * 16.0, cZ * 16.0) } + /** Get the biome at the block position. */ + val biome: Biome get() = reader!!.getBiome(pos) + + fun blockData(offset: Int3) = (pos + offset).let { pos -> + reader!!.getBlockState(pos).let { state -> + BlockData( + state, + Minecraft.getInstance().blockColors.getColor(state, reader!!, pos, 0), + state.getPackedLightmapCoords(reader!!, pos) + ) + } + } + + fun shouldSideBeRendered(dir: Direction) = Block.shouldSideBeRendered(blockState(Int3.zero), reader, pos, dir) + /** Is the block surrounded by other blocks that satisfy the predicate on all sides? */ - fun isSurroundedBy(predicate: (IBlockState)->Boolean) = forgeDirOffsets.all { predicate(blockState(it)) } + fun isSurroundedBy(predicate: (BlockState)->Boolean) = forgeDirOffsets.all { predicate(blockState(it)) } + val isSurroundedByNormal: Boolean get() = forgeDirOffsets.all { isNormalCube(it) } /** Get a semi-random value based on the block coordinate and the given seed. */ fun random(seed: Int) = semiRandom(pos.x, pos.y, pos.z, seed) @@ -114,9 +124,9 @@ class BlockContext( /** Get the distance of the block from the camera (player). */ val cameraDistance: Int get() { - val camera = Minecraft.getMinecraft().renderViewEntity ?: return 0 + val camera = Minecraft.getInstance().renderViewEntity ?: return 0 return abs(pos.x - MathHelper.floor(camera.posX)) + - abs(pos.y - MathHelper.floor(camera.posY)) + - abs(pos.z - MathHelper.floor(camera.posZ)) + abs(pos.y - MathHelper.floor(camera.posY)) + + abs(pos.z - MathHelper.floor(camera.posZ)) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/mods/octarinecore/client/render/AbstractEntityFX.kt b/src/main/kotlin/mods/octarinecore/client/render/AbstractEntityFX.kt index 579deae..3fc07bf 100644 --- a/src/main/kotlin/mods/octarinecore/client/render/AbstractEntityFX.kt +++ b/src/main/kotlin/mods/octarinecore/client/render/AbstractEntityFX.kt @@ -3,13 +3,16 @@ package mods.octarinecore.client.render import mods.octarinecore.PI2 import mods.octarinecore.common.Double3 import net.minecraft.client.Minecraft +import net.minecraft.client.particle.IParticleRenderType import net.minecraft.client.particle.Particle +import net.minecraft.client.particle.SpriteTexturedParticle +import net.minecraft.client.renderer.ActiveRenderInfo import net.minecraft.client.renderer.BufferBuilder import net.minecraft.client.renderer.texture.TextureAtlasSprite import net.minecraft.entity.Entity import net.minecraft.world.World -abstract class AbstractEntityFX(world: World, x: Double, y: Double, z: Double) : Particle(world, x, y, z) { +abstract class AbstractEntityFX(world: World, x: Double, y: Double, z: Double) : SpriteTexturedParticle(world, x, y, z) { companion object { @JvmStatic val sin = Array(64) { idx -> Math.sin(PI2 / 64.0 * idx) } @@ -21,8 +24,8 @@ abstract class AbstractEntityFX(world: World, x: Double, y: Double, z: Double) : val prevPos = Double3.zero val velocity = Double3.zero - override fun onUpdate() { - super.onUpdate() + override fun tick() { + super.tick() currentPos.setTo(posX, posY, posZ) prevPos.setTo(prevPosX, prevPosY, prevPosZ) velocity.setTo(motionX, motionY, motionZ) @@ -41,12 +44,12 @@ abstract class AbstractEntityFX(world: World, x: Double, y: Double, z: Double) : abstract val isValid: Boolean /** Add the particle to the effect renderer if it is valid. */ - fun addIfValid() { if (isValid) Minecraft.getMinecraft().effectRenderer.addEffect(this) } + fun addIfValid() { if (isValid) Minecraft.getInstance().particles.addEffect(this) } - override fun renderParticle(worldRenderer: BufferBuilder, entity: Entity, partialTickTime: Float, rotX: Float, rotZ: Float, rotYZ: Float, rotXY: Float, rotXZ: Float) { + override fun renderParticle(buffer: BufferBuilder, entity: ActiveRenderInfo, partialTicks: Float, rotX: Float, rotZ: Float, rotYZ: Float, rotXY: Float, rotXZ: Float) { billboardRot.first.setTo(rotX + rotXY, rotZ, rotYZ + rotXZ) billboardRot.second.setTo(rotX - rotXY, -rotZ, rotYZ - rotXZ) - render(worldRenderer, partialTickTime) + render(buffer, partialTicks) } /** * Render a particle quad. @@ -67,7 +70,7 @@ abstract class AbstractEntityFX(world: World, x: Double, y: Double, z: Double) : prevPos: Double3 = this.prevPos, size: Double = particleScale.toDouble(), rotation: Int = 0, - icon: TextureAtlasSprite = particleTexture, + icon: TextureAtlasSprite = sprite, isMirrored: Boolean = false, alpha: Float = this.particleAlpha) { @@ -115,7 +118,8 @@ abstract class AbstractEntityFX(world: World, x: Double, y: Double, z: Double) : .endVertex() } - override fun getFXLayer() = 1 + // override fun getFXLayer() = 1 + override fun getRenderType(): IParticleRenderType = IParticleRenderType.PARTICLE_SHEET_TRANSLUCENT fun setColor(color: Int) { particleBlue = (color and 255) / 256.0f diff --git a/src/main/kotlin/mods/octarinecore/client/render/Model.kt b/src/main/kotlin/mods/octarinecore/client/render/Model.kt index a1ff3f3..91313bb 100644 --- a/src/main/kotlin/mods/octarinecore/client/render/Model.kt +++ b/src/main/kotlin/mods/octarinecore/client/render/Model.kt @@ -3,7 +3,7 @@ package mods.octarinecore.client.render import mods.octarinecore.common.* import mods.octarinecore.minmax import mods.octarinecore.replace -import net.minecraft.util.EnumFacing +import net.minecraft.util.Direction import java.lang.Math.max import java.lang.Math.min @@ -59,7 +59,7 @@ data class Quad(val v1: Vertex, val v2: Vertex, val v3: Vertex, val v4: Vertex) val normal: Double3 get() = (v2.xyz - v1.xyz).cross(v4.xyz - v1.xyz).normalize fun move(trans: Double3) = transformV { it.copy(xyz = it.xyz + trans) } - fun move(trans: Pair) = move(Double3(trans.second) * trans.first) + fun move(trans: Pair) = move(Double3(trans.second) * trans.first) fun scale (scale: Double) = transformV { it.copy(xyz = it.xyz * scale) } fun scale (scale: Double3) = transformV { it.copy(xyz = Double3(it.xyz.x * scale.x, it.xyz.y * scale.y, it.xyz.z * scale.z)) } fun scaleUV (scale: Double) = transformV { it.copy(uv = UV(it.uv.u * scale, it.uv.v * scale)) } @@ -123,7 +123,7 @@ class Model() { ) } - fun faceQuad(face: EnumFacing): Quad { + fun faceQuad(face: Direction): Quad { val base = face.vec * 0.5 val top = faceCorners[face.ordinal].topLeft.first.vec * 0.5 val left = faceCorners[face.ordinal].topLeft.second.vec * 0.5 diff --git a/src/main/kotlin/mods/octarinecore/client/render/ModelRenderer.kt b/src/main/kotlin/mods/octarinecore/client/render/ModelRenderer.kt index be6d06e..d043b19 100644 --- a/src/main/kotlin/mods/octarinecore/client/render/ModelRenderer.kt +++ b/src/main/kotlin/mods/octarinecore/client/render/ModelRenderer.kt @@ -5,8 +5,8 @@ import mods.octarinecore.common.* import net.minecraft.client.Minecraft import net.minecraft.client.renderer.BufferBuilder import net.minecraft.client.renderer.texture.TextureAtlasSprite -import net.minecraft.util.EnumFacing -import net.minecraft.util.EnumFacing.* +import net.minecraft.util.Direction +import net.minecraft.util.Direction.* typealias QuadIconResolver = (ShadingContext, Int, Quad) -> TextureAtlasSprite? typealias PostProcessLambda = RenderVertex.(ShadingContext, Int, Quad, Int, Vertex) -> Unit @@ -43,7 +43,7 @@ class ModelRenderer : ShadingContext() { aoEnabled = Minecraft.isAmbientOcclusionEnabled() // make sure we have space in the buffer for our quads plus one - worldRenderer.ensureSpaceForQuads(model.quads.size + 1) +// worldRenderer.ensureSpaceForQuads(model.quads.size + 1) model.quads.forEachIndexed { quadIdx, quad -> if (quadFilter(quadIdx, quad)) { @@ -81,18 +81,18 @@ open class ShadingContext { var aoEnabled = Minecraft.isAmbientOcclusionEnabled() val aoFaces = Array(6) { AoFaceData(forgeDirs[it]) } - val EnumFacing.aoMultiplier: Float get() = when(this) { + val Direction.aoMultiplier: Float get() = when(this) { UP -> 1.0f DOWN -> 0.5f NORTH, SOUTH -> 0.8f EAST, WEST -> 0.6f } - fun updateShading(offset: Int3, predicate: (EnumFacing) -> Boolean = { true }) { + fun updateShading(offset: Int3, predicate: (Direction) -> Boolean = { true }) { forgeDirs.forEach { if (predicate(it)) aoFaces[it.ordinal].update(offset, multiplier = it.aoMultiplier) } } - fun aoShading(face: EnumFacing, corner1: EnumFacing, corner2: EnumFacing) = + fun aoShading(face: Direction, corner1: Direction, corner2: Direction) = aoFaces[face.rotate(rotation).ordinal][corner1.rotate(rotation), corner2.rotate(rotation)] fun blockData(offset: Int3) = blockContext.blockData(offset.rotate(rotation)) @@ -169,13 +169,13 @@ class RenderVertex() { } -fun BufferBuilder.ensureSpaceForQuads(num: Int) { - rawIntBuffer.position(bufferSize) - growBuffer(num * vertexFormat.size) -} +//fun BufferBuilder.ensureSpaceForQuads(num: Int) { +// rawIntBuffer.position(bufferSize) +// growBuffer(num * vertexFormat.size) +//} -val allFaces: (EnumFacing) -> Boolean = { true } -val topOnly: (EnumFacing) -> Boolean = { it == UP } +val allFaces: (Direction) -> Boolean = { true } +val topOnly: (Direction) -> Boolean = { it == UP } /** Perform no post-processing */ val noPost: PostProcessLambda = { _, _, _, _, _ -> } \ No newline at end of file diff --git a/src/main/kotlin/mods/octarinecore/client/render/OffsetBlockAccess.kt b/src/main/kotlin/mods/octarinecore/client/render/OffsetBlockAccess.kt deleted file mode 100644 index 82ba826..0000000 --- a/src/main/kotlin/mods/octarinecore/client/render/OffsetBlockAccess.kt +++ /dev/null @@ -1,44 +0,0 @@ -package mods.octarinecore.client.render - -import mods.octarinecore.common.Int3 -import mods.octarinecore.common.plus -import net.minecraft.util.EnumFacing -import net.minecraft.util.math.BlockPos -import net.minecraft.world.IBlockAccess - -/** - * Delegating [IBlockAccess] that fakes a _modified_ location to return values from a _target_ location. - * All other locations are handled normally. - * - * @param[original] the [IBlockAccess] that is delegated to - */ -@Suppress("NOTHING_TO_INLINE") -class OffsetBlockAccess(val original: IBlockAccess, val modded: BlockPos, val target: BlockPos) : IBlockAccess { - - inline fun actualPos(pos: BlockPos?) = - if (pos != null && pos.x == modded.x && pos.y == modded.y && pos.z == modded.z) target else pos - - override fun getBiome(pos: BlockPos?) = original.getBiome(actualPos(pos)) - override fun getBlockState(pos: BlockPos?) = original.getBlockState(actualPos(pos)) - override fun getCombinedLight(pos: BlockPos?, lightValue: Int) = original.getCombinedLight(actualPos(pos), lightValue) - override fun getStrongPower(pos: BlockPos?, direction: EnumFacing?) = original.getStrongPower(actualPos(pos), direction) - override fun getTileEntity(pos: BlockPos?) = original.getTileEntity(actualPos(pos)) - override fun getWorldType() = original.worldType - override fun isAirBlock(pos: BlockPos?) = original.isAirBlock(actualPos(pos)) - override fun isSideSolid(pos: BlockPos?, side: EnumFacing?, _default: Boolean) = original.isSideSolid(actualPos(pos), side, _default) -} -/** - * Temporarily replaces the [IBlockAccess] used by this [BlockContext] and the corresponding [ExtendedRenderBlocks] - * to use an [OffsetBlockAccess] while executing this lambda. - * - * @param[modded] the _modified_ location - * @param[target] the _target_ location - * @param[func] the lambda to execute - */ -inline fun BlockContext.withOffset(modded: Int3, target: Int3, func: () -> T): T { - val original = world!! - world = OffsetBlockAccess(original, pos + modded, pos + target) - val result = func() - world = original - return result -} \ No newline at end of file diff --git a/src/main/kotlin/mods/octarinecore/client/render/OffsetBlockReader.kt b/src/main/kotlin/mods/octarinecore/client/render/OffsetBlockReader.kt new file mode 100644 index 0000000..e6654f8 --- /dev/null +++ b/src/main/kotlin/mods/octarinecore/client/render/OffsetBlockReader.kt @@ -0,0 +1,54 @@ +package mods.octarinecore.client.render + +import mods.octarinecore.common.Int3 +import mods.octarinecore.common.plus +import net.minecraft.util.math.BlockPos +import net.minecraft.world.IBlockReader +import net.minecraft.world.IEnviromentBlockReader +import net.minecraft.world.LightType + +/** + * Delegating [IBlockAccess] that fakes a _modified_ location to return values from a _target_ location. + * All other locations are handled normally. + * + * @param[original] the [IBlockAccess] that is delegated to + */ +@Suppress("NOTHING_TO_INLINE", "NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS", "HasPlatformType") +open class OffsetBlockReader(open val original: IBlockReader, val modded: BlockPos, val target: BlockPos) : IBlockReader { + inline fun actualPos(pos: BlockPos) = if (pos != null && pos.x == modded.x && pos.y == modded.y && pos.z == modded.z) target else pos + + override fun getBlockState(pos: BlockPos) = original.getBlockState(actualPos(pos)) + override fun getTileEntity(pos: BlockPos) = original.getTileEntity(actualPos(pos)) + override fun getFluidState(pos: BlockPos) = original.getFluidState(actualPos(pos)) +} + +@Suppress("NOTHING_TO_INLINE", "NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS", "HasPlatformType") +class OffsetEnvBlockReader(val original: IEnviromentBlockReader, val modded: BlockPos, val target: BlockPos) : IEnviromentBlockReader by original { + inline fun actualPos(pos: BlockPos) = if (pos != null && pos.x == modded.x && pos.y == modded.y && pos.z == modded.z) target else pos + + override fun getBlockState(pos: BlockPos) = original.getBlockState(actualPos(pos)) + override fun getTileEntity(pos: BlockPos) = original.getTileEntity(actualPos(pos)) + override fun getFluidState(pos: BlockPos) = original.getFluidState(actualPos(pos)) + + override fun getLightFor(type: LightType, pos: BlockPos) = original.getLightFor(type, actualPos(pos)) + override fun getCombinedLight(pos: BlockPos, light: Int) = original.getCombinedLight(actualPos(pos), light) + override fun getBiome(pos: BlockPos) = original.getBiome(actualPos(pos)) +} + +/** + * Temporarily replaces the [IBlockReader] used by this [BlockContext] and the corresponding [ExtendedRenderBlocks] + * to use an [OffsetEnvBlockReader] while executing this lambda. + * + * @param[modded] the _modified_ location + * @param[target] the _target_ location + * @param[func] the lambda to execute + */ +//inline fun BlockContext.withOffset(modded: Int3, target: Int3, func: () -> T): T { +// val original = reader!! +// reader = OffsetEnvBlockReader(original, pos + modded, pos + target) +// val result = func() +// reader = original +// return result +//} + +inline fun BlockContext.offset(modded: Int3, target: Int3) = BlockContext(OffsetEnvBlockReader(reader!!, pos + modded, pos + target), pos) \ No newline at end of file diff --git a/src/main/kotlin/mods/octarinecore/client/render/Shaders.kt b/src/main/kotlin/mods/octarinecore/client/render/Shaders.kt index e59be36..865c135 100644 --- a/src/main/kotlin/mods/octarinecore/client/render/Shaders.kt +++ b/src/main/kotlin/mods/octarinecore/client/render/Shaders.kt @@ -1,7 +1,7 @@ package mods.octarinecore.client.render import mods.octarinecore.common.* -import net.minecraft.util.EnumFacing +import net.minecraft.util.Direction const val defaultCornerDimming = 0.5f @@ -10,17 +10,17 @@ const val defaultEdgeDimming = 0.8f // ================================ // Shader instantiation lambdas // ================================ -fun cornerAo(fallbackAxis: EnumFacing.Axis): CornerShaderFactory = { face, dir1, dir2 -> +fun cornerAo(fallbackAxis: Direction.Axis): CornerShaderFactory = { face, dir1, dir2 -> val fallbackDir = listOf(face, dir1, dir2).find { it.axis == fallbackAxis }!! CornerSingleFallback(face, dir1, dir2, fallbackDir) } -val cornerFlat = { face: EnumFacing, dir1: EnumFacing, dir2: EnumFacing -> FaceFlat(face) } -fun cornerAoTri(func: (AoData, AoData)-> AoData) = { face: EnumFacing, dir1: EnumFacing, dir2: EnumFacing -> +val cornerFlat = { face: Direction, dir1: Direction, dir2: Direction -> FaceFlat(face) } +fun cornerAoTri(func: (AoData, AoData)-> AoData) = { face: Direction, dir1: Direction, dir2: Direction -> CornerTri(face, dir1, dir2, func) } val cornerAoMaxGreen = cornerAoTri { s1, s2 -> if (s1.green > s2.green) s1 else s2 } -fun cornerInterpolate(edgeAxis: EnumFacing.Axis, weight: Float, dimming: Float): CornerShaderFactory = { dir1, dir2, dir3 -> +fun cornerInterpolate(edgeAxis: Direction.Axis, weight: Float, dimming: Float): CornerShaderFactory = { dir1, dir2, dir3 -> val edgeDir = listOf(dir1, dir2, dir3).find { it.axis == edgeAxis }!! val faceDirs = listOf(dir1, dir2, dir3).filter { it.axis != edgeAxis } CornerInterpolateDimming(faceDirs[0], faceDirs[1], edgeDir, weight, dimming) @@ -34,7 +34,7 @@ object NoShader : Shader { override fun rotate(rot: Rotation) = this } -class CornerSingleFallback(val face: EnumFacing, val dir1: EnumFacing, val dir2: EnumFacing, val fallbackDir: EnumFacing, val fallbackDimming: Float = defaultCornerDimming) : Shader { +class CornerSingleFallback(val face: Direction, val dir1: Direction, val dir2: Direction, val fallbackDir: Direction, val fallbackDimming: Float = defaultCornerDimming) : Shader { val offset = Int3(fallbackDir) override fun shade(context: ShadingContext, vertex: RenderVertex) { val shading = context.aoShading(face, dir1, dir2) @@ -56,7 +56,7 @@ inline fun accumulate(v1: AoData?, v2: AoData?, func: ((AoData, AoData)-> AoData return null } -class CornerTri(val face: EnumFacing, val dir1: EnumFacing, val dir2: EnumFacing, +class CornerTri(val face: Direction, val dir1: Direction, val dir2: Direction, val func: ((AoData, AoData)-> AoData)) : Shader { override fun shade(context: ShadingContext, vertex: RenderVertex) { var acc = accumulate( @@ -72,15 +72,15 @@ class CornerTri(val face: EnumFacing, val dir1: EnumFacing, val dir2: EnumFacing override fun rotate(rot: Rotation) = CornerTri(face.rotate(rot), dir1.rotate(rot), dir2.rotate(rot), func) } -class EdgeInterpolateFallback(val face: EnumFacing, val edgeDir: EnumFacing, val pos: Double, val fallbackDimming: Float = defaultEdgeDimming): Shader { +class EdgeInterpolateFallback(val face: Direction, val edgeDir: Direction, val pos: Double, val fallbackDimming: Float = defaultEdgeDimming): Shader { val offset = Int3(edgeDir) val edgeAxis = axes.find { it != face.axis && it != edgeDir.axis }!! val weightN = (0.5 - pos).toFloat() val weightP = (0.5 + pos).toFloat() override fun shade(context: ShadingContext, vertex: RenderVertex) { - val shadingP = context.aoShading(face, edgeDir, (edgeAxis to EnumFacing.AxisDirection.POSITIVE).face) - val shadingN = context.aoShading(face, edgeDir, (edgeAxis to EnumFacing.AxisDirection.NEGATIVE).face) + val shadingP = context.aoShading(face, edgeDir, (edgeAxis to Direction.AxisDirection.POSITIVE).face) + val shadingN = context.aoShading(face, edgeDir, (edgeAxis to Direction.AxisDirection.NEGATIVE).face) if (!shadingP.valid && !shadingN.valid) context.blockData(offset).let { return vertex.shade(it.brightness brMul fallbackDimming, it.color colorMul fallbackDimming) } @@ -91,7 +91,7 @@ class EdgeInterpolateFallback(val face: EnumFacing, val edgeDir: EnumFacing, val override fun rotate(rot: Rotation) = EdgeInterpolateFallback(face.rotate(rot), edgeDir.rotate(rot), pos) } -class CornerInterpolateDimming(val face1: EnumFacing, val face2: EnumFacing, val edgeDir: EnumFacing, +class CornerInterpolateDimming(val face1: Direction, val face2: Direction, val edgeDir: Direction, val weight: Float, val dimming: Float, val fallbackDimming: Float = defaultCornerDimming) : Shader { val offset = Int3(edgeDir) override fun shade(context: ShadingContext, vertex: RenderVertex) { @@ -111,7 +111,7 @@ class CornerInterpolateDimming(val face1: EnumFacing, val face2: EnumFacing, val CornerInterpolateDimming(face1.rotate(rot), face2.rotate(rot), edgeDir.rotate(rot), weight, dimming, fallbackDimming) } -class FaceCenter(val face: EnumFacing): Shader { +class FaceCenter(val face: Direction): Shader { override fun shade(context: ShadingContext, vertex: RenderVertex) { vertex.red = 0.0f; vertex.green = 0.0f; vertex.blue = 0.0f; val b = IntArray(4) @@ -128,7 +128,7 @@ class FaceCenter(val face: EnumFacing): Shader { override fun rotate(rot: Rotation) = FaceCenter(face.rotate(rot)) } -class FaceFlat(val face: EnumFacing): Shader { +class FaceFlat(val face: Direction): Shader { override fun shade(context: ShadingContext, vertex: RenderVertex) { val color = context.blockData(Int3.zero).color vertex.shade(context.blockData(face.offset).brightness, color) diff --git a/src/main/kotlin/mods/octarinecore/client/render/Shading.kt b/src/main/kotlin/mods/octarinecore/client/render/Shading.kt index 3eeed56..0d98b07 100644 --- a/src/main/kotlin/mods/octarinecore/client/render/Shading.kt +++ b/src/main/kotlin/mods/octarinecore/client/render/Shading.kt @@ -1,17 +1,20 @@ package mods.octarinecore.client.render +import mods.betterfoliage.BetterFoliage import mods.betterfoliage.loader.Refs import mods.octarinecore.common.* import mods.octarinecore.metaprog.allAvailable import net.minecraft.client.Minecraft import net.minecraft.client.renderer.BlockModelRenderer -import net.minecraft.util.EnumFacing -import net.minecraft.util.EnumFacing.* +import net.minecraft.client.renderer.BlockModelRenderer.AmbientOcclusionFace +import net.minecraft.util.Direction +import net.minecraft.util.Direction.* +import org.apache.logging.log4j.Level import java.lang.Math.min import java.util.* -typealias EdgeShaderFactory = (EnumFacing, EnumFacing) -> Shader -typealias CornerShaderFactory = (EnumFacing, EnumFacing, EnumFacing) -> Shader +typealias EdgeShaderFactory = (Direction, Direction) -> Shader +typealias CornerShaderFactory = (Direction, Direction, Direction) -> Shader typealias ShaderFactory = (Quad, Vertex) -> Shader /** Holds shading values for block corners as calculated by vanilla Minecraft rendering. */ @@ -46,12 +49,13 @@ class AoData() { } } -class AoFaceData(val face: EnumFacing) { - val ao = Refs.AmbientOcclusionFace.element!!.let { - if (allAvailable(Refs.OptifineClassTransformer)) it.getDeclaredConstructor().newInstance() - else it.getDeclaredConstructor(Refs.BlockModelRenderer.element!!) - .newInstance(BlockModelRenderer(Minecraft.getMinecraft().blockColors)) - } as BlockModelRenderer.AmbientOcclusionFace +class AoFaceData(val face: Direction) { + companion object { + private val aoFactory = BlockModelRenderer.AmbientOcclusionFace::class.java.let { + it.getDeclaredConstructor(BlockModelRenderer::class.java).apply { isAccessible = true } + }.let { ctor -> { ctor.newInstance(Minecraft.getInstance().blockRendererDispatcher.blockModelRenderer) } } + } + val ao = aoFactory() val top = faceCorners[face.ordinal].topLeft.first val left = faceCorners[face.ordinal].topLeft.second @@ -74,11 +78,11 @@ class AoFaceData(val face: EnumFacing) { val quadBounds: FloatArray = FloatArray(12) val flags = BitSet(3).apply { set(0) } - ao.updateVertexBrightness(ctx.world, blockState, ctx.pos + offset, face, quadBounds, flags) + ao.updateVertexBrightness(ctx.reader!!, blockState, ctx.pos + offset, face, quadBounds, flags) ordered.forEachIndexed { idx, aoData -> aoData.set(ao.vertexBrightness[idx], ao.vertexColorMultiplier[idx] * multiplier) } } - operator fun get(dir1: EnumFacing, dir2: EnumFacing): AoData { + operator fun get(dir1: Direction, dir2: Direction): AoData { val isTop = top == dir1 || top == dir2 val isLeft = left == dir1 || left == dir2 return if (isTop) { @@ -143,7 +147,7 @@ interface Shader { * @param[corner] shader instantiation lambda for corner vertices * @param[edge] shader instantiation lambda for edge midpoint vertices */ -fun faceOrientedAuto(overrideFace: EnumFacing? = null, +fun faceOrientedAuto(overrideFace: Direction? = null, corner: CornerShaderFactory? = null, edge: EdgeShaderFactory? = null) = fun(quad: Quad, vertex: Vertex): Shader { @@ -170,7 +174,7 @@ fun faceOrientedAuto(overrideFace: EnumFacing? = null, * @param[overrideEdge] assume the given edge instead of going by the _quad_ normal * @param[corner] shader instantiation lambda */ -fun edgeOrientedAuto(overrideEdge: Pair? = null, +fun edgeOrientedAuto(overrideEdge: Pair? = null, corner: CornerShaderFactory) = fun(quad: Quad, vertex: Vertex): Shader { val edgeDir = overrideEdge ?: nearestAngle(quad.normal, boxEdges) { it.first.vec + it.second.vec }.first @@ -181,11 +185,11 @@ fun edgeOrientedAuto(overrideEdge: Pair? = null, return corner(nearestFace, nearestCorner.first, nearestCorner.second) } -fun faceOrientedInterpolate(overrideFace: EnumFacing? = null) = +fun faceOrientedInterpolate(overrideFace: Direction? = null) = fun(quad: Quad, vertex: Vertex): Shader { val resolver = faceOrientedAuto(overrideFace, edge = { face, edgeDir -> val axis = axes.find { it != face.axis && it != edgeDir.axis }!! - val vec = Double3((axis to EnumFacing.AxisDirection.POSITIVE).face) + val vec = Double3((axis to Direction.AxisDirection.POSITIVE).face) val pos = vertex.xyz.dot(vec) EdgeInterpolateFallback(face, edgeDir, pos) }) diff --git a/src/main/kotlin/mods/octarinecore/client/resource/CenteringTextureGenerator.kt b/src/main/kotlin/mods/octarinecore/client/resource/CenteringTextureGenerator.kt index 623e0b9..3347d1d 100644 --- a/src/main/kotlin/mods/octarinecore/client/resource/CenteringTextureGenerator.kt +++ b/src/main/kotlin/mods/octarinecore/client/resource/CenteringTextureGenerator.kt @@ -1,13 +1,23 @@ package mods.octarinecore.client.resource +import net.minecraft.util.ResourceLocation +import net.minecraftforge.resource.VanillaResourceType import java.awt.image.BufferedImage +import java.io.InputStream import java.lang.Math.* -class CenteringTextureGenerator(domain: String, val aspectWidth: Int, val aspectHeight: Int) : TextureGenerator(domain) { +class CenteringTextureGenerator( + domain: String, + val aspectWidth: Int, + val aspectHeight: Int +) : GeneratorBase(domain, VanillaResourceType.TEXTURES) { - override fun generate(params: ParameterList): BufferedImage? { - val target = targetResource(params)!! - val baseTexture = resourceManager[target.second]?.loadImage() ?: return null + override val locationMapper = Atlas.BLOCKS::unwrap + + override fun exists(key: ResourceLocation) = resourceManager.hasResource(Atlas.BLOCKS.wrap(key)) + + override fun get(key: ResourceLocation): InputStream? { + val baseTexture = resourceManager[Atlas.BLOCKS.wrap(key)]?.loadImage() ?: return null val frameWidth = baseTexture.width val frameHeight = baseTexture.width * aspectHeight / aspectWidth @@ -28,6 +38,6 @@ class CenteringTextureGenerator(domain: String, val aspectWidth: Int, val aspect graphics.drawImage(resultFrame, 0, size * frame, null) } - return resultTexture + return resultTexture.asStream } } \ No newline at end of file diff --git a/src/main/kotlin/mods/octarinecore/client/resource/ModelProcessor.kt b/src/main/kotlin/mods/octarinecore/client/resource/ModelProcessor.kt index 0db7f8f..fcca56a 100644 --- a/src/main/kotlin/mods/octarinecore/client/resource/ModelProcessor.kt +++ b/src/main/kotlin/mods/octarinecore/client/resource/ModelProcessor.kt @@ -1,57 +1,51 @@ package mods.octarinecore.client.resource import com.google.common.base.Joiner -import mods.betterfoliage.client.Client -import mods.betterfoliage.loader.Refs import mods.octarinecore.client.render.BlockContext import mods.octarinecore.common.Int3 import mods.octarinecore.common.config.IBlockMatcher import mods.octarinecore.common.config.ModelTextureList -import mods.octarinecore.filterValuesNotNull +import mods.octarinecore.common.plus import mods.octarinecore.findFirst -import net.minecraft.block.Block -import net.minecraft.block.state.IBlockState -import net.minecraft.client.renderer.block.model.ModelResourceLocation -import net.minecraft.client.renderer.block.statemap.DefaultStateMapper -import net.minecraft.client.renderer.block.statemap.IStateMapper -import net.minecraft.client.renderer.texture.TextureAtlasSprite -import net.minecraft.client.renderer.texture.TextureMap +import net.minecraft.block.BlockState +import net.minecraft.client.renderer.BlockModelShapes +import net.minecraft.client.renderer.model.* +import net.minecraft.client.renderer.texture.AtlasTexture import net.minecraft.util.ResourceLocation import net.minecraft.util.math.BlockPos -import net.minecraft.world.IBlockAccess +import net.minecraft.world.IBlockReader import net.minecraftforge.client.event.TextureStitchEvent -import net.minecraftforge.client.model.IModel import net.minecraftforge.client.model.ModelLoader -import net.minecraftforge.common.MinecraftForge -import net.minecraftforge.fml.common.eventhandler.Event -import net.minecraftforge.fml.common.eventhandler.EventPriority -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.eventbus.api.Event +import net.minecraftforge.eventbus.api.EventPriority +import net.minecraftforge.eventbus.api.SubscribeEvent +import net.minecraftforge.registries.ForgeRegistries import org.apache.logging.log4j.Level import org.apache.logging.log4j.Logger -class LoadModelDataEvent(val loader: ModelLoader) : Event() +class LoadModelDataEvent(val bakery: ModelBakery) : Event() interface ModelRenderRegistry { - operator fun get(ctx: BlockContext) = get(ctx.blockState(Int3.zero), ctx.world!!, ctx.pos) - operator fun get(state: IBlockState, world: IBlockAccess, pos: BlockPos): T? + operator fun get(ctx: BlockContext) = get(ctx.blockState(Int3.zero), ctx.reader!!, ctx.pos) + operator fun get(ctx: BlockContext, offset: Int3) = get(ctx.blockState(offset), ctx.reader!!, ctx.pos + offset) + operator fun get(state: BlockState, world: IBlockReader, pos: BlockPos): T? } interface ModelRenderDataExtractor { - fun processModel(state: IBlockState, modelLoc: ModelResourceLocation, model: IModel): ModelRenderKey? + fun processModel(state: BlockState, modelLoc: ModelResourceLocation, models: List>): ModelRenderKey? } interface ModelRenderKey { val logger: Logger? - fun onPreStitch(atlas: TextureMap) {} - fun resolveSprites(atlas: TextureMap): T + fun onPreStitch(event: TextureStitchEvent.Pre) {} + fun resolveSprites(atlas: AtlasTexture): T } abstract class ModelRenderRegistryRoot : ModelRenderRegistry { val subRegistries = mutableListOf>() - override fun get(state: IBlockState, world: IBlockAccess, pos: BlockPos) = subRegistries.findFirst { it[state, world, pos] } + override fun get(state: BlockState, world: IBlockReader, pos: BlockPos) = subRegistries.findFirst { it[state, world, pos] } fun addRegistry(registry: ModelRenderRegistry) { subRegistries.add(registry) - MinecraftForge.EVENT_BUS.register(registry) } } @@ -59,40 +53,41 @@ abstract class ModelRenderRegistryBase : ModelRenderRegistry, ModelRenderD open val logger: Logger? = null open val logName: String get() = this::class.java.name - val stateToKey = mutableMapOf>() - var stateToValue = mapOf() + val stateToKey = mutableMapOf>() + var stateToValue = mapOf() - override fun get(state: IBlockState, world: IBlockAccess, pos: BlockPos) = stateToValue[state] + override fun get(state: BlockState, world: IBlockReader, pos: BlockPos) = stateToValue[state] @Suppress("UNCHECKED_CAST") @SubscribeEvent fun handleLoadModelData(event: LoadModelDataEvent) { stateToValue = emptyMap() - val stateMappings = Block.REGISTRY.flatMap { block -> - val mapper = event.loader.blockModelShapes.blockStateMapper.blockStateMap[block] as? IStateMapper ?: DefaultStateMapper() - (mapper.putStateModelLocations(block as Block) as Map).entries + val stateMappings = ForgeRegistries.BLOCKS.flatMap { block -> + block.stateContainer.validStates.map { state -> state to BlockModelShapes.getModelLocation(state) } } - val stateModels = Refs.stateModels.get(event.loader) as Map +// val unbakedModels = (Refs.unbakedModels.get(event.loader) as Map<*, *>).filter { it.value is IUnbakedModel } as Map - stateMappings.forEach { mapping -> - if (mapping.key.block != null) stateModels[mapping.value]?.let { model -> - try { - processModel(mapping.key, mapping.value, model)?.let { stateToKey[mapping.key] = it } - } catch (e: Exception) { - logger?.warn("Exception while trying to process model ${mapping.value}", e) - } + val missingModel = event.bakery.getUnbakedModel(ModelBakery.MODEL_MISSING) + stateMappings.forEach { (state, stateModelResource) -> + val allModels = event.bakery.let { it.unwrapVariants(it.getUnbakedModel(stateModelResource) to stateModelResource) }.filter { it.second != missingModel } + try { + processModel(state, stateModelResource, allModels)?.let { stateToKey[state] = it } + } catch (e: Exception) { + logger?.warn("Exception while trying to process model ${stateModelResource}", e) } } } @SubscribeEvent(priority = EventPriority.LOW) fun handlePreStitch(event: TextureStitchEvent.Pre) { - stateToKey.forEach { (_, key) -> key.onPreStitch(event.map) } + if (event.map.basePath != "textures") return + stateToKey.forEach { (_, key) -> key.onPreStitch(event) } } @SubscribeEvent(priority = EventPriority.LOW) fun handlePostStitch(event: TextureStitchEvent.Post) { + if (event.map.basePath != "textures") return stateToValue = stateToKey.mapValues { (_, key) -> key.resolveSprites(event.map) } stateToKey.clear() } @@ -103,23 +98,23 @@ abstract class ModelRenderRegistryConfigurable : ModelRenderRegistryBase() abstract val matchClasses: IBlockMatcher abstract val modelTextures: List - override fun processModel(state: IBlockState, modelLoc: ModelResourceLocation, model: IModel): ModelRenderKey? { + override fun processModel(state: BlockState, modelLoc: ModelResourceLocation, models: List>): ModelRenderKey? { val matchClass = matchClasses.matchingClass(state.block) ?: return null logger?.log(Level.DEBUG, "$logName: block state ${state.toString()}") logger?.log(Level.DEBUG, "$logName: class ${state.block.javaClass.name} matches ${matchClass.name}") - val allModels = model.modelBlockAndLoc.distinctBy { it.second } - if (allModels.isEmpty()) { + if (models.isEmpty()) { logger?.log(Level.DEBUG, "$logName: no models found") return null } - allModels.forEach { blockLoc -> - val modelMatch = modelTextures.firstOrNull { blockLoc.derivesFrom(it.modelLocation) } + models.filter { it.first is BlockModel }.forEach { (model, location) -> + model as BlockModel + val modelMatch = modelTextures.firstOrNull { (model to location).derivesFrom(it.modelLocation) } if (modelMatch != null) { - logger?.log(Level.DEBUG, "$logName: model ${blockLoc.second} matches ${modelMatch.modelLocation}") + logger?.log(Level.DEBUG, "$logName: model ${model} matches ${modelMatch.modelLocation}") - val textures = modelMatch.textureNames.map { it to blockLoc.first.resolveTextureName(it) } + val textures = modelMatch.textureNames.map { it to model.resolveTextureName(it) } val texMapString = Joiner.on(", ").join(textures.map { "${it.first}=${it.second}" }) logger?.log(Level.DEBUG, "$logName: textures [$texMapString]") @@ -132,5 +127,11 @@ abstract class ModelRenderRegistryConfigurable : ModelRenderRegistryBase() return null } - abstract fun processModel(state: IBlockState, textures: List) : ModelRenderKey? -} \ No newline at end of file + abstract fun processModel(state: BlockState, textures: List) : ModelRenderKey? +} + +fun ModelBakery.unwrapVariants(modelAndLoc: Pair): List> = when(val model = modelAndLoc.first) { + is VariantList -> model.variantList.flatMap { variant -> unwrapVariants(getUnbakedModel(variant.modelLocation) to variant.modelLocation) } + is BlockModel -> listOf(modelAndLoc) + else -> emptyList() +} diff --git a/src/main/kotlin/mods/octarinecore/client/resource/ResourceGeneration.kt b/src/main/kotlin/mods/octarinecore/client/resource/ResourceGeneration.kt index 772e1e9..feaba01 100644 --- a/src/main/kotlin/mods/octarinecore/client/resource/ResourceGeneration.kt +++ b/src/main/kotlin/mods/octarinecore/client/resource/ResourceGeneration.kt @@ -1,65 +1,111 @@ package mods.octarinecore.client.resource -import mods.octarinecore.metaprog.reflectField -import net.minecraft.client.resources.IResourcePack -import net.minecraft.client.resources.data.IMetadataSection -import net.minecraft.client.resources.data.IMetadataSectionSerializer -import net.minecraft.client.resources.data.MetadataSerializer -import net.minecraft.client.resources.data.PackMetadataSection +import net.minecraft.client.Minecraft +import net.minecraft.resources.* +import net.minecraft.resources.ResourcePackType.CLIENT_RESOURCES +import net.minecraft.resources.data.IMetadataSectionSerializer +import net.minecraft.resources.data.PackMetadataSection import net.minecraft.util.ResourceLocation -import net.minecraft.util.text.TextComponentString -import net.minecraftforge.fml.client.FMLClientHandler +import net.minecraft.util.text.StringTextComponent +import net.minecraftforge.resource.IResourceType +import net.minecraftforge.resource.ISelectiveResourceReloadListener import java.io.InputStream import java.util.* +import java.util.function.Predicate +import java.util.function.Supplier /** - * [IResourcePack] containing generated resources. Adds itself to the default resource pack list - * of Minecraft, so it is invisible and always active. + * [IResourcePack] containing generated resources * * @param[name] Name of the resource pack * @param[generators] List of resource generators */ -class GeneratorPack(val name: String, vararg val generators: GeneratorBase) : IResourcePack { +class GeneratorPack(val packName: String, val packDescription: String, val packImage: String) : IResourcePack { - fun inject() { - FMLClientHandler.instance().reflectField>("resourcePackList")!!.add(this) + val generators = mutableListOf>() + + val packFinder = Finder(this) + override fun getName() = packName + override fun getResourceNamespaces(type: ResourcePackType) = if (type == CLIENT_RESOURCES) generators.map { it.namespace }.toSet() else emptySet() + + override fun getMetadata(deserializer: IMetadataSectionSerializer): T? { + if (deserializer.sectionName != "pack") return null + return PackMetadataSection(StringTextComponent(packDescription), 4) as? T } - override fun getPackName() = name - override fun getPackImage() = null - override fun getResourceDomains() = HashSet(generators.map { it.domain }) - override fun getPackMetadata(serializer: MetadataSerializer?, sectionName: String?) = - if (sectionName == "pack") PackMetadataSection(TextComponentString("Generated resources"), 1) as? T else null + override fun resourceExists(type: ResourcePackType, location: ResourceLocation?) = + location != null && + type == CLIENT_RESOURCES && + generators.find { it.namespace == location.namespace && it.resourceExists(location) } != null - override fun resourceExists(location: ResourceLocation?): Boolean = - if (location == null) false - else generators.find { - it.domain == location.namespace && it.resourceExists(location) - } != null + override fun getResourceStream(type: ResourcePackType, location: ResourceLocation) = + if (location != null && type == CLIENT_RESOURCES) + generators.firstOrNull { it.namespace == location.namespace && it.resourceExists(location) }?.getInputStream(location) + else + null - override fun getInputStream(location: ResourceLocation?): InputStream? = - if (location == null) null - else generators.filter { - it.domain == location.namespace && it.resourceExists(location) - }.map { it.getInputStream(location) } - .filterNotNull().first() + override fun getAllResourceLocations(type: ResourcePackType, pathIn: String, maxDepth: Int, filter: Predicate) = emptyList() + override fun getRootResourceStream(fileName: String) = fileName.let { if (it == "pack.png") packImage else it }.let { this::class.java.classLoader.getResourceAsStream(it) } + override fun close() {} -// override fun getPackMetadata(p_135058_1_: IMetadataSerializer?, p_135058_2_: String?): T { -// return if (type == "pack") PackMetadataSection(ChatComponentText("Generated resources"), 1) else null -// } + class Finder(val pack: GeneratorPack) : IPackFinder { + override fun addPackInfosToMap(nameToPackMap: MutableMap, packInfoFactory: ResourcePackInfo.IFactory) { + val packInfo = ResourcePackInfo.createResourcePack( + pack.packName, + true, + Supplier { pack } as Supplier, + packInfoFactory, + ResourcePackInfo.Priority.BOTTOM + ) + nameToPackMap[pack.packName] = packInfo!! + } + } } /** * Abstract base class for resource generators * - * @param[domain] Resource domain of generator + * @param[namespace] Resource namespace of generator + * @param[generatedType] IResourceType of generated resources */ -abstract class GeneratorBase(val domain: String) { - /** @see [IResourcePack.resourceExists] */ - abstract fun resourceExists(location: ResourceLocation?): Boolean +abstract class GeneratorBase(val namespace: String, val generatedType: IResourceType) : ISelectiveResourceReloadListener { + val keyToId = mutableMapOf() + val idToKey = mutableMapOf() + open val locationMapper: (ResourceLocation)->ResourceLocation = { it } + + init { resourceManager.addReloadListener(this) } + + abstract fun get(key: T): InputStream? + abstract fun exists(key: T): Boolean + + fun registerResource(key: T): ResourceLocation { + keyToId[key]?.let { return ResourceLocation(namespace, it) } + val id = UUID.randomUUID().toString() + keyToId[key] = id + idToKey[id] = key + return ResourceLocation(namespace, id) + } + + fun resourceExists(location: ResourceLocation?): Boolean { + val key = location?.let { locationMapper(it) }?.path?.let { idToKey[it] } ?: return false + return exists(key) + } + + fun getInputStream(location: ResourceLocation?): InputStream? { + val key = location?.let { locationMapper(it) }?.path?.let { idToKey[it] } ?: return null + return get(key) + } + + open fun onReload(resourceManager: IResourceManager) { + keyToId.clear() + idToKey.clear() + } + + override fun onResourceManagerReload(resourceManager: IResourceManager, resourcePredicate: Predicate) { + if (resourcePredicate.test(generatedType)) onReload(resourceManager) + } + - /** @see [IResourcePack.getInputStream] */ - abstract fun getInputStream(location: ResourceLocation?): InputStream? } /** @@ -70,6 +116,7 @@ abstract class GeneratorBase(val domain: String) { * @param[params] key-value pairs * @param[value] keyless extra value */ +/* class ParameterList(val params: Map, val value: String?) { override fun toString() = params.entries @@ -117,4 +164,5 @@ abstract class ParameterBasedGenerator(domain: String) : GeneratorBase(domain) { resourceExists(ParameterList.fromString(location?.path ?: "")) override fun getInputStream(location: ResourceLocation?) = getInputStream(ParameterList.fromString(location?.path ?: "")) -} \ No newline at end of file +} + */ diff --git a/src/main/kotlin/mods/octarinecore/client/resource/ResourceHandler.kt b/src/main/kotlin/mods/octarinecore/client/resource/ResourceHandler.kt index 321a343..9a93a11 100644 --- a/src/main/kotlin/mods/octarinecore/client/resource/ResourceHandler.kt +++ b/src/main/kotlin/mods/octarinecore/client/resource/ResourceHandler.kt @@ -3,29 +3,42 @@ package mods.octarinecore.client.resource import mods.octarinecore.client.render.Model import mods.octarinecore.common.Double3 import mods.octarinecore.common.Int3 +import mods.octarinecore.stripEnd +import mods.octarinecore.stripStart +import net.minecraft.client.renderer.texture.AtlasTexture import net.minecraft.client.renderer.texture.TextureAtlasSprite -import net.minecraft.client.renderer.texture.TextureMap import net.minecraft.util.ResourceLocation import net.minecraft.util.math.BlockPos import net.minecraft.util.math.MathHelper -import net.minecraft.world.World -import net.minecraft.world.gen.NoiseGeneratorSimplex +import net.minecraft.world.IWorld +import net.minecraft.world.gen.SimplexNoiseGenerator import net.minecraftforge.client.event.TextureStitchEvent import net.minecraftforge.common.MinecraftForge import net.minecraftforge.event.world.WorldEvent +import net.minecraftforge.eventbus.api.IEventBus +import net.minecraftforge.eventbus.api.SubscribeEvent import net.minecraftforge.fml.client.event.ConfigChangedEvent -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.fml.config.ModConfig import java.util.* +enum class Atlas(val basePath: String) { + BLOCKS("textures"), + PARTICLES("textures/particle"); + + fun wrap(resource: ResourceLocation) = ResourceLocation(resource.namespace, "$basePath/${resource.path}.png") + fun unwrap(resource: ResourceLocation) = resource.stripStart("$basePath/").stripEnd(".png") + fun matches(event: TextureStitchEvent) = event.map.basePath == basePath +} + // ============================ // Resource types // ============================ interface IStitchListener { - fun onPreStitch(atlas: TextureMap) - fun onPostStitch(atlas: TextureMap) + fun onPreStitch(event: TextureStitchEvent.Pre) + fun onPostStitch(atlas: AtlasTexture) } interface IConfigChangeListener { fun onConfigChange() } -interface IWorldLoadListener { fun onWorldLoad(world: World) } +interface IWorldLoadListener { fun onWorldLoad(world: IWorld) } /** * Base class for declarative resource handling. @@ -34,7 +47,11 @@ interface IWorldLoadListener { fun onWorldLoad(world: World) } * * @param[modId] mod ID associated with this handler (used to filter config change events) */ -open class ResourceHandler(val modId: String) { +open class ResourceHandler( + val modId: String, + val modBus: IEventBus, + val targetAtlas: Atlas = Atlas.BLOCKS +) { val resources = mutableListOf() open fun afterPreStitch() {} @@ -43,15 +60,15 @@ open class ResourceHandler(val modId: String) { // ============================ // Self-registration // ============================ - init { MinecraftForge.EVENT_BUS.register(this) } + init { modBus.register(this) } // ============================ // Resource declarations // ============================ - fun iconStatic(domain: String, path: String) = IconHolder(domain, path).apply { resources.add(this) } - fun iconStatic(location: ResourceLocation) = iconStatic(location.namespace, location.path) - fun iconSet(domain: String, pathPattern: String) = IconSet(domain, pathPattern).apply { this@ResourceHandler.resources.add(this) } - fun iconSet(location: ResourceLocation) = iconSet(location.namespace, location.path) + fun iconStatic(location: ()->ResourceLocation) = IconHolder(location).apply { resources.add(this) } + fun iconStatic(location: ResourceLocation) = iconStatic { location } + fun iconStatic(domain: String, path: String) = iconStatic(ResourceLocation(domain, path)) + fun iconSet(targetAtlas: Atlas = Atlas.BLOCKS, location: (Int)->ResourceLocation) = IconSet(targetAtlas, location).apply { this@ResourceHandler.resources.add(this) } fun model(init: Model.()->Unit) = ModelHolder(init).apply { resources.add(this) } fun modelSet(num: Int, init: Model.(Int)->Unit) = ModelSet(num, init).apply { resources.add(this) } fun vectorSet(num: Int, init: (Int)-> Double3) = VectorSet(num, init).apply { resources.add(this) } @@ -62,19 +79,21 @@ open class ResourceHandler(val modId: String) { // ============================ @SubscribeEvent fun onPreStitch(event: TextureStitchEvent.Pre) { - resources.forEach { (it as? IStitchListener)?.onPreStitch(event.map) } + if (!targetAtlas.matches(event)) return + resources.forEach { (it as? IStitchListener)?.onPreStitch(event) } afterPreStitch() } @SubscribeEvent fun onPostStitch(event: TextureStitchEvent.Post) { + if (!targetAtlas.matches(event)) return resources.forEach { (it as? IStitchListener)?.onPostStitch(event.map) } afterPostStitch() } @SubscribeEvent - fun handleConfigChange(event: ConfigChangedEvent.OnConfigChangedEvent) { - if (event.modID == modId) resources.forEach { (it as? IConfigChangeListener)?.onConfigChange() } + fun handleModConfigChange(event: ModConfig.ModConfigEvent) { + resources.forEach { (it as? IConfigChangeListener)?.onConfigChange() } } @SubscribeEvent @@ -85,33 +104,38 @@ open class ResourceHandler(val modId: String) { // ============================ // Resource container classes // ============================ -class IconHolder(val domain: String, val name: String) : IStitchListener { - val iconRes = ResourceLocation(domain, name) +class IconHolder(val location: ()->ResourceLocation) : IStitchListener { + var iconRes: ResourceLocation? = null var icon: TextureAtlasSprite? = null - override fun onPreStitch(atlas: TextureMap) { atlas.registerSprite(iconRes) } - override fun onPostStitch(atlas: TextureMap) { icon = atlas[iconRes] } + override fun onPreStitch(event: TextureStitchEvent.Pre) { + iconRes = location() + event.addSprite(iconRes) + } + override fun onPostStitch(atlas: AtlasTexture) { + icon = atlas[iconRes!!] + } } class ModelHolder(val init: Model.()->Unit): IConfigChangeListener { - var model: Model = Model().apply(init) + var model: Model = Model() override fun onConfigChange() { model = Model().apply(init) } } -class IconSet(val domain: String, val namePattern: String) : IStitchListener { +class IconSet(val targetAtlas: Atlas, val location: (Int)->ResourceLocation) : IStitchListener { val resources = arrayOfNulls(16) val icons = arrayOfNulls(16) var num = 0 - override fun onPreStitch(atlas: TextureMap) { + override fun onPreStitch(event: TextureStitchEvent.Pre) { num = 0 (0..15).forEach { idx -> icons[idx] = null - val locReal = ResourceLocation(domain, "textures/${namePattern.format(idx)}.png") - if (resourceManager[locReal] != null) resources[num++] = ResourceLocation(domain, namePattern.format(idx)).apply { atlas.registerSprite(this) } + val loc = location(idx) + if (resourceManager[targetAtlas.wrap(loc)] != null) resources[num++] = loc.apply { event.addSprite(this) } } } - override fun onPostStitch(atlas: TextureMap) { + override fun onPostStitch(atlas: AtlasTexture) { (0 until num).forEach { idx -> icons[idx] = atlas[resources[idx]!!] } } @@ -119,20 +143,20 @@ class IconSet(val domain: String, val namePattern: String) : IStitchListener { } class ModelSet(val num: Int, val init: Model.(Int)->Unit): IConfigChangeListener { - val models = Array(num) { Model().apply{ init(it) } } + val models = Array(num) { Model() } override fun onConfigChange() { (0 until num).forEach { models[it] = Model().apply{ init(it) } } } operator fun get(idx: Int) = models[idx % num] } class VectorSet(val num: Int, val init: (Int)->Double3): IConfigChangeListener { - val models = Array(num) { init(it) } + val models = Array(num) { Double3.zero } override fun onConfigChange() { (0 until num).forEach { models[it] = init(it) } } operator fun get(idx: Int) = models[idx % num] } -class SimplexNoise() : IWorldLoadListener { - var noise = NoiseGeneratorSimplex() - override fun onWorldLoad(world: World) { noise = NoiseGeneratorSimplex(Random(world.worldInfo.seed)) +class SimplexNoise : IWorldLoadListener { + var noise = SimplexNoiseGenerator(Random()) + override fun onWorldLoad(world: IWorld) { noise = SimplexNoiseGenerator(Random(world.worldInfo.seed)) } operator fun get(x: Int, z: Int) = MathHelper.floor((noise.getValue(x.toDouble(), z.toDouble()) + 1.0) * 32.0) operator fun get(pos: Int3) = get(pos.x, pos.z) diff --git a/src/main/kotlin/mods/octarinecore/client/resource/TextureGenerator.kt b/src/main/kotlin/mods/octarinecore/client/resource/TextureGenerator.kt index 713aac1..7ecb1cc 100644 --- a/src/main/kotlin/mods/octarinecore/client/resource/TextureGenerator.kt +++ b/src/main/kotlin/mods/octarinecore/client/resource/TextureGenerator.kt @@ -1,7 +1,7 @@ package mods.octarinecore.client.resource import mods.octarinecore.client.resource.ResourceType.* -import net.minecraft.client.resources.IResource +import net.minecraft.resources.IResource import net.minecraft.util.ResourceLocation import java.awt.image.BufferedImage import java.io.InputStream @@ -20,6 +20,7 @@ enum class ResourceType { * * @param[domain] Resource domain of generator */ +/* abstract class TextureGenerator(domain: String) : ParameterBasedGenerator(domain) { /** @@ -29,7 +30,7 @@ abstract class TextureGenerator(domain: String) : ParameterBasedGenerator(domain * @param[extraParams] additional parameters of the generated texture */ fun generatedResource(iconName: String, vararg extraParams: Pair) = ResourceLocation( - domain, + namespace, textureLocation(iconName).let { ParameterList( mapOf("dom" to it.namespace, "path" to it.path) + @@ -83,4 +84,6 @@ abstract class TextureGenerator(domain: String) : ParameterBasedGenerator(domain while(size > 2) { sizes.add(size); size /= 2 } return sizes.map { resourceManager[maskPath(it)] }.filterNotNull().firstOrNull() } -} \ No newline at end of file +} + + */ diff --git a/src/main/kotlin/mods/octarinecore/client/resource/Utils.kt b/src/main/kotlin/mods/octarinecore/client/resource/Utils.kt index 2f65ecb..a035d5d 100644 --- a/src/main/kotlin/mods/octarinecore/client/resource/Utils.kt +++ b/src/main/kotlin/mods/octarinecore/client/resource/Utils.kt @@ -4,16 +4,17 @@ package mods.octarinecore.client.resource import mods.betterfoliage.loader.Refs import mods.octarinecore.PI2 import mods.octarinecore.client.render.HSB -import mods.octarinecore.metaprog.reflectField +import mods.octarinecore.stripEnd import mods.octarinecore.stripStart import mods.octarinecore.tryDefault import net.minecraft.client.Minecraft -import net.minecraft.client.renderer.block.model.ModelBlock +import net.minecraft.client.renderer.model.BlockModel +import net.minecraft.client.renderer.texture.AtlasTexture +import net.minecraft.client.renderer.texture.MissingTextureSprite import net.minecraft.client.renderer.texture.TextureAtlasSprite -import net.minecraft.client.renderer.texture.TextureMap -import net.minecraft.client.resources.IResource -import net.minecraft.client.resources.IResourceManager -import net.minecraft.client.resources.SimpleReloadableResourceManager +import net.minecraft.resources.IResource +import net.minecraft.resources.IResourceManager +import net.minecraft.resources.SimpleReloadableResourceManager import net.minecraft.util.ResourceLocation import net.minecraftforge.client.model.IModel import java.awt.image.BufferedImage @@ -24,8 +25,9 @@ import java.lang.Math.* import javax.imageio.ImageIO /** Concise getter for the Minecraft resource manager. */ -val resourceManager: SimpleReloadableResourceManager get() = - Minecraft.getMinecraft().resourceManager as SimpleReloadableResourceManager +val resourceManager: SimpleReloadableResourceManager + get() = + Minecraft.getInstance().resourceManager as SimpleReloadableResourceManager /** Append a string to the [ResourceLocation]'s path. */ operator fun ResourceLocation.plus(str: String) = ResourceLocation(namespace, path + str) @@ -36,8 +38,10 @@ operator fun IResourceManager.get(domain: String, path: String): IResource? = ge operator fun IResourceManager.get(location: ResourceLocation): IResource? = tryDefault(null) { getResource(location) } /** Index operator to get a texture sprite. */ -operator fun TextureMap.get(name: String): TextureAtlasSprite? = getTextureExtry(ResourceLocation(name).toString()) -operator fun TextureMap.get(res: ResourceLocation): TextureAtlasSprite? = getTextureExtry(res.toString()) +operator fun AtlasTexture.get(res: ResourceLocation): TextureAtlasSprite? = getSprite(res) +operator fun AtlasTexture.get(name: String): TextureAtlasSprite? = getSprite(ResourceLocation(name)) + +val missingSprite: TextureAtlasSprite get() = MissingTextureSprite.func_217790_a() /** Load an image resource. */ fun IResource.loadImage(): BufferedImage? = ImageIO.read(this.inputStream) @@ -65,18 +69,18 @@ val BufferedImage.asStream: InputStream get() = * and the result transformed back to the RGB color space. */ val TextureAtlasSprite.averageColor: Int? get() { - val locationNoDirs = ResourceLocation(iconName).stripStart("blocks/") - val locationWithDirs = ResourceLocation(locationNoDirs.namespace, "textures/blocks/%s.png".format(locationNoDirs.path)) - val image = resourceManager[locationWithDirs]?.loadImage() ?: return null +// val locationNoDirs = ResourceLocation(iconName).stripStart("blocks/") +// val locationWithDirs = ResourceLocation(locationNoDirs.namespace, "textures/blocks/%s.png".format(locationNoDirs.path)) +// val image = resourceManager[locationWithDirs]?.loadImage() ?: return null var numOpaque = 0 var sumHueX = 0.0 var sumHueY = 0.0 var sumSaturation = 0.0f var sumBrightness = 0.0f - for (x in 0..image.width - 1) - for (y in 0..image.height - 1) { - val pixel = image[x, y] + for (x in 0..width - 1) + for (y in 0..height - 1) { + val pixel = getPixelRGBA(0, x, y); val alpha = (pixel shr 24) and 255 val hsb = HSB.fromColor(pixel) if (alpha == 255) { @@ -101,27 +105,9 @@ fun textureLocation(iconName: String) = ResourceLocation(iconName).let { else ResourceLocation(it.namespace, "textures/${it.path}") } -@Suppress("UNCHECKED_CAST") -val IModel.modelBlockAndLoc: List> get() { - if (Refs.VanillaModelWrapper.isInstance(this)) - return listOf(Pair(Refs.model_VMW.get(this) as ModelBlock, Refs.location_VMW.get(this) as ResourceLocation)) - else if (Refs.WeightedRandomModel.isInstance(this)) Refs.models_WRM.get(this)?.let { - return (it as List).flatMap(IModel::modelBlockAndLoc) - } - else if (Refs.MultipartModel.isInstance(this)) Refs.partModels_MPM.get(this)?.let { - return (it as Map).flatMap { it.value.modelBlockAndLoc } - } else { - this::class.java.declaredFields.find { it.type.isInstance(IModel::class.java) }?.let { modelField -> - modelField.isAccessible = true - return (modelField.get(this) as IModel).modelBlockAndLoc - } - } - return listOf() -} - -fun Pair.derivesFrom(targetLocation: ResourceLocation): Boolean { +fun Pair.derivesFrom(targetLocation: ResourceLocation): Boolean { if (second.stripStart("models/") == targetLocation) return true if (first.parent != null && first.parentLocation != null) - return Pair(first.parent, first.parentLocation!!).derivesFrom(targetLocation) + return Pair(first.parent!!, first.parentLocation!!).derivesFrom(targetLocation) return false } diff --git a/src/main/kotlin/mods/octarinecore/common/Geometry.kt b/src/main/kotlin/mods/octarinecore/common/Geometry.kt index deffa20..8b369aa 100644 --- a/src/main/kotlin/mods/octarinecore/common/Geometry.kt +++ b/src/main/kotlin/mods/octarinecore/common/Geometry.kt @@ -1,11 +1,11 @@ package mods.octarinecore.common import mods.octarinecore.cross -import net.minecraft.util.EnumFacing -import net.minecraft.util.EnumFacing.* -import net.minecraft.util.EnumFacing.Axis.* -import net.minecraft.util.EnumFacing.AxisDirection.NEGATIVE -import net.minecraft.util.EnumFacing.AxisDirection.POSITIVE +import net.minecraft.util.Direction +import net.minecraft.util.Direction.* +import net.minecraft.util.Direction.Axis.* +import net.minecraft.util.Direction.AxisDirection.NEGATIVE +import net.minecraft.util.Direction.AxisDirection.POSITIVE import net.minecraft.util.math.BlockPos // ================================ @@ -13,19 +13,19 @@ import net.minecraft.util.math.BlockPos // ================================ val axes = listOf(X, Y, Z) val axisDirs = listOf(POSITIVE, NEGATIVE) -val EnumFacing.dir: AxisDirection get() = axisDirection +val Direction.dir: AxisDirection get() = axisDirection val AxisDirection.sign: String get() = when(this) { POSITIVE -> "+"; NEGATIVE -> "-" } -val forgeDirs = EnumFacing.values() +val forgeDirs = Direction.values() val forgeDirsHorizontal = listOf(NORTH, SOUTH, EAST, WEST) val forgeDirOffsets = forgeDirs.map { Int3(it) } -val Pair.face: EnumFacing get() = when(this) { +val Pair.face: Direction get() = when(this) { X to POSITIVE -> EAST; X to NEGATIVE -> WEST; Y to POSITIVE -> UP; Y to NEGATIVE -> DOWN; Z to POSITIVE -> SOUTH; else -> NORTH; } -val EnumFacing.perpendiculars: List get() = +val Direction.perpendiculars: List get() = axes.filter { it != this.axis }.cross(axisDirs).map { it.face } -val EnumFacing.offset: Int3 get() = forgeDirOffsets[ordinal] +val Direction.offset: Int3 get() = forgeDirOffsets[ordinal] /** Old ForgeDirection rotation matrix yanked from 1.7.10 */ val ROTATION_MATRIX: Array get() = arrayOf( @@ -40,15 +40,15 @@ val ROTATION_MATRIX: Array get() = arrayOf( // ================================ // Vectors // ================================ -operator fun EnumFacing.times(scale: Double) = +operator fun Direction.times(scale: Double) = Double3(directionVec.x.toDouble() * scale, directionVec.y.toDouble() * scale, directionVec.z.toDouble() * scale) -val EnumFacing.vec: Double3 get() = Double3(directionVec.x.toDouble(), directionVec.y.toDouble(), directionVec.z.toDouble()) +val Direction.vec: Double3 get() = Double3(directionVec.x.toDouble(), directionVec.y.toDouble(), directionVec.z.toDouble()) operator fun BlockPos.plus(other: Int3) = BlockPos(x + other.x, y + other.y, z + other.z) /** 3D vector of [Double]s. Offers both mutable operations, and immutable operations in operator notation. */ data class Double3(var x: Double, var y: Double, var z: Double) { constructor(x: Float, y: Float, z: Float) : this(x.toDouble(), y.toDouble(), z.toDouble()) - constructor(dir: EnumFacing) : this(dir.directionVec.x.toDouble(), dir.directionVec.y.toDouble(), dir.directionVec.z.toDouble()) + constructor(dir: Direction) : this(dir.directionVec.x.toDouble(), dir.directionVec.y.toDouble(), dir.directionVec.z.toDouble()) companion object { val zero: Double3 get() = Double3(0.0, 0.0, 0.0) fun weight(v1: Double3, weight1: Double, v2: Double3, weight2: Double) = @@ -92,13 +92,13 @@ data class Double3(var x: Double, var y: Double, var z: Double) { infix fun cross(o: Double3) = Double3(y * o.z - z * o.y, z * o.x - x * o.z, x * o.y - y * o.x) val length: Double get() = Math.sqrt(x * x + y * y + z * z) val normalize: Double3 get() = (1.0 / length).let { Double3(x * it, y * it, z * it) } - val nearestCardinal: EnumFacing get() = nearestAngle(this, forgeDirs.asIterable()) { it.vec }.first + val nearestCardinal: Direction get() = nearestAngle(this, forgeDirs.asIterable()) { it.vec }.first } /** 3D vector of [Int]s. Offers both mutable operations, and immutable operations in operator notation. */ data class Int3(var x: Int, var y: Int, var z: Int) { - constructor(dir: EnumFacing) : this(dir.directionVec.x, dir.directionVec.y, dir.directionVec.z) - constructor(offset: Pair) : this( + constructor(dir: Direction) : this(dir.directionVec.x, dir.directionVec.y, dir.directionVec.z) + constructor(offset: Pair) : this( offset.first * offset.second.directionVec.x, offset.first * offset.second.directionVec.y, offset.first * offset.second.directionVec.z @@ -109,7 +109,7 @@ data class Int3(var x: Int, var y: Int, var z: Int) { // immutable operations operator fun plus(other: Int3) = Int3(x + other.x, y + other.y, z + other.z) - operator fun plus(other: Pair) = Int3( + operator fun plus(other: Pair) = Int3( x + other.first * other.second.directionVec.x, y + other.first * other.second.directionVec.y, z + other.first * other.second.directionVec.z @@ -145,17 +145,17 @@ data class Int3(var x: Int, var y: Int, var z: Int) { // ================================ // Rotation // ================================ -val EnumFacing.rotations: Array get() = - Array(6) { idx -> EnumFacing.values()[ROTATION_MATRIX[ordinal][idx]] } -fun EnumFacing.rotate(rot: Rotation) = rot.forward[ordinal] -fun rot(axis: EnumFacing) = Rotation.rot90[axis.ordinal] +val Direction.rotations: Array get() = + Array(6) { idx -> Direction.values()[ROTATION_MATRIX[ordinal][idx]] } +fun Direction.rotate(rot: Rotation) = rot.forward[ordinal] +fun rot(axis: Direction) = Rotation.rot90[axis.ordinal] /** * Class representing an arbitrary rotation (or combination of rotations) around cardinal axes by 90 degrees. * In effect, a permutation of [ForgeDirection]s. */ @Suppress("NOTHING_TO_INLINE") -class Rotation(val forward: Array, val reverse: Array) { +class Rotation(val forward: Array, val reverse: Array) { operator fun plus(other: Rotation) = Rotation( Array(6) { idx -> forward[other.forward[idx].ordinal] }, Array(6) { idx -> other.reverse[reverse[idx].ordinal] } @@ -163,9 +163,9 @@ class Rotation(val forward: Array, val reverse: Array) { operator fun unaryMinus() = Rotation(reverse, forward) operator fun times(num: Int) = when(num % 4) { 1 -> this; 2 -> this + this; 3 -> -this; else -> identity } - inline fun rotatedComponent(dir: EnumFacing, x: Int, y: Int, z: Int) = + inline fun rotatedComponent(dir: Direction, x: Int, y: Int, z: Int) = when(reverse[dir.ordinal]) { EAST -> x; WEST -> -x; UP -> y; DOWN -> -y; SOUTH -> z; NORTH -> -z; else -> 0 } - inline fun rotatedComponent(dir: EnumFacing, x: Double, y: Double, z: Double) = + inline fun rotatedComponent(dir: Direction, x: Double, y: Double, z: Double) = when(reverse[dir.ordinal]) { EAST -> x; WEST -> -x; UP -> y; DOWN -> -y; SOUTH -> z; NORTH -> -z; else -> 0.0 } companion object { @@ -204,11 +204,11 @@ fun nearestPosition(vertex: Double3, objs: Iterable, objPos: (T)-> Double fun nearestAngle(vector: Double3, objs: Iterable, objAngle: (T)-> Double3): Pair = objs.map { it to objAngle(it).dot(vector) }.maxBy { it.second }!! -data class FaceCorners(val topLeft: Pair, - val topRight: Pair, - val bottomLeft: Pair, - val bottomRight: Pair) { - constructor(top: EnumFacing, left: EnumFacing) : +data class FaceCorners(val topLeft: Pair, + val topRight: Pair, + val bottomLeft: Pair, + val bottomRight: Pair) { + constructor(top: Direction, left: Direction) : this(top to left, top to left.opposite, top.opposite to left, top.opposite to left.opposite) val asArray = arrayOf(topLeft, topRight, bottomLeft, bottomRight) diff --git a/src/main/kotlin/mods/octarinecore/common/config/BlackWhiteListConfigOption.kt b/src/main/kotlin/mods/octarinecore/common/config/BlackWhiteListConfigOption.kt deleted file mode 100644 index 8b60d06..0000000 --- a/src/main/kotlin/mods/octarinecore/common/config/BlackWhiteListConfigOption.kt +++ /dev/null @@ -1,56 +0,0 @@ -package mods.octarinecore.common.config - -import mods.octarinecore.client.gui.NonVerboseArrayEntry -import mods.octarinecore.client.resource.get -import mods.octarinecore.client.resource.getLines -import mods.octarinecore.client.resource.resourceManager -import net.minecraftforge.common.config.Configuration -import net.minecraftforge.common.config.Property - -abstract class BlackWhiteListConfigOption(val domain: String, val path: String) : ConfigPropertyBase() { - - val blackList = mutableListOf() - val whiteList = mutableListOf() - var blacklistProperty: Property? = null - var whitelistProperty: Property? = null - - override val hasChanged: Boolean - get() = blacklistProperty?.hasChanged() ?: false || whitelistProperty?.hasChanged() ?: false - - override val guiProperties: List get() = listOf(whitelistProperty!!, blacklistProperty!!) - - override fun attach(target: Configuration, langPrefix: String, categoryName: String, propertyName: String) { - lang = null - val defaults = readDefaults(domain, path) - blacklistProperty = target.get(categoryName, "${propertyName}Blacklist", defaults.first) - whitelistProperty = target.get(categoryName, "${propertyName}Whitelist", defaults.second) - listOf(blacklistProperty!!, whitelistProperty!!).forEach { - it.configEntryClass = NonVerboseArrayEntry::class.java - it.languageKey = "$langPrefix.$categoryName.${it.name}" - } - read() - } - - abstract fun convertValue(line: String): VALUE? - - override fun read() { - listOf(Pair(blackList, blacklistProperty!!), Pair(whiteList, whitelistProperty!!)).forEach { - it.first.clear() - it.second.stringList.forEach { line -> - val value = convertValue(line) - if (value != null) it.first.add(value) - } - } - } - - fun readDefaults(domain: String, path: String): Pair, Array> { - val blackList = arrayListOf() - val whiteList = arrayListOf() - val defaults = resourceManager[domain, path]?.getLines() - defaults?.map{ it.trim() }?.filter { !it.startsWith("//") && it.isNotEmpty() }?.forEach { - if (it.startsWith("-")) { blackList.add(it.substring(1)) } - else { whiteList.add(it) } - } - return (blackList.toTypedArray() to whiteList.toTypedArray()) - } -} \ No newline at end of file diff --git a/src/main/kotlin/mods/octarinecore/common/config/DelegatingConfig.kt b/src/main/kotlin/mods/octarinecore/common/config/DelegatingConfig.kt index 92948e2..26285d8 100644 --- a/src/main/kotlin/mods/octarinecore/common/config/DelegatingConfig.kt +++ b/src/main/kotlin/mods/octarinecore/common/config/DelegatingConfig.kt @@ -1,256 +1,80 @@ +@file:JvmName("DelegatingConfigKt") + package mods.octarinecore.common.config -import com.google.common.collect.LinkedListMultimap -import mods.betterfoliage.loader.Refs -import mods.octarinecore.metaprog.reflectField -import mods.octarinecore.metaprog.reflectFieldsOfType +import mods.octarinecore.metaprog.reflectDelegates import mods.octarinecore.metaprog.reflectNestedObjects -import net.minecraftforge.common.MinecraftForge -import net.minecraftforge.common.config.ConfigElement -import net.minecraftforge.common.config.Configuration -import net.minecraftforge.common.config.Property -import net.minecraftforge.fml.client.config.GuiConfigEntries -import net.minecraftforge.fml.client.config.IConfigElement -import net.minecraftforge.fml.client.event.ConfigChangedEvent -import net.minecraftforge.fml.common.FMLCommonHandler -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.common.ForgeConfigSpec +import kotlin.properties.ReadOnlyProperty import kotlin.reflect.KProperty -// ============================ -// Configuration object base -// ============================ -/** - * Base class for declarative configuration handling. - * - * Subclasses should be singleton objects, containing one layer of further singleton objects representing - * config categories (nesting is not supported). - * - * Both the root object (maps to the category _global_) and category objects can contain [ConfigPropertyBase] - * instances (either directly or as a delegate), which handle the Forge [Configuration] itself. - * - * Config properties map to language keys by their field names. - * - * @param[modId] mod ID this configuration is linked to - * @param[langPrefix] prefix to use for language keys - */ -abstract class DelegatingConfig(val modId: String, val langPrefix: String) { +open class DelegatingConfig(val modId: String, val langPrefix: String) { + fun build() = ForgeConfigSpec.Builder().apply { ConfigBuildContext(langPrefix, emptyList(), this).addCategory(this@DelegatingConfig) }.build() +} - init { MinecraftForge.EVENT_BUS.register(this) } +class ConfigBuildContext(val langPrefix: String, val path: List, val builder: ForgeConfigSpec.Builder) { - /** The [Configuration] backing this config object. */ - var config: Configuration? = null - val rootGuiElements = mutableListOf() - - /** Attach this config object to the given [Configuration] and update all properties. */ - fun attach(config: Configuration) { - this.config = config - val subProperties = LinkedListMultimap.create() - rootGuiElements.clear() - - forEachProperty { category, name, property -> - property.lang = property.lang ?: "$category.$name" - property.attach(config, langPrefix, category, name) - property.guiProperties.forEach { guiProperty -> - property.guiClass?.let { guiProperty.setConfigEntryClass(it) } - if (category == "global") rootGuiElements.add(ConfigElement(guiProperty)) - else subProperties.put(category, guiProperty.name) - } + fun addCategory(configObj: Any) { + configObj.reflectNestedObjects.forEach { (name, category) -> + builder.push(name) + descend(name).addCategory(category) + builder.pop() } - for (category in subProperties.keySet()) { - val configCategory = config.getCategory(category) - configCategory.setLanguageKey("$langPrefix.$category") - configCategory.setPropertyOrder(subProperties[category]) - rootGuiElements.add(ConfigElement(configCategory)) - } - save() - - // hide all categories not in the config singleton - config.categoryNames.forEach { - config.getCategory(it).setShowInGui(it in subProperties.keySet()) + configObj.reflectDelegates(ConfigDelegate::class.java).forEach { (name, delegate) -> + descend(name).apply { delegate.addToBuilder(this) } } } - /** - * Execute the given lambda for all config properties. - * Lambda params: (category name, property name, property instance) - */ - inline fun forEachProperty(init: (String, String, ConfigPropertyBase)->Unit) { - reflectFieldsOfType(ConfigPropertyBase::class.java).forEach { property -> - init("global", property.first.split("$")[0], property.second as ConfigPropertyBase) - } - for (category in reflectNestedObjects) { - category.second.reflectFieldsOfType(ConfigPropertyBase::class.java).forEach { property -> - init(category.first, property.first.split("$")[0], property.second as ConfigPropertyBase) - } - } + fun descend(pathName: String) = ConfigBuildContext(langPrefix, path + pathName, builder) +} + +open class ConfigCategory(val comment: String? = null) { +} + +abstract class ConfigDelegate : ReadOnlyProperty { + lateinit var configValue: ForgeConfigSpec.ConfigValue + var cachedValue: T? = null + + override fun getValue(thisRef: Any, property: KProperty<*>): T { + if (cachedValue == null) cachedValue = configValue.get() + return cachedValue!! } - /** Save changes to the [Configuration]. */ - fun save() { if (config?.hasChanged() ?: false) config!!.save() } - - /** - * Returns true if any of the given configuration elements have changed. - * Supports both categories and - */ - fun hasChanged(elements: List): Boolean { - reflectNestedObjects.forEach { category -> - if (category.second in elements && config?.getCategory(category.first)?.hasChanged() ?: false) return true - } - forEachProperty { category, name, property -> - if (property in elements && property.hasChanged) return true - } - return false + abstract fun getConfigValue(name: String, builder: ForgeConfigSpec.Builder): ForgeConfigSpec.ConfigValue + fun addToBuilder(ctx: ConfigBuildContext) { + val langKey = ctx.langPrefix + "." + (langPrefixOverride ?: ctx.path.joinToString(".")) + ctx.builder.translation(langKey) + configValue = getConfigValue(ctx.path.last(), ctx.builder) } - /** Called when the configuration for the mod changes. */ - abstract fun onChange(event: ConfigChangedEvent.PostConfigChangedEvent) + var langPrefixOverride: String? = null + fun lang(prefix: String) = apply { langPrefixOverride = prefix } - @SubscribeEvent - fun handleConfigChange(event: ConfigChangedEvent.PostConfigChangedEvent) { - if (event.modID == modId) { - // refresh values - forEachProperty { c, n, prop -> prop.read() } - - // call mod-specific handler - onChange(event) - - // save to file - save() - Refs.resetChangedState.invoke(config!!) - } - } - - /** Extension to get the underlying delegate of a field */ - operator fun Any.get(name: String) = this.reflectField("$name\$delegate") } -// ============================ -// Property delegates -// ============================ - -/** Base class for config property delegates. */ -abstract class ConfigPropertyBase { - /** Language key of the property. */ - var lang: String? = null - - /** GUI class to use. */ - var guiClass: Class? = null - - /** @return true if the property has changed. */ - abstract val hasChanged: Boolean - - /** Attach this delegate to a Forge [Configuration]. */ - abstract fun attach(target: Configuration, langPrefix: String, categoryName: String, propertyName: String) - - /** List of [Property] instances backing this delegate. */ - abstract val guiProperties: List - - /** Re-read the property value from the [Configuration]. */ - open fun read() {} +class DelegatingBooleanValue(val defaultValue: Boolean) : ConfigDelegate() { + override fun getConfigValue(name: String, builder: ForgeConfigSpec.Builder) = builder.define(name, defaultValue) } -class ObsoleteConfigProperty : ConfigPropertyBase() { - override fun attach(target: Configuration, langPrefix: String, categoryName: String, propertyName: String) { - target.getCategory(categoryName)?.remove(propertyName) - } - override val guiProperties = emptyList() - override val hasChanged: Boolean get() = false +class DelegatingIntValue( + val minValue: Int = 0, + val maxValue: Int = 1, + val defaultValue: Int = 0 +) : ConfigDelegate() { + override fun getConfigValue(name: String, builder: ForgeConfigSpec.Builder) = builder.defineInRange(name, defaultValue, minValue, maxValue) } -/** Delegate for a property backed by a single [Property] instance. */ -abstract class ConfigPropertyDelegate() : ConfigPropertyBase() { - /** Cached value of the property. */ - var cached: T? = null - /** The [Property] backing this delegate. */ - var property: Property? = null - - override val guiProperties: List get() = listOf(property!!) - override val hasChanged: Boolean get() = property?.hasChanged() ?: false - - /** Chained setter for the language key. */ - fun lang(lang: String) = apply { this.lang = lang } - - /** Read the backing [Property] instance. */ - abstract fun Property.read(): T - - /** Write the backing [Property] instance. */ - abstract fun Property.write(value: T) - - /** Get the backing [Property] instance. */ - abstract fun resolve(target: Configuration, category: String, name: String): Property - - /** Kotlin deleagation implementation. */ - operator fun getValue(thisRef: Any, delegator: KProperty<*>): T { - if (cached != null) return cached!! - cached = property!!.read() - return cached!! - } - - /** Kotlin deleagation implementation. */ - operator fun setValue(thisRef: Any, delegator: KProperty<*>, value: T) { - cached = value - property!!.write(value) - } - - override fun read() { cached = null } - - override fun attach(target: Configuration, langPrefix: String, categoryName: String, propertyName: String) { - cached = null - property = resolve(target, categoryName, propertyName) - property!!.setLanguageKey("$langPrefix.$lang") - } -} - -/** [Double]-typed property delegate. */ -class ConfigPropertyDouble(val min: Double, val max: Double, val default: Double) : - ConfigPropertyDelegate() { - override fun resolve(target: Configuration, category: String, name: String) = - target.get(category, name, default, null).apply { setMinValue(min); setMaxValue(max) } - override fun Property.read() = property!!.double - override fun Property.write(value: Double) = property!!.set(value) -} - -/** [Float]-typed property delegate. */ -class ConfigPropertyFloat(val min: Double, val max: Double, val default: Double) : - ConfigPropertyDelegate() { - override fun resolve(target: Configuration, category: String, name: String) = - target.get(category, name, default, null).apply { setMinValue(min); setMaxValue(max) } - override fun Property.read() = property!!.double.toFloat() - override fun Property.write(value: Float) = property!!.set(value.toDouble()) -} - -/** [Int]-typed property delegate. */ -class ConfigPropertyInt(val min: Int, val max: Int, val default: Int) : - ConfigPropertyDelegate() { - override fun resolve(target: Configuration, category: String, name: String) = - target.get(category, name, default, null).apply { setMinValue(min); setMaxValue(max) } - override fun Property.read() = property!!.int - override fun Property.write(value: Int) = property!!.set(value) -} - -/** [Boolean]-typed property delegate. */ -class ConfigPropertyBoolean(val default: Boolean) : - ConfigPropertyDelegate() { - override fun resolve(target: Configuration, category: String, name: String) = - target.get(category, name, default, null) - override fun Property.read() = property!!.boolean - override fun Property.write(value: Boolean) = property!!.set(value) -} - -/** [Int] array typed property delegate. */ -class ConfigPropertyIntList(val defaults: ()->Array) : - ConfigPropertyDelegate>() { - override fun resolve(target: Configuration, category: String, name: String) = - target.get(category, name, defaults().toIntArray(), null) - override fun Property.read() = property!!.intList.toTypedArray() - override fun Property.write(value: Array) = property!!.set(value.toIntArray()) +class DelegatingDoubleValue( + val minValue: Double = 0.0, + val maxValue: Double = 1.0, + val defaultValue: Double = 0.0 +) : ConfigDelegate() { + override fun getConfigValue(name: String, builder: ForgeConfigSpec.Builder) = builder.defineInRange(name, defaultValue, minValue, maxValue) } // ============================ // Delegate factory methods // ============================ -fun double(min: Double = 0.0, max: Double = 1.0, default: Double) = ConfigPropertyDouble(min, max, default) -fun float(min: Double = 0.0, max: Double = 1.0, default: Double) = ConfigPropertyFloat(min, max, default) -fun int(min: Int = 0, max: Int, default: Int) = ConfigPropertyInt(min, max, default) -fun intList(defaults: ()->Array) = ConfigPropertyIntList(defaults) -fun boolean(default: Boolean) = ConfigPropertyBoolean(default) \ No newline at end of file +fun double(min: Double = 0.0, max: Double = 1.0, default: Double) = DelegatingDoubleValue(min, max, default) +fun int(min: Int = 0, max: Int, default: Int) = DelegatingIntValue(min, max, default) +fun boolean(default: Boolean) = DelegatingBooleanValue(default) \ No newline at end of file diff --git a/src/main/kotlin/mods/octarinecore/common/config/Matchers.kt b/src/main/kotlin/mods/octarinecore/common/config/Matchers.kt index 64699f2..33acf59 100644 --- a/src/main/kotlin/mods/octarinecore/common/config/Matchers.kt +++ b/src/main/kotlin/mods/octarinecore/common/config/Matchers.kt @@ -1,8 +1,11 @@ package mods.octarinecore.common.config +import mods.octarinecore.client.resource.getLines +import mods.octarinecore.client.resource.resourceManager import mods.octarinecore.metaprog.getJavaClass import net.minecraft.block.Block import net.minecraft.util.ResourceLocation +import org.apache.logging.log4j.Logger interface IBlockMatcher { fun matchesClass(block: Block): Boolean @@ -19,8 +22,11 @@ class SimpleBlockMatcher(vararg val classes: Class<*>) : IBlockMatcher { } } -class ConfigurableBlockMatcher(domain: String, path: String) : IBlockMatcher, BlackWhiteListConfigOption>(domain, path) { - override fun convertValue(line: String) = getJavaClass(line) +class ConfigurableBlockMatcher(val logger: Logger, 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 @@ -35,16 +41,34 @@ class ConfigurableBlockMatcher(domain: String, path: String) : IBlockMatcher, Bl whiteList.forEach { if (it.isAssignableFrom(blockClass)) return it } return null } + + fun readDefaults() { + blackList.clear() + whiteList.clear() + resourceManager.getAllResources(location).forEach { resource -> + logger.debug("Reading resource $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) } + + } + } + } } data class ModelTextureList(val modelLocation: ResourceLocation, val textureNames: List) { constructor(vararg args: String) : this(ResourceLocation(args[0]), listOf(*args).drop(1)) } -class ModelTextureListConfigOption(domain: String, path: String, val minTextures: Int) : StringListConfigOption(domain, path) { - override fun convertValue(line: String): ModelTextureList? { - val elements = line.split(",") - if (elements.size < minTextures + 1) return null - return ModelTextureList(ResourceLocation(elements.first()), elements.drop(1)) +class ModelTextureListConfiguration(val logger: Logger, val location: ResourceLocation) { + val modelList = mutableListOf() + fun readDefaults() { + resourceManager.getAllResources(location).forEach { resource -> + logger.debug("Reading resource $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))) + } + } } } \ No newline at end of file diff --git a/src/main/kotlin/mods/octarinecore/common/config/StringListConfigOption.kt b/src/main/kotlin/mods/octarinecore/common/config/StringListConfigOption.kt deleted file mode 100644 index fa76780..0000000 --- a/src/main/kotlin/mods/octarinecore/common/config/StringListConfigOption.kt +++ /dev/null @@ -1,43 +0,0 @@ -package mods.octarinecore.common.config - -import mods.octarinecore.client.gui.NonVerboseArrayEntry -import mods.octarinecore.client.resource.get -import mods.octarinecore.client.resource.getLines -import mods.octarinecore.client.resource.resourceManager -import net.minecraftforge.common.config.Configuration -import net.minecraftforge.common.config.Property - -abstract class StringListConfigOption(val domain: String, val path: String) : ConfigPropertyBase() { - - val list = mutableListOf() - lateinit var listProperty: Property - - override val hasChanged: Boolean get() = listProperty.hasChanged() ?: false - override val guiProperties: List get() = listOf(listProperty) - - override fun attach(target: Configuration, langPrefix: String, categoryName: String, propertyName: String) { - lang = null - val defaults = readDefaults(domain, path) - listProperty = target.get(categoryName, "${propertyName}", defaults) - listProperty.configEntryClass = NonVerboseArrayEntry::class.java - listProperty.languageKey = "$langPrefix.$categoryName.${listProperty.name}" - read() - } - - abstract fun convertValue(line: String): VALUE? - - override fun read() { - list.clear() - listProperty.stringList.forEach { line -> - val value = convertValue(line) - if (value != null) list.add(value) - } - } - - fun readDefaults(domain: String, path: String): Array { - val list = arrayListOf() - val defaults = resourceManager[domain, path]?.getLines() - defaults?.map { it.trim() }?.filter { !it.startsWith("//") && it.isNotEmpty() }?.forEach { list.add(it) } - return list.toTypedArray() - } -} \ No newline at end of file diff --git a/src/main/kotlin/mods/octarinecore/metaprog/Reflection.kt b/src/main/kotlin/mods/octarinecore/metaprog/Reflection.kt index 98729ec..4b56c73 100644 --- a/src/main/kotlin/mods/octarinecore/metaprog/Reflection.kt +++ b/src/main/kotlin/mods/octarinecore/metaprog/Reflection.kt @@ -43,6 +43,14 @@ fun Any.reflectFieldsOfType(vararg types: Class<*>) = this.javaClass.declaredFie .map { field -> field.name to field.let { it.isAccessible = true; it.get(this) } } .filterNotNull() +fun Any.reflectFields(type: Class) = this.javaClass.declaredFields + .filter { field -> type.isAssignableFrom(field.type) } + .map { field -> field.name to field.let { it.isAccessible = true; it.get(this) as T } } + +fun Any.reflectDelegates(type: Class) = this.javaClass.declaredFields + .filter { field -> type.isAssignableFrom(field.type) && field.name.contains("$") } + .map { field -> field.name.split("$")[0] to field.let { it.isAccessible = true; it.get(this) } as T } + enum class Namespace { MCP, SRG } abstract class Resolvable { diff --git a/src/main/kotlin/mods/octarinecore/metaprog/Transformation.kt b/src/main/kotlin/mods/octarinecore/metaprog/Transformation.kt deleted file mode 100644 index 3d4bc30..0000000 --- a/src/main/kotlin/mods/octarinecore/metaprog/Transformation.kt +++ /dev/null @@ -1,212 +0,0 @@ -package mods.octarinecore.metaprog - -import mods.octarinecore.metaprog.Namespace.* -import net.minecraft.launchwrapper.IClassTransformer -import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin -import org.apache.logging.log4j.LogManager -import org.objectweb.asm.ClassReader -import org.objectweb.asm.ClassWriter -import org.objectweb.asm.Opcodes -import org.objectweb.asm.tree.* -import java.io.File -import java.io.FileOutputStream - -/** - * Base class for convenient bytecode transformers. - */ -open class Transformer : IClassTransformer { - - val log = LogManager.getLogger(this) - - /** The list of transformers and targets. */ - var methodTransformers: MutableListUnit>> = arrayListOf() - - /** Add a transformation to perform. Call this during instance initialization. - * - * @param[method] the target method of the transformation - * @param[trans] method transformation lambda - */ - fun transformMethod(method: MethodRef, trans: MethodTransformContext.()->Unit) = methodTransformers.add(method to trans) - - override fun transform(name: String?, transformedName: String?, classData: ByteArray?): ByteArray? { - if (classData == null) return null - val classNode = ClassNode().apply { val reader = ClassReader(classData); reader.accept(this, 0) } - var workDone = false - var writerFlags = 0 - - synchronized(this) { - methodTransformers.forEach { (targetMethod, transform) -> - if (transformedName != targetMethod.parentClass.name) return@forEach - - for (method in classNode.methods) { - val namespace = Namespace.values().find { - method.name == targetMethod.name(it) && method.desc == targetMethod.asmDescriptor(it) - } ?: continue - when (namespace) { - MCP -> log.info("Found method ${targetMethod.parentClass.name}.${targetMethod.name(MCP)} ${targetMethod.asmDescriptor(MCP)}") - SRG -> log.info("Found method ${targetMethod.parentClass.name}.${targetMethod.name(namespace)} ${targetMethod.asmDescriptor(namespace)} (matching ${targetMethod.name(MCP)})") - } - - // write input bytecode for debugging - definitely not in production... - //File("BF_debug").mkdir() - //FileOutputStream(File("BF_debug/$transformedName.class")).apply { - // write(classData) - // close() - //} - - // transform - writerFlags = MethodTransformContext(method, namespace, writerFlags).apply(transform).writerFlags - workDone = true - } - } - } - - return if (!workDone) classData else ClassWriter(writerFlags).apply { classNode.accept(this) }.toByteArray() - } -} - -/** - * Allows builder-style declarative definition of transformations. Transformation lambdas are extension - * methods on this class. - * - * @param[method] the [MethodNode] currently being transformed - * @param[environment] the type of environment we are in - */ -class MethodTransformContext(val method: MethodNode, val environment: Namespace, var writerFlags: Int) { - - fun applyWriterFlags(vararg flagValue: Int) { flagValue.forEach { writerFlags = writerFlags or it } } - - fun makePublic() { - method.access = (method.access or Opcodes.ACC_PUBLIC) and (Opcodes.ACC_PRIVATE or Opcodes.ACC_PROTECTED).inv() - } - - /** - * Find the first instruction that matches a predicate. - * - * @param[start] the instruction node to start iterating from - * @param[predicate] the predicate to check - */ - fun find(start: AbstractInsnNode, predicate: (AbstractInsnNode) -> Boolean): AbstractInsnNode? { - var current: AbstractInsnNode? = start - while (current != null && !predicate(current)) current = current.next - return current - } - - /** Find the first instruction in the current [MethodNode] that matches a predicate. */ - fun find(predicate: (AbstractInsnNode)->Boolean): AbstractInsnNode? = find(method.instructions.first, predicate) - - /** Find the first instruction in the current [MethodNode] with the given opcode. */ - fun find(opcode: Int) = find { it.opcode == opcode } - - /** - * Insert new instructions after this one. - * - * @param[init] builder-style lambda to assemble instruction list - */ - fun AbstractInsnNode.insertAfter(init: InstructionList.()->Unit) = InstructionList(environment).apply{ - this.init(); list.reversed().forEach { method.instructions.insert(this@insertAfter, it) } - } - - /** - * Insert new instructions before this one. - * - * @param[init] builder-style lambda to assemble instruction list - */ - fun AbstractInsnNode.insertBefore(init: InstructionList.()->Unit) = InstructionList(environment).apply{ - val insertBeforeNode = this@insertBefore //.let { if (it.previous is FrameNode) it.previous else it } - this.init(); list.forEach { method.instructions.insertBefore(insertBeforeNode, it) } - } - - fun AbstractInsnNode.replace(init: InstructionList.()->Unit) = InstructionList(environment).apply { - insertAfter(init) - method.instructions.remove(this@replace) - } - /** Remove all isntructiuons between the given two (inclusive). */ - fun Pair.remove() { - var current: AbstractInsnNode? = first - while (current != null && current != second) { - val next = current.next - method.instructions.remove(current) - current = next - } - if (current != null) method.instructions.remove(current) - } - - /** - * Replace all isntructiuons between the given two (inclusive) with the specified instruction list. - * - * @param[init] builder-style lambda to assemble instruction list - */ - fun Pair.replace(init: InstructionList.()->Unit) { - val beforeInsn = first.previous - remove() - beforeInsn.insertAfter(init) - } - - /** - * Matches variable instructions. - * - * @param[opcode] instruction opcode - * @param[idx] variable the opcode references - */ - fun varinsn(opcode: Int, idx: Int): (AbstractInsnNode)->Boolean = { insn -> - insn.opcode == opcode && insn is VarInsnNode && insn.`var` == idx - } - - fun invokeName(name: String): (AbstractInsnNode)->Boolean = { insn -> - (insn as? MethodInsnNode)?.name == name - } - - fun invokeRef(ref: MethodRef): (AbstractInsnNode)->Boolean = { insn -> - (insn as? MethodInsnNode)?.let { - it.name == ref.name(environment) && it.owner == ref.parentClass.name.replace(".", "/") - } ?: false - } -} - -/** - * Allows builder-style declarative definition of instruction lists. - * - * @param[environment] the type of environment we are in - */ -class InstructionList(val environment: Namespace) { - - fun insn(opcode: Int) = list.add(InsnNode(opcode)) - - /** The instruction list being assembled. */ - val list: MutableList = arrayListOf() - - /** - * Adds a variable instruction. - * - * @param[opcode] instruction opcode - * @param[idx] variable the opcode references - */ - fun varinsn(opcode: Int, idx: Int) = list.add(VarInsnNode(opcode, idx)) - - /** - * Adds an INVOKESTATIC instruction. - * - * @param[target] the target method of the instruction - * @param[isInterface] true if the target method is defined by an interface - */ - fun invokeStatic(target: MethodRef, isInterface: Boolean = false) = list.add(MethodInsnNode( - Opcodes.INVOKESTATIC, - target.parentClass.name.replace(".", "/"), - target.name(environment), - target.asmDescriptor(environment), - isInterface - )) - - /** - * Adds a GETFIELD instruction. - * - * @param[target] the target field of the instruction - */ - fun getField(target: FieldRef) = list.add(FieldInsnNode( - Opcodes.GETFIELD, - target.parentClass.name.replace(".", "/"), - target.name(environment), - target.asmDescriptor(environment) - )) -} \ No newline at end of file diff --git a/src/main/resources/META-INF/BetterFoliage_at.cfg b/src/main/resources/META-INF/BetterFoliage_at.cfg deleted file mode 100644 index a856162..0000000 --- a/src/main/resources/META-INF/BetterFoliage_at.cfg +++ /dev/null @@ -1,15 +0,0 @@ -public net.minecraft.client.renderer.BlockModelRenderer$AmbientOcclusionFace -public net.minecraft.client.renderer.BlockModelRenderer$AmbientOcclusionFace field_178206_b # vertexColorMultiplier -public net.minecraft.client.renderer.BlockModelRenderer$AmbientOcclusionFace field_178207_c # vertexBrightness - -public net.minecraft.client.renderer.block.model.ModelBakery field_177610_k # blockModelShapes - -public net.minecraft.client.renderer.block.statemap.BlockStateMapper field_178450_a # blockStateMap - -public net.minecraft.client.renderer.BufferBuilder field_178999_b # rawIntBuffer -public net.minecraft.client.renderer.BufferBuilder func_181670_b(I)V # growBuffer -public net.minecraft.client.renderer.BufferBuilder func_181664_j()I # getBufferSize - -public net.minecraft.client.renderer.BlockModelRenderer field_187499_a # blockColors - -public net.minecraft.world.ChunkCache field_72815_e # world \ No newline at end of file diff --git a/src/main/resources/META-INF/MANIFEST.MF b/src/main/resources/META-INF/MANIFEST.MF new file mode 100644 index 0000000..813534a --- /dev/null +++ b/src/main/resources/META-INF/MANIFEST.MF @@ -0,0 +1,6 @@ +Manifest-Version: 1.0 +Specification-Title: BetterFoliage +Implementation-Title: BetterFoliage +Specification-Vendor: octarine-noise +Implementation-Vendor: octarine-noise +MixinConnector: mods.betterfoliage.MixinConnector diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg new file mode 100644 index 0000000..8c13014 --- /dev/null +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -0,0 +1,20 @@ +public net.minecraft.client.renderer.BlockModelRenderer$AmbientOcclusionFace +public net.minecraft.client.renderer.BlockModelRenderer$AmbientOcclusionFace +public net.minecraft.client.renderer.BlockModelRenderer$AmbientOcclusionFace field_178206_b #vertexColorMultiplier +public net.minecraft.client.renderer.BlockModelRenderer$AmbientOcclusionFace field_178207_c #vertexBrightness + +public net.minecraft.block.BlockState$Cache + +public net.minecraft.client.renderer.chunk.ChunkRenderCache field_212408_i #world + +#public net.minecraft.client.renderer.block.model.ModelBakery field_177610_k # blockModelShapes + +#public net.minecraft.client.renderer.block.statemap.BlockStateMapper field_178450_a # blockStateMap + +#public net.minecraft.client.renderer.BufferBuilder field_178999_b # rawIntBuffer +#public net.minecraft.client.renderer.BufferBuilder func_181670_b(I)V # growBuffer +#public net.minecraft.client.renderer.BufferBuilder func_181664_j()I # getBufferSize + +#public net.minecraft.client.renderer.BlockModelRenderer field_187499_a # blockColors + +#public net.minecraft.world.ChunkCache field_72815_e # world \ No newline at end of file diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml new file mode 100644 index 0000000..66386ef --- /dev/null +++ b/src/main/resources/META-INF/mods.toml @@ -0,0 +1,14 @@ +modLoader="kotlinfml" +loaderVersion="[1.4,)" +issueTrackerURL="https://github.com/octarine-noise/BetterFoliage/issues" + +[[mods]] + modId="betterfoliage" + version="${version}" + displayName="Better Foliage" + authors="octarine-noise" + description=''' +Leafier leaves and grassier grass. + ''' + displayURL="https://www.curseforge.com/minecraft/mc-mods/better-foliage" + side="CLIENT" \ No newline at end of file diff --git a/src/main/resources/assets/betterfoliage/cactus_default.cfg b/src/main/resources/assets/betterfoliage/cactus_default.cfg index b5720e8..33675c2 100644 --- a/src/main/resources/assets/betterfoliage/cactus_default.cfg +++ b/src/main/resources/assets/betterfoliage/cactus_default.cfg @@ -1,5 +1,2 @@ // Vanilla -net.minecraft.block.BlockCactus - -// TerraFirmaCraft -com.bioxx.tfc.Blocks.Vanilla.BlockCustomCactus \ No newline at end of file +net.minecraft.block.CactusBlock diff --git a/src/main/resources/assets/betterfoliage/crop_default.cfg b/src/main/resources/assets/betterfoliage/crop_default.cfg index 87d6691..778ccbf 100644 --- a/src/main/resources/assets/betterfoliage/crop_default.cfg +++ b/src/main/resources/assets/betterfoliage/crop_default.cfg @@ -1,10 +1,10 @@ // Vanilla -net.minecraft.block.BlockTallGrass -net.minecraft.block.BlockCrops --net.minecraft.block.BlockReed --net.minecraft.block.BlockDoublePlant --net.minecraft.block.BlockCarrot --net.minecraft.block.BlockPotato +net.minecraft.block.TallGrassBlock +net.minecraft.block.CropsBlock +-net.minecraft.block.ReedBlock +-net.minecraft.block.DoublePlantBlock +-net.minecraft.block.CarrotBlock +-net.minecraft.block.PotatoBlock // Biomes O'Plenty biomesoplenty.common.block.BlockBOPFlower @@ -13,24 +13,3 @@ biomesoplenty.common.block.BlockBOPPlant // Tinkers' Construct tconstruct.blocks.slime.SlimeTallGrass - -// Plant Mega Pack -plantmegapack.block.PMPBlockBerrybush -plantmegapack.block.PMPBlockCrops -plantmegapack.block.PMPBlockDesert -plantmegapack.block.PMPBlockFern -plantmegapack.block.PMPBlockFlowerMulti -plantmegapack.block.PMPBlockFlowerSingle -plantmegapack.block.PMPBlockForest -plantmegapack.block.PMPBlockGrass -plantmegapack.block.PMPBlockJungle -plantmegapack.block.PMPBlockMountain -plantmegapack.block.PMPBlockSavanna -plantmegapack.block.PMPBlockShrub -plantmegapack.block.PMPBlockWetlands - -// Pam's HarvestCraft -com.pam.harvestcraft.BlockPamCrop -com.pam.harvestcraft.BlockPamDesertGarden -com.pam.harvestcraft.BlockPamNormalGarden -com.pam.harvestcraft.BlockPamWaterGarden diff --git a/src/main/resources/assets/betterfoliage/dirt_default.cfg b/src/main/resources/assets/betterfoliage/dirt_default.cfg index ee9a405..247dd14 100644 --- a/src/main/resources/assets/betterfoliage/dirt_default.cfg +++ b/src/main/resources/assets/betterfoliage/dirt_default.cfg @@ -1,18 +1,2 @@ // Vanilla -net.minecraft.block.BlockDirt - -// Biomes O'Plenty -biomesoplenty.common.block.BlockBOPDirt - -// Enhanced Biomes -enhancedbiomes.blocks.BlockSoilEB - -// TerraFirmaCraft -com.bioxx.tfc.Blocks.Terrain.BlockDirt - -// Aether -net.aetherteam.aether.blocks.natural.BlockAetherDirt -com.gildedgames.aether.common.blocks.natural.BlockAetherDirt - -// Tinker's Construct -slimeknights.tconstruct.world.block.BlockSlimeDirt +net.minecraft.block.DirtBlock diff --git a/src/main/resources/assets/betterfoliage/grass_blocks_default.cfg b/src/main/resources/assets/betterfoliage/grass_blocks_default.cfg index bc144c2..eb0a164 100644 --- a/src/main/resources/assets/betterfoliage/grass_blocks_default.cfg +++ b/src/main/resources/assets/betterfoliage/grass_blocks_default.cfg @@ -1,18 +1,2 @@ // Vanilla -net.minecraft.block.BlockGrass - -// Biomes O'Plenty -biomesoplenty.common.block.BlockBOPGrass - -// Tinker's Construct -tconstruct.blocks.slime.SlimeGrass - -// Enhanced Biomes -enhancedbiomes.blocks.BlockGrassEB - -// TerraFirmaCraft -com.bioxx.tfc.Blocks.Terrain.BlockGrass - -// AbyssalCraft -com.shinoow.abyssalcraft.common.blocks.BlockDreadGrass -com.shinoow.abyssalcraft.common.blocks.BlockDarklandsgrass +net.minecraft.block.GrassBlock diff --git a/src/main/resources/assets/betterfoliage/grass_models_default.cfg b/src/main/resources/assets/betterfoliage/grass_models_default.cfg index a147254..7c7e5c6 100644 --- a/src/main/resources/assets/betterfoliage/grass_models_default.cfg +++ b/src/main/resources/assets/betterfoliage/grass_models_default.cfg @@ -1,6 +1,3 @@ // Vanilla -block/grass,top +block/grass_block,top block/cube_bottom_top,top - -// Lithos Core -block/soil/grass_master,top diff --git a/src/main/resources/assets/betterfoliage/leaves_blocks_default.cfg b/src/main/resources/assets/betterfoliage/leaves_blocks_default.cfg index 2c2df57..839b864 100644 --- a/src/main/resources/assets/betterfoliage/leaves_blocks_default.cfg +++ b/src/main/resources/assets/betterfoliage/leaves_blocks_default.cfg @@ -1,8 +1,2 @@ // Vanilla -net.minecraft.block.BlockLeaves - -// Biomes O' Plenty -biomesoplenty.common.block.BlockBOPLeaves - -// Aether II -com.gildedgames.aether.common.blocks.natural.BlockAetherLeaves +net.minecraft.block.LeavesBlock diff --git a/src/main/resources/assets/betterfoliage/log_blocks_default.cfg b/src/main/resources/assets/betterfoliage/log_blocks_default.cfg index 07e32a3..b71b073 100644 --- a/src/main/resources/assets/betterfoliage/log_blocks_default.cfg +++ b/src/main/resources/assets/betterfoliage/log_blocks_default.cfg @@ -1,35 +1,2 @@ // Vanilla -net.minecraft.block.BlockLog - -// Biomes O'Plenty -biomesoplenty.common.block.BlockBOPLog - -// Natura -com.progwml6.natura.common.block.BlockEnumLog - -// Thaumcraft -thaumcraft.common.blocks.world.plants.BlockLogsTC - -// Forestry -forestry.arboriculture.gadgets.BlockLog - -// Extra Biomes XL --extrabiomes.blocks.BlockMiniLog - -// TerraFirmaCraft -com.bioxx.tfc.Blocks.Flora.BlockLogVert -com.bioxx.tfc.Blocks.Flora.BlockLogNatural - -// The Agricultural Revolution a.k.a. Cooking Plus -CookingPlus.blocks.CookingPlusPalmLog -CookingPlus.blocks.CookingPlusTangleLog -CookingPlus.blocks.CookingPlusTangleHeart - -// IC2 -ic2.core.block.BlockRubWood - -// TechReborn -techreborn.blocks.BlockRubberLog - -//Better With Mods -betterwithmods.blocks.BlockStump +net.minecraft.block.LogBlock diff --git a/src/main/resources/assets/betterfoliage/mycelium_blocks_default.cfg b/src/main/resources/assets/betterfoliage/mycelium_blocks_default.cfg index 970dc3f..73e1a43 100644 --- a/src/main/resources/assets/betterfoliage/mycelium_blocks_default.cfg +++ b/src/main/resources/assets/betterfoliage/mycelium_blocks_default.cfg @@ -1,5 +1,2 @@ // Vanilla -net.minecraft.block.BlockMycelium - -// NetherEx -nex.block.BlockMycelium +net.minecraft.block.MyceliumBlock diff --git a/src/main/resources/assets/betterfoliage/netherrack_blocks_default.cfg b/src/main/resources/assets/betterfoliage/netherrack_blocks_default.cfg index ca37623..7ff4300 100644 --- a/src/main/resources/assets/betterfoliage/netherrack_blocks_default.cfg +++ b/src/main/resources/assets/betterfoliage/netherrack_blocks_default.cfg @@ -1,5 +1,2 @@ // Vanilla -net.minecraft.block.BlockNetherrack - -// NetherEx -nex.block.BlockNetherrack +net.minecraft.block.NetherrackBlock diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_algae_0.png b/src/main/resources/assets/betterfoliage/textures/blocks/better_algae_0.png similarity index 100% rename from src/main/resources/assets/bettergrassandleaves/textures/blocks/better_algae_0.png rename to src/main/resources/assets/betterfoliage/textures/blocks/better_algae_0.png diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_algae_1.png b/src/main/resources/assets/betterfoliage/textures/blocks/better_algae_1.png similarity index 100% rename from src/main/resources/assets/bettergrassandleaves/textures/blocks/better_algae_1.png rename to src/main/resources/assets/betterfoliage/textures/blocks/better_algae_1.png diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_algae_2.png b/src/main/resources/assets/betterfoliage/textures/blocks/better_algae_2.png similarity index 100% rename from src/main/resources/assets/bettergrassandleaves/textures/blocks/better_algae_2.png rename to src/main/resources/assets/betterfoliage/textures/blocks/better_algae_2.png diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_algae_3.png b/src/main/resources/assets/betterfoliage/textures/blocks/better_algae_3.png similarity index 100% rename from src/main/resources/assets/bettergrassandleaves/textures/blocks/better_algae_3.png rename to src/main/resources/assets/betterfoliage/textures/blocks/better_algae_3.png diff --git a/src/main/resources/assets/betterfoliage/textures/blocks/better_cactus.png b/src/main/resources/assets/betterfoliage/textures/blocks/better_cactus.png new file mode 100644 index 0000000000000000000000000000000000000000..435a58fdafbae3cf62d637857bb241fd63f2a046 GIT binary patch literal 1659 zcmV->288*EP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGr5dZ)e5dq33^FIIp1`tU^K~z{r#a7vF z97PnpRn^_ovv|wm2ckeifC!-k@cy`>3$g31Rd%iMxAqTF0a4Eud{pMST&nwq1 z#_>BJz8>1|FCx#K0xBD?-1+vN;u<>q z+fN&De40Gd0Y>)w4-XU_pyA${5#I#quV=yJ+KE!Zl`h%csG=b{va>M}-HXfR`>+1^ ze-3=~`P-qtoJ*Q37#2yEjP%Z=4c4i=XVl)K$|#^Oh;%%Qsd+weO%^MZ?t6R4z$#(=-#G4$ft8%=__fW0uxCp&D6-g>h}M)1;%n zO8M@~yQiXX!hu7>pRR})3BijRoX>)*yoKt}8nvafCRN%s!Sm^z`0-Ai4v?B=tC*JsES(-XXx1R*nQI_A+REz28gkw68fBGa+A^!lh|n%j$af1P@LiF#e}j%^2%Z?)e}|m`__d8*>e#4k?&T zM*@}57;l60K#&QLa)waL52T=hKFNAU-uw9SVgzVBUsnhiS2lH$2=vcpqB9j!KqFKh z4T5y7#PQ6T=mn5yQ6Lxcev)+8vSxp?k=Nc|ifdY#L*T;oRcGL3Z!N6}Ti!?BA=DWa z5^j$OX;71h^JC6!=h0b`wW(MYQ)jq!kA~$O4-Oq*ZdfiH`!b}RfvKnnq>fRL<*XP7 zR`ZV41H<4;)X_d$_+zSYWqoamq1CqZF_^(hKF5PY2abA`FB|en#T;UTVHB7dOOOV5 zbNi(ehtDuAOSl>D=m@U5@RqY8VxKf)r_NsP37gyO_dEiC4R!BrxeLoFh7G+#2B+^I(nYs7cg63z>3)#IINF$egOt<#_cQ2`)dtoeZVrmbg| z7$J@~m`yUaPLLm*Gudn6e~X6HT}^pj(M>U}g2|qfAHROeR!k=z|2d9L1&UG}JWP^K zx8c}wcWQi?l5n}y)P-0;6M>u0Tt;K`$;q150VVaKn2c)25kRII{gH#*P4L7X)O}(g35YHcJR2y z>2b=*cs%ici3(`pAjg7cUbBEvC=>ayO9tY}(nROQ%N zY;Gyi8QFh4ddgFeWY`Pj(#_R)6!Vo&@@24@!Gl=74z?-1!FEf-x;k(~1^rqvMQJuj zni|jTdj~PCi;PoFaG({GqWpUMz8Y;-Qtj5Mt(~f|K~)p)xw}<`GbpzJI{ISAYGo7; zDv@xu!1i6)q#C-Icj`J#PDP*u!Pk2B}MI5(vFUsg531vDio3m2BMFmv6qfqiC3G zlzk5MMBqj4Yd5Zh_HN&g{%gn2dp|P;FI%1~1usuT{sq?WS1eFn9k&1g002ovPDHLk FV1oXZ8h!u( literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/betterfoliage/textures/blocks/better_cactus_arm_0.png b/src/main/resources/assets/betterfoliage/textures/blocks/better_cactus_arm_0.png new file mode 100644 index 0000000000000000000000000000000000000000..9adb008689fc906e44686b3c1b129e7190d42f6c GIT binary patch literal 2923 zcmV-x3zYPUP)004&%004{+008|`004nN004b?008NW002DY000@xb3BE2000Uv zX+uL$Nkc;*P;zf(X>4Tx07%E3mUmQC*A|D*y?1({%`gH|hTglt0MdJtUPWP;8DJ;_ z4l^{dA)*2iMMRn+NKnLp(NH8-M6nPQRImpm2q-ZaMN}+rM%Ih2ti1Q~^84egZ|$@9 zx%=$B&srA%lBX}1mj+7#kjfMAgFKw+5s^`J>;QlP9$S?PR%=$HTzo3l9?ED;xoI3-JvF1F8#m>QQXW*8-A zz9>Nv%ZWK*kqtikEV84R*{M9Xh{ZXlvs2k(?iKO2Od&_ah_8qXGr62B5#JKAMv5?% zE8;ie*i;TP0{|3BY!`4?i6S-;F^L}%f`(o2L0Dz>ZZynda zx(`h}FNp#{x{a}MR#uh~m%}m=7xWMPPlvyuufAs_KJJh5&|Nw4Oks+EF0LCZEhSCJ zr)Q)ySsc3IpNIG#2mW;)20@&74xhslMTCi_jLS<9wVTK03b<)JI+ypKn)naH{-njZ z7KzgM5l~}{fYfy=Kz{89C<+lE(fh?+|D$id_%I-TdEqLPi*x_)H~nY9rQ#)noA5c# zB`Ac>67n+__r%Wu$9dISw03U@r;Pdb`_%=KWKZEBGfDjQH zqKX(I48#TTN1~8;gpaI8ijWGV0cl0Lkv`-mGK$O~Z&4T&1w}_0qHIx~s8AFOwFb2w zRf4KU9Y%GadQmq~W2jlwM>H9&h}K8jpuNx$=mc~Yx)5D~ZbG-CFQRXwC(y4k7z_=g zjj_UbVj?j~n6;P^%sxyT<{V}aGme?VVzKgAeXJeUAIroFu!Yzv>{0Al>=1SW`vynE zso>0T?zku%50{Utz#YMz!42UiaSM1Uye8fT?~iBWbMU43MtnE^I(`DbK#(SA6YK~f zge1ZyLM5SA?cA^NYNxAX$R>L=^W`U z=_Q#=)*?HSqsRjC4stX30{Id7jRZx)NWx2kEwMqOMxsMvNaDF9UQ$!iNpiJhu4IMe z3CZh{Gg5ddEh!f%rqp_=8mW^~BT{qH6lqgwf9X`|66qt-SEQ$8urgXQZZd3{0-1v{ z7i7jM2t}RZLSa!hQyM83DHBu-Rh#NXO`;Z4zoQONXJut%m&u07X3N&do|YY@Av7(T z7cGTWN;^&)roCIDw8Uu%XUX;@txJZM%*!p6bCl!A70I>9-IjYNPnUO-PnO>$-zoo4 z0i~d)5U7x)uwUV#!pu_YQro4hrA14RFTJM-E9xl*DXvvKsMxPKr=+app_HyvrF21Q zMwzDUsGOu+u6#y$T7{xwufkO+S2?TllrBqmqNmU+>Amz>RYg@#RiSFV>VWEknzmY~ zTE1GF+Cz1MIzv5Pys-#cBCZ~; zMXm#GGH#)6)ozd6)!Y-@Tijj2>R4y()XvmDLKXQ&yjjk&I!+oQOrohQ}U>eb4k~HZbSnyy9x( zW?3$*y{uH6t~>7#3G*6dj`%lF|oWk4CLGP(p*(a%)B zP)E2$IF@OjS(EuDD=h0owsbZxyFW)SXM4_Mu6ypcYf)=iYkTrk^ETy;t#evezaCm2 zx4vhC`i6oH6B|7?9^ORQl)UMue3SgL{8yX9H+L5(6>KaR-{P^QrBI@fUpTVWc5B@> z)Hd$6f$iqotG0hEVi#R4HYu(seqX{Wx%!RiH@;dd*9H0$NjB!N_E9`?+$Pe+^P4d?`Y6!s5po@n0fF?V_0L~w~TL_n-rRgn?4-k z9U46xbhx+Ks=4`y;*ru8xJB49eKh*$jqhB)>uNP@t#6~X6(0k~gvXwKAN&3Aai8No zCm1JMf6)A)ww=;m)B$zmbj)@pc8+#Mb`75NKH1Z4+ui=7(T|5tsh+AiEql834Bs>djZ*&hXA3QVUFm(Q=>&;8Iyl!2)z2f%ZaOm)z zk?4`pJM24CcT?`ZxR-fv;r_-4=m$j)r5;v1Qhe0#v+mDrqn4wm$6Uwy9|u3aKh7F| z_DjYu?mT-%DP~zdZD6*{hzpfVoGnQ(rI47rl{xbNDUeZQr}_casZQ@3HSIKj?nw{^;}Z z!Kc(upZ)~{nDhK^CfpAI000SaNLh0L01FcU01FcV0GgZ_0001{NklvdRuo|FlsPJD+5fZ_YZ$EyuSXG;pX`Vj8LUufZ_s}W?pd)s0ahY%WGf2hJgUOW)Q&Y0&y)K zFdO6o5I}atk!4qLy8r}0E&$mI10c;HfK4+9U>LBu{Tw665Saf#G{|;rni&`v7yur` VOM}EW3TOZT002ovPDHLkV1i(IbQu5u literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/betterfoliage/textures/blocks/better_cactus_arm_1.png b/src/main/resources/assets/betterfoliage/textures/blocks/better_cactus_arm_1.png new file mode 100644 index 0000000000000000000000000000000000000000..7523c1e78d1e3ccaefd9ad15a32c08091a0434a8 GIT binary patch literal 2955 zcmV;63v~2}P)004&%004{+008|`004nN004b?008NW002DY000@xb3BE2000Uv zX+uL$Nkc;*P;zf(X>4Tx07%E3mUmQC*A|D*y?1({%`gH|hTglt0MdJtUPWP;8DJ;_ z4l^{dA)*2iMMRn+NKnLp(NH8-M6nPQRImpm2q-ZaMN}+rM%Ih2ti1Q~^84egZ|$@9 zx%=$B&srA%lBX}1mj+7#kjfMAgFKw+5s^`J>;QlP9$S?PR%=$HTzo3l9?ED;xoI3-JvF1F8#m>QQXW*8-A zz9>Nv%ZWK*kqtikEV84R*{M9Xh{ZXlvs2k(?iKO2Od&_ah_8qXGr62B5#JKAMv5?% zE8;ie*i;TP0{|3BY!`4?i6S-;F^L}%f`(o2L0Dz>ZZynda zx(`h}FNp#{x{a}MR#uh~m%}m=7xWMPPlvyuufAs_KJJh5&|Nw4Oks+EF0LCZEhSCJ zr)Q)ySsc3IpNIG#2mW;)20@&74xhslMTCi_jLS<9wVTK03b<)JI+ypKn)naH{-njZ z7KzgM5l~}{fYfy=Kz{89C<+lE(fh?+|D$id_%I-TdEqLPi*x_)H~nY9rQ#)noA5c# zB`Ac>67n+__r%Wu$9dISw03U@r;Pdb`_%=KWKZEBGfDjQH zqKX(I48#TTN1~8;gpaI8ijWGV0cl0Lkv`-mGK$O~Z&4T&1w}_0qHIx~s8AFOwFb2w zRf4KU9Y%GadQmq~W2jlwM>H9&h}K8jpuNx$=mc~Yx)5D~ZbG-CFQRXwC(y4k7z_=g zjj_UbVj?j~n6;P^%sxyT<{V}aGme?VVzKgAeXJeUAIroFu!Yzv>{0Al>=1SW`vynE zso>0T?zku%50{Utz#YMz!42UiaSM1Uye8fT?~iBWbMU43MtnE^I(`DbK#(SA6YK~f zge1ZyLM5SA?cA^NYNxAX$R>L=^W`U z=_Q#=)*?HSqsRjC4stX30{Id7jRZx)NWx2kEwMqOMxsMvNaDF9UQ$!iNpiJhu4IMe z3CZh{Gg5ddEh!f%rqp_=8mW^~BT{qH6lqgwf9X`|66qt-SEQ$8urgXQZZd3{0-1v{ z7i7jM2t}RZLSa!hQyM83DHBu-Rh#NXO`;Z4zoQONXJut%m&u07X3N&do|YY@Av7(T z7cGTWN;^&)roCIDw8Uu%XUX;@txJZM%*!p6bCl!A70I>9-IjYNPnUO-PnO>$-zoo4 z0i~d)5U7x)uwUV#!pu_YQro4hrA14RFTJM-E9xl*DXvvKsMxPKr=+app_HyvrF21Q zMwzDUsGOu+u6#y$T7{xwufkO+S2?TllrBqmqNmU+>Amz>RYg@#RiSFV>VWEknzmY~ zTE1GF+Cz1MIzv5Pys-#cBCZ~; zMXm#GGH#)6)ozd6)!Y-@Tijj2>R4y()XvmDLKXQ&yjjk&I!+oQOrohQ}U>eb4k~HZbSnyy9x( zW?3$*y{uH6t~>7#3G*6dj`%lF|oWk4CLGP(p*(a%)B zP)E2$IF@OjS(EuDD=h0owsbZxyFW)SXM4_Mu6ypcYf)=iYkTrk^ETy;t#evezaCm2 zx4vhC`i6oH6B|7?9^ORQl)UMue3SgL{8yX9H+L5(6>KaR-{P^QrBI@fUpTVWc5B@> z)Hd$6f$iqotG0hEVi#R4HYu(seqX{Wx%!RiH@;dd*9H0$NjB!N_E9`?+$Pe+^P4d?`Y6!s5po@n0fF?V_0L~w~TL_n-rRgn?4-k z9U46xbhx+Ks=4`y;*ru8xJB49eKh*$jqhB)>uNP@t#6~X6(0k~gvXwKAN&3Aai8No zCm1JMf6)A)ww=;m)B$zmbj)@pc8+#Mb`75NKH1Z4+ui=7(T|5tsh+AiEql834Bs>djZ*&hXA3QVUFm(Q=>&;8Iyl!2)z2f%ZaOm)z zk?4`pJM24CcT?`ZxR-fv;r_-4=m$j)r5;v1Qhe0#v+mDrqn4wm$6Uwy9|u3aKh7F| z_DjYu?mT-%DP~zdZD6*{hzpfVoGnQ(rI47rl{xbNDUeZQr}_casZQ@3HSIKj?nw{^;}Z z!Kc(upZ)~{nDhK^CfpAI000SaNLh0L01FcU01FcV0GgZ_0002SNklBjvoiep`Wws! zf%gx8G8|cUl@ZDX0~8m4Bw?CCia~%^oC8c_(+mO_E&v$-QY>f24;5u#`1$28+$HD+ zVGTraEgmQf0@!(&!QKI3f?fdG0MhXJ-rtz9C@E-gg23FX~^bgB#zjkbiTH zU^LuKkCH)_`**q&++C;O-a3U(dpW@P57&zNS52y&JEd5g!Ng3;PsTN&*}vYghGTgA zc%z74Y`zK~Y!uDE&J@XhmIpfl&gqTB9L^d!wiOixojuy2i8g9pl>1q4Q{mUp{N-p_3jRJC*(ggPLeh3i*02-HPFkk>A`T2N3AkKkP^)J7U7R_ z^RW&L5Z6N+k_jm&MtL1G_42)BfVxZI{oKn4&4h@NYXQnI4loDdk}0WtUo(Pq9V&(Z z09Q8B&lDl?{(6fRK3$$)ibV_GGzCDy1;kcFHVzQtoo2@^&yqEJx?1Yc345#|G%R3t z?sbf77yzoBMY)iIN4QAR5e|Zg_JbWTjT!OoFpwYH zgvSYL{K=?RxNnK~@-Ugki2FQqL4Mqi(+@HJ0gigH1#p)@mH+?%07*qoM6N<$g7RWR Axc~qF diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_cactus_arm_0.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_cactus_arm_0.png deleted file mode 100644 index dd7de0576d3fcc9db517a3d35eac16d1ae43693a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2963 zcmV;E3vBd>P)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0002KNkli$002ov JPDHLkV1k$YdmaD) diff --git a/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_cactus_arm_1.png b/src/main/resources/assets/bettergrassandleaves/textures/blocks/better_cactus_arm_1.png deleted file mode 100644 index b758ab48186d6617702fac0ceea4c65b2f06ed7f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3011 zcmV;!3q16RP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0002)Nkl6|Wa%YBiAvg7 zIB{2r5^%dg-E}thc;r9-|FJ~~fqO!7XZ!>FHGncYjMrF*>vy1x4&FMEZkIu=X8583 zz`cFotrNcjD5Ha3&rz!x01wZa%h>_oizW&(kuWayowa!y_Av(Xnto3^-7JuK0>I-- z20*qmA>A$~n$-pru&?QfXvubaDmQe4H!WRuPPpA(k0J^dr>X);-nTU*ytv;Mc zHw(J5Mdk@z+4A*XMST#l@0{&S=zZuxoc*MFwKpby4*){{Yx5WX@yP%H002ovPDHLk FV1n{;nJNGP diff --git a/src/main/resources/betterfoliage.common.mixins.json b/src/main/resources/betterfoliage.common.mixins.json new file mode 100644 index 0000000..57a7336 --- /dev/null +++ b/src/main/resources/betterfoliage.common.mixins.json @@ -0,0 +1,21 @@ +{ + "required": true, + "package": "mods.betterfoliage.mixin", + "refmap": "betterfoliage.refmap.json", + "compatibilityLevel": "JAVA_8", + "minVersion": "0.8-SNAPSHOT", + "mixins": [ + ], + "client": [ + "BlockMixin", + "BlockStateMixin", + "ChunkRenderMixin", + "ClientWorldMixin", + "ModelBakeryMixin" + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file diff --git a/src/main/resources/betterfoliage.optifine.mixins.json b/src/main/resources/betterfoliage.optifine.mixins.json new file mode 100644 index 0000000..d4b3c97 --- /dev/null +++ b/src/main/resources/betterfoliage.optifine.mixins.json @@ -0,0 +1,17 @@ +{ + "required": true, + "package": "mods.betterfoliage.mixin", + "refmap": "betterfoliage.refmap.json", + "compatibilityLevel": "JAVA_8", + "minVersion": "0.8-SNAPSHOT", + "mixins": [ + ], + "client": [ + "ChunkRenderOptifineMixin" + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file diff --git a/src/main/resources/betterfoliage.vanilla.mixins.json b/src/main/resources/betterfoliage.vanilla.mixins.json new file mode 100644 index 0000000..ecb9d8c --- /dev/null +++ b/src/main/resources/betterfoliage.vanilla.mixins.json @@ -0,0 +1,17 @@ +{ + "required": true, + "package": "mods.betterfoliage.mixin", + "refmap": "betterfoliage.refmap.json", + "compatibilityLevel": "JAVA_8", + "minVersion": "0.8-SNAPSHOT", + "mixins": [ + ], + "client": [ + "ChunkRenderVanillaMixin" + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file diff --git a/src/main/resources/bf_generated_pack.png b/src/main/resources/bf_generated_pack.png new file mode 100644 index 0000000000000000000000000000000000000000..18a72dba06be16ced2b80654e784ea802549f77a GIT binary patch literal 682 zcmV;b0#*HqP)00001b5ch_0Itp) z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0zXMaK~!i%?U_wW z12GVWw;vXYB8Wo&g&unJQAlEyC;tx^j{S5q*Bm+__i6^>?Rv$v$KhXJO`V2 zn3*@3NhWQpvmRxKOq)IrmLwoHNkD9pfY>Afu}K1Alk0`n4>KB-)4e`lUUX@~hGV&m z)_6c88+!rpvATa&V>j)|aP#+WuzueG#%i`&sMo!$8{qU@T@5{cP30Pz7OceZ!82gaZFbz@7CI^2LCjqfZ0%GGY zpm0N>x1&*5JO%V#=eg)7LuO|xjzs_>JN`VPi2*Jwto{7zQB5o1w(Q40ZRYsTrdscT z9cYcvT+k$sw`E6zs3UU8mbnXIbyoS?UvFdt=t+-i4%u1@2r%!mkXQsD8fMq7-UfQ~P29C^ zD!&JG%!N05;HFy%nfHLg8eh`_WQrJ(VeJDakAijp_-%s9GAfu}K1AlLW*j35ZP+5SJ|b1+IrPT!7Q5 QRsaA107*qoM6N<$f($4m{{R30 literal 0 HcmV?d00001 diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta index 4a45a2a..395ba16 100644 --- a/src/main/resources/pack.mcmeta +++ b/src/main/resources/pack.mcmeta @@ -1,6 +1,6 @@ { "pack": { - "pack_format": 1, + "pack_format": 4, "description": "Better Foliage mod resources made by Meringue" } }