port to MC 1.8
13
build.gradle
@@ -1,12 +1,12 @@
|
|||||||
apply plugin: "forge"
|
apply plugin: "forge"
|
||||||
apply plugin: "kotlin"
|
apply plugin: 'kotlin'
|
||||||
|
|
||||||
group = 'com.github.octarine-noise'
|
group = 'com.github.octarine-noise'
|
||||||
version = "2.0"
|
version = "2.0"
|
||||||
archivesBaseName = rootProject.name + '-MC1.7.10'
|
archivesBaseName = rootProject.name + '-MC1.8'
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.0.0-beta-4583'
|
ext.kotlin_version = '1.0.0-beta-4584'
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
maven {
|
maven {
|
||||||
@@ -29,10 +29,12 @@ configurations {
|
|||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
shade "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
shade "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||||
|
|
||||||
}
|
}
|
||||||
minecraft {
|
minecraft {
|
||||||
version = '1.7.10-10.13.4.1448-1.7.10'
|
version = '1.8-11.14.3.1502'
|
||||||
srgExtra "PK: kotlin mods/betterfoliage/kotlin"
|
mappings = 'stable_18'
|
||||||
|
srgExtra "PK: kotlin mods/octarinecore/kotlin"
|
||||||
}
|
}
|
||||||
|
|
||||||
processResources {
|
processResources {
|
||||||
@@ -55,6 +57,7 @@ jar {
|
|||||||
manifest {
|
manifest {
|
||||||
attributes "FMLCorePlugin": "mods.betterfoliage.loader.BetterFoliageLoader"
|
attributes "FMLCorePlugin": "mods.betterfoliage.loader.BetterFoliageLoader"
|
||||||
attributes "FMLCorePluginContainsFMLMod": "mods.betterfoliage.BetterFoliageMod"
|
attributes "FMLCorePluginContainsFMLMod": "mods.betterfoliage.BetterFoliageMod"
|
||||||
|
attributes "FMLAT": "BetterFoliage_at.cfg"
|
||||||
}
|
}
|
||||||
configurations.shade.each { dep ->
|
configurations.shade.each { dep ->
|
||||||
from(project.zipTree(dep)){
|
from(project.zipTree(dep)){
|
||||||
|
|||||||
25
src/main/java/net/minecraft/client/BFBlockModelRenderer.java
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package net.minecraft.client;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.client.renderer.BlockModelRenderer;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
|
||||||
|
import java.util.BitSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FFS why isn't this public static...
|
||||||
|
*/
|
||||||
|
public class BFBlockModelRenderer extends BlockModelRenderer {
|
||||||
|
public class BFAmbientOcclusionFace extends BlockModelRenderer.AmbientOcclusionFace {}
|
||||||
|
|
||||||
|
private static BFBlockModelRenderer INSTANCE = new BFBlockModelRenderer();
|
||||||
|
|
||||||
|
public static BFAmbientOcclusionFace getVanillaAoObject() {
|
||||||
|
return INSTANCE.new BFAmbientOcclusionFace();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void fillQuadBounds2(Block blockIn, int[] vertexData, EnumFacing facingIn, float[] quadBounds, BitSet boundsFlags) {
|
||||||
|
INSTANCE.fillQuadBounds(blockIn, vertexData, facingIn, quadBounds, boundsFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,19 +1,15 @@
|
|||||||
package mods.betterfoliage
|
package mods.betterfoliage
|
||||||
|
|
||||||
import cpw.mods.fml.common.FMLCommonHandler
|
|
||||||
import cpw.mods.fml.common.Mod
|
|
||||||
import cpw.mods.fml.common.event.FMLPostInitializationEvent
|
|
||||||
import cpw.mods.fml.common.event.FMLPreInitializationEvent
|
|
||||||
import cpw.mods.fml.common.network.NetworkCheckHandler
|
|
||||||
import cpw.mods.fml.relauncher.Side
|
|
||||||
import mods.betterfoliage.client.Client
|
import mods.betterfoliage.client.Client
|
||||||
import mods.betterfoliage.client.config.Config
|
import mods.betterfoliage.client.config.Config
|
||||||
import mods.betterfoliage.client.integration.ShadersModIntegration
|
|
||||||
import mods.betterfoliage.client.integration.TFCIntegration
|
|
||||||
import mods.betterfoliage.loader.Refs
|
|
||||||
import mods.octarinecore.metaprog.ClassRef
|
|
||||||
import net.minecraftforge.common.config.Configuration
|
import net.minecraftforge.common.config.Configuration
|
||||||
import org.apache.logging.log4j.Level.*
|
import net.minecraftforge.fml.common.FMLCommonHandler
|
||||||
|
import net.minecraftforge.fml.common.Mod
|
||||||
|
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent
|
||||||
|
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent
|
||||||
|
import net.minecraftforge.fml.common.network.NetworkCheckHandler
|
||||||
|
import net.minecraftforge.fml.relauncher.Side
|
||||||
|
import org.apache.logging.log4j.Level.INFO
|
||||||
import org.apache.logging.log4j.Logger
|
import org.apache.logging.log4j.Logger
|
||||||
|
|
||||||
@Mod(
|
@Mod(
|
||||||
@@ -28,7 +24,7 @@ object BetterFoliageMod {
|
|||||||
const val MOD_NAME = "Better Foliage"
|
const val MOD_NAME = "Better Foliage"
|
||||||
const val DOMAIN = "betterfoliage"
|
const val DOMAIN = "betterfoliage"
|
||||||
const val LEGACY_DOMAIN = "bettergrassandleaves"
|
const val LEGACY_DOMAIN = "bettergrassandleaves"
|
||||||
const val MC_VERSIONS = "[1.7.10]"
|
const val MC_VERSIONS = "[1.8]"
|
||||||
const val GUI_FACTORY = "mods.betterfoliage.client.gui.ConfigGuiFactory"
|
const val GUI_FACTORY = "mods.betterfoliage.client.gui.ConfigGuiFactory"
|
||||||
|
|
||||||
var log: Logger? = null
|
var log: Logger? = null
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
package mods.betterfoliage.client
|
package mods.betterfoliage.client
|
||||||
|
|
||||||
import cpw.mods.fml.client.FMLClientHandler
|
|
||||||
import cpw.mods.fml.relauncher.Side
|
|
||||||
import cpw.mods.fml.relauncher.SideOnly
|
|
||||||
import mods.betterfoliage.BetterFoliageMod
|
import mods.betterfoliage.BetterFoliageMod
|
||||||
import mods.betterfoliage.client.gui.ConfigGuiFactory
|
import mods.betterfoliage.client.gui.ConfigGuiFactory
|
||||||
import mods.betterfoliage.client.integration.CLCIntegration
|
|
||||||
import mods.betterfoliage.client.integration.ShadersModIntegration
|
import mods.betterfoliage.client.integration.ShadersModIntegration
|
||||||
import mods.betterfoliage.client.integration.TFCIntegration
|
|
||||||
import mods.betterfoliage.client.render.*
|
import mods.betterfoliage.client.render.*
|
||||||
import mods.betterfoliage.client.texture.*
|
import mods.betterfoliage.client.texture.GrassGenerator
|
||||||
|
import mods.betterfoliage.client.texture.GrassRegistry
|
||||||
|
import mods.betterfoliage.client.texture.LeafGenerator
|
||||||
|
import mods.betterfoliage.client.texture.LeafRegistry
|
||||||
import mods.octarinecore.client.KeyHandler
|
import mods.octarinecore.client.KeyHandler
|
||||||
import mods.octarinecore.client.resource.CenteringTextureGenerator
|
import mods.octarinecore.client.resource.CenteringTextureGenerator
|
||||||
import mods.octarinecore.client.resource.GeneratorPack
|
import mods.octarinecore.client.resource.GeneratorPack
|
||||||
import net.minecraft.client.Minecraft
|
import net.minecraft.client.Minecraft
|
||||||
|
import net.minecraftforge.fml.client.FMLClientHandler
|
||||||
|
import net.minecraftforge.fml.relauncher.Side
|
||||||
|
import net.minecraftforge.fml.relauncher.SideOnly
|
||||||
import org.apache.logging.log4j.Level
|
import org.apache.logging.log4j.Level
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -65,9 +66,7 @@ object Client {
|
|||||||
GrassRegistry,
|
GrassRegistry,
|
||||||
LeafWindTracker,
|
LeafWindTracker,
|
||||||
RisingSoulTextures,
|
RisingSoulTextures,
|
||||||
TFCIntegration,
|
ShadersModIntegration
|
||||||
ShadersModIntegration,
|
|
||||||
CLCIntegration
|
|
||||||
)
|
)
|
||||||
|
|
||||||
fun log(level: Level, msg: String) = BetterFoliageMod.log!!.log(level, msg)
|
fun log(level: Level, msg: String) = BetterFoliageMod.log!!.log(level, msg)
|
||||||
|
|||||||
@@ -2,32 +2,33 @@
|
|||||||
@file:SideOnly(Side.CLIENT)
|
@file:SideOnly(Side.CLIENT)
|
||||||
package mods.betterfoliage.client
|
package mods.betterfoliage.client
|
||||||
|
|
||||||
import cpw.mods.fml.relauncher.Side
|
|
||||||
import cpw.mods.fml.relauncher.SideOnly
|
|
||||||
import mods.betterfoliage.client.config.Config
|
import mods.betterfoliage.client.config.Config
|
||||||
import mods.betterfoliage.client.render.EntityFallingLeavesFX
|
import mods.betterfoliage.client.render.EntityFallingLeavesFX
|
||||||
import mods.betterfoliage.client.render.EntityRisingSoulFX
|
import mods.betterfoliage.client.render.EntityRisingSoulFX
|
||||||
|
import mods.betterfoliage.client.render.down1
|
||||||
|
import mods.betterfoliage.client.render.up1
|
||||||
import mods.octarinecore.client.render.blockContext
|
import mods.octarinecore.client.render.blockContext
|
||||||
|
import mods.octarinecore.client.resource.LoadModelDataEvent
|
||||||
|
import mods.octarinecore.common.plus
|
||||||
import net.minecraft.block.Block
|
import net.minecraft.block.Block
|
||||||
import net.minecraft.client.Minecraft
|
import net.minecraft.block.state.IBlockState
|
||||||
|
import net.minecraft.client.renderer.BlockRendererDispatcher
|
||||||
|
import net.minecraft.client.renderer.WorldRenderer
|
||||||
import net.minecraft.init.Blocks
|
import net.minecraft.init.Blocks
|
||||||
|
import net.minecraft.util.BlockPos
|
||||||
|
import net.minecraft.util.EnumFacing
|
||||||
|
import net.minecraft.util.EnumWorldBlockLayer
|
||||||
|
import net.minecraft.util.EnumWorldBlockLayer.CUTOUT
|
||||||
|
import net.minecraft.util.EnumWorldBlockLayer.CUTOUT_MIPPED
|
||||||
import net.minecraft.world.IBlockAccess
|
import net.minecraft.world.IBlockAccess
|
||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
|
import net.minecraftforge.client.model.ModelLoader
|
||||||
|
import net.minecraftforge.common.MinecraftForge
|
||||||
|
import net.minecraftforge.fml.relauncher.Side
|
||||||
|
import net.minecraftforge.fml.relauncher.SideOnly
|
||||||
|
|
||||||
fun getRenderTypeOverride(blockAccess: IBlockAccess, x: Int, y: Int, z: Int, block: Block, original: Int): Int {
|
fun shouldRenderBlockSideOverride(original: Boolean, blockAccess: IBlockAccess, pos: BlockPos, side: EnumFacing): Boolean {
|
||||||
if (!Config.enabled) return original;
|
return original || (Config.enabled && Config.roundLogs.enabled && Config.blocks.logs.matchesID(blockAccess.getBlockState(pos).block));
|
||||||
|
|
||||||
// universal sign for DON'T RENDER ME!
|
|
||||||
if (original == -1) return original;
|
|
||||||
|
|
||||||
return blockContext.let { ctx ->
|
|
||||||
ctx.set(blockAccess, x, y, z)
|
|
||||||
Client.renderers.find { it.isEligible(ctx) }?.renderId ?: original
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun shouldRenderBlockSideOverride(original: Boolean, blockAccess: IBlockAccess, x: Int, y: Int, z: Int, side: Int): Boolean {
|
|
||||||
return original || (Config.enabled && Config.roundLogs.enabled && Config.blocks.logs.matchesID(blockAccess.getBlock(x, y, z)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getAmbientOcclusionLightValueOverride(original: Float, block: Block): Float {
|
fun getAmbientOcclusionLightValueOverride(original: Float, block: Block): Float {
|
||||||
@@ -39,20 +40,58 @@ fun getUseNeighborBrightnessOverride(original: Boolean, block: Block): Boolean {
|
|||||||
return original || (Config.enabled && Config.roundLogs.enabled && Config.blocks.logs.matchesID(block));
|
return original || (Config.enabled && Config.roundLogs.enabled && Config.blocks.logs.matchesID(block));
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onRandomDisplayTick(block: Block, world: World, x: Int, y: Int, z: Int) {
|
fun onRandomDisplayTick(world: World, state: IBlockState, pos: BlockPos) {
|
||||||
if (Config.enabled &&
|
if (Config.enabled &&
|
||||||
Config.risingSoul.enabled &&
|
Config.risingSoul.enabled &&
|
||||||
block == Blocks.soul_sand &&
|
state.block == Blocks.soul_sand &&
|
||||||
world.isAirBlock(x, y + 1, z) &&
|
world.isAirBlock(pos + up1) &&
|
||||||
Math.random() < Config.risingSoul.chance) {
|
Math.random() < Config.risingSoul.chance) {
|
||||||
EntityRisingSoulFX(world, x, y, z).addIfValid()
|
EntityRisingSoulFX(world, pos).addIfValid()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Config.enabled &&
|
if (Config.enabled &&
|
||||||
Config.fallingLeaves.enabled &&
|
Config.fallingLeaves.enabled &&
|
||||||
Config.blocks.leaves.matchesID(block) &&
|
Config.blocks.leaves.matchesID(state.block) &&
|
||||||
world.isAirBlock(x, y - 1, z) &&
|
world.isAirBlock(pos + down1) &&
|
||||||
Math.random() < Config.fallingLeaves.chance) {
|
Math.random() < Config.fallingLeaves.chance) {
|
||||||
EntityFallingLeavesFX(world, x, y, z).addIfValid()
|
EntityFallingLeavesFX(world, pos).addIfValid()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onAfterLoadModelDefinitions(loader: ModelLoader) {
|
||||||
|
MinecraftForge.EVENT_BUS.post(LoadModelDataEvent(loader))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun renderWorldBlock(dispatcher: BlockRendererDispatcher,
|
||||||
|
state: IBlockState,
|
||||||
|
pos: BlockPos,
|
||||||
|
blockAccess: IBlockAccess,
|
||||||
|
worldRenderer: WorldRenderer,
|
||||||
|
layer: EnumWorldBlockLayer
|
||||||
|
): Boolean {
|
||||||
|
val isCutout = layer == CUTOUT_MIPPED || layer == CUTOUT
|
||||||
|
val needsCutout = state.block.canRenderInLayer(CUTOUT_MIPPED) || state.block.canRenderInLayer(CUTOUT)
|
||||||
|
val canRender = (isCutout && needsCutout) || state.block.canRenderInLayer(layer)
|
||||||
|
|
||||||
|
blockContext.let { ctx ->
|
||||||
|
ctx.set(blockAccess, pos)
|
||||||
|
Client.renderers.forEach { renderer ->
|
||||||
|
if (renderer.isEligible(ctx)) {
|
||||||
|
return if (renderer.moveToCutout) {
|
||||||
|
if (isCutout) renderer.render(ctx, dispatcher, worldRenderer, layer) else false
|
||||||
|
} else {
|
||||||
|
renderer.render(ctx, dispatcher, worldRenderer, layer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return if (canRender) dispatcher.renderBlock(state, pos, blockAccess, worldRenderer) else false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun canRenderBlockInLayer(block: Block, layer: EnumWorldBlockLayer): Boolean {
|
||||||
|
if (layer == CUTOUT_MIPPED && !block.canRenderInLayer(CUTOUT)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return block.canRenderInLayer(layer)
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
package mods.betterfoliage.client.config
|
package mods.betterfoliage.client.config
|
||||||
|
|
||||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent
|
|
||||||
import mods.octarinecore.client.gui.NonVerboseArrayEntry
|
import mods.octarinecore.client.gui.NonVerboseArrayEntry
|
||||||
import mods.octarinecore.client.resource.get
|
import mods.octarinecore.client.resource.get
|
||||||
import mods.octarinecore.client.resource.getLines
|
import mods.octarinecore.client.resource.getLines
|
||||||
import mods.octarinecore.client.resource.resourceManager
|
import mods.octarinecore.client.resource.resourceManager
|
||||||
import mods.octarinecore.config.ConfigPropertyBase
|
import mods.octarinecore.common.config.ConfigPropertyBase
|
||||||
import mods.octarinecore.metaprog.getJavaClass
|
import mods.octarinecore.metaprog.getJavaClass
|
||||||
import net.minecraft.block.Block
|
import net.minecraft.block.Block
|
||||||
import net.minecraft.client.multiplayer.WorldClient
|
import net.minecraft.client.multiplayer.WorldClient
|
||||||
@@ -13,6 +12,7 @@ import net.minecraftforge.common.MinecraftForge
|
|||||||
import net.minecraftforge.common.config.Configuration
|
import net.minecraftforge.common.config.Configuration
|
||||||
import net.minecraftforge.common.config.Property
|
import net.minecraftforge.common.config.Property
|
||||||
import net.minecraftforge.event.world.WorldEvent
|
import net.minecraftforge.event.world.WorldEvent
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Match blocks based on their class names. Caches block IDs for faster lookup.
|
* Match blocks based on their class names. Caches block IDs for faster lookup.
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
package mods.betterfoliage.client.config
|
package mods.betterfoliage.client.config
|
||||||
|
|
||||||
import cpw.mods.fml.client.event.ConfigChangedEvent
|
|
||||||
import cpw.mods.fml.relauncher.Side
|
|
||||||
import cpw.mods.fml.relauncher.SideOnly
|
|
||||||
import mods.betterfoliage.BetterFoliageMod
|
import mods.betterfoliage.BetterFoliageMod
|
||||||
import mods.betterfoliage.client.gui.BiomeListConfigEntry
|
import mods.betterfoliage.client.gui.BiomeListConfigEntry
|
||||||
import mods.octarinecore.config.*
|
import mods.octarinecore.common.config.*
|
||||||
import mods.octarinecore.metaprog.reflectField
|
import mods.octarinecore.metaprog.reflectField
|
||||||
import net.minecraft.client.Minecraft
|
import net.minecraft.client.Minecraft
|
||||||
import net.minecraft.world.biome.BiomeGenBase
|
import net.minecraft.world.biome.BiomeGenBase
|
||||||
|
import net.minecraftforge.fml.client.event.ConfigChangedEvent
|
||||||
|
import net.minecraftforge.fml.relauncher.Side
|
||||||
|
import net.minecraftforge.fml.relauncher.SideOnly
|
||||||
|
|
||||||
// BetterFoliage-specific property delegates
|
// BetterFoliage-specific property delegates
|
||||||
private fun featureEnable() = boolean(true).lang("enabled")
|
private fun featureEnable() = boolean(true).lang("enabled")
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
package mods.betterfoliage.client.gui
|
package mods.betterfoliage.client.gui
|
||||||
|
|
||||||
import cpw.mods.fml.client.config.GuiConfig
|
|
||||||
import cpw.mods.fml.client.config.GuiConfigEntries
|
|
||||||
import cpw.mods.fml.client.config.IConfigElement
|
|
||||||
import mods.octarinecore.client.gui.IdListConfigEntry
|
import mods.octarinecore.client.gui.IdListConfigEntry
|
||||||
import net.minecraft.world.biome.BiomeGenBase
|
import net.minecraft.world.biome.BiomeGenBase
|
||||||
|
import net.minecraftforge.fml.client.config.GuiConfig
|
||||||
|
import net.minecraftforge.fml.client.config.GuiConfigEntries
|
||||||
|
import net.minecraftforge.fml.client.config.IConfigElement
|
||||||
|
|
||||||
/** Toggleable list of all defined biomes. */
|
/** Toggleable list of all defined biomes. */
|
||||||
class BiomeListConfigEntry(
|
class BiomeListConfigEntry(
|
||||||
owningScreen: GuiConfig,
|
owningScreen: GuiConfig,
|
||||||
owningEntryList: GuiConfigEntries,
|
owningEntryList: GuiConfigEntries,
|
||||||
configElement: IConfigElement<*>)
|
configElement: IConfigElement)
|
||||||
: IdListConfigEntry<BiomeGenBase>(owningScreen, owningEntryList, configElement) {
|
: IdListConfigEntry<BiomeGenBase>(owningScreen, owningEntryList, configElement) {
|
||||||
|
|
||||||
override val baseSet: List<BiomeGenBase> get() = BiomeGenBase.getBiomeGenArray().filterNotNull()
|
override val baseSet: List<BiomeGenBase> get() = BiomeGenBase.getBiomeGenArray().filterNotNull()
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
package mods.betterfoliage.client.gui
|
package mods.betterfoliage.client.gui
|
||||||
|
|
||||||
import cpw.mods.fml.client.IModGuiFactory
|
|
||||||
import cpw.mods.fml.client.IModGuiFactory.RuntimeOptionCategoryElement
|
|
||||||
import cpw.mods.fml.client.config.GuiConfig
|
|
||||||
import mods.betterfoliage.BetterFoliageMod
|
import mods.betterfoliage.BetterFoliageMod
|
||||||
import mods.betterfoliage.client.config.Config
|
import mods.betterfoliage.client.config.Config
|
||||||
import net.minecraft.client.Minecraft
|
import net.minecraft.client.Minecraft
|
||||||
import net.minecraft.client.gui.GuiScreen
|
import net.minecraft.client.gui.GuiScreen
|
||||||
|
import net.minecraftforge.fml.client.IModGuiFactory
|
||||||
|
import net.minecraftforge.fml.client.config.GuiConfig
|
||||||
|
|
||||||
class ConfigGuiFactory : IModGuiFactory {
|
class ConfigGuiFactory : IModGuiFactory {
|
||||||
|
|
||||||
override fun mainConfigGuiClass() = ConfigGuiBetterFoliage::class.java
|
override fun mainConfigGuiClass() = ConfigGuiBetterFoliage::class.java
|
||||||
override fun runtimeGuiCategories() = hashSetOf<RuntimeOptionCategoryElement>()
|
override fun runtimeGuiCategories() = hashSetOf<IModGuiFactory.RuntimeOptionCategoryElement>()
|
||||||
override fun getHandlerFor(element: RuntimeOptionCategoryElement?) = null
|
override fun getHandlerFor(element: IModGuiFactory.RuntimeOptionCategoryElement?) = null
|
||||||
override fun initialize(minecraftInstance: Minecraft?) { }
|
override fun initialize(minecraftInstance: Minecraft?) { }
|
||||||
|
|
||||||
class ConfigGuiBetterFoliage(parentScreen: GuiScreen?) : GuiConfig(
|
class ConfigGuiBetterFoliage(parentScreen: GuiScreen?) : GuiConfig(
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
package mods.betterfoliage.client.integration
|
|
||||||
|
|
||||||
import mods.betterfoliage.client.Client
|
|
||||||
import mods.betterfoliage.loader.Refs
|
|
||||||
import mods.octarinecore.client.render.brightnessComponents
|
|
||||||
import org.apache.logging.log4j.Level.*
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Integration for Colored Lights Core.
|
|
||||||
*/
|
|
||||||
object CLCIntegration {
|
|
||||||
|
|
||||||
init {
|
|
||||||
if (Refs.CLCLoadingPlugin.element != null) {
|
|
||||||
Client.log(INFO, "Colored Lights Core integration enabled")
|
|
||||||
brightnessComponents = listOf(4, 8, 12, 16, 20)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +1,17 @@
|
|||||||
package mods.betterfoliage.client.integration
|
package mods.betterfoliage.client.integration
|
||||||
|
|
||||||
import cpw.mods.fml.relauncher.Side
|
|
||||||
import cpw.mods.fml.relauncher.SideOnly
|
|
||||||
import mods.betterfoliage.client.Client
|
import mods.betterfoliage.client.Client
|
||||||
import mods.betterfoliage.client.config.Config
|
import mods.betterfoliage.client.config.Config
|
||||||
import mods.betterfoliage.loader.Refs
|
import mods.betterfoliage.loader.Refs
|
||||||
import mods.octarinecore.metaprog.allAvailable
|
import mods.octarinecore.metaprog.allAvailable
|
||||||
import net.minecraft.block.Block
|
import net.minecraft.block.Block
|
||||||
|
import net.minecraft.block.BlockTallGrass
|
||||||
|
import net.minecraft.block.state.IBlockState
|
||||||
|
import net.minecraft.client.renderer.WorldRenderer
|
||||||
import net.minecraft.init.Blocks
|
import net.minecraft.init.Blocks
|
||||||
import org.apache.logging.log4j.Level.*
|
import net.minecraftforge.fml.relauncher.Side
|
||||||
|
import net.minecraftforge.fml.relauncher.SideOnly
|
||||||
|
import org.apache.logging.log4j.Level.INFO
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Integration for ShadersMod.
|
* Integration for ShadersMod.
|
||||||
@@ -17,37 +20,53 @@ import org.apache.logging.log4j.Level.*
|
|||||||
object ShadersModIntegration {
|
object ShadersModIntegration {
|
||||||
|
|
||||||
@JvmStatic var isPresent = false
|
@JvmStatic var isPresent = false
|
||||||
@JvmStatic val tallGrassEntityData = Block.blockRegistry.getIDForObject(Blocks.tallgrass) and 65535 or (Blocks.tallgrass.renderType shl 16)
|
@JvmStatic val tallGrassEntityData = entityDataFor(Blocks.tallgrass.defaultState.withProperty(BlockTallGrass.TYPE, BlockTallGrass.EnumType.GRASS))
|
||||||
@JvmStatic val leavesEntityData = Block.blockRegistry.getIDForObject(Blocks.leaves) and 65535 or (Blocks.leaves.renderType shl 16)
|
@JvmStatic val leavesEntityData = entityDataFor(Blocks.leaves.defaultState)
|
||||||
|
|
||||||
|
fun entityDataFor(blockState: IBlockState) =
|
||||||
|
(Block.blockRegistry.getIDForObject(blockState.block).toLong() and 65535) or
|
||||||
|
((blockState.block.renderType.toLong() and 65535) shl 16) or
|
||||||
|
(blockState.block.getMetaFromState(blockState).toLong() shl 32)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called from transformed ShadersMod code.
|
* Called from transformed ShadersMod code.
|
||||||
* @see mods.betterfoliage.loader.BetterFoliageTransformer
|
* @see mods.betterfoliage.loader.BetterFoliageTransformer
|
||||||
*/
|
*/
|
||||||
@JvmStatic fun getBlockIdOverride(original: Int, block: Block): Int {
|
@JvmStatic fun getBlockIdOverride(original: Long, blockState: IBlockState): Long {
|
||||||
if (Config.blocks.leaves.matchesID(original and 65535)) return leavesEntityData
|
if (Config.blocks.leaves.matchesID(blockState.block)) return leavesEntityData
|
||||||
if (Config.blocks.crops.matchesID(original and 65535)) return tallGrassEntityData
|
if (Config.blocks.crops.matchesID(blockState.block)) return tallGrassEntityData
|
||||||
return original
|
return original
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (allAvailable(Refs.pushEntity_I, Refs.popEntity)) {
|
if (allAvailable(Refs.sVertexBuilder, Refs.pushEntity_state, Refs.pushEntity_num, Refs.popEntity)) {
|
||||||
Client.log(INFO, "ShadersMod integration enabled")
|
Client.log(INFO, "ShadersMod integration enabled")
|
||||||
isPresent = true
|
isPresent = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Quads rendered inside this block will behave as tallgrass blocks in shader programs. */
|
/** Quads rendered inside this block will behave as tallgrass blocks in shader programs. */
|
||||||
inline fun grass(enabled: Boolean = true, func: ()->Unit) {
|
inline fun grass(renderer: WorldRenderer, enabled: Boolean = true, func: ()->Unit) {
|
||||||
if (isPresent && enabled) Refs.pushEntity_I.invokeStatic(tallGrassEntityData)
|
if ((isPresent && enabled)) {
|
||||||
func()
|
val vertexBuilder = Refs.sVertexBuilder.get(renderer)!!
|
||||||
if (isPresent && enabled) Refs.popEntity.invokeStatic()
|
Refs.pushEntity_num.invoke(vertexBuilder, tallGrassEntityData)
|
||||||
|
func()
|
||||||
|
Refs.popEntity.invoke(vertexBuilder)
|
||||||
|
} else {
|
||||||
|
func()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Quads rendered inside this block will behave as leaf blocks in shader programs. */
|
/** Quads rendered inside this block will behave as leaf blocks in shader programs. */
|
||||||
inline fun leaves(enabled: Boolean = true, func: ()->Unit) {
|
inline fun leaves(renderer: WorldRenderer, enabled: Boolean = true, func: ()->Unit) {
|
||||||
if (isPresent && enabled) Refs.pushEntity_I.invokeStatic(leavesEntityData)
|
if ((isPresent && enabled)) {
|
||||||
func()
|
val vertexBuilder = Refs.sVertexBuilder.get(renderer)!!
|
||||||
if (isPresent && enabled) Refs.popEntity.invokeStatic()
|
Refs.pushEntity_num.invoke(vertexBuilder, leavesEntityData.toLong())
|
||||||
|
func()
|
||||||
|
Refs.popEntity.invoke(vertexBuilder)
|
||||||
|
} else {
|
||||||
|
func()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
package mods.betterfoliage.client.integration
|
|
||||||
|
|
||||||
import cpw.mods.fml.common.Loader
|
|
||||||
import cpw.mods.fml.relauncher.Side
|
|
||||||
import cpw.mods.fml.relauncher.SideOnly
|
|
||||||
import mods.betterfoliage.client.Client
|
|
||||||
import mods.octarinecore.client.render.Axis
|
|
||||||
import net.minecraft.block.Block
|
|
||||||
import org.apache.logging.log4j.Level
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Integration for TerraFirmaCraft
|
|
||||||
*/
|
|
||||||
@SideOnly(Side.CLIENT)
|
|
||||||
object TFCIntegration {
|
|
||||||
@JvmStatic val vanillaLogAxis = Client.logRenderer.axisFunc
|
|
||||||
|
|
||||||
init {
|
|
||||||
if (Loader.isModLoaded("terrafirmacraft")) {
|
|
||||||
Client.log(Level.INFO, "TerraFirmaCraft found - setting up compatibility")
|
|
||||||
|
|
||||||
// patch axis detection for log blocks to support TFC logs
|
|
||||||
Client.logRenderer.axisFunc = { block: Block, meta: Int ->
|
|
||||||
block.javaClass.name.let {
|
|
||||||
if (it.startsWith("com.bioxx.tfc")) {
|
|
||||||
if (it.contains("Horiz"))
|
|
||||||
if (meta shr 3 == 0) Axis.Z else Axis.X
|
|
||||||
else
|
|
||||||
Axis.Y
|
|
||||||
} else {
|
|
||||||
vanillaLogAxis(block, meta)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,35 @@
|
|||||||
package mods.betterfoliage.client.render
|
package mods.betterfoliage.client.render
|
||||||
|
|
||||||
|
import mods.betterfoliage.client.config.BlockMatcher
|
||||||
import mods.betterfoliage.client.render.AbstractRenderColumn.BlockType.*
|
import mods.betterfoliage.client.render.AbstractRenderColumn.BlockType.*
|
||||||
import mods.betterfoliage.client.render.AbstractRenderColumn.QuadrantType.*
|
import mods.betterfoliage.client.render.AbstractRenderColumn.QuadrantType.*
|
||||||
import mods.octarinecore.client.render.*
|
import mods.octarinecore.client.render.*
|
||||||
import net.minecraft.block.Block
|
import mods.octarinecore.client.resource.BlockTextureInspector
|
||||||
import net.minecraft.client.renderer.RenderBlocks
|
import mods.octarinecore.common.Int3
|
||||||
import net.minecraftforge.common.util.ForgeDirection.*
|
import mods.octarinecore.common.Rotation
|
||||||
|
import mods.octarinecore.common.face
|
||||||
|
import mods.octarinecore.common.rot
|
||||||
|
import net.minecraft.block.state.IBlockState
|
||||||
|
import net.minecraft.client.renderer.BlockRendererDispatcher
|
||||||
|
import net.minecraft.client.renderer.WorldRenderer
|
||||||
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite
|
||||||
|
import net.minecraft.client.renderer.texture.TextureMap
|
||||||
|
import net.minecraft.util.EnumFacing
|
||||||
|
import net.minecraft.util.EnumFacing.*
|
||||||
|
import net.minecraft.util.EnumWorldBlockLayer
|
||||||
|
|
||||||
|
data class ColumnInfo(val topTexture: TextureAtlasSprite,
|
||||||
|
val bottomTexture: TextureAtlasSprite,
|
||||||
|
val sideTexture: TextureAtlasSprite)
|
||||||
|
|
||||||
|
open class ColumnTextures(val matcher: BlockMatcher) : BlockTextureInspector<ColumnInfo>() {
|
||||||
|
init {
|
||||||
|
matchClassAndModel(matcher, "block/column_side", listOf("end", "end", "side"))
|
||||||
|
matchClassAndModel(matcher, "block/cube_column", listOf("end", "end", "side"))
|
||||||
|
}
|
||||||
|
override fun processTextures(textures: List<TextureAtlasSprite>, atlas: TextureMap) =
|
||||||
|
ColumnInfo(textures[0], textures[1], textures[2])
|
||||||
|
}
|
||||||
|
|
||||||
/** Index of SOUTH-EAST quadrant. */
|
/** Index of SOUTH-EAST quadrant. */
|
||||||
const val SE = 0
|
const val SE = 0
|
||||||
@@ -30,7 +54,7 @@ abstract class AbstractRenderColumn(modId: String) : AbstractBlockRenderingHandl
|
|||||||
// ============================
|
// ============================
|
||||||
abstract val radiusSmall: Double
|
abstract val radiusSmall: Double
|
||||||
abstract val radiusLarge: Double
|
abstract val radiusLarge: Double
|
||||||
abstract val surroundPredicate: (Block) -> Boolean
|
abstract val surroundPredicate: (IBlockState) -> Boolean
|
||||||
abstract val connectPerpendicular: Boolean
|
abstract val connectPerpendicular: Boolean
|
||||||
abstract val connectSolids: Boolean
|
abstract val connectSolids: Boolean
|
||||||
abstract val lenientConnect: Boolean
|
abstract val lenientConnect: Boolean
|
||||||
@@ -89,26 +113,26 @@ abstract class AbstractRenderColumn(modId: String) : AbstractBlockRenderingHandl
|
|||||||
val transitionTop = model { mix(sideRoundLarge.model, sideRoundSmall.model) { it > 1 } }
|
val transitionTop = model { mix(sideRoundLarge.model, sideRoundSmall.model) { it > 1 } }
|
||||||
val transitionBottom = model { mix(sideRoundSmall.model, sideRoundLarge.model) { it > 1 } }
|
val transitionBottom = model { mix(sideRoundSmall.model, sideRoundLarge.model) { it > 1 } }
|
||||||
|
|
||||||
val sideTexture = { ctx: ShadingContext, qi: Int, q: Quad -> if ((qi and 1) == 0) ctx.icon(SOUTH) else ctx.icon(EAST) }
|
|
||||||
val upTexture = { ctx: ShadingContext, qi: Int, q: Quad -> ctx.icon(UP) }
|
|
||||||
val downTexture = { ctx: ShadingContext, qi: Int, q: Quad -> ctx.icon(DOWN) }
|
|
||||||
|
|
||||||
inline fun continous(q1: QuadrantType, q2: QuadrantType) =
|
inline fun continous(q1: QuadrantType, q2: QuadrantType) =
|
||||||
q1 == q2 || ((q1 == SQUARE || q1 == INVISIBLE) && (q2 == SQUARE || q2 == INVISIBLE))
|
q1 == q2 || ((q1 == SQUARE || q1 == INVISIBLE) && (q2 == SQUARE || q2 == INVISIBLE))
|
||||||
|
|
||||||
abstract val axisFunc: (Block, Int)->Axis
|
abstract val axisFunc: (IBlockState)->EnumFacing.Axis
|
||||||
abstract val blockPredicate: (Block, Int)->Boolean
|
abstract val blockPredicate: (IBlockState)->Boolean
|
||||||
|
|
||||||
|
abstract val sideTexture: (ShadingContext, Int, Quad)->TextureAtlasSprite?
|
||||||
|
abstract val upTexture: (ShadingContext, Int, Quad)->TextureAtlasSprite?
|
||||||
|
abstract val downTexture: (ShadingContext, Int, Quad)->TextureAtlasSprite?
|
||||||
|
|
||||||
@Suppress("NON_EXHAUSTIVE_WHEN")
|
@Suppress("NON_EXHAUSTIVE_WHEN")
|
||||||
override fun render(ctx: BlockContext, parent: RenderBlocks): Boolean {
|
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean {
|
||||||
if (ctx.isSurroundedBy(surroundPredicate) ) return false
|
if (ctx.isSurroundedBy(surroundPredicate) ) return false
|
||||||
|
|
||||||
// get AO data
|
// get AO data
|
||||||
if (renderWorldBlockBase(parent, face = neverRender)) return true
|
modelRenderer.updateShading(Int3.zero, allFaces)
|
||||||
|
|
||||||
// check log neighborhood
|
// check log neighborhood
|
||||||
val logAxis = ctx.blockAxis
|
val logAxis = ctx.blockAxis
|
||||||
val baseRotation = rotationFromUp[(logAxis to Dir.P).face.ordinal]
|
val baseRotation = rotationFromUp[(logAxis to AxisDirection.POSITIVE).face.ordinal]
|
||||||
|
|
||||||
val upType = ctx.blockType(baseRotation, logAxis, Int3(0, 1, 0))
|
val upType = ctx.blockType(baseRotation, logAxis, Int3(0, 1, 0))
|
||||||
val downType = ctx.blockType(baseRotation, logAxis, Int3(0, -1, 0))
|
val downType = ctx.blockType(baseRotation, logAxis, Int3(0, -1, 0))
|
||||||
@@ -141,6 +165,7 @@ abstract class AbstractRenderColumn(modId: String) : AbstractBlockRenderingHandl
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sideModel != null) modelRenderer.render(
|
if (sideModel != null) modelRenderer.render(
|
||||||
|
renderer,
|
||||||
sideModel,
|
sideModel,
|
||||||
rotation,
|
rotation,
|
||||||
blockContext.blockCenter,
|
blockContext.blockCenter,
|
||||||
@@ -192,6 +217,7 @@ abstract class AbstractRenderColumn(modId: String) : AbstractBlockRenderingHandl
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (upModel != null) modelRenderer.render(
|
if (upModel != null) modelRenderer.render(
|
||||||
|
renderer,
|
||||||
upModel,
|
upModel,
|
||||||
rotation,
|
rotation,
|
||||||
blockContext.blockCenter,
|
blockContext.blockCenter,
|
||||||
@@ -200,6 +226,7 @@ abstract class AbstractRenderColumn(modId: String) : AbstractBlockRenderingHandl
|
|||||||
postProcess = noPost
|
postProcess = noPost
|
||||||
)
|
)
|
||||||
if (downModel != null) modelRenderer.render(
|
if (downModel != null) modelRenderer.render(
|
||||||
|
renderer,
|
||||||
downModel,
|
downModel,
|
||||||
rotation,
|
rotation,
|
||||||
blockContext.blockCenter,
|
blockContext.blockCenter,
|
||||||
@@ -283,19 +310,18 @@ abstract class AbstractRenderColumn(modId: String) : AbstractBlockRenderingHandl
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Get the axis of the block */
|
/** Get the axis of the block */
|
||||||
val BlockContext.blockAxis: Axis get() = axisFunc(block(Int3.zero), meta(Int3.zero))
|
val BlockContext.blockAxis: Axis get() = axisFunc(blockState(Int3.zero))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the type of the block at the given offset in a rotated reference frame.
|
* Get the type of the block at the given offset in a rotated reference frame.
|
||||||
*/
|
*/
|
||||||
fun BlockContext.blockType(rotation: Rotation, axis: Axis, offset: Int3): BlockType {
|
fun BlockContext.blockType(rotation: Rotation, axis: Axis, offset: Int3): BlockType {
|
||||||
val offsetRot = offset.rotate(rotation)
|
val offsetRot = offset.rotate(rotation)
|
||||||
val logBlock = block(offsetRot)
|
val state = blockState(offsetRot)
|
||||||
val logMeta = meta(offsetRot)
|
return if (!blockPredicate(state)) {
|
||||||
return if (!blockPredicate(logBlock, logMeta)) {
|
if (state.block.isOpaqueCube) SOLID else NONSOLID
|
||||||
if (logBlock.isOpaqueCube) SOLID else NONSOLID
|
|
||||||
} else {
|
} else {
|
||||||
if (axisFunc(logBlock, logMeta) == axis) PARALLEL else PERPENDICULAR
|
if (axisFunc(state) == axis) PARALLEL else PERPENDICULAR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,31 +1,31 @@
|
|||||||
package mods.betterfoliage.client.render
|
package mods.betterfoliage.client.render
|
||||||
|
|
||||||
import cpw.mods.fml.common.FMLCommonHandler
|
|
||||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent
|
|
||||||
import cpw.mods.fml.common.gameevent.TickEvent
|
|
||||||
import cpw.mods.fml.relauncher.Side
|
|
||||||
import cpw.mods.fml.relauncher.SideOnly
|
|
||||||
import mods.betterfoliage.client.config.Config
|
import mods.betterfoliage.client.config.Config
|
||||||
import mods.betterfoliage.client.texture.LeafRegistry
|
import mods.betterfoliage.client.texture.LeafRegistry
|
||||||
import mods.octarinecore.PI2
|
import mods.octarinecore.PI2
|
||||||
import mods.octarinecore.client.render.AbstractEntityFX
|
import mods.octarinecore.client.render.AbstractEntityFX
|
||||||
import mods.octarinecore.client.render.Double3
|
|
||||||
import mods.octarinecore.client.render.HSB
|
import mods.octarinecore.client.render.HSB
|
||||||
|
import mods.octarinecore.common.Double3
|
||||||
import mods.octarinecore.minmax
|
import mods.octarinecore.minmax
|
||||||
import mods.octarinecore.random
|
import mods.octarinecore.random
|
||||||
import net.minecraft.client.Minecraft
|
import net.minecraft.client.Minecraft
|
||||||
import net.minecraft.client.renderer.Tessellator
|
import net.minecraft.client.renderer.WorldRenderer
|
||||||
|
import net.minecraft.util.BlockPos
|
||||||
import net.minecraft.util.MathHelper
|
import net.minecraft.util.MathHelper
|
||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
import net.minecraftforge.common.MinecraftForge
|
import net.minecraftforge.common.MinecraftForge
|
||||||
import net.minecraftforge.common.util.ForgeDirection.DOWN
|
|
||||||
import net.minecraftforge.event.world.WorldEvent
|
import net.minecraftforge.event.world.WorldEvent
|
||||||
|
import net.minecraftforge.fml.common.FMLCommonHandler
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
|
||||||
|
import net.minecraftforge.fml.common.gameevent.TickEvent
|
||||||
|
import net.minecraftforge.fml.relauncher.Side
|
||||||
|
import net.minecraftforge.fml.relauncher.SideOnly
|
||||||
import org.lwjgl.opengl.GL11
|
import org.lwjgl.opengl.GL11
|
||||||
import java.lang.Math.*
|
import java.lang.Math.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class EntityFallingLeavesFX(world: World, x: Int, y: Int, z: Int) :
|
class EntityFallingLeavesFX(world: World, pos: BlockPos) :
|
||||||
AbstractEntityFX(world, x.toDouble() + 0.5, y.toDouble(), z.toDouble() + 0.5) {
|
AbstractEntityFX(world, pos.x.toDouble() + 0.5, pos.y.toDouble(), pos.z.toDouble() + 0.5) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic val biomeBrightnessMultiplier = 0.5f
|
@JvmStatic val biomeBrightnessMultiplier = 0.5f
|
||||||
@@ -41,10 +41,10 @@ AbstractEntityFX(world, x.toDouble() + 0.5, y.toDouble(), z.toDouble() + 0.5) {
|
|||||||
motionY = -Config.fallingLeaves.speed
|
motionY = -Config.fallingLeaves.speed
|
||||||
particleScale = Config.fallingLeaves.size.toFloat() * 0.1f
|
particleScale = Config.fallingLeaves.size.toFloat() * 0.1f
|
||||||
|
|
||||||
val block = world.getBlock(x, y, z)
|
val state = world.getBlockState(pos)
|
||||||
LeafRegistry.leaves[block.getIcon(world, x, y, z, DOWN.ordinal)]?.let {
|
LeafRegistry[world.getBlockState(pos)]?.let {
|
||||||
particleIcon = it.particleTextures[rand.nextInt(1024)]
|
particleIcon = it.particleTextures[rand.nextInt(1024)]
|
||||||
calculateParticleColor(it.averageColor, block.colorMultiplier(world, x, y, z))
|
calculateParticleColor(it.averageColor, state.block.colorMultiplier(world, pos))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,9 +67,9 @@ AbstractEntityFX(world, x.toDouble() + 0.5, y.toDouble(), z.toDouble() + 0.5) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun render(tessellator: Tessellator, partialTickTime: Float) {
|
override fun render(worldRenderer: WorldRenderer, partialTickTime: Float) {
|
||||||
if (Config.fallingLeaves.opacityHack) GL11.glDepthMask(true)
|
if (Config.fallingLeaves.opacityHack) GL11.glDepthMask(true)
|
||||||
renderParticleQuad(tessellator, partialTickTime, rotation = particleRot, isMirrored = isMirrored)
|
renderParticleQuad(worldRenderer, partialTickTime, rotation = particleRot, isMirrored = isMirrored)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun calculateParticleColor(textureAvgColor: Int, blockColor: Int) {
|
fun calculateParticleColor(textureAvgColor: Int, blockColor: Int) {
|
||||||
|
|||||||
@@ -1,22 +1,23 @@
|
|||||||
package mods.betterfoliage.client.render
|
package mods.betterfoliage.client.render
|
||||||
|
|
||||||
import cpw.mods.fml.relauncher.Side
|
|
||||||
import cpw.mods.fml.relauncher.SideOnly
|
|
||||||
import mods.betterfoliage.BetterFoliageMod
|
import mods.betterfoliage.BetterFoliageMod
|
||||||
import mods.betterfoliage.client.Client
|
import mods.betterfoliage.client.Client
|
||||||
import mods.betterfoliage.client.config.Config
|
import mods.betterfoliage.client.config.Config
|
||||||
import mods.octarinecore.client.render.AbstractEntityFX
|
import mods.octarinecore.client.render.AbstractEntityFX
|
||||||
import mods.octarinecore.client.render.Double3
|
|
||||||
import mods.octarinecore.client.resource.ResourceHandler
|
import mods.octarinecore.client.resource.ResourceHandler
|
||||||
|
import mods.octarinecore.common.Double3
|
||||||
import mods.octarinecore.forEachPairIndexed
|
import mods.octarinecore.forEachPairIndexed
|
||||||
import net.minecraft.client.renderer.Tessellator
|
import net.minecraft.client.renderer.WorldRenderer
|
||||||
|
import net.minecraft.util.BlockPos
|
||||||
import net.minecraft.util.MathHelper
|
import net.minecraft.util.MathHelper
|
||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
import org.apache.logging.log4j.Level.*
|
import net.minecraftforge.fml.relauncher.Side
|
||||||
|
import net.minecraftforge.fml.relauncher.SideOnly
|
||||||
|
import org.apache.logging.log4j.Level.INFO
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class EntityRisingSoulFX(world: World, x: Int, y: Int, z: Int) :
|
class EntityRisingSoulFX(world: World, pos: BlockPos) :
|
||||||
AbstractEntityFX(world, x.toDouble() + 0.5, y.toDouble() + 1.0, z.toDouble() + 0.5) {
|
AbstractEntityFX(world, pos.x.toDouble() + 0.5, pos.y.toDouble() + 1.0, pos.z.toDouble() + 0.5) {
|
||||||
|
|
||||||
val particleTrail: Deque<Double3> = linkedListOf()
|
val particleTrail: Deque<Double3> = linkedListOf()
|
||||||
val initialPhase = rand.nextInt(64)
|
val initialPhase = rand.nextInt(64)
|
||||||
@@ -40,11 +41,11 @@ AbstractEntityFX(world, x.toDouble() + 0.5, y.toDouble() + 1.0, z.toDouble() + 0
|
|||||||
if (!Config.enabled) setDead()
|
if (!Config.enabled) setDead()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun render(tessellator: Tessellator, partialTickTime: Float) {
|
override fun render(worldRenderer: WorldRenderer, partialTickTime: Float) {
|
||||||
var alpha = Config.risingSoul.opacity
|
var alpha = Config.risingSoul.opacity
|
||||||
if (particleAge > particleMaxAge - 40) alpha *= (particleMaxAge - particleAge) / 40.0f
|
if (particleAge > particleMaxAge - 40) alpha *= (particleMaxAge - particleAge) / 40.0f
|
||||||
|
|
||||||
renderParticleQuad(tessellator, partialTickTime,
|
renderParticleQuad(worldRenderer, partialTickTime,
|
||||||
size = Config.risingSoul.headSize * 0.25,
|
size = Config.risingSoul.headSize * 0.25,
|
||||||
alpha = alpha
|
alpha = alpha
|
||||||
)
|
)
|
||||||
@@ -53,7 +54,7 @@ AbstractEntityFX(world, x.toDouble() + 0.5, y.toDouble() + 1.0, z.toDouble() + 0
|
|||||||
particleTrail.forEachPairIndexed { idx, current, previous ->
|
particleTrail.forEachPairIndexed { idx, current, previous ->
|
||||||
scale *= Config.risingSoul.sizeDecay
|
scale *= Config.risingSoul.sizeDecay
|
||||||
alpha *= Config.risingSoul.opacityDecay
|
alpha *= Config.risingSoul.opacityDecay
|
||||||
if (idx % Config.risingSoul.trailDensity == 0) renderParticleQuad(tessellator, partialTickTime,
|
if (idx % Config.risingSoul.trailDensity == 0) renderParticleQuad(worldRenderer, partialTickTime,
|
||||||
currentPos = current,
|
currentPos = current,
|
||||||
prevPos = previous,
|
prevPos = previous,
|
||||||
size = scale,
|
size = scale,
|
||||||
@@ -66,8 +67,8 @@ AbstractEntityFX(world, x.toDouble() + 0.5, y.toDouble() + 1.0, z.toDouble() + 0
|
|||||||
|
|
||||||
@SideOnly(Side.CLIENT)
|
@SideOnly(Side.CLIENT)
|
||||||
object RisingSoulTextures : ResourceHandler(BetterFoliageMod.MOD_ID) {
|
object RisingSoulTextures : ResourceHandler(BetterFoliageMod.MOD_ID) {
|
||||||
val headIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "rising_soul_%d")
|
val headIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/rising_soul_%d")
|
||||||
val trackIcon = iconStatic(BetterFoliageMod.LEGACY_DOMAIN, "soul_track")
|
val trackIcon = iconStatic(BetterFoliageMod.LEGACY_DOMAIN, "blocks/soul_track")
|
||||||
|
|
||||||
override fun afterStitch() {
|
override fun afterStitch() {
|
||||||
Client.log(INFO, "Registered ${headIcons.num} soul particle textures")
|
Client.log(INFO, "Registered ${headIcons.num} soul particle textures")
|
||||||
|
|||||||
@@ -3,8 +3,9 @@ package mods.betterfoliage.client.render
|
|||||||
|
|
||||||
import mods.betterfoliage.client.config.Config
|
import mods.betterfoliage.client.config.Config
|
||||||
import mods.octarinecore.client.render.*
|
import mods.octarinecore.client.render.*
|
||||||
|
import mods.octarinecore.common.Double3
|
||||||
import mods.octarinecore.exchange
|
import mods.octarinecore.exchange
|
||||||
import net.minecraftforge.common.util.ForgeDirection.*
|
import net.minecraft.util.EnumFacing.*
|
||||||
|
|
||||||
/** Weight of the same-side AO values on the outer edges of the 45deg chamfered column faces. */
|
/** Weight of the same-side AO values on the outer edges of the 45deg chamfered column faces. */
|
||||||
const val chamferAffinity = 0.9f
|
const val chamferAffinity = 0.9f
|
||||||
|
|||||||
@@ -5,16 +5,19 @@ import mods.betterfoliage.client.Client
|
|||||||
import mods.betterfoliage.client.config.Config
|
import mods.betterfoliage.client.config.Config
|
||||||
import mods.betterfoliage.client.integration.ShadersModIntegration
|
import mods.betterfoliage.client.integration.ShadersModIntegration
|
||||||
import mods.octarinecore.client.render.*
|
import mods.octarinecore.client.render.*
|
||||||
|
import mods.octarinecore.common.Int3
|
||||||
|
import mods.octarinecore.common.Rotation
|
||||||
import net.minecraft.block.material.Material
|
import net.minecraft.block.material.Material
|
||||||
import net.minecraft.client.renderer.RenderBlocks
|
import net.minecraft.client.renderer.BlockRendererDispatcher
|
||||||
import net.minecraft.init.Blocks
|
import net.minecraft.client.renderer.WorldRenderer
|
||||||
|
import net.minecraft.util.EnumWorldBlockLayer
|
||||||
import org.apache.logging.log4j.Level.INFO
|
import org.apache.logging.log4j.Level.INFO
|
||||||
|
|
||||||
class RenderAlgae : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
class RenderAlgae : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
||||||
|
|
||||||
val noise = simplexNoise()
|
val noise = simplexNoise()
|
||||||
|
|
||||||
val algaeIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "better_algae_%d")
|
val algaeIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_algae_%d")
|
||||||
val algaeModels = modelSet(64, RenderGrass.grassTopQuads)
|
val algaeModels = modelSet(64, RenderGrass.grassTopQuads)
|
||||||
|
|
||||||
override fun afterStitch() {
|
override fun afterStitch() {
|
||||||
@@ -28,15 +31,17 @@ class RenderAlgae : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
|||||||
ctx.block(up1).material == Material.water &&
|
ctx.block(up1).material == Material.water &&
|
||||||
Config.blocks.dirt.matchesID(ctx.block) &&
|
Config.blocks.dirt.matchesID(ctx.block) &&
|
||||||
ctx.biomeId in Config.algae.biomes &&
|
ctx.biomeId in Config.algae.biomes &&
|
||||||
noise[ctx.x, ctx.z] < Config.algae.population
|
noise[ctx.pos] < Config.algae.population
|
||||||
|
|
||||||
override fun render(ctx: BlockContext, parent: RenderBlocks): Boolean {
|
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean {
|
||||||
if (renderWorldBlockBase(parent, face = alwaysRender)) return true
|
renderWorldBlockBase(ctx, dispatcher, renderer, null)
|
||||||
|
modelRenderer.updateShading(Int3.zero, allFaces)
|
||||||
|
|
||||||
val rand = ctx.semiRandomArray(3)
|
val rand = ctx.semiRandomArray(3)
|
||||||
|
|
||||||
ShadersModIntegration.grass(Config.algae.shaderWind) {
|
ShadersModIntegration.grass(renderer, Config.algae.shaderWind) {
|
||||||
modelRenderer.render(
|
modelRenderer.render(
|
||||||
|
renderer,
|
||||||
algaeModels[rand[2]],
|
algaeModels[rand[2]],
|
||||||
Rotation.identity,
|
Rotation.identity,
|
||||||
icon = { ctx, qi, q -> algaeIcons[rand[qi and 1]]!! },
|
icon = { ctx, qi, q -> algaeIcons[rand[qi and 1]]!! },
|
||||||
|
|||||||
@@ -4,8 +4,13 @@ import mods.betterfoliage.BetterFoliageMod
|
|||||||
import mods.betterfoliage.client.Client
|
import mods.betterfoliage.client.Client
|
||||||
import mods.betterfoliage.client.config.Config
|
import mods.betterfoliage.client.config.Config
|
||||||
import mods.octarinecore.client.render.*
|
import mods.octarinecore.client.render.*
|
||||||
import net.minecraft.client.renderer.RenderBlocks
|
import mods.octarinecore.client.resource.BlockTextureInspector
|
||||||
import net.minecraftforge.common.util.ForgeDirection.*
|
import mods.octarinecore.common.Int3
|
||||||
|
import mods.octarinecore.common.Rotation
|
||||||
|
import net.minecraft.client.renderer.BlockRendererDispatcher
|
||||||
|
import net.minecraft.client.renderer.WorldRenderer
|
||||||
|
import net.minecraft.util.EnumFacing.*
|
||||||
|
import net.minecraft.util.EnumWorldBlockLayer
|
||||||
import org.apache.logging.log4j.Level
|
import org.apache.logging.log4j.Level
|
||||||
|
|
||||||
class RenderCactus : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
class RenderCactus : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
||||||
@@ -13,8 +18,13 @@ class RenderCactus : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
|||||||
val cactusStemRadius = 0.4375
|
val cactusStemRadius = 0.4375
|
||||||
val cactusArmRotation = listOf(NORTH, SOUTH, EAST, WEST).map { Rotation.rot90[it.ordinal] }
|
val cactusArmRotation = listOf(NORTH, SOUTH, EAST, WEST).map { Rotation.rot90[it.ordinal] }
|
||||||
|
|
||||||
val iconCross = iconStatic(BetterFoliageMod.LEGACY_DOMAIN, "better_cactus")
|
val iconCross = iconStatic(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_cactus")
|
||||||
val iconArm = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "better_cactus_arm_%d")
|
val iconArm = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_cactus_arm_%d")
|
||||||
|
val iconBase = object : ColumnTextures(Config.blocks.cactus) {
|
||||||
|
init {
|
||||||
|
matchClassAndModel(matcher, "block/cactus", listOf("top", "bottom", "side"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val modelStem = model {
|
val modelStem = model {
|
||||||
horizontalRectangle(x1 = -cactusStemRadius, x2 = cactusStemRadius, z1 = -cactusStemRadius, z2 = cactusStemRadius, y = 0.5)
|
horizontalRectangle(x1 = -cactusStemRadius, x2 = cactusStemRadius, z1 = -cactusStemRadius, z2 = cactusStemRadius, y = 0.5)
|
||||||
@@ -53,18 +63,23 @@ class RenderCactus : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
|||||||
ctx.cameraDistance < Config.cactus.distance &&
|
ctx.cameraDistance < Config.cactus.distance &&
|
||||||
Config.blocks.cactus.matchesID(ctx.block)
|
Config.blocks.cactus.matchesID(ctx.block)
|
||||||
|
|
||||||
override fun render(ctx: BlockContext, parent: RenderBlocks): Boolean {
|
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean {
|
||||||
// get AO data
|
// get AO data
|
||||||
if (renderWorldBlockBase(parent, face = neverRender)) return true
|
modelRenderer.updateShading(Int3.zero, allFaces)
|
||||||
|
val icons = iconBase[ctx.blockState(Int3.zero)] ?: return renderWorldBlockBase(ctx, dispatcher, renderer, null)
|
||||||
|
|
||||||
modelRenderer.render(
|
modelRenderer.render(
|
||||||
|
renderer,
|
||||||
modelStem.model,
|
modelStem.model,
|
||||||
Rotation.identity,
|
Rotation.identity,
|
||||||
icon = { ctx, qi, q -> ctx.icon(forgeDirs[qi])},
|
icon = { ctx, qi, q -> when(qi) {
|
||||||
|
0 -> icons.bottomTexture; 1 -> icons.topTexture; else -> icons.sideTexture
|
||||||
|
} },
|
||||||
rotateUV = { 0 },
|
rotateUV = { 0 },
|
||||||
postProcess = noPost
|
postProcess = noPost
|
||||||
)
|
)
|
||||||
modelRenderer.render(
|
modelRenderer.render(
|
||||||
|
renderer,
|
||||||
modelCross[ctx.random(0)],
|
modelCross[ctx.random(0)],
|
||||||
Rotation.identity,
|
Rotation.identity,
|
||||||
icon = { ctx, qi, q -> iconCross.icon!!},
|
icon = { ctx, qi, q -> iconCross.icon!!},
|
||||||
@@ -72,6 +87,7 @@ class RenderCactus : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
|||||||
postProcess = noPost
|
postProcess = noPost
|
||||||
)
|
)
|
||||||
modelRenderer.render(
|
modelRenderer.render(
|
||||||
|
renderer,
|
||||||
modelArm[ctx.random(1)],
|
modelArm[ctx.random(1)],
|
||||||
cactusArmRotation[ctx.random(2) % 4],
|
cactusArmRotation[ctx.random(2) % 4],
|
||||||
icon = { ctx2, qi, q -> iconArm[ctx.random(3)]!!},
|
icon = { ctx2, qi, q -> iconArm[ctx.random(3)]!!},
|
||||||
|
|||||||
@@ -2,9 +2,13 @@ package mods.betterfoliage.client.render
|
|||||||
|
|
||||||
import mods.betterfoliage.BetterFoliageMod
|
import mods.betterfoliage.BetterFoliageMod
|
||||||
import mods.betterfoliage.client.config.Config
|
import mods.betterfoliage.client.config.Config
|
||||||
import mods.octarinecore.client.render.*
|
import mods.octarinecore.client.render.AbstractBlockRenderingHandler
|
||||||
import net.minecraft.block.material.Material
|
import mods.octarinecore.client.render.BlockContext
|
||||||
import net.minecraft.client.renderer.RenderBlocks
|
import mods.octarinecore.client.render.withOffset
|
||||||
|
import mods.octarinecore.common.Int3
|
||||||
|
import net.minecraft.client.renderer.BlockRendererDispatcher
|
||||||
|
import net.minecraft.client.renderer.WorldRenderer
|
||||||
|
import net.minecraft.util.EnumWorldBlockLayer
|
||||||
|
|
||||||
class RenderConnectedGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
class RenderConnectedGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
||||||
override fun isEligible(ctx: BlockContext) =
|
override fun isEligible(ctx: BlockContext) =
|
||||||
@@ -13,10 +17,10 @@ class RenderConnectedGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_
|
|||||||
Config.blocks.grass.matchesID(ctx.block(up1)) &&
|
Config.blocks.grass.matchesID(ctx.block(up1)) &&
|
||||||
(Config.connectedGrass.snowEnabled || !ctx.block(up2).isSnow)
|
(Config.connectedGrass.snowEnabled || !ctx.block(up2).isSnow)
|
||||||
|
|
||||||
override fun render(ctx: BlockContext, parent: RenderBlocks): Boolean {
|
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean {
|
||||||
return ctx.withOffset(Int3.zero, up1) {
|
return ctx.withOffset(Int3.zero, up1) {
|
||||||
ctx.withOffset(up1, up2) {
|
ctx.withOffset(up1, up2) {
|
||||||
renderWorldBlockBase(parent, face = alwaysRender)
|
renderWorldBlockBase(ctx, dispatcher, renderer, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,15 @@ package mods.betterfoliage.client.render
|
|||||||
|
|
||||||
import mods.betterfoliage.BetterFoliageMod
|
import mods.betterfoliage.BetterFoliageMod
|
||||||
import mods.betterfoliage.client.config.Config
|
import mods.betterfoliage.client.config.Config
|
||||||
import mods.octarinecore.client.render.*
|
import mods.octarinecore.client.render.AbstractBlockRenderingHandler
|
||||||
import net.minecraft.client.renderer.RenderBlocks
|
import mods.octarinecore.client.render.BlockContext
|
||||||
import net.minecraftforge.common.util.ForgeDirection.*
|
import mods.octarinecore.client.render.withOffset
|
||||||
|
import mods.octarinecore.common.Int3
|
||||||
|
import mods.octarinecore.common.offset
|
||||||
|
import net.minecraft.client.renderer.BlockRendererDispatcher
|
||||||
|
import net.minecraft.client.renderer.WorldRenderer
|
||||||
|
import net.minecraft.util.EnumFacing.*
|
||||||
|
import net.minecraft.util.EnumWorldBlockLayer
|
||||||
|
|
||||||
class RenderConnectedGrassLog : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
class RenderConnectedGrassLog : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
||||||
|
|
||||||
@@ -15,17 +21,17 @@ class RenderConnectedGrassLog : AbstractBlockRenderingHandler(BetterFoliageMod.M
|
|||||||
Config.blocks.dirt.matchesID(ctx.block) &&
|
Config.blocks.dirt.matchesID(ctx.block) &&
|
||||||
Config.blocks.logs.matchesID(ctx.block(up1))
|
Config.blocks.logs.matchesID(ctx.block(up1))
|
||||||
|
|
||||||
override fun render(ctx: BlockContext, parent: RenderBlocks): Boolean {
|
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean {
|
||||||
val grassDir = grassCheckDirs.find {
|
val grassDir = grassCheckDirs.find {
|
||||||
Config.blocks.grass.matchesID(ctx.block(it.offset))
|
Config.blocks.grass.matchesID(ctx.block(it.offset))
|
||||||
}
|
}
|
||||||
|
|
||||||
return if (grassDir != null) {
|
return if (grassDir != null) {
|
||||||
ctx.withOffset(Int3.zero, grassDir.offset) {
|
ctx.withOffset(Int3.zero, grassDir.offset) {
|
||||||
renderWorldBlockBase(parent, face = alwaysRender)
|
renderWorldBlockBase(ctx, dispatcher, renderer, null)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
renderWorldBlockBase(parent, face = alwaysRender)
|
renderWorldBlockBase(ctx, dispatcher, renderer, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,18 +4,24 @@ import mods.betterfoliage.BetterFoliageMod
|
|||||||
import mods.betterfoliage.client.Client
|
import mods.betterfoliage.client.Client
|
||||||
import mods.betterfoliage.client.config.Config
|
import mods.betterfoliage.client.config.Config
|
||||||
import mods.octarinecore.client.render.*
|
import mods.octarinecore.client.render.*
|
||||||
|
import mods.octarinecore.common.Int3
|
||||||
|
import mods.octarinecore.common.forgeDirOffsets
|
||||||
|
import mods.octarinecore.common.forgeDirs
|
||||||
import mods.octarinecore.random
|
import mods.octarinecore.random
|
||||||
import net.minecraft.block.material.Material
|
import net.minecraft.block.material.Material
|
||||||
import net.minecraft.client.renderer.RenderBlocks
|
import net.minecraft.client.renderer.BlockRendererDispatcher
|
||||||
import net.minecraftforge.common.util.ForgeDirection.UP
|
import net.minecraft.client.renderer.WorldRenderer
|
||||||
|
import net.minecraft.util.EnumFacing.Axis
|
||||||
|
import net.minecraft.util.EnumFacing.UP
|
||||||
|
import net.minecraft.util.EnumWorldBlockLayer
|
||||||
import org.apache.logging.log4j.Level.INFO
|
import org.apache.logging.log4j.Level.INFO
|
||||||
|
|
||||||
class RenderCoral : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
class RenderCoral : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
||||||
|
|
||||||
val noise = simplexNoise()
|
val noise = simplexNoise()
|
||||||
|
|
||||||
val coralIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "better_coral_%d")
|
val coralIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_coral_%d")
|
||||||
val crustIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "better_crust_%d")
|
val crustIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_crust_%d")
|
||||||
val coralModels = modelSet(64) { modelIdx ->
|
val coralModels = modelSet(64) { modelIdx ->
|
||||||
verticalRectangle(x1 = -0.5, z1 = 0.5, x2 = 0.5, z2 = -0.5, yBottom = 0.0, yTop = 1.0)
|
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)
|
.scale(Config.coral.size).move(0.5 to UP)
|
||||||
@@ -32,7 +38,8 @@ class RenderCoral : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun afterStitch() {
|
override fun afterStitch() {
|
||||||
Client.log(INFO, "Registered ${coralIcons.num} algae textures")
|
Client.log(INFO, "Registered ${coralIcons.num} coral textures")
|
||||||
|
Client.log(INFO, "Registered ${crustIcons.num} coral crust textures")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isEligible(ctx: BlockContext) =
|
override fun isEligible(ctx: BlockContext) =
|
||||||
@@ -42,15 +49,17 @@ class RenderCoral : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
|||||||
ctx.block(up1).material == Material.water &&
|
ctx.block(up1).material == Material.water &&
|
||||||
Config.blocks.sand.matchesID(ctx.block) &&
|
Config.blocks.sand.matchesID(ctx.block) &&
|
||||||
ctx.biomeId in Config.coral.biomes &&
|
ctx.biomeId in Config.coral.biomes &&
|
||||||
noise[ctx.x, ctx.z] < Config.coral.population
|
noise[ctx.pos] < Config.coral.population
|
||||||
|
|
||||||
override fun render(ctx: BlockContext, parent: RenderBlocks): Boolean {
|
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean {
|
||||||
if (renderWorldBlockBase(parent, face = alwaysRender)) return true
|
renderWorldBlockBase(ctx, dispatcher, renderer, null)
|
||||||
|
modelRenderer.updateShading(Int3.zero, allFaces)
|
||||||
|
|
||||||
forgeDirs.forEachIndexed { idx, face ->
|
forgeDirs.forEachIndexed { idx, face ->
|
||||||
if (!ctx.block(forgeDirOffsets[idx]).isOpaqueCube && blockContext.random(idx) < Config.coral.chance) {
|
if (!ctx.block(forgeDirOffsets[idx]).isOpaqueCube && blockContext.random(idx) < Config.coral.chance) {
|
||||||
var variation = blockContext.random(6)
|
var variation = blockContext.random(6)
|
||||||
modelRenderer.render(
|
modelRenderer.render(
|
||||||
|
renderer,
|
||||||
coralModels[variation++],
|
coralModels[variation++],
|
||||||
rotationFromUp[idx],
|
rotationFromUp[idx],
|
||||||
icon = { ctx, qi, q -> if (qi == 4) crustIcons[variation]!! else coralIcons[variation + (qi and 1)]!!},
|
icon = { ctx, qi, q -> if (qi == 4) crustIcons[variation]!! else coralIcons[variation + (qi and 1)]!!},
|
||||||
|
|||||||
@@ -6,10 +6,16 @@ import mods.betterfoliage.client.config.Config
|
|||||||
import mods.betterfoliage.client.integration.ShadersModIntegration
|
import mods.betterfoliage.client.integration.ShadersModIntegration
|
||||||
import mods.betterfoliage.client.texture.GrassRegistry
|
import mods.betterfoliage.client.texture.GrassRegistry
|
||||||
import mods.octarinecore.client.render.*
|
import mods.octarinecore.client.render.*
|
||||||
|
import mods.octarinecore.common.Double3
|
||||||
|
import mods.octarinecore.common.Int3
|
||||||
|
import mods.octarinecore.common.Rotation
|
||||||
import mods.octarinecore.random
|
import mods.octarinecore.random
|
||||||
import net.minecraft.block.material.Material
|
import net.minecraft.block.material.Material
|
||||||
import net.minecraft.client.renderer.RenderBlocks
|
import net.minecraft.client.renderer.BlockRendererDispatcher
|
||||||
import net.minecraftforge.common.util.ForgeDirection.UP
|
import net.minecraft.client.renderer.WorldRenderer
|
||||||
|
import net.minecraft.util.EnumFacing.Axis
|
||||||
|
import net.minecraft.util.EnumFacing.UP
|
||||||
|
import net.minecraft.util.EnumWorldBlockLayer
|
||||||
import org.apache.logging.log4j.Level.INFO
|
import org.apache.logging.log4j.Level.INFO
|
||||||
|
|
||||||
class RenderGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
class RenderGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
||||||
@@ -25,10 +31,10 @@ class RenderGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val normalIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "better_grass_long_%d")
|
val normalIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_grass_long_%d")
|
||||||
val snowedIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "better_grass_snowed_%d")
|
val snowedIcons = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_grass_snowed_%d")
|
||||||
val normalGenIcon = iconStatic(Client.genGrass.generatedResource("minecraft:tallgrass", "snowed" to false))
|
val normalGenIcon = iconStatic(Client.genGrass.generatedResource("minecraft:blocks/tallgrass", "snowed" to false))
|
||||||
val snowedGenIcon = iconStatic(Client.genGrass.generatedResource("minecraft:tallgrass", "snowed" to true))
|
val snowedGenIcon = iconStatic(Client.genGrass.generatedResource("minecraft:blocks/tallgrass", "snowed" to true))
|
||||||
|
|
||||||
val grassModels = modelSet(64, grassTopQuads)
|
val grassModels = modelSet(64, grassTopQuads)
|
||||||
|
|
||||||
@@ -43,61 +49,58 @@ class RenderGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
|||||||
(Config.shortGrass.grassEnabled || Config.connectedGrass.enabled) &&
|
(Config.shortGrass.grassEnabled || Config.connectedGrass.enabled) &&
|
||||||
Config.blocks.grass.matchesID(ctx.block)
|
Config.blocks.grass.matchesID(ctx.block)
|
||||||
|
|
||||||
override fun render(ctx: BlockContext, parent: RenderBlocks): Boolean {
|
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean {
|
||||||
val isConnected = ctx.block(down1).let { Config.blocks.dirt.matchesID(it) || Config.blocks.grass.matchesID(it) }
|
val isConnected = ctx.block(down1).let { Config.blocks.dirt.matchesID(it) || Config.blocks.grass.matchesID(it) }
|
||||||
val isSnowed = ctx.block(up1).isSnow
|
val isSnowed = ctx.block(up1).isSnow
|
||||||
val connectedGrass = isConnected && Config.connectedGrass.enabled && (!isSnowed || Config.connectedGrass.snowEnabled)
|
val connectedGrass = isConnected && Config.connectedGrass.enabled && (!isSnowed || Config.connectedGrass.snowEnabled)
|
||||||
|
|
||||||
val grassInfo = GrassRegistry.grass[ctx.icon(UP)]
|
val grassInfo = GrassRegistry[ctx.blockState(Int3.zero)] ?: return renderWorldBlockBase(ctx, dispatcher, renderer, layer)
|
||||||
if (grassInfo == null) {
|
val blockColor = ctx.blockData(Int3.zero, 0).color
|
||||||
renderWorldBlockBase(parent, face = alwaysRender)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
val cubeTexture = if (isSnowed) ctx.icon(up1, UP) else null ?: grassInfo.grassTopTexture
|
|
||||||
val blockColor = ctx.blockColor(Int3.zero)
|
|
||||||
|
|
||||||
if (connectedGrass) {
|
if (connectedGrass) {
|
||||||
// get AO data
|
// get full AO data
|
||||||
if (renderWorldBlockBase(parent, face = neverRender)) return true
|
modelRenderer.updateShading(Int3.zero, allFaces)
|
||||||
|
|
||||||
// render full grass block
|
// render full grass block
|
||||||
modelRenderer.render(
|
modelRenderer.render(
|
||||||
|
renderer,
|
||||||
fullCube,
|
fullCube,
|
||||||
Rotation.identity,
|
Rotation.identity,
|
||||||
ctx.blockCenter,
|
ctx.blockCenter,
|
||||||
icon = { ctx, qi, q -> cubeTexture },
|
icon = { ctx, qi, q -> grassInfo.grassTopTexture },
|
||||||
rotateUV = { 2 },
|
rotateUV = { 2 },
|
||||||
postProcess = { ctx, qi, q, vi, v ->
|
postProcess = { ctx, qi, q, vi, v ->
|
||||||
if (isSnowed) { if(!ctx.aoEnabled) setGrey(1.4f) }
|
if (isSnowed) { if(!ctx.aoEnabled) setGrey(1.4f) }
|
||||||
else if (qi != UP.ordinal && ctx.aoEnabled) multiplyColor(blockColor)
|
else if (ctx.aoEnabled) multiplyColor(blockColor)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// render normally
|
renderWorldBlockBase(ctx, dispatcher, renderer, null)
|
||||||
if (renderWorldBlockBase(parent, face = alwaysRender)) return true
|
|
||||||
|
// get AO data only for block top
|
||||||
|
modelRenderer.updateShading(Int3.zero, topOnly)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Config.shortGrass.grassEnabled) return true
|
if (!Config.shortGrass.grassEnabled) return true
|
||||||
if (isSnowed && !Config.shortGrass.snowEnabled) return true
|
if (isSnowed && !Config.shortGrass.snowEnabled) return true
|
||||||
if (ctx.block(up1).isOpaqueCube) return true
|
if (ctx.block(up1).material != Material.air) return true
|
||||||
|
|
||||||
// render grass quads
|
// render grass quads
|
||||||
val iconset = if (isSnowed) snowedIcons else normalIcons
|
val iconset = if (isSnowed) snowedIcons else normalIcons
|
||||||
val iconGen = if (isSnowed) snowedGenIcon else normalGenIcon
|
val iconGen = if (isSnowed) snowedGenIcon else normalGenIcon
|
||||||
val rand = ctx.semiRandomArray(2)
|
val rand = ctx.semiRandomArray(2)
|
||||||
|
|
||||||
ShadersModIntegration.grass(Config.shortGrass.shaderWind) {
|
ShadersModIntegration.grass(renderer, Config.shortGrass.shaderWind) {
|
||||||
modelRenderer.render(
|
modelRenderer.render(
|
||||||
|
renderer,
|
||||||
grassModels[rand[0]],
|
grassModels[rand[0]],
|
||||||
Rotation.identity,
|
Rotation.identity,
|
||||||
ctx.blockCenter + (if (isSnowed) snowOffset else Double3.zero),
|
ctx.blockCenter + (if (isSnowed) snowOffset else Double3.zero),
|
||||||
icon = if (Config.shortGrass.useGenerated)
|
icon = { ctx: ShadingContext, qi: Int, q: Quad ->
|
||||||
{ ctx: ShadingContext, qi: Int, q: Quad -> iconGen.icon!! }
|
if (Config.shortGrass.useGenerated) iconGen.icon!! else iconset[rand[qi and 1]]!!
|
||||||
else
|
},
|
||||||
{ ctx: ShadingContext, qi: Int, q: Quad -> iconset[rand[qi and 1]]!! },
|
|
||||||
rotateUV = { 0 },
|
rotateUV = { 0 },
|
||||||
postProcess = if (isSnowed) whitewash else if (grassInfo.overrideColor == null) noPost else
|
postProcess = { ctx, qi, q, vi, v -> if (isSnowed) setGrey(1.4f) else multiplyColor(grassInfo.overrideColor ?: blockColor) }
|
||||||
{ ctx, qi, q, vi, v -> multiplyColor(grassInfo.overrideColor) }
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,16 @@ import mods.betterfoliage.client.integration.ShadersModIntegration
|
|||||||
import mods.betterfoliage.client.texture.LeafRegistry
|
import mods.betterfoliage.client.texture.LeafRegistry
|
||||||
import mods.octarinecore.PI2
|
import mods.octarinecore.PI2
|
||||||
import mods.octarinecore.client.render.*
|
import mods.octarinecore.client.render.*
|
||||||
|
import mods.octarinecore.common.Double3
|
||||||
|
import mods.octarinecore.common.Int3
|
||||||
|
import mods.octarinecore.common.Rotation
|
||||||
|
import mods.octarinecore.common.vec
|
||||||
import mods.octarinecore.random
|
import mods.octarinecore.random
|
||||||
import net.minecraft.block.material.Material
|
import net.minecraft.block.material.Material
|
||||||
import net.minecraft.client.renderer.RenderBlocks
|
import net.minecraft.client.renderer.BlockRendererDispatcher
|
||||||
import net.minecraftforge.common.util.ForgeDirection.DOWN
|
import net.minecraft.client.renderer.WorldRenderer
|
||||||
import net.minecraftforge.common.util.ForgeDirection.UP
|
import net.minecraft.util.EnumFacing.UP
|
||||||
|
import net.minecraft.util.EnumWorldBlockLayer
|
||||||
import java.lang.Math.cos
|
import java.lang.Math.cos
|
||||||
import java.lang.Math.sin
|
import java.lang.Math.sin
|
||||||
|
|
||||||
@@ -23,7 +28,7 @@ class RenderLeaves : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
|||||||
.scale(Config.leaves.size)
|
.scale(Config.leaves.size)
|
||||||
.toCross(UP).addAll()
|
.toCross(UP).addAll()
|
||||||
}
|
}
|
||||||
val snowedIcon = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "better_leaves_snowed_%d")
|
val snowedIcon = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_leaves_snowed_%d")
|
||||||
|
|
||||||
val perturbs = vectorSet(64) { idx ->
|
val perturbs = vectorSet(64) { idx ->
|
||||||
val angle = PI2 * idx / 64.0
|
val angle = PI2 * idx / 64.0
|
||||||
@@ -37,27 +42,30 @@ class RenderLeaves : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
|||||||
ctx.cameraDistance < Config.leaves.distance &&
|
ctx.cameraDistance < Config.leaves.distance &&
|
||||||
Config.blocks.leaves.matchesID(ctx.block)
|
Config.blocks.leaves.matchesID(ctx.block)
|
||||||
|
|
||||||
override fun render(ctx: BlockContext, parent: RenderBlocks): Boolean {
|
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean {
|
||||||
val isSnowed = ctx.block(up1).material.let {
|
val isSnowed = ctx.block(up1).material.let {
|
||||||
it == Material.snow || it == Material.craftedSnow
|
it == Material.snow || it == Material.craftedSnow
|
||||||
}
|
}
|
||||||
|
renderWorldBlockBase(ctx, dispatcher, renderer, null)
|
||||||
|
val leafInfo = LeafRegistry[ctx.blockState(Int3.zero)] ?: return true
|
||||||
|
val blockColor = ctx.blockData(Int3.zero, 0).color
|
||||||
|
|
||||||
if (renderWorldBlockBase(parent, face = alwaysRender)) return true
|
modelRenderer.updateShading(Int3.zero, allFaces)
|
||||||
|
ShadersModIntegration.leaves(renderer) {
|
||||||
val leafInfo = LeafRegistry.leaves[ctx.icon(DOWN)]
|
|
||||||
if (leafInfo != null) ShadersModIntegration.leaves {
|
|
||||||
val rand = ctx.semiRandomArray(2)
|
val rand = ctx.semiRandomArray(2)
|
||||||
(if (Config.leaves.dense) denseLeavesRot else normalLeavesRot).forEach { rotation ->
|
(if (Config.leaves.dense) denseLeavesRot else normalLeavesRot).forEach { rotation ->
|
||||||
modelRenderer.render(
|
modelRenderer.render(
|
||||||
|
renderer,
|
||||||
leavesModel.model,
|
leavesModel.model,
|
||||||
rotation,
|
rotation,
|
||||||
ctx.blockCenter + perturbs[rand[0]],
|
ctx.blockCenter + perturbs[rand[0]],
|
||||||
icon = { ctx, qi, q -> leafInfo.roundLeafTexture },
|
icon = { ctx, qi, q -> leafInfo.roundLeafTexture },
|
||||||
rotateUV = { q -> rand[1] },
|
rotateUV = { q -> rand[1] },
|
||||||
postProcess = noPost
|
postProcess = { ctx, qi, q, vi, v -> multiplyColor(blockColor) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (isSnowed) modelRenderer.render(
|
if (isSnowed) modelRenderer.render(
|
||||||
|
renderer,
|
||||||
leavesModel.model,
|
leavesModel.model,
|
||||||
Rotation.identity,
|
Rotation.identity,
|
||||||
ctx.blockCenter + perturbs[rand[0]],
|
ctx.blockCenter + perturbs[rand[0]],
|
||||||
|
|||||||
@@ -3,9 +3,15 @@ package mods.betterfoliage.client.render
|
|||||||
import mods.betterfoliage.BetterFoliageMod
|
import mods.betterfoliage.BetterFoliageMod
|
||||||
import mods.betterfoliage.client.Client
|
import mods.betterfoliage.client.Client
|
||||||
import mods.betterfoliage.client.config.Config
|
import mods.betterfoliage.client.config.Config
|
||||||
|
import mods.betterfoliage.client.integration.ShadersModIntegration
|
||||||
import mods.octarinecore.client.render.*
|
import mods.octarinecore.client.render.*
|
||||||
import net.minecraft.client.renderer.RenderBlocks
|
import mods.octarinecore.common.Int3
|
||||||
import net.minecraftforge.common.util.ForgeDirection.*
|
import mods.octarinecore.common.Rotation
|
||||||
|
import net.minecraft.client.renderer.BlockRendererDispatcher
|
||||||
|
import net.minecraft.client.renderer.WorldRenderer
|
||||||
|
import net.minecraft.util.EnumFacing.DOWN
|
||||||
|
import net.minecraft.util.EnumFacing.UP
|
||||||
|
import net.minecraft.util.EnumWorldBlockLayer
|
||||||
import org.apache.logging.log4j.Level
|
import org.apache.logging.log4j.Level
|
||||||
|
|
||||||
class RenderLilypad : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
class RenderLilypad : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
||||||
@@ -21,8 +27,8 @@ class RenderLilypad : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
|||||||
.setFlatShader(FlatOffsetNoColor(Int3.zero))
|
.setFlatShader(FlatOffsetNoColor(Int3.zero))
|
||||||
.toCross(UP).addAll()
|
.toCross(UP).addAll()
|
||||||
}
|
}
|
||||||
val rootIcon = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "better_lilypad_roots_%d")
|
val rootIcon = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_lilypad_roots_%d")
|
||||||
val flowerIcon = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "better_lilypad_flower_%d")
|
val flowerIcon = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_lilypad_flower_%d")
|
||||||
val perturbs = vectorSet(64) { modelIdx -> xzDisk(modelIdx) * Config.lilypad.hOffset }
|
val perturbs = vectorSet(64) { modelIdx -> xzDisk(modelIdx) * Config.lilypad.hOffset }
|
||||||
|
|
||||||
override fun afterStitch() {
|
override fun afterStitch() {
|
||||||
@@ -35,21 +41,27 @@ class RenderLilypad : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
|||||||
ctx.cameraDistance < Config.lilypad.distance &&
|
ctx.cameraDistance < Config.lilypad.distance &&
|
||||||
Config.blocks.lilypad.matchesID(ctx.block)
|
Config.blocks.lilypad.matchesID(ctx.block)
|
||||||
|
|
||||||
override fun render(ctx: BlockContext, parent: RenderBlocks): Boolean {
|
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean {
|
||||||
if (renderWorldBlockBase(parent, face = alwaysRender)) return true
|
renderWorldBlockBase(ctx, dispatcher, renderer, null)
|
||||||
|
modelRenderer.updateShading(Int3.zero, allFaces)
|
||||||
|
|
||||||
val rand = ctx.semiRandomArray(5)
|
val rand = ctx.semiRandomArray(5)
|
||||||
modelRenderer.render(
|
|
||||||
rootModel.model,
|
ShadersModIntegration.grass(renderer) {
|
||||||
Rotation.identity,
|
modelRenderer.render(
|
||||||
ctx.blockCenter.add(perturbs[rand[2]]),
|
renderer,
|
||||||
forceFlat = true,
|
rootModel.model,
|
||||||
icon = { ctx, qi, q -> rootIcon[rand[qi and 1]]!! },
|
Rotation.identity,
|
||||||
rotateUV = { 0 },
|
ctx.blockCenter.add(perturbs[rand[2]]),
|
||||||
postProcess = noPost
|
forceFlat = true,
|
||||||
)
|
icon = { ctx, qi, q -> rootIcon[rand[qi and 1]]!! },
|
||||||
|
rotateUV = { 0 },
|
||||||
|
postProcess = noPost
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (rand[3] < Config.lilypad.flowerChance) modelRenderer.render(
|
if (rand[3] < Config.lilypad.flowerChance) modelRenderer.render(
|
||||||
|
renderer,
|
||||||
flowerModel.model,
|
flowerModel.model,
|
||||||
Rotation.identity,
|
Rotation.identity,
|
||||||
ctx.blockCenter.add(perturbs[rand[4]]),
|
ctx.blockCenter.add(perturbs[rand[4]]),
|
||||||
|
|||||||
@@ -2,9 +2,16 @@ package mods.betterfoliage.client.render
|
|||||||
|
|
||||||
import mods.betterfoliage.BetterFoliageMod
|
import mods.betterfoliage.BetterFoliageMod
|
||||||
import mods.betterfoliage.client.config.Config
|
import mods.betterfoliage.client.config.Config
|
||||||
import mods.octarinecore.client.render.Axis
|
|
||||||
import mods.octarinecore.client.render.BlockContext
|
import mods.octarinecore.client.render.BlockContext
|
||||||
import net.minecraft.block.Block
|
import mods.octarinecore.client.render.Quad
|
||||||
|
import mods.octarinecore.client.render.ShadingContext
|
||||||
|
import mods.octarinecore.client.resource.BlockTextureInspector
|
||||||
|
import mods.octarinecore.common.Int3
|
||||||
|
import net.minecraft.block.BlockLog
|
||||||
|
import net.minecraft.block.state.IBlockState
|
||||||
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite
|
||||||
|
import net.minecraft.client.renderer.texture.TextureMap
|
||||||
|
import net.minecraft.util.EnumFacing.Axis
|
||||||
|
|
||||||
class RenderLog : AbstractRenderColumn(BetterFoliageMod.MOD_ID) {
|
class RenderLog : AbstractRenderColumn(BetterFoliageMod.MOD_ID) {
|
||||||
|
|
||||||
@@ -13,18 +20,32 @@ class RenderLog : AbstractRenderColumn(BetterFoliageMod.MOD_ID) {
|
|||||||
ctx.cameraDistance < Config.roundLogs.distance &&
|
ctx.cameraDistance < Config.roundLogs.distance &&
|
||||||
Config.blocks.logs.matchesID(ctx.block)
|
Config.blocks.logs.matchesID(ctx.block)
|
||||||
|
|
||||||
override var axisFunc = { block: Block, meta: Int -> when ((meta shr 2) and 3) {
|
override var axisFunc = { state: IBlockState ->
|
||||||
1 -> Axis.X
|
when (state.getValue(BlockLog.LOG_AXIS).toString()) {
|
||||||
2 -> Axis.Z
|
"x" -> Axis.X
|
||||||
else -> Axis.Y
|
"z" -> Axis.Z
|
||||||
} }
|
else -> Axis.Y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override val blockPredicate = { block: Block, meta: Int -> Config.blocks.logs.matchesID(block) }
|
val columnTextures = ColumnTextures(Config.blocks.logs)
|
||||||
override val surroundPredicate = { block: Block -> block.isOpaqueCube && !Config.blocks.logs.matchesID(block) }
|
|
||||||
|
override val blockPredicate = { state: IBlockState -> Config.blocks.logs.matchesID(state.block) }
|
||||||
|
override val surroundPredicate = { state: IBlockState -> state.block.isOpaqueCube && !Config.blocks.logs.matchesID(state.block) }
|
||||||
|
|
||||||
override val connectPerpendicular: Boolean get() = Config.roundLogs.connectPerpendicular
|
override val connectPerpendicular: Boolean get() = Config.roundLogs.connectPerpendicular
|
||||||
override val connectSolids: Boolean get() = Config.roundLogs.connectSolids
|
override val connectSolids: Boolean get() = Config.roundLogs.connectSolids
|
||||||
override val lenientConnect: Boolean get() = Config.roundLogs.lenientConnect
|
override val lenientConnect: Boolean get() = Config.roundLogs.lenientConnect
|
||||||
override val radiusLarge: Double get() = Config.roundLogs.radiusLarge
|
override val radiusLarge: Double get() = Config.roundLogs.radiusLarge
|
||||||
override val radiusSmall: Double get() = Config.roundLogs.radiusSmall
|
override val radiusSmall: Double get() = Config.roundLogs.radiusSmall
|
||||||
|
|
||||||
|
override val downTexture = { ctx: ShadingContext, idx: Int, quad: Quad ->
|
||||||
|
columnTextures[ctx.blockData(Int3.zero).state]?.bottomTexture
|
||||||
|
}
|
||||||
|
override val sideTexture = { ctx: ShadingContext, idx: Int, quad: Quad ->
|
||||||
|
columnTextures[ctx.blockData(Int3.zero).state]?.sideTexture
|
||||||
|
}
|
||||||
|
override val upTexture = { ctx: ShadingContext, idx: Int, quad: Quad ->
|
||||||
|
columnTextures[ctx.blockData(Int3.zero).state]?.topTexture
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -3,15 +3,22 @@ package mods.betterfoliage.client.render
|
|||||||
import mods.betterfoliage.BetterFoliageMod
|
import mods.betterfoliage.BetterFoliageMod
|
||||||
import mods.betterfoliage.client.Client
|
import mods.betterfoliage.client.Client
|
||||||
import mods.betterfoliage.client.config.Config
|
import mods.betterfoliage.client.config.Config
|
||||||
import mods.octarinecore.client.render.*
|
import mods.octarinecore.client.render.AbstractBlockRenderingHandler
|
||||||
|
import mods.octarinecore.client.render.BlockContext
|
||||||
|
import mods.octarinecore.client.render.modelRenderer
|
||||||
|
import mods.octarinecore.client.render.noPost
|
||||||
|
import mods.octarinecore.common.Double3
|
||||||
|
import mods.octarinecore.common.Rotation
|
||||||
import net.minecraft.block.material.Material
|
import net.minecraft.block.material.Material
|
||||||
import net.minecraft.client.renderer.RenderBlocks
|
import net.minecraft.client.renderer.BlockRendererDispatcher
|
||||||
|
import net.minecraft.client.renderer.WorldRenderer
|
||||||
import net.minecraft.init.Blocks
|
import net.minecraft.init.Blocks
|
||||||
|
import net.minecraft.util.EnumWorldBlockLayer
|
||||||
import org.apache.logging.log4j.Level.INFO
|
import org.apache.logging.log4j.Level.INFO
|
||||||
|
|
||||||
class RenderMycelium : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
class RenderMycelium : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
||||||
|
|
||||||
val myceliumIcon = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "better_mycel_%d")
|
val myceliumIcon = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_mycel_%d")
|
||||||
val myceliumModel = modelSet(64, RenderGrass.grassTopQuads)
|
val myceliumModel = modelSet(64, RenderGrass.grassTopQuads)
|
||||||
|
|
||||||
override fun afterStitch() {
|
override fun afterStitch() {
|
||||||
@@ -24,17 +31,17 @@ class RenderMycelium : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
|||||||
ctx.cameraDistance < Config.shortGrass.distance
|
ctx.cameraDistance < Config.shortGrass.distance
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun render(ctx: BlockContext, parent: RenderBlocks): Boolean {
|
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean {
|
||||||
val isSnowed = ctx.block(up1).material.let {
|
val isSnowed = ctx.block(up1).isSnow
|
||||||
it == Material.snow || it == Material.craftedSnow
|
|
||||||
}
|
renderWorldBlockBase(ctx, dispatcher, renderer, null)
|
||||||
|
|
||||||
if (renderWorldBlockBase(parent, face = alwaysRender)) return true
|
|
||||||
if (isSnowed && !Config.shortGrass.snowEnabled) return true
|
if (isSnowed && !Config.shortGrass.snowEnabled) return true
|
||||||
if (ctx.block(up1).isOpaqueCube) return true
|
if (ctx.block(up1).isOpaqueCube) return true
|
||||||
|
|
||||||
val rand = ctx.semiRandomArray(2)
|
val rand = ctx.semiRandomArray(2)
|
||||||
modelRenderer.render(
|
modelRenderer.render(
|
||||||
|
renderer,
|
||||||
myceliumModel[rand[0]],
|
myceliumModel[rand[0]],
|
||||||
Rotation.identity,
|
Rotation.identity,
|
||||||
ctx.blockCenter + (if (isSnowed) snowOffset else Double3.zero),
|
ctx.blockCenter + (if (isSnowed) snowOffset else Double3.zero),
|
||||||
|
|||||||
@@ -4,16 +4,19 @@ import mods.betterfoliage.BetterFoliageMod
|
|||||||
import mods.betterfoliage.client.Client
|
import mods.betterfoliage.client.Client
|
||||||
import mods.betterfoliage.client.config.Config
|
import mods.betterfoliage.client.config.Config
|
||||||
import mods.octarinecore.client.render.*
|
import mods.octarinecore.client.render.*
|
||||||
|
import mods.octarinecore.common.Int3
|
||||||
|
import mods.octarinecore.common.Rotation
|
||||||
import mods.octarinecore.random
|
import mods.octarinecore.random
|
||||||
import net.minecraft.client.renderer.RenderBlocks
|
import net.minecraft.client.renderer.BlockRendererDispatcher
|
||||||
|
import net.minecraft.client.renderer.WorldRenderer
|
||||||
import net.minecraft.init.Blocks
|
import net.minecraft.init.Blocks
|
||||||
import net.minecraftforge.common.util.ForgeDirection.DOWN
|
import net.minecraft.util.EnumWorldBlockLayer
|
||||||
import net.minecraftforge.common.util.ForgeDirection.UP
|
import net.minecraft.util.EnumFacing.*
|
||||||
import org.apache.logging.log4j.Level.INFO
|
import org.apache.logging.log4j.Level.INFO
|
||||||
|
|
||||||
class RenderNetherrack : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
class RenderNetherrack : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
||||||
|
|
||||||
val netherrackIcon = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "better_netherrack_%d")
|
val netherrackIcon = iconSet(BetterFoliageMod.LEGACY_DOMAIN, "blocks/better_netherrack_%d")
|
||||||
val netherrackModel = modelSet(64) { modelIdx ->
|
val netherrackModel = modelSet(64) { modelIdx ->
|
||||||
verticalRectangle(x1 = -0.5, z1 = 0.5, x2 = 0.5, z2 = -0.5, yTop = -0.5,
|
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))
|
yBottom = -0.5 - random(Config.netherrack.heightMin, Config.netherrack.heightMax))
|
||||||
@@ -33,12 +36,14 @@ class RenderNetherrack : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID)
|
|||||||
ctx.cameraDistance < Config.netherrack.distance
|
ctx.cameraDistance < Config.netherrack.distance
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun render(ctx: BlockContext, parent: RenderBlocks): Boolean {
|
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean {
|
||||||
if (renderWorldBlockBase(parent, face = alwaysRender)) return true
|
renderWorldBlockBase(ctx, dispatcher, renderer, null)
|
||||||
if (ctx.block(down1).isOpaqueCube) return true
|
if (ctx.block(down1).isOpaqueCube) return true
|
||||||
|
modelRenderer.updateShading(Int3.zero, allFaces)
|
||||||
|
|
||||||
val rand = ctx.semiRandomArray(2)
|
val rand = ctx.semiRandomArray(2)
|
||||||
modelRenderer.render(
|
modelRenderer.render(
|
||||||
|
renderer,
|
||||||
netherrackModel[rand[0]],
|
netherrackModel[rand[0]],
|
||||||
Rotation.identity,
|
Rotation.identity,
|
||||||
icon = { ctx, qi, q -> netherrackIcon[rand[qi and 1]]!! },
|
icon = { ctx, qi, q -> netherrackIcon[rand[qi and 1]]!! },
|
||||||
|
|||||||
@@ -5,16 +5,20 @@ import mods.betterfoliage.client.Client
|
|||||||
import mods.betterfoliage.client.config.Config
|
import mods.betterfoliage.client.config.Config
|
||||||
import mods.betterfoliage.client.integration.ShadersModIntegration
|
import mods.betterfoliage.client.integration.ShadersModIntegration
|
||||||
import mods.octarinecore.client.render.*
|
import mods.octarinecore.client.render.*
|
||||||
|
import mods.octarinecore.common.Int3
|
||||||
|
import mods.octarinecore.common.Rotation
|
||||||
import mods.octarinecore.random
|
import mods.octarinecore.random
|
||||||
import net.minecraft.block.material.Material
|
import net.minecraft.block.material.Material
|
||||||
import net.minecraft.client.renderer.RenderBlocks
|
import net.minecraft.client.renderer.BlockRendererDispatcher
|
||||||
import net.minecraftforge.common.util.ForgeDirection.UP
|
import net.minecraft.client.renderer.WorldRenderer
|
||||||
|
import net.minecraft.util.EnumFacing.UP
|
||||||
|
import net.minecraft.util.EnumWorldBlockLayer
|
||||||
import org.apache.logging.log4j.Level
|
import org.apache.logging.log4j.Level
|
||||||
|
|
||||||
class RenderReeds : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
class RenderReeds : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
||||||
|
|
||||||
val noise = simplexNoise()
|
val noise = simplexNoise()
|
||||||
val reedIcons = iconSet(Client.genReeds.generatedResource("${BetterFoliageMod.LEGACY_DOMAIN}:better_reed_%d"))
|
val reedIcons = iconSet(Client.genReeds.generatedResource("${BetterFoliageMod.LEGACY_DOMAIN}:blocks/better_reed_%d"))
|
||||||
val reedModels = modelSet(64) { modelIdx ->
|
val reedModels = modelSet(64) { modelIdx ->
|
||||||
val height = random(Config.reed.heightMin, Config.reed.heightMax)
|
val height = random(Config.reed.heightMin, Config.reed.heightMax)
|
||||||
val waterline = 0.875f
|
val waterline = 0.875f
|
||||||
@@ -44,14 +48,16 @@ class RenderReeds : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
|
|||||||
ctx.block(up1).material == Material.water &&
|
ctx.block(up1).material == Material.water &&
|
||||||
Config.blocks.dirt.matchesID(ctx.block) &&
|
Config.blocks.dirt.matchesID(ctx.block) &&
|
||||||
ctx.biomeId in Config.reed.biomes &&
|
ctx.biomeId in Config.reed.biomes &&
|
||||||
noise[ctx.x, ctx.z] < Config.reed.population
|
noise[ctx.pos] < Config.reed.population
|
||||||
|
|
||||||
override fun render(ctx: BlockContext, parent: RenderBlocks): Boolean {
|
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean {
|
||||||
if (renderWorldBlockBase(parent, face = alwaysRender)) return true
|
renderWorldBlockBase(ctx, dispatcher, renderer, null)
|
||||||
|
modelRenderer.updateShading(Int3.zero, allFaces)
|
||||||
|
|
||||||
val iconVar = ctx.random(1)
|
val iconVar = ctx.random(1)
|
||||||
ShadersModIntegration.grass(Config.reed.shaderWind) {
|
ShadersModIntegration.grass(renderer, Config.reed.shaderWind) {
|
||||||
modelRenderer.render(
|
modelRenderer.render(
|
||||||
|
renderer,
|
||||||
reedModels[ctx.random(0)],
|
reedModels[ctx.random(0)],
|
||||||
Rotation.identity,
|
Rotation.identity,
|
||||||
forceFlat = true,
|
forceFlat = true,
|
||||||
|
|||||||
@@ -3,13 +3,14 @@ package mods.betterfoliage.client.render
|
|||||||
|
|
||||||
import mods.octarinecore.PI2
|
import mods.octarinecore.PI2
|
||||||
import mods.octarinecore.client.render.*
|
import mods.octarinecore.client.render.*
|
||||||
|
import mods.octarinecore.common.Double3
|
||||||
|
import mods.octarinecore.common.Int3
|
||||||
|
import mods.octarinecore.common.Rotation
|
||||||
|
import mods.octarinecore.common.times
|
||||||
import net.minecraft.block.Block
|
import net.minecraft.block.Block
|
||||||
import net.minecraft.block.material.Material
|
import net.minecraft.block.material.Material
|
||||||
import net.minecraft.tileentity.TileEntity
|
import net.minecraft.util.EnumFacing
|
||||||
import net.minecraft.world.IBlockAccess
|
import net.minecraft.util.EnumFacing.*
|
||||||
import net.minecraft.world.biome.BiomeGenBase
|
|
||||||
import net.minecraftforge.common.util.ForgeDirection
|
|
||||||
import net.minecraftforge.common.util.ForgeDirection.*
|
|
||||||
|
|
||||||
val up1 = Int3(1 to UP)
|
val up1 = Int3(1 to UP)
|
||||||
val up2 = Int3(2 to UP)
|
val up2 = Int3(2 to UP)
|
||||||
@@ -24,11 +25,11 @@ val greywash: RenderVertex.(ShadingContext, Int, Quad, Int, Vertex)->Unit = { ct
|
|||||||
|
|
||||||
val Block.isSnow: Boolean get() = material.let { it == Material.snow || it == Material.craftedSnow }
|
val Block.isSnow: Boolean get() = material.let { it == Material.snow || it == Material.craftedSnow }
|
||||||
|
|
||||||
fun Quad.toCross(rotAxis: ForgeDirection, trans: (Quad)->Quad) =
|
fun Quad.toCross(rotAxis: EnumFacing, trans: (Quad)->Quad) =
|
||||||
(0..3).map { rotIdx ->
|
(0..3).map { rotIdx ->
|
||||||
trans(rotate(Rotation.rot90[rotAxis.ordinal] * rotIdx).mirrorUV(rotIdx > 1, false))
|
trans(rotate(Rotation.rot90[rotAxis.ordinal] * rotIdx).mirrorUV(rotIdx > 1, false))
|
||||||
}
|
}
|
||||||
fun Quad.toCross(rotAxis: ForgeDirection) = toCross(rotAxis) { it }
|
fun Quad.toCross(rotAxis: EnumFacing) = toCross(rotAxis) { it }
|
||||||
|
|
||||||
fun xzDisk(modelIdx: Int) = (PI2 * modelIdx / 64.0).let { Double3(Math.cos(it), 0.0, Math.sin(it)) }
|
fun xzDisk(modelIdx: Int) = (PI2 * modelIdx / 64.0).let { Double3(Math.cos(it), 0.0, Math.sin(it)) }
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
package mods.betterfoliage.client.texture
|
package mods.betterfoliage.client.texture
|
||||||
|
|
||||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent
|
|
||||||
import cpw.mods.fml.relauncher.Side
|
|
||||||
import cpw.mods.fml.relauncher.SideOnly
|
|
||||||
import mods.betterfoliage.client.Client
|
import mods.betterfoliage.client.Client
|
||||||
import mods.betterfoliage.client.config.Config
|
import mods.betterfoliage.client.config.Config
|
||||||
import mods.octarinecore.client.render.HSB
|
import mods.octarinecore.client.render.HSB
|
||||||
import mods.octarinecore.client.resource.averageColor
|
import mods.octarinecore.client.resource.*
|
||||||
import net.minecraft.block.Block
|
import net.minecraft.block.state.IBlockState
|
||||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite
|
||||||
import net.minecraft.client.renderer.texture.TextureMap
|
import net.minecraft.client.renderer.texture.TextureMap
|
||||||
import net.minecraft.util.IIcon
|
import net.minecraft.client.resources.model.ModelResourceLocation
|
||||||
import net.minecraftforge.client.event.TextureStitchEvent
|
import net.minecraftforge.client.event.TextureStitchEvent
|
||||||
|
import net.minecraftforge.client.model.IModel
|
||||||
import net.minecraftforge.common.MinecraftForge
|
import net.minecraftforge.common.MinecraftForge
|
||||||
import org.apache.logging.log4j.Level.DEBUG
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
|
||||||
|
import net.minecraftforge.fml.relauncher.Side
|
||||||
|
import net.minecraftforge.fml.relauncher.SideOnly
|
||||||
import org.apache.logging.log4j.Level.INFO
|
import org.apache.logging.log4j.Level.INFO
|
||||||
|
|
||||||
const val defaultGrassColor = 0
|
const val defaultGrassColor = 0
|
||||||
@@ -34,36 +34,21 @@ class GrassInfo(
|
|||||||
|
|
||||||
/** Collects and manages rendering-related information for grass blocks. */
|
/** Collects and manages rendering-related information for grass blocks. */
|
||||||
@SideOnly(Side.CLIENT)
|
@SideOnly(Side.CLIENT)
|
||||||
object GrassRegistry {
|
object GrassRegistry : BlockTextureInspector<GrassInfo>() {
|
||||||
|
|
||||||
val grass: MutableMap<IIcon, GrassInfo> = hashMapOf()
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
MinecraftForge.EVENT_BUS.register(this)
|
matchClassAndModel(Config.blocks.grass, "block/grass", listOf("top"))
|
||||||
|
matchClassAndModel(Config.blocks.grass, "block/cube_bottom_top", listOf("top"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
override fun onAfterModelLoad() {
|
||||||
fun handleTextureReload(event: TextureStitchEvent.Pre) {
|
super.onAfterModelLoad()
|
||||||
if (event.map.textureType != 0) return
|
|
||||||
grass.clear()
|
|
||||||
Client.log(INFO, "Inspecting grass textures")
|
Client.log(INFO, "Inspecting grass textures")
|
||||||
|
|
||||||
Block.blockRegistry.forEach { block ->
|
|
||||||
if (Config.blocks.grass.matchesClass(block as Block)) {
|
|
||||||
block.registerBlockIcons { location ->
|
|
||||||
val original = event.map.getTextureExtry(location)
|
|
||||||
Client.log(DEBUG, "Found grass texture: $location")
|
|
||||||
registerGrass(event.map, original)
|
|
||||||
return@registerBlockIcons original
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun registerGrass(atlas: TextureMap, icon: TextureAtlasSprite) {
|
override fun processTextures(textures: List<TextureAtlasSprite>, atlas: TextureMap): GrassInfo {
|
||||||
val hsb = HSB.fromColor(icon.averageColor ?: defaultGrassColor)
|
val hsb = HSB.fromColor(textures[0].averageColor ?: defaultGrassColor)
|
||||||
val overrideColor = if (hsb.saturation > Config.shortGrass.saturationThreshold) hsb.copy(brightness = 0.8f).asColor else null
|
val overrideColor = if (hsb.saturation > Config.shortGrass.saturationThreshold) hsb.copy(brightness = 0.8f).asColor else null
|
||||||
grass.put(icon, GrassInfo(icon, overrideColor))
|
return GrassInfo(textures[0], overrideColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,21 +1,20 @@
|
|||||||
package mods.betterfoliage.client.texture
|
package mods.betterfoliage.client.texture
|
||||||
|
|
||||||
import cpw.mods.fml.common.FMLCommonHandler
|
|
||||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent
|
|
||||||
import cpw.mods.fml.relauncher.Side
|
|
||||||
import cpw.mods.fml.relauncher.SideOnly
|
|
||||||
import mods.betterfoliage.client.Client
|
import mods.betterfoliage.client.Client
|
||||||
import mods.betterfoliage.client.config.Config
|
import mods.betterfoliage.client.config.Config
|
||||||
|
import mods.octarinecore.client.resource.BlockTextureInspector
|
||||||
import mods.octarinecore.client.resource.IconSet
|
import mods.octarinecore.client.resource.IconSet
|
||||||
import mods.octarinecore.client.resource.averageColor
|
import mods.octarinecore.client.resource.averageColor
|
||||||
import net.minecraft.block.Block
|
|
||||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite
|
||||||
import net.minecraft.client.renderer.texture.TextureMap
|
import net.minecraft.client.renderer.texture.TextureMap
|
||||||
import net.minecraft.util.IIcon
|
|
||||||
import net.minecraft.util.ResourceLocation
|
import net.minecraft.util.ResourceLocation
|
||||||
import net.minecraftforge.client.event.TextureStitchEvent
|
import net.minecraftforge.client.event.TextureStitchEvent
|
||||||
import net.minecraftforge.common.MinecraftForge
|
import net.minecraftforge.common.MinecraftForge
|
||||||
import org.apache.logging.log4j.Level.*
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
|
||||||
|
import net.minecraftforge.fml.relauncher.Side
|
||||||
|
import net.minecraftforge.fml.relauncher.SideOnly
|
||||||
|
import org.apache.logging.log4j.Level.INFO
|
||||||
|
import org.apache.logging.log4j.Level.WARN
|
||||||
|
|
||||||
const val defaultLeafColor = 0
|
const val defaultLeafColor = 0
|
||||||
|
|
||||||
@@ -36,49 +35,24 @@ class LeafInfo(
|
|||||||
|
|
||||||
/** Collects and manages rendering-related information for leaf blocks. */
|
/** Collects and manages rendering-related information for leaf blocks. */
|
||||||
@SideOnly(Side.CLIENT)
|
@SideOnly(Side.CLIENT)
|
||||||
object LeafRegistry {
|
object LeafRegistry : BlockTextureInspector<LeafInfo>() {
|
||||||
|
|
||||||
val leaves: MutableMap<IIcon, LeafInfo> = hashMapOf()
|
|
||||||
val particles: MutableMap<String, IconSet> = hashMapOf()
|
val particles: MutableMap<String, IconSet> = hashMapOf()
|
||||||
val typeMappings = TextureMatcher()
|
val typeMappings = TextureMatcher().apply { loadMappings(ResourceLocation("betterfoliage", "leafTypeMappings.cfg")) }
|
||||||
|
|
||||||
init {
|
init {
|
||||||
MinecraftForge.EVENT_BUS.register(this)
|
matchClassAndModel(Config.blocks.leaves, "minecraft:block/leaves", listOf("all"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
override fun processTextures(textures: List<TextureAtlasSprite>, atlas: TextureMap): LeafInfo {
|
||||||
fun handleTextureReload(event: TextureStitchEvent.Pre) {
|
val texture = textures[0]
|
||||||
if (event.map.textureType != 0) return
|
var leafType = typeMappings.getType(texture) ?: "default"
|
||||||
leaves.clear()
|
val generated = atlas.registerSprite(
|
||||||
particles.clear()
|
Client.genLeaves.generatedResource(texture.iconName, "type" to leafType)
|
||||||
typeMappings.loadMappings(ResourceLocation("betterfoliage", "leafTypeMappings.cfg"))
|
|
||||||
Client.log(INFO, "Generating leaf textures")
|
|
||||||
|
|
||||||
IconSet("betterfoliage", "falling_leaf_default_%d").let {
|
|
||||||
it.onStitch(event.map)
|
|
||||||
particles.put("default", it)
|
|
||||||
}
|
|
||||||
|
|
||||||
Block.blockRegistry.forEach { block ->
|
|
||||||
if (Config.blocks.leaves.matchesClass(block as Block)) {
|
|
||||||
block.registerBlockIcons { location ->
|
|
||||||
val original = event.map.getTextureExtry(location)
|
|
||||||
Client.log(DEBUG, "Found leaf texture: $location")
|
|
||||||
registerLeaf(event.map, original)
|
|
||||||
return@registerBlockIcons original
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun registerLeaf(atlas: TextureMap, icon: TextureAtlasSprite) {
|
|
||||||
var leafType = typeMappings.getType(icon) ?: "default"
|
|
||||||
val generated = atlas.registerIcon(
|
|
||||||
Client.genLeaves.generatedResource(icon.iconName, "type" to leafType).toString()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (leafType !in particles.keys) {
|
if (leafType !in particles.keys) {
|
||||||
val particleSet = IconSet("betterfoliage", "falling_leaf_${leafType}_%d")
|
val particleSet = IconSet("betterfoliage", "blocks/falling_leaf_${leafType}_%d")
|
||||||
particleSet.onStitch(atlas)
|
particleSet.onStitch(atlas)
|
||||||
if (particleSet.num == 0) {
|
if (particleSet.num == 0) {
|
||||||
Client.log(WARN, "Leaf particle textures not found for leaf type: $leafType")
|
Client.log(WARN, "Leaf particle textures not found for leaf type: $leafType")
|
||||||
@@ -88,7 +62,6 @@ object LeafRegistry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val leafInfo = LeafInfo(generated as TextureAtlasSprite, leafType)
|
return LeafInfo(generated as TextureAtlasSprite, leafType)
|
||||||
leaves.put(icon, leafInfo)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,69 +1,42 @@
|
|||||||
package mods.betterfoliage.loader
|
package mods.betterfoliage.loader
|
||||||
|
|
||||||
import cpw.mods.fml.relauncher.FMLLaunchHandler
|
import mods.octarinecore.metaprog.ASMPlugin
|
||||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin
|
import mods.octarinecore.metaprog.Transformer
|
||||||
import mods.octarinecore.metaprog.*
|
import mods.octarinecore.metaprog.allAvailable
|
||||||
|
import net.minecraftforge.fml.relauncher.FMLLaunchHandler
|
||||||
|
import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin
|
||||||
import org.objectweb.asm.Opcodes.*
|
import org.objectweb.asm.Opcodes.*
|
||||||
|
|
||||||
@IFMLLoadingPlugin.TransformerExclusions(
|
@IFMLLoadingPlugin.TransformerExclusions(
|
||||||
"mods.betterfoliage.loader",
|
"mods.betterfoliage.loader",
|
||||||
"mods.octarinecore.metaprog",
|
"mods.octarinecore.metaprog",
|
||||||
"kotlin",
|
"kotlin",
|
||||||
"mods.betterfoliage.kotlin"
|
"mods.octarinecore.kotlin"
|
||||||
)
|
)
|
||||||
class BetterFoliageLoader : ASMPlugin(BetterFoliageTransformer::class.java)
|
class BetterFoliageLoader : ASMPlugin(BetterFoliageTransformer::class.java)
|
||||||
|
|
||||||
class BetterFoliageTransformer : Transformer() {
|
class BetterFoliageTransformer : Transformer() {
|
||||||
|
|
||||||
|
val isOptifinePresent = allAvailable(Refs.OptifineClassTransformer)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (FMLLaunchHandler.side().isClient) setupClient()
|
if (FMLLaunchHandler.side().isClient) setupClient()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setupClient() {
|
fun setupClient() {
|
||||||
// where: RenderBlocks.renderBlockByRenderType()
|
|
||||||
// what: invoke BF code to overrule the return value of Block.getRenderType()
|
|
||||||
// why: allows us to use custom block renderers for any block, without touching block code
|
|
||||||
transformMethod(Refs.renderBlockByRenderType) {
|
|
||||||
find(varinsn(ISTORE, 5))?.insertAfter {
|
|
||||||
log.info("Applying block render type override")
|
|
||||||
varinsn(ALOAD, 0)
|
|
||||||
getField(Refs.blockAccess)
|
|
||||||
varinsn(ILOAD, 2)
|
|
||||||
varinsn(ILOAD, 3)
|
|
||||||
varinsn(ILOAD, 4)
|
|
||||||
varinsn(ALOAD, 1)
|
|
||||||
varinsn(ILOAD, 5)
|
|
||||||
invokeStatic(Refs.getRenderTypeOverride)
|
|
||||||
varinsn(ISTORE, 5)
|
|
||||||
} ?: log.warn("Failed to apply block render type override!")
|
|
||||||
}
|
|
||||||
|
|
||||||
// where: WorldClient.doVoidFogParticles(), right before the end of the loop
|
// where: WorldClient.doVoidFogParticles(), right before the end of the loop
|
||||||
// what: invoke BF code for every random display tick
|
// what: invoke BF code for every random display tick
|
||||||
// why: allows us to catch random display ticks, without touching block code
|
// why: allows us to catch random display ticks, without touching block code
|
||||||
transformMethod(Refs.doVoidFogParticles) {
|
transformMethod(Refs.doVoidFogParticles) {
|
||||||
find(IINC)?.insertBefore {
|
find(IINC)?.insertBefore {
|
||||||
log.info("Applying random display tick call hook")
|
log.info("Applying random display tick call hook")
|
||||||
varinsn(ALOAD, 10)
|
|
||||||
varinsn(ALOAD, 0)
|
varinsn(ALOAD, 0)
|
||||||
varinsn(ILOAD, 7)
|
varinsn(ALOAD, 13)
|
||||||
varinsn(ILOAD, 8)
|
varinsn(ALOAD, if (isOptifinePresent) 8 else 12)
|
||||||
varinsn(ILOAD, 9)
|
|
||||||
invokeStatic(Refs.onRandomDisplayTick)
|
invokeStatic(Refs.onRandomDisplayTick)
|
||||||
} ?: log.warn("Failed to apply random display tick call hook!")
|
} ?: log.warn("Failed to apply random display tick call hook!")
|
||||||
}
|
}
|
||||||
|
|
||||||
// where: shadersmodcore.client.Shaders.pushEntity()
|
|
||||||
// what: invoke BF code to overrule block data
|
|
||||||
// why: allows us to change the block ID seen by shader programs
|
|
||||||
transformMethod(Refs.pushEntity) {
|
|
||||||
find(IASTORE)?.insertBefore {
|
|
||||||
log.info("Applying Shaders.pushEntity() block id override")
|
|
||||||
varinsn(ALOAD, 1)
|
|
||||||
invokeStatic(Refs.getBlockIdOverride)
|
|
||||||
} ?: log.warn("Failed to apply Shaders.pushEntity() block id override!")
|
|
||||||
}
|
|
||||||
|
|
||||||
// where: Block.getAmbientOcclusionLightValue()
|
// where: Block.getAmbientOcclusionLightValue()
|
||||||
// what: invoke BF code to overrule AO transparency value
|
// what: invoke BF code to overrule AO transparency value
|
||||||
// why: allows us to have light behave properly on non-solid log blocks without
|
// why: allows us to have light behave properly on non-solid log blocks without
|
||||||
@@ -95,12 +68,67 @@ class BetterFoliageTransformer : Transformer() {
|
|||||||
find(IRETURN)?.insertBefore {
|
find(IRETURN)?.insertBefore {
|
||||||
log.info("Applying Block.shouldSideBeRendered() override")
|
log.info("Applying Block.shouldSideBeRendered() override")
|
||||||
varinsn(ALOAD, 1)
|
varinsn(ALOAD, 1)
|
||||||
varinsn(ILOAD, 2)
|
varinsn(ALOAD, 2)
|
||||||
varinsn(ILOAD, 3)
|
varinsn(ALOAD, 3)
|
||||||
varinsn(ILOAD, 4)
|
|
||||||
varinsn(ILOAD, 5)
|
|
||||||
invokeStatic(Refs.shouldRenderBlockSideOverride)
|
invokeStatic(Refs.shouldRenderBlockSideOverride)
|
||||||
} ?: log.warn("Failed to apply Block.shouldSideBeRendered() override!")
|
} ?: log.warn("Failed to apply Block.shouldSideBeRendered() override!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// where: ModelLoader.setupModelRegistry(), right before the textures are loaded
|
||||||
|
// what: invoke handler code with ModelLoader instance
|
||||||
|
// why: allows us to iterate the unbaked models in ModelLoader in time to register textures
|
||||||
|
transformMethod(Refs.setupModelRegistry) {
|
||||||
|
find(invokeName("addAll"))?.insertAfter {
|
||||||
|
log.info("Applying ModelLoader lifecycle callback")
|
||||||
|
varinsn(ALOAD, 0)
|
||||||
|
invokeStatic(Refs.onAfterLoadModelDefinitions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// where: RenderChunk.rebuildChunk()
|
||||||
|
// what: replace call to BlockRendererDispatcher.renderBlock()
|
||||||
|
// why: allows us to perform additional rendering for each block
|
||||||
|
// what: invoke code to overrule result of Block.canRenderInLayer()
|
||||||
|
// why: allows us to render transparent quads for blocks which are only on the SOLID layer
|
||||||
|
transformMethod(Refs.rebuildChunk) {
|
||||||
|
find(invokeRef(Refs.renderBlock))?.replace {
|
||||||
|
log.info("Applying RenderChunk block render override")
|
||||||
|
varinsn(ALOAD, if (isOptifinePresent) 21 else 18)
|
||||||
|
invokeStatic(Refs.renderWorldBlock)
|
||||||
|
}
|
||||||
|
if (isOptifinePresent) {
|
||||||
|
find(varinsn(ISTORE, 22))?.insertBefore {
|
||||||
|
log.info("Applying RenderChunk block layer override")
|
||||||
|
insn(POP)
|
||||||
|
varinsn(ALOAD, 17)
|
||||||
|
varinsn(ALOAD, 21)
|
||||||
|
invokeStatic(Refs.canRenderBlockInLayer)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
find(invokeRef(Refs.canRenderInLayer))?.replace {
|
||||||
|
log.info("Applying RenderChunk block layer override")
|
||||||
|
invokeStatic(Refs.canRenderBlockInLayer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// where: net.minecraft.client.renderer.BlockModelRenderer$AmbientOcclusionFace
|
||||||
|
// what: make constructor public
|
||||||
|
// why: use vanilla AO calculation at will without duplicating code
|
||||||
|
transformMethod(Refs.AOF_constructor) {
|
||||||
|
log.info("Setting AmbientOcclusionFace constructor public")
|
||||||
|
makePublic()
|
||||||
|
}
|
||||||
|
|
||||||
|
// where: shadersmod.client.SVertexBuilder.pushEntity()
|
||||||
|
// what: invoke code to overrule block data
|
||||||
|
// why: allows us to change the block ID seen by shader programs
|
||||||
|
transformMethod(Refs.pushEntity_state) {
|
||||||
|
find(invokeRef(Refs.pushEntity_num))?.insertBefore {
|
||||||
|
log.info("Applying SVertexBuilder.pushEntity() block ID override")
|
||||||
|
varinsn(ALOAD, 0)
|
||||||
|
invokeStatic(Refs.getBlockIdOverride)
|
||||||
|
} ?: log.warn("Failed to apply SVertexBuilder.pushEntity() block ID override!")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package mods.betterfoliage.loader
|
package mods.betterfoliage.loader
|
||||||
|
|
||||||
import cpw.mods.fml.relauncher.FMLInjectionData
|
|
||||||
import mods.octarinecore.metaprog.ClassRef
|
import mods.octarinecore.metaprog.ClassRef
|
||||||
import mods.octarinecore.metaprog.FieldRef
|
import mods.octarinecore.metaprog.FieldRef
|
||||||
import mods.octarinecore.metaprog.MethodRef
|
import mods.octarinecore.metaprog.MethodRef
|
||||||
|
import net.minecraftforge.fml.relauncher.FMLInjectionData
|
||||||
|
|
||||||
/** Singleton object holding references to foreign code elements. */
|
/** Singleton object holding references to foreign code elements. */
|
||||||
object Refs {
|
object Refs {
|
||||||
@@ -14,58 +14,76 @@ object Refs {
|
|||||||
val List = ClassRef("java.util.List")
|
val List = ClassRef("java.util.List")
|
||||||
|
|
||||||
// Minecraft
|
// Minecraft
|
||||||
val IBlockAccess = ClassRef("net.minecraft.world.IBlockAccess", "ahl")
|
val IBlockAccess = ClassRef("net.minecraft.world.IBlockAccess", "ard")
|
||||||
|
val IBlockState = ClassRef("net.minecraft.block.state.IBlockState", "bec")
|
||||||
|
val BlockPos = ClassRef("net.minecraft.util.BlockPos", "dt")
|
||||||
|
val EnumWorldBlockLayer = ClassRef("net.minecraft.util.EnumWorldBlockLayer", "aql")
|
||||||
|
val EnumFacing = ClassRef("net.minecraft.util.EnumFacing", "ej")
|
||||||
|
|
||||||
val Block = ClassRef("net.minecraft.block.Block", "aji")
|
val Block = ClassRef("net.minecraft.block.Block", "atr")
|
||||||
val getAmbientOcclusionLightValue = MethodRef(Block, "getAmbientOcclusionLightValue", "func_149685_I", "I", ClassRef.float)
|
val canRenderInLayer = MethodRef(Block, "canRenderInLayer", ClassRef.boolean, EnumWorldBlockLayer)
|
||||||
val getUseNeighborBrightness = MethodRef(Block, "getUseNeighborBrightness", "func_149710_n", "n", ClassRef.boolean)
|
val getAmbientOcclusionLightValue = MethodRef(Block, "getAmbientOcclusionLightValue", "func_149685_I", "f", ClassRef.float)
|
||||||
val shouldSideBeRendered = MethodRef(Block, "shouldSideBeRendered", "func_149646_a", "a", ClassRef.boolean, IBlockAccess, ClassRef.int, ClassRef.int, ClassRef.int, ClassRef.int)
|
val getUseNeighborBrightness = MethodRef(Block, "getUseNeighborBrightness", "func_149710_n", "q", ClassRef.boolean)
|
||||||
|
val shouldSideBeRendered = MethodRef(Block, "shouldSideBeRendered", "func_149646_a", "a", ClassRef.boolean, IBlockAccess, BlockPos, EnumFacing)
|
||||||
|
|
||||||
val RenderBlocks = ClassRef("net.minecraft.client.renderer.RenderBlocks", "blm")
|
val BlockModelRenderer = ClassRef("net.minecraft.client.renderer.BlockModelRenderer", "cln")
|
||||||
val blockAccess = FieldRef(RenderBlocks, "blockAccess", null, "a", IBlockAccess)
|
val AmbientOcclusionFace = ClassRef("net.minecraft.client.renderer.BlockModelRenderer\$AmbientOcclusionFace", "clq")
|
||||||
val renderBlockByRenderType = MethodRef(RenderBlocks, "renderBlockByRenderType", null, "b", ClassRef.boolean, Block, ClassRef.int, ClassRef.int, ClassRef.int)
|
val ChunkCompileTaskGenerator = ClassRef("net.minecraft.client.renderer.chunk.ChunkCompileTaskGenerator", "coa")
|
||||||
|
val WorldRenderer = ClassRef("net.minecraft.client.renderer.WorldRenderer", "civ")
|
||||||
|
val AOF_constructor = MethodRef(AmbientOcclusionFace, "<init>", ClassRef.void, BlockModelRenderer)
|
||||||
|
|
||||||
val WorldClient = ClassRef("net.minecraft.client.multiplayer.WorldClient", "bjf")
|
val RenderChunk = ClassRef("net.minecraft.client.renderer.chunk.RenderChunk", "cop")
|
||||||
val doVoidFogParticles = MethodRef(WorldClient, "doVoidFogParticles", null, "C", ClassRef.void, ClassRef.int, ClassRef.int, ClassRef.int)
|
val rebuildChunk = MethodRef(RenderChunk, "rebuildChunk", "func_178581_b", "b", ClassRef.void, ClassRef.float, ClassRef.float, ClassRef.float, ChunkCompileTaskGenerator)
|
||||||
|
|
||||||
val World = ClassRef("net.minecraft.world.World", "ahb")
|
val BlockRendererDispatcher = ClassRef("net.minecraft.client.renderer.BlockRendererDispatcher", "cll")
|
||||||
|
val renderBlock = MethodRef(BlockRendererDispatcher, "renderBlock", "func_175018_a", "a", ClassRef.boolean, IBlockState, BlockPos, IBlockAccess, WorldRenderer)
|
||||||
|
|
||||||
val TextureMap = ClassRef("net.minecraft.client.renderer.texture.TextureMap", "bpr")
|
val World = ClassRef("net.minecraft.world.World", "aqu")
|
||||||
val mapRegisteredSprites = FieldRef(TextureMap, "mapRegisteredSprites", "field_110574_e", "bpr", Map)
|
val WorldClient = ClassRef("net.minecraft.client.multiplayer.WorldClient", "cen")
|
||||||
|
val doVoidFogParticles = MethodRef(WorldClient, "doVoidFogParticles", "func_73029_E", "b", ClassRef.void, ClassRef.int, ClassRef.int, ClassRef.int)
|
||||||
|
|
||||||
val IMetadataSerializer = ClassRef("net.minecraft.client.resources.data.IMetadataSerializer", "brw")
|
// val IMetadataSerializer = ClassRef("net.minecraft.client.resources.data.IMetadataSerializer", "brw")
|
||||||
val SimpleReloadableResourceManager = ClassRef("net.minecraft.client.resources.SimpleReloadableResourceManager", "brg")
|
// val SimpleReloadableResourceManager = ClassRef("net.minecraft.client.resources.SimpleReloadableResourceManager", "brg")
|
||||||
val metadataSerializer = FieldRef(SimpleReloadableResourceManager, "rmMetadataSerializer", "field_110547_c", "f", IMetadataSerializer)
|
// val metadataSerializer = FieldRef(SimpleReloadableResourceManager, "rmMetadataSerializer", "field_110547_c", "f", IMetadataSerializer)
|
||||||
|
|
||||||
val IIcon = ClassRef("net.minecraft.util.IIcon", "rf")
|
|
||||||
val TextureAtlasSprite = ClassRef("net.minecraft.client.renderer.texture.TextureAtlasSprite", "bqd")
|
val TextureAtlasSprite = ClassRef("net.minecraft.client.renderer.texture.TextureAtlasSprite", "bqd")
|
||||||
|
|
||||||
|
val IRegistry = ClassRef("net.minecraft.util.IRegistry", "ez")
|
||||||
|
val ModelLoader = ClassRef("net.minecraftforge.client.model.ModelLoader")
|
||||||
|
val stateModels = FieldRef(ModelLoader, "stateModels", Map)
|
||||||
|
val setupModelRegistry = MethodRef(ModelLoader, "setupModelRegistry", "func_177570_a", "a", IRegistry)
|
||||||
|
|
||||||
|
val IModel = ClassRef("net.minecraftforge.client.model.IModel", "")
|
||||||
|
val ModelBlock = ClassRef("net.minecraft.client.renderer.block.model.ModelBlock", "cmc")
|
||||||
|
val ModelResourceLocation = ClassRef("net.minecraft.client.renderer.block.model.ModelResourceLocation", "cmc")
|
||||||
|
val VanillaModelWrapper = ClassRef("net.minecraftforge.client.model.ModelLoader\$VanillaModelWrapper")
|
||||||
|
val model_VMW = FieldRef(VanillaModelWrapper, "model", ModelBlock)
|
||||||
|
val location_VMW = FieldRef(VanillaModelWrapper, "location", ModelBlock)
|
||||||
|
val WeightedPartWrapper = ClassRef("net.minecraftforge.client.model.ModelLoader\$WeightedPartWrapper")
|
||||||
|
val model_WPW = FieldRef(WeightedPartWrapper, "model", IModel)
|
||||||
|
val WeightedRandomModel = ClassRef("net.minecraftforge.client.model.ModelLoader\$WeightedRandomModel")
|
||||||
|
val models_WRM = FieldRef(WeightedRandomModel, "models", List)
|
||||||
|
|
||||||
// Better Foliage
|
// Better Foliage
|
||||||
val BetterFoliageHooks = ClassRef("mods.betterfoliage.client.Hooks")
|
val BetterFoliageHooks = ClassRef("mods.betterfoliage.client.Hooks")
|
||||||
val getAmbientOcclusionLightValueOverride = MethodRef(BetterFoliageHooks, "getAmbientOcclusionLightValueOverride", ClassRef.float, ClassRef.float, Block)
|
val getAmbientOcclusionLightValueOverride = MethodRef(BetterFoliageHooks, "getAmbientOcclusionLightValueOverride", ClassRef.float, ClassRef.float, Block)
|
||||||
val getUseNeighborBrightnessOverride = MethodRef(BetterFoliageHooks, "getUseNeighborBrightnessOverride", ClassRef.boolean, ClassRef.boolean, Block)
|
val getUseNeighborBrightnessOverride = MethodRef(BetterFoliageHooks, "getUseNeighborBrightnessOverride", ClassRef.boolean, ClassRef.boolean, Block)
|
||||||
val shouldRenderBlockSideOverride = MethodRef(BetterFoliageHooks, "shouldRenderBlockSideOverride", ClassRef.boolean, ClassRef.boolean, IBlockAccess, ClassRef.int, ClassRef.int, ClassRef.int, ClassRef.int)
|
val shouldRenderBlockSideOverride = MethodRef(BetterFoliageHooks, "shouldRenderBlockSideOverride", ClassRef.boolean, ClassRef.boolean, IBlockAccess, BlockPos, EnumFacing)
|
||||||
val getRenderTypeOverride = MethodRef(BetterFoliageHooks, "getRenderTypeOverride", ClassRef.int, IBlockAccess, ClassRef.int, ClassRef.int, ClassRef.int, Block, ClassRef.int)
|
val onRandomDisplayTick = MethodRef(BetterFoliageHooks, "onRandomDisplayTick", ClassRef.void, World, IBlockState, BlockPos)
|
||||||
val onRandomDisplayTick = MethodRef(BetterFoliageHooks, "onRandomDisplayTick", ClassRef.void, Block, World, ClassRef.int, ClassRef.int, ClassRef.int)
|
val onAfterLoadModelDefinitions = MethodRef(BetterFoliageHooks, "onAfterLoadModelDefinitions", ClassRef.void, ModelLoader)
|
||||||
|
val renderWorldBlock = MethodRef(BetterFoliageHooks, "renderWorldBlock", ClassRef.boolean, BlockRendererDispatcher, IBlockState, BlockPos, IBlockAccess, WorldRenderer, EnumWorldBlockLayer)
|
||||||
// Shaders mod
|
val canRenderBlockInLayer = MethodRef(BetterFoliageHooks, "canRenderBlockInLayer", ClassRef.boolean, Block, EnumWorldBlockLayer)
|
||||||
val Shaders = ClassRef("shadersmodcore.client.Shaders")
|
|
||||||
val pushEntity = MethodRef(Shaders, "pushEntity", ClassRef.void, RenderBlocks, Block, ClassRef.int, ClassRef.int, ClassRef.int)
|
|
||||||
val pushEntity_I = MethodRef(Shaders, "pushEntity", ClassRef.void, ClassRef.int)
|
|
||||||
val popEntity = MethodRef(Shaders, "popEntity", ClassRef.void)
|
|
||||||
|
|
||||||
val ShadersModIntegration = ClassRef("mods.betterfoliage.client.integration.ShadersModIntegration")
|
|
||||||
val getBlockIdOverride = MethodRef(ShadersModIntegration, "getBlockIdOverride", ClassRef.int, ClassRef.int, Block)
|
|
||||||
|
|
||||||
// Optifine
|
// Optifine
|
||||||
val ConnectedTextures = ClassRef("ConnectedTextures")
|
val OptifineClassTransformer = ClassRef("optifine.OptiFineClassTransformer")
|
||||||
val getConnectedTexture = MethodRef(ConnectedTextures, "getConnectedTexture", IIcon, IBlockAccess, Block, ClassRef.int, ClassRef.int, ClassRef.int, ClassRef.int, IIcon)
|
|
||||||
val CTBlockProperties = FieldRef(ConnectedTextures, "blockProperties", null)
|
|
||||||
val CTTileProperties = FieldRef(ConnectedTextures, "tileProperties", null)
|
|
||||||
|
|
||||||
val ConnectedProperties = ClassRef("ConnectedProperties")
|
// ShadersMod
|
||||||
val CPTileIcons = FieldRef(ConnectedProperties, "tileIcons", null)
|
val SVertexBuilder = ClassRef("shadersmod.client.SVertexBuilder")
|
||||||
|
val sVertexBuilder = FieldRef(WorldRenderer, "sVertexBuilder", SVertexBuilder)
|
||||||
|
val pushEntity_state = MethodRef(SVertexBuilder, "pushEntity", ClassRef.void, IBlockState, BlockPos, IBlockAccess, WorldRenderer)
|
||||||
|
val pushEntity_num = MethodRef(SVertexBuilder, "pushEntity", ClassRef.void, ClassRef.long)
|
||||||
|
val popEntity = MethodRef(SVertexBuilder, "popEntity", ClassRef.void)
|
||||||
|
|
||||||
// Colored Lights Core
|
val ShadersModIntegration = ClassRef("mods.betterfoliage.client.integration.ShadersModIntegration")
|
||||||
val CLCLoadingPlugin = ClassRef("coloredlightscore.src.asm.ColoredLightsCoreLoadingPlugin")
|
val getBlockIdOverride = MethodRef(ShadersModIntegration, "getBlockIdOverride", ClassRef.long, ClassRef.long, IBlockState)
|
||||||
}
|
}
|
||||||
@@ -24,6 +24,15 @@ inline fun <T> MutableList<T>.exchange(idx1: Int, idx2: Int) {
|
|||||||
/** Cross product of this [Iterable] with the parameter. */
|
/** Cross product of this [Iterable] with the parameter. */
|
||||||
fun <A, B> Iterable<A>.cross(other: Iterable<B>) = flatMap { a -> other.map { b -> a to b } }
|
fun <A, B> Iterable<A>.cross(other: Iterable<B>) = flatMap { a -> other.map { b -> a to b } }
|
||||||
|
|
||||||
|
inline fun <C, R, T> Iterable<T>.mapAs(transform: (C) -> R) = map { transform(it as C) }
|
||||||
|
|
||||||
|
inline fun <T1, T2> forEachNested(list1: Iterable<T1>, list2: Iterable<T2>, func: (T1, T2)-> Unit) =
|
||||||
|
list1.forEach { e1 ->
|
||||||
|
list2.forEach { e2 ->
|
||||||
|
func(e1, e2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Property-level delegate backed by a [ThreadLocal].
|
* Property-level delegate backed by a [ThreadLocal].
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package mods.octarinecore.client
|
package mods.octarinecore.client
|
||||||
|
|
||||||
import cpw.mods.fml.client.registry.ClientRegistry
|
|
||||||
import cpw.mods.fml.common.FMLCommonHandler
|
|
||||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent
|
|
||||||
import cpw.mods.fml.common.gameevent.InputEvent
|
|
||||||
import net.minecraft.client.settings.KeyBinding
|
import net.minecraft.client.settings.KeyBinding
|
||||||
|
import net.minecraftforge.fml.client.registry.ClientRegistry
|
||||||
|
import net.minecraftforge.fml.common.FMLCommonHandler
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
|
||||||
|
import net.minecraftforge.fml.common.gameevent.InputEvent
|
||||||
|
|
||||||
class KeyHandler(val modId: String, val defaultKey: Int, val lang: String, val action: (InputEvent.KeyInputEvent)->Unit) {
|
class KeyHandler(val modId: String, val defaultKey: Int, val lang: String, val action: (InputEvent.KeyInputEvent)->Unit) {
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package mods.octarinecore.client.gui
|
package mods.octarinecore.client.gui
|
||||||
|
|
||||||
import cpw.mods.fml.client.config.*
|
|
||||||
import net.minecraft.client.gui.GuiScreen
|
import net.minecraft.client.gui.GuiScreen
|
||||||
import net.minecraft.client.resources.I18n
|
import net.minecraft.client.resources.I18n
|
||||||
import net.minecraft.util.EnumChatFormatting.GOLD
|
import net.minecraft.util.EnumChatFormatting.GOLD
|
||||||
import net.minecraft.util.EnumChatFormatting.YELLOW
|
import net.minecraft.util.EnumChatFormatting.YELLOW
|
||||||
|
import net.minecraftforge.fml.client.config.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for a config GUI element.
|
* Base class for a config GUI element.
|
||||||
@@ -12,9 +12,9 @@ import net.minecraft.util.EnumChatFormatting.YELLOW
|
|||||||
* The config representation is an integer list of the selected objects' IDs.
|
* The config representation is an integer list of the selected objects' IDs.
|
||||||
*/
|
*/
|
||||||
abstract class IdListConfigEntry<T>(
|
abstract class IdListConfigEntry<T>(
|
||||||
owningScreen: GuiConfig,
|
owningScreen: GuiConfig,
|
||||||
owningEntryList: GuiConfigEntries,
|
owningEntryList: GuiConfigEntries,
|
||||||
configElement: IConfigElement<*>
|
configElement: IConfigElement
|
||||||
) : GuiConfigEntries.CategoryEntry(owningScreen, owningEntryList, configElement) {
|
) : GuiConfigEntries.CategoryEntry(owningScreen, owningEntryList, configElement) {
|
||||||
|
|
||||||
/** Create the child GUI elements. */
|
/** Create the child GUI elements. */
|
||||||
@@ -25,10 +25,14 @@ abstract class IdListConfigEntry<T>(
|
|||||||
init { stripTooltipDefaultText(toolTip as MutableList<String>) }
|
init { stripTooltipDefaultText(toolTip as MutableList<String>) }
|
||||||
|
|
||||||
override fun buildChildScreen(): GuiScreen {
|
override fun buildChildScreen(): GuiScreen {
|
||||||
return GuiConfig(this.owningScreen, createChildren(), this.owningScreen.modID,
|
return GuiConfig(
|
||||||
owningScreen.allRequireWorldRestart || this.configElement.requiresWorldRestart(),
|
this.owningScreen,
|
||||||
owningScreen.allRequireMcRestart || this.configElement.requiresMcRestart(), this.owningScreen.title,
|
createChildren(),
|
||||||
((if (this.owningScreen.titleLine2 == null) "" else this.owningScreen.titleLine2) + " > " + this.name))
|
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 {
|
override fun saveConfigElement(): Boolean {
|
||||||
@@ -45,14 +49,14 @@ abstract class IdListConfigEntry<T>(
|
|||||||
|
|
||||||
/** Child config GUI element of a single toggleable object. */
|
/** Child config GUI element of a single toggleable object. */
|
||||||
inner class ItemWrapperElement(val item: T, value: Boolean, val default: Boolean) :
|
inner class ItemWrapperElement(val item: T, value: Boolean, val default: Boolean) :
|
||||||
DummyConfigElement<Boolean>(item.itemName, default, ConfigGuiType.BOOLEAN, item.itemName) {
|
DummyConfigElement(item.itemName, default, ConfigGuiType.BOOLEAN, item.itemName) {
|
||||||
init { set(value) }
|
|
||||||
|
init {
|
||||||
|
this.value = value
|
||||||
|
this.defaultValue = default
|
||||||
|
}
|
||||||
|
|
||||||
override fun getComment() = I18n.format("${configElement.languageKey}.tooltip.element", "${GOLD}${item.itemName}${YELLOW}")
|
override fun getComment() = I18n.format("${configElement.languageKey}.tooltip.element", "${GOLD}${item.itemName}${YELLOW}")
|
||||||
override fun set(value: Boolean) { this.value = value }
|
|
||||||
fun setDefault(value: Boolean) { this.defaultValue = value }
|
|
||||||
val booleanValue: Boolean get() = value as Boolean
|
val booleanValue: Boolean get() = value as Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,21 +1,21 @@
|
|||||||
package mods.octarinecore.client.gui
|
package mods.octarinecore.client.gui
|
||||||
|
|
||||||
import cpw.mods.fml.client.config.GuiConfig
|
|
||||||
import cpw.mods.fml.client.config.GuiConfigEntries
|
|
||||||
import cpw.mods.fml.client.config.IConfigElement
|
|
||||||
import net.minecraft.client.resources.I18n
|
import net.minecraft.client.resources.I18n
|
||||||
import net.minecraft.util.EnumChatFormatting.*
|
import net.minecraft.util.EnumChatFormatting.AQUA
|
||||||
|
import net.minecraftforge.fml.client.config.GuiConfig
|
||||||
|
import net.minecraftforge.fml.client.config.GuiConfigEntries
|
||||||
|
import net.minecraftforge.fml.client.config.IConfigElement
|
||||||
|
|
||||||
class NonVerboseArrayEntry(
|
class NonVerboseArrayEntry(
|
||||||
owningScreen: GuiConfig,
|
owningScreen: GuiConfig,
|
||||||
owningEntryList: GuiConfigEntries,
|
owningEntryList: GuiConfigEntries,
|
||||||
configElement: IConfigElement<*>
|
configElement: IConfigElement
|
||||||
) : GuiConfigEntries.ArrayEntry(owningScreen, owningEntryList, configElement) {
|
) : GuiConfigEntries.ArrayEntry(owningScreen, owningEntryList, configElement) {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
stripTooltipDefaultText(toolTip as MutableList<String>)
|
stripTooltipDefaultText(toolTip as MutableList<String>)
|
||||||
val shortDefaults = I18n.format("${configElement.languageKey}.arrayEntry", configElement.defaults.size)
|
val shortDefaults = I18n.format("${configElement.languageKey}.arrayEntry", configElement.defaults.size)
|
||||||
toolTip.addAll(mc.fontRenderer.listFormattedStringToWidth("$AQUA${I18n.format("fml.configgui.tooltip.default", shortDefaults)}", 300))
|
toolTip.addAll(mc.fontRendererObj.listFormattedStringToWidth("$AQUA${I18n.format("fml.configgui.tooltip.default", shortDefaults)}", 300))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateValueButtonText() {
|
override fun updateValueButtonText() {
|
||||||
|
|||||||
@@ -1,23 +1,21 @@
|
|||||||
@file:JvmName("RendererHolder")
|
@file:JvmName("RendererHolder")
|
||||||
package mods.octarinecore.client.render
|
package mods.octarinecore.client.render
|
||||||
|
|
||||||
import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler
|
|
||||||
import cpw.mods.fml.client.registry.RenderingRegistry
|
|
||||||
import mods.octarinecore.ThreadLocalDelegate
|
import mods.octarinecore.ThreadLocalDelegate
|
||||||
import mods.octarinecore.client.resource.ResourceHandler
|
import mods.octarinecore.client.resource.ResourceHandler
|
||||||
|
import mods.octarinecore.common.Double3
|
||||||
|
import mods.octarinecore.common.Int3
|
||||||
|
import mods.octarinecore.common.forgeDirOffsets
|
||||||
|
import mods.octarinecore.common.plus
|
||||||
import net.minecraft.block.Block
|
import net.minecraft.block.Block
|
||||||
|
import net.minecraft.block.state.IBlockState
|
||||||
import net.minecraft.client.Minecraft
|
import net.minecraft.client.Minecraft
|
||||||
import net.minecraft.client.renderer.RenderBlocks
|
import net.minecraft.client.renderer.BlockRendererDispatcher
|
||||||
import net.minecraft.util.IIcon
|
import net.minecraft.client.renderer.WorldRenderer
|
||||||
|
import net.minecraft.util.BlockPos
|
||||||
|
import net.minecraft.util.EnumWorldBlockLayer
|
||||||
import net.minecraft.util.MathHelper
|
import net.minecraft.util.MathHelper
|
||||||
import net.minecraft.world.IBlockAccess
|
import net.minecraft.world.IBlockAccess
|
||||||
import net.minecraftforge.common.util.ForgeDirection
|
|
||||||
|
|
||||||
/**
|
|
||||||
* [ThreadLocal] instance of [ExtendedRenderBlocks] used instead of the vanilla [RenderBlocks] to get the
|
|
||||||
* AO values and textures used in rendering without duplicating vanilla code.
|
|
||||||
*/
|
|
||||||
val renderBlocks by ThreadLocalDelegate { ExtendedRenderBlocks() }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [ThreadLocal] instance of [BlockContext] representing the block being rendered.
|
* [ThreadLocal] instance of [BlockContext] representing the block being rendered.
|
||||||
@@ -29,121 +27,77 @@ val blockContext by ThreadLocalDelegate { BlockContext() }
|
|||||||
*/
|
*/
|
||||||
val modelRenderer by ThreadLocalDelegate { ModelRenderer() }
|
val modelRenderer by ThreadLocalDelegate { ModelRenderer() }
|
||||||
|
|
||||||
abstract class AbstractBlockRenderingHandler(modId: String) : ResourceHandler(modId), ISimpleBlockRenderingHandler {
|
abstract class AbstractBlockRenderingHandler(modId: String) : ResourceHandler(modId) {
|
||||||
|
|
||||||
// ============================
|
val moveToCutout: Boolean get() = true
|
||||||
// Self-registration
|
|
||||||
// ============================
|
|
||||||
val id = RenderingRegistry.getNextAvailableRenderId()
|
|
||||||
init {
|
|
||||||
RenderingRegistry.registerBlockHandler(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================
|
// ============================
|
||||||
// Custom rendering
|
// Custom rendering
|
||||||
// ============================
|
// ============================
|
||||||
abstract fun isEligible(ctx: BlockContext): Boolean
|
abstract fun isEligible(ctx: BlockContext): Boolean
|
||||||
abstract fun render(ctx: BlockContext, parent: RenderBlocks): Boolean
|
abstract fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer): Boolean
|
||||||
|
|
||||||
// ============================
|
|
||||||
// Interface implementation
|
|
||||||
// ============================
|
|
||||||
override fun renderWorldBlock(world: IBlockAccess?, x: Int, y: Int, z: Int, block: Block?, modelId: Int, parentRenderer: RenderBlocks?): Boolean {
|
|
||||||
renderBlocks.blockAccess = world
|
|
||||||
return render(blockContext, parentRenderer!!)
|
|
||||||
}
|
|
||||||
override fun renderInventoryBlock(block: Block?, metadata: Int, modelId: Int, renderer: RenderBlocks?) {}
|
|
||||||
override fun shouldRender3DInInventory(modelId: Int) = true
|
|
||||||
override fun getRenderId(): Int = id
|
|
||||||
|
|
||||||
// ============================
|
// ============================
|
||||||
// Vanilla rendering wrapper
|
// Vanilla rendering wrapper
|
||||||
// ============================
|
// ============================
|
||||||
/**
|
/**
|
||||||
* Render the block in the current [BlockContext], and capture shading and texture data.
|
* Render the block in the current [BlockContext], and capture shading and texture data.
|
||||||
*
|
|
||||||
* @param[parentRenderer] parent renderer passed in by rendering pipeline, used only for block breaking overlay
|
|
||||||
* @param[targetPass] which render pass to save shading and texture data from
|
|
||||||
* @param[block] lambda to use to render the block if it does not have a custom renderer
|
|
||||||
* @param[face] lambda to determine which faces of the block to render
|
|
||||||
*/
|
*/
|
||||||
fun renderWorldBlockBase(
|
fun renderWorldBlockBase(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: WorldRenderer, layer: EnumWorldBlockLayer?): Boolean {
|
||||||
parentRenderer: RenderBlocks = renderBlocks,
|
ctx.blockState(Int3.zero).let {
|
||||||
targetPass: Int = 1,
|
if (layer == null || it.block.canRenderInLayer(layer))
|
||||||
block: () -> Unit = { blockContext.let { ctx -> renderBlocks.renderStandardBlock(ctx.block, ctx.x, ctx.y, ctx.z) } },
|
return dispatcher.renderBlock(it, ctx.pos, ctx.world, renderer)
|
||||||
face: (ShadingCapture, ForgeDirection, Int, IIcon?) -> Boolean
|
|
||||||
): Boolean {
|
|
||||||
val ctx = blockContext
|
|
||||||
val renderBlocks = renderBlocks
|
|
||||||
|
|
||||||
// use original renderer for block breaking overlay
|
|
||||||
if (parentRenderer.hasOverrideBlockTexture()) {
|
|
||||||
parentRenderer.setRenderBoundsFromBlock(ctx.block);
|
|
||||||
parentRenderer.renderStandardBlock(ctx.block, ctx.x, ctx.y, ctx.z);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
// render block
|
|
||||||
renderBlocks.capture.reset(targetPass)
|
|
||||||
renderBlocks.capture.renderCallback = face
|
|
||||||
renderBlocks.setRenderBoundsFromBlock(ctx.block);
|
|
||||||
val handler = renderingHandlers[ctx.block.renderType];
|
|
||||||
if (handler != null && ctx.block.renderType != 0) {
|
|
||||||
handler.renderWorldBlock(ctx.world, ctx.x, ctx.y, ctx.z, ctx.block, ctx.block.renderType, renderBlocks);
|
|
||||||
} else {
|
|
||||||
block()
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class BlockData(val state: IBlockState, val color: Int, val brightness: Int)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the block being rendered. Has properties and methods to query the neighborhood of the block in
|
* Represents the block being rendered. Has properties and methods to query the neighborhood of the block in
|
||||||
* block-relative coordinates.
|
* block-relative coordinates.
|
||||||
*/
|
*/
|
||||||
class BlockContext() {
|
class BlockContext() {
|
||||||
var world: IBlockAccess? = null
|
var world: IBlockAccess? = null
|
||||||
var x: Int = 0
|
var pos = BlockPos.ORIGIN
|
||||||
var y: Int = 0
|
|
||||||
var z: Int = 0
|
|
||||||
|
|
||||||
fun set(world: IBlockAccess, x: Int, y: Int, z: Int) { this.world = world; this.x = x; this.y = y; this.z = z; }
|
fun set(world: IBlockAccess, pos: BlockPos) { this.world = world; this.pos = pos; }
|
||||||
|
|
||||||
/** Get the [Block] at the given offset. */
|
val block: Block get() = block(Int3.zero)
|
||||||
val block: Block get() = world!!.getBlock(x, y, z)
|
fun block(offset: Int3) = blockState(offset).block
|
||||||
fun block(offset: Int3) = world!!.getBlock(x + offset.x, y + offset.y, z + offset.z)
|
fun blockState(offset: Int3) = (pos + offset).let { world!!.getBlockState(it) }
|
||||||
|
fun blockData(offset: Int3, pass: Int) = (pos + offset).let { pos ->
|
||||||
/** Get the metadata at the given offset. */
|
world!!.getBlockState(pos).let { state ->
|
||||||
val meta: Int get() = world!!.getBlockMetadata(x, y, z)
|
BlockData(
|
||||||
fun meta(offset: Int3) = world!!.getBlockMetadata(x + offset.x, y + offset.y, z + offset.z)
|
state,
|
||||||
|
state.block.colorMultiplier(world!!, pos, pass),
|
||||||
/** Get the block color multiplier at the given offset. */
|
state.block.getMixedBrightnessForBlock(world!!, pos)
|
||||||
val blockColor: Int get() = block.colorMultiplier(world, x, y, z)
|
)
|
||||||
fun blockColor(offset: Int3) = block(offset).colorMultiplier(world, x + offset.x, y + offset.y, z + offset.z)
|
}
|
||||||
|
}
|
||||||
/** Get the block brightness at the given offset. */
|
|
||||||
val blockBrightness: Int get() = block.getMixedBrightnessForBlock(world, x, y, z)
|
|
||||||
fun blockBrightness(offset: Int3) = block(offset).getMixedBrightnessForBlock(world, x + offset.x, y + offset.y, z + offset.z)
|
|
||||||
|
|
||||||
/** Get the biome ID at the block position. */
|
/** Get the biome ID at the block position. */
|
||||||
val biomeId: Int get() = world!!.getBiomeGenForCoords(x, z).biomeID
|
val biomeId: Int get() = world!!.getBiomeGenForCoords(pos).biomeID
|
||||||
|
|
||||||
/** Get the texture on a given face of the block being rendered. */
|
|
||||||
fun icon(face: ForgeDirection) = block(Int3.zero).getIcon(face.ordinal, meta(Int3.zero))
|
|
||||||
/** Get the texture on a given face of the block at the given offset. */
|
|
||||||
fun icon(offset: Int3, face: ForgeDirection) = block(offset).getIcon(face.ordinal, meta(offset))
|
|
||||||
|
|
||||||
/** Get the centerpoint of the block being rendered. */
|
/** Get the centerpoint of the block being rendered. */
|
||||||
val blockCenter: Double3 get() = Double3(x + 0.5, y + 0.5, z + 0.5)
|
val blockCenter: Double3 get() = Double3(pos.x + 0.5, pos.y + 0.5, pos.z + 0.5)
|
||||||
|
|
||||||
|
val chunkBase: Double3 get() {
|
||||||
|
val cX = if (pos.x >= 0) pos.x / 16 else (pos.x + 1) / 16 - 1
|
||||||
|
val cY = pos.y / 16
|
||||||
|
val cZ = if (pos.z >= 0) pos.z / 16 else (pos.z + 1) / 16 - 1
|
||||||
|
return Double3(cX * 16.0, cY * 16.0, cZ * 16.0)
|
||||||
|
}
|
||||||
|
|
||||||
/** Is the block surrounded by other blocks that satisfy the predicate on all sides? */
|
/** Is the block surrounded by other blocks that satisfy the predicate on all sides? */
|
||||||
fun isSurroundedBy(predicate: (Block)->Boolean) = forgeDirOffsets.all { predicate(block(it)) }
|
fun isSurroundedBy(predicate: (IBlockState)->Boolean) = forgeDirOffsets.all { predicate(blockState(it)) }
|
||||||
|
|
||||||
/** Get a semi-random value based on the block coordinate and the given seed. */
|
/** Get a semi-random value based on the block coordinate and the given seed. */
|
||||||
fun random(seed: Int): Int {
|
fun random(seed: Int): Int {
|
||||||
var value = (x * x + y * y + z * z + x * y + y * z + z * x + (seed * seed)) and 63
|
var value = (pos.x * pos.x + pos.y * pos.y + pos.z * pos.z + pos.x * pos.y + pos.y * pos.z + pos.z * pos.x + (seed * seed)) and 63
|
||||||
value = (3 * x * value + 5 * y * value + 7 * z * value + (11 * seed)) and 63
|
value = (3 * pos.x * value + 5 * pos.y * value + 7 * pos.z * value + (11 * seed)) and 63
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,8 +107,8 @@ class BlockContext() {
|
|||||||
/** Get the distance of the block from the camera (player). */
|
/** Get the distance of the block from the camera (player). */
|
||||||
val cameraDistance: Int get() {
|
val cameraDistance: Int get() {
|
||||||
val camera = Minecraft.getMinecraft().renderViewEntity ?: return 0
|
val camera = Minecraft.getMinecraft().renderViewEntity ?: return 0
|
||||||
return Math.abs(x - MathHelper.floor_double(camera.posX)) +
|
return Math.abs(pos.x - MathHelper.floor_double(camera.posX)) +
|
||||||
Math.abs(y - MathHelper.floor_double(camera.posY)) +
|
Math.abs(pos.y - MathHelper.floor_double(camera.posY)) +
|
||||||
Math.abs(z - MathHelper.floor_double(camera.posZ))
|
Math.abs(pos.z - MathHelper.floor_double(camera.posZ))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
package mods.octarinecore.client.render
|
package mods.octarinecore.client.render
|
||||||
|
|
||||||
import mods.octarinecore.PI2
|
import mods.octarinecore.PI2
|
||||||
|
import mods.octarinecore.common.Double3
|
||||||
import net.minecraft.client.Minecraft
|
import net.minecraft.client.Minecraft
|
||||||
import net.minecraft.client.particle.EntityFX
|
import net.minecraft.client.particle.EntityFX
|
||||||
import net.minecraft.client.renderer.Tessellator
|
import net.minecraft.client.renderer.WorldRenderer
|
||||||
import net.minecraft.util.IIcon
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite
|
||||||
|
import net.minecraft.entity.Entity
|
||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
|
|
||||||
abstract class AbstractEntityFX(world: World, x: Double, y: Double, z: Double) : EntityFX(world, x, y, z) {
|
abstract class AbstractEntityFX(world: World, x: Double, y: Double, z: Double) : EntityFX(world, x, y, z) {
|
||||||
@@ -30,7 +32,7 @@ abstract class AbstractEntityFX(world: World, x: Double, y: Double, z: Double) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Render the particle. */
|
/** Render the particle. */
|
||||||
abstract fun render(tessellator: Tessellator, partialTickTime: Float)
|
abstract fun render(worldRenderer: WorldRenderer, partialTickTime: Float)
|
||||||
|
|
||||||
/** Update particle on world tick. */
|
/** Update particle on world tick. */
|
||||||
abstract fun update()
|
abstract fun update()
|
||||||
@@ -41,12 +43,11 @@ abstract class AbstractEntityFX(world: World, x: Double, y: Double, z: Double) :
|
|||||||
/** Add the particle to the effect renderer if it is valid. */
|
/** 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.getMinecraft().effectRenderer.addEffect(this) }
|
||||||
|
|
||||||
override fun renderParticle(tessellator: Tessellator, partialTickTime: Float, rotX: Float, rotZ: Float, rotYZ: Float, rotXY: Float, rotXZ: Float) {
|
override fun renderParticle(worldRenderer: WorldRenderer, entity: Entity, partialTickTime: Float, rotX: Float, rotZ: Float, rotYZ: Float, rotXY: Float, rotXZ: Float) {
|
||||||
billboardRot.first.setTo(rotX + rotXY, rotZ, rotYZ + rotXZ)
|
billboardRot.first.setTo(rotX + rotXY, rotZ, rotYZ + rotXZ)
|
||||||
billboardRot.second.setTo(rotX - rotXY, -rotZ, rotYZ - rotXZ)
|
billboardRot.second.setTo(rotX - rotXY, -rotZ, rotYZ - rotXZ)
|
||||||
render(tessellator, partialTickTime)
|
render(worldRenderer, partialTickTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render a particle quad.
|
* Render a particle quad.
|
||||||
*
|
*
|
||||||
@@ -60,13 +61,13 @@ abstract class AbstractEntityFX(world: World, x: Double, y: Double, z: Double) :
|
|||||||
* @param[isMirrored] mirror particle texture along V-axis
|
* @param[isMirrored] mirror particle texture along V-axis
|
||||||
* @param[alpha] aplha blending
|
* @param[alpha] aplha blending
|
||||||
*/
|
*/
|
||||||
fun renderParticleQuad(tessellator: Tessellator,
|
fun renderParticleQuad(worldRenderer: WorldRenderer,
|
||||||
partialTickTime: Float,
|
partialTickTime: Float,
|
||||||
currentPos: Double3 = this.currentPos,
|
currentPos: Double3 = this.currentPos,
|
||||||
prevPos: Double3 = this.prevPos,
|
prevPos: Double3 = this.prevPos,
|
||||||
size: Double = particleScale.toDouble(),
|
size: Double = particleScale.toDouble(),
|
||||||
rotation: Int = 0,
|
rotation: Int = 0,
|
||||||
icon: IIcon = particleIcon,
|
icon: TextureAtlasSprite = particleIcon,
|
||||||
isMirrored: Boolean = false,
|
isMirrored: Boolean = false,
|
||||||
alpha: Float = this.particleAlpha) {
|
alpha: Float = this.particleAlpha) {
|
||||||
|
|
||||||
@@ -81,11 +82,11 @@ abstract class AbstractEntityFX(world: World, x: Double, y: Double, z: Double) :
|
|||||||
val v2 = if (rotation == 0) billboardRot.second * size else
|
val v2 = if (rotation == 0) billboardRot.second * size else
|
||||||
Double3.weight(billboardRot.first, -sin[rotation and 63] * size, billboardRot.second, cos[rotation and 63] * size)
|
Double3.weight(billboardRot.first, -sin[rotation and 63] * size, billboardRot.second, cos[rotation and 63] * size)
|
||||||
|
|
||||||
tessellator.setColorRGBA_F(this.particleRed, this.particleGreen, this.particleBlue, alpha)
|
worldRenderer.setColorRGBA_F(this.particleRed, this.particleGreen, this.particleBlue, alpha)
|
||||||
tessellator.addVertexWithUV(center.x - v1.x, center.y - v1.y, center.z - v1.z, maxU, maxV)
|
worldRenderer.addVertexWithUV(center.x - v1.x, center.y - v1.y, center.z - v1.z, maxU, maxV)
|
||||||
tessellator.addVertexWithUV(center.x - v2.x, center.y - v2.y, center.z - v2.z, maxU, minV)
|
worldRenderer.addVertexWithUV(center.x - v2.x, center.y - v2.y, center.z - v2.z, maxU, minV)
|
||||||
tessellator.addVertexWithUV(center.x + v1.x, center.y + v1.y, center.z + v1.z, minU, minV)
|
worldRenderer.addVertexWithUV(center.x + v1.x, center.y + v1.y, center.z + v1.z, minU, minV)
|
||||||
tessellator.addVertexWithUV(center.x + v2.x, center.y + v2.y, center.z + v2.z, minU, maxV)
|
worldRenderer.addVertexWithUV(center.x + v2.x, center.y + v2.y, center.z + v2.z, minU, maxV)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getFXLayer() = 1
|
override fun getFXLayer() = 1
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package mods.octarinecore.client.render
|
package mods.octarinecore.client.render
|
||||||
|
|
||||||
|
import mods.octarinecore.common.*
|
||||||
import mods.octarinecore.minmax
|
import mods.octarinecore.minmax
|
||||||
import mods.octarinecore.replace
|
import mods.octarinecore.replace
|
||||||
import net.minecraftforge.common.util.ForgeDirection
|
import net.minecraft.util.EnumFacing
|
||||||
import java.lang.Math.*
|
import java.lang.Math.max
|
||||||
|
import java.lang.Math.min
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vertex UV coordinates
|
* Vertex UV coordinates
|
||||||
@@ -57,7 +59,7 @@ data class Quad(val v1: Vertex, val v2: Vertex, val v3: Vertex, val v4: Vertex)
|
|||||||
val normal: Double3 get() = (v2.xyz - v1.xyz).cross(v4.xyz - v1.xyz).normalize
|
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: Double3) = transformV { it.copy(xyz = it.xyz + trans) }
|
||||||
fun move(trans: Pair<Double, ForgeDirection>) = move(Double3(trans.second) * trans.first)
|
fun move(trans: Pair<Double, EnumFacing>) = move(Double3(trans.second) * trans.first)
|
||||||
fun scale (scale: Double) = transformV { it.copy(xyz = it.xyz * scale) }
|
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 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)) }
|
fun scaleUV (scale: Double) = transformV { it.copy(uv = UV(it.uv.u * scale, it.uv.v * scale)) }
|
||||||
@@ -115,7 +117,7 @@ class Model() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun faceQuad(face: ForgeDirection): Quad {
|
fun faceQuad(face: EnumFacing): Quad {
|
||||||
val base = face.vec * 0.5
|
val base = face.vec * 0.5
|
||||||
val top = faceCorners[face.ordinal].topLeft.first.vec * 0.5
|
val top = faceCorners[face.ordinal].topLeft.first.vec * 0.5
|
||||||
val left = faceCorners[face.ordinal].topLeft.second.vec * 0.5
|
val left = faceCorners[face.ordinal].topLeft.second.vec * 0.5
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
package mods.octarinecore.client.render
|
package mods.octarinecore.client.render
|
||||||
|
|
||||||
|
import mods.octarinecore.client.resource.resourceManager
|
||||||
|
import mods.octarinecore.common.*
|
||||||
import net.minecraft.client.Minecraft
|
import net.minecraft.client.Minecraft
|
||||||
import net.minecraft.client.renderer.Tessellator
|
import net.minecraft.client.renderer.WorldRenderer
|
||||||
import net.minecraft.util.IIcon
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite
|
||||||
import net.minecraftforge.common.util.ForgeDirection
|
import net.minecraft.util.EnumFacing
|
||||||
import net.minecraftforge.common.util.ForgeDirection.*
|
import net.minecraft.util.EnumFacing.*
|
||||||
|
|
||||||
class ModelRenderer() : ShadingContext() {
|
class ModelRenderer() : ShadingContext() {
|
||||||
|
|
||||||
@@ -25,11 +27,12 @@ class ModelRenderer() : ShadingContext() {
|
|||||||
* @param[postProcess] lambda to perform arbitrary modifications on the [RenderVertex] just before it goes to the [Tessellator]
|
* @param[postProcess] lambda to perform arbitrary modifications on the [RenderVertex] just before it goes to the [Tessellator]
|
||||||
*/
|
*/
|
||||||
inline fun render(
|
inline fun render(
|
||||||
|
worldRenderer: WorldRenderer,
|
||||||
model: Model,
|
model: Model,
|
||||||
rot: Rotation,
|
rot: Rotation,
|
||||||
trans: Double3 = blockContext.blockCenter,
|
trans: Double3 = blockContext.blockCenter,
|
||||||
forceFlat: Boolean = false,
|
forceFlat: Boolean = false,
|
||||||
icon: (ShadingContext, Int, Quad) -> IIcon,
|
icon: (ShadingContext, Int, Quad) -> TextureAtlasSprite?,
|
||||||
rotateUV: (Quad) -> Int,
|
rotateUV: (Quad) -> Int,
|
||||||
postProcess: RenderVertex.(ShadingContext, Int, Quad, Int, Vertex) -> Unit
|
postProcess: RenderVertex.(ShadingContext, Int, Quad, Int, Vertex) -> Unit
|
||||||
) {
|
) {
|
||||||
@@ -38,17 +41,19 @@ class ModelRenderer() : ShadingContext() {
|
|||||||
|
|
||||||
model.quads.forEachIndexed { quadIdx, quad ->
|
model.quads.forEachIndexed { quadIdx, quad ->
|
||||||
val drawIcon = icon(this, quadIdx, quad)
|
val drawIcon = icon(this, quadIdx, quad)
|
||||||
val uvRot = rotateUV(quad)
|
if (drawIcon != null) {
|
||||||
quad.verts.forEachIndexed { vertIdx, vert ->
|
val uvRot = rotateUV(quad)
|
||||||
temp.init(vert)
|
quad.verts.forEachIndexed { vertIdx, vert ->
|
||||||
temp.rotate(rotation).translate(trans).rotateUV(uvRot).setIcon(drawIcon)
|
temp.init(vert)
|
||||||
val shader = if (aoEnabled && !forceFlat) vert.aoShader else vert.flatShader
|
temp.rotate(rotation).translate(trans).rotateUV(uvRot).setIcon(drawIcon)
|
||||||
shader.shade(this, temp)
|
val shader = if (aoEnabled && !forceFlat) vert.aoShader else vert.flatShader
|
||||||
temp.postProcess(this, quadIdx, quad, vertIdx, vert)
|
shader.shade(this, temp)
|
||||||
Tessellator.instance.apply {
|
temp.postProcess(this, quadIdx, quad, vertIdx, vert)
|
||||||
setBrightness(temp.brightness)
|
worldRenderer.setTextureUV(temp.u, temp.v)
|
||||||
setColorOpaque_F(temp.red, temp.green, temp.blue)
|
worldRenderer.setBrightness(temp.brightness)
|
||||||
addVertexWithUV(temp.x, temp.y, temp.z, temp.u, temp.v)
|
worldRenderer.setColorOpaque_F(temp.red, temp.green, temp.blue)
|
||||||
|
worldRenderer.addVertex(temp.x, temp.y, temp.z)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -61,13 +66,16 @@ class ModelRenderer() : ShadingContext() {
|
|||||||
open class ShadingContext {
|
open class ShadingContext {
|
||||||
var rotation = Rotation.identity
|
var rotation = Rotation.identity
|
||||||
var aoEnabled = Minecraft.isAmbientOcclusionEnabled()
|
var aoEnabled = Minecraft.isAmbientOcclusionEnabled()
|
||||||
|
val aoFaces = Array(6) { AoFaceData(forgeDirs[it]) }
|
||||||
|
|
||||||
fun aoShading(face: ForgeDirection, corner1: ForgeDirection, corner2: ForgeDirection) =
|
fun updateShading(offset: Int3, predicate: (EnumFacing) -> Boolean = { true }) {
|
||||||
renderBlocks.capture.aoShading(face.rotate(rotation), corner1.rotate(rotation), corner2.rotate(rotation))
|
forgeDirs.forEach { if (predicate(it)) aoFaces[it.ordinal].update(offset) }
|
||||||
|
}
|
||||||
|
|
||||||
fun blockColor(offset: Int3) = blockContext.blockColor(offset.rotate(rotation))
|
fun aoShading(face: EnumFacing, corner1: EnumFacing, corner2: EnumFacing) =
|
||||||
fun blockBrightness(offset: Int3) = blockContext.blockBrightness(offset.rotate(rotation))
|
aoFaces[face.rotate(rotation).ordinal][corner1.rotate(rotation), corner2.rotate(rotation)]
|
||||||
fun icon(face: ForgeDirection) = blockContext.icon(face.rotate(rotation))
|
|
||||||
|
fun blockData(offset: Int3) = blockContext.blockData(offset.rotate(rotation), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -112,7 +120,7 @@ class RenderVertex() {
|
|||||||
else -> { return this }
|
else -> { return this }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline fun setIcon(icon: IIcon): RenderVertex {
|
inline fun setIcon(icon: TextureAtlasSprite): RenderVertex {
|
||||||
u = (icon.maxU - icon.minU) * (u + 0.5) + icon.minU
|
u = (icon.maxU - icon.minU) * (u + 0.5) + icon.minU
|
||||||
v = (icon.maxV - icon.minV) * (v + 0.5) + icon.minV
|
v = (icon.maxV - icon.minV) * (v + 0.5) + icon.minV
|
||||||
return this
|
return this
|
||||||
@@ -134,5 +142,8 @@ class RenderVertex() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val allFaces: (EnumFacing) -> Boolean = { true }
|
||||||
|
val topOnly: (EnumFacing) -> Boolean = { it == UP }
|
||||||
|
|
||||||
/** Perform no post-processing */
|
/** Perform no post-processing */
|
||||||
val noPost: RenderVertex.(ShadingContext, Int, Quad, Int, Vertex) -> Unit = { ctx, qi, q, vi, v -> }
|
val noPost: RenderVertex.(ShadingContext, Int, Quad, Int, Vertex) -> Unit = { ctx, qi, q, vi, v -> }
|
||||||
@@ -1,54 +1,33 @@
|
|||||||
package mods.octarinecore.client.render
|
package mods.octarinecore.client.render
|
||||||
|
|
||||||
import mods.octarinecore.minmax
|
import mods.octarinecore.common.Int3
|
||||||
|
import mods.octarinecore.common.plus
|
||||||
|
import net.minecraft.util.BlockPos
|
||||||
|
import net.minecraft.util.EnumFacing
|
||||||
import net.minecraft.world.IBlockAccess
|
import net.minecraft.world.IBlockAccess
|
||||||
import net.minecraftforge.common.util.ForgeDirection
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delegating [IBlockAccess] that fakes a _modified_ location to return values from a _target_ location.
|
* Delegating [IBlockAccess] that fakes a _modified_ location to return values from a _target_ location.
|
||||||
* All other locations are handled normally.
|
* All other locations are handled normally.
|
||||||
*
|
*
|
||||||
* @param[original] the [IBlockAccess] that is delegated to
|
* @param[original] the [IBlockAccess] that is delegated to
|
||||||
* @param[xModded] x coordinate of the _modified_ location
|
|
||||||
* @param[yModded] y coordinate of the _modified_ location
|
|
||||||
* @param[zModded] z coordinate of the _modified_ location
|
|
||||||
* @param[xTarget] x coordinate of the _target_ location
|
|
||||||
* @param[yTarget] y coordinate of the _target_ location
|
|
||||||
* @param[zTarget] z coordinate of the _target_ location
|
|
||||||
*/
|
*/
|
||||||
class OffsetBlockAccess(val original: IBlockAccess,
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
@JvmField val xModded: Int, @JvmField val yModded: Int, @JvmField val zModded: Int,
|
class OffsetBlockAccess(val original: IBlockAccess, val modded: BlockPos, val target: BlockPos) : IBlockAccess {
|
||||||
@JvmField val xTarget: Int, @JvmField val yTarget: Int, @JvmField val zTarget: Int) : IBlockAccess {
|
|
||||||
|
|
||||||
inline fun <reified T> withOffset(x: Int, y: Int, z: Int, func: (Int,Int,Int)->T): T {
|
inline fun actualPos(pos: BlockPos?) =
|
||||||
if (x == xModded && y == yModded && z == zModded) {
|
if (pos != null && pos.x == modded.x && pos.y == modded.y && pos.z == modded.z) target else pos
|
||||||
return func(xTarget, yTarget, zTarget)
|
|
||||||
} else {
|
|
||||||
return func(x, y, z)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getBlock(x: Int, y: Int, z: Int) = withOffset(x, y, z)
|
|
||||||
{ xAct, yAct, zAct -> original.getBlock(xAct, yAct, zAct) }
|
|
||||||
override fun getBlockMetadata(x: Int, y: Int, z: Int) = withOffset(x, y, z)
|
|
||||||
{ xAct, yAct, zAct -> original.getBlockMetadata(xAct, yAct, zAct) }
|
|
||||||
override fun getTileEntity(x: Int, y: Int, z: Int) = withOffset(x, y, z)
|
|
||||||
{ xAct, yAct, zAct -> original.getTileEntity(xAct, yAct, zAct) }
|
|
||||||
override fun isSideSolid(x: Int, y: Int, z: Int, side: ForgeDirection?, _default: Boolean) = withOffset(x, y, z)
|
|
||||||
{ xAct, yAct, zAct -> original.isSideSolid(xAct, yAct, zAct, side, _default) }
|
|
||||||
override fun isAirBlock(x: Int, y: Int, z: Int) = withOffset(x, y, z)
|
|
||||||
{ xAct, yAct, zAct -> original.isAirBlock(xAct, yAct, zAct) }
|
|
||||||
override fun getLightBrightnessForSkyBlocks(x: Int, y: Int, z: Int, side: Int) = withOffset(x, y, z)
|
|
||||||
{ xAct, yAct, zAct -> original.getLightBrightnessForSkyBlocks(xAct, yAct, zAct, side) }
|
|
||||||
override fun isBlockProvidingPowerTo(x: Int, y: Int, z: Int, side: Int) = withOffset(x, y, z)
|
|
||||||
{ xAct, yAct, zAct -> original.isBlockProvidingPowerTo(xAct, yAct, zAct, side) }
|
|
||||||
override fun getBiomeGenForCoords(x: Int, z: Int) = withOffset(x, 0, z)
|
|
||||||
{ xAct, yAct, zAct -> original.getBiomeGenForCoords(xAct, zAct) }
|
|
||||||
|
|
||||||
override fun getHeight() = original.height
|
|
||||||
override fun extendedLevelsInChunkCache() = original.extendedLevelsInChunkCache()
|
override fun extendedLevelsInChunkCache() = original.extendedLevelsInChunkCache()
|
||||||
|
override fun getBiomeGenForCoords(pos: BlockPos?) = original.getBiomeGenForCoords(actualPos(pos))
|
||||||
|
override fun getBlockState(pos: BlockPos?) = original.getBlockState(actualPos(pos))
|
||||||
|
override fun getCombinedLight(pos: BlockPos?, lightValue: Int) = original.getCombinedLight(actualPos(pos), lightValue)
|
||||||
|
override fun getStrongPower(pos: BlockPos?, direction: EnumFacing?) = original.getStrongPower(actualPos(pos), direction)
|
||||||
|
override fun getTileEntity(pos: BlockPos?) = original.getTileEntity(actualPos(pos))
|
||||||
|
override fun getWorldType() = original.worldType
|
||||||
|
override fun isAirBlock(pos: BlockPos?) = original.isAirBlock(actualPos(pos))
|
||||||
|
override fun isSideSolid(pos: BlockPos?, side: EnumFacing?, _default: Boolean) = original.isSideSolid(actualPos(pos), side, _default)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Temporarily replaces the [IBlockAccess] used by this [BlockContext] and the corresponding [ExtendedRenderBlocks]
|
* Temporarily replaces the [IBlockAccess] used by this [BlockContext] and the corresponding [ExtendedRenderBlocks]
|
||||||
* to use an [OffsetBlockAccess] while executing this lambda.
|
* to use an [OffsetBlockAccess] while executing this lambda.
|
||||||
@@ -59,10 +38,8 @@ class OffsetBlockAccess(val original: IBlockAccess,
|
|||||||
*/
|
*/
|
||||||
inline fun <reified T> BlockContext.withOffset(modded: Int3, target: Int3, func: () -> T): T {
|
inline fun <reified T> BlockContext.withOffset(modded: Int3, target: Int3, func: () -> T): T {
|
||||||
val original = world!!
|
val original = world!!
|
||||||
world = OffsetBlockAccess(original, x + modded.x, y + modded.y, z + modded.z, x + target.x, y + target.y, z + target.z)
|
world = OffsetBlockAccess(original, pos + modded, pos + target)
|
||||||
renderBlocks.blockAccess = world
|
|
||||||
val result = func()
|
val result = func()
|
||||||
world = original
|
world = original
|
||||||
renderBlocks.blockAccess = original
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
package mods.octarinecore.client.render
|
|
||||||
|
|
||||||
import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler
|
|
||||||
import cpw.mods.fml.client.registry.RenderingRegistry
|
|
||||||
import mods.octarinecore.metaprog.reflectField
|
|
||||||
import mods.octarinecore.metaprog.reflectStaticField
|
|
||||||
import net.minecraft.block.Block
|
|
||||||
import net.minecraft.client.renderer.RenderBlocks
|
|
||||||
import net.minecraft.util.IIcon
|
|
||||||
import net.minecraftforge.common.util.ForgeDirection
|
|
||||||
import net.minecraftforge.common.util.ForgeDirection.*
|
|
||||||
|
|
||||||
/** Reference to the handler list in Forge [RenderingRegistry]. */
|
|
||||||
val renderingHandlers: Map<Int, ISimpleBlockRenderingHandler> = RenderingRegistry::class.java
|
|
||||||
.reflectStaticField<RenderingRegistry>("INSTANCE")!!
|
|
||||||
.reflectField<Map<Int, ISimpleBlockRenderingHandler>>("blockRenderers")!!
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used instead of the vanilla [RenderBlocks] to get to the AO values and textures used in rendering
|
|
||||||
* without duplicating vanilla code.
|
|
||||||
*/
|
|
||||||
class ExtendedRenderBlocks : RenderBlocks() {
|
|
||||||
|
|
||||||
/** Captures the AO values and textures used in a specific rendering pass when rendering a block. */
|
|
||||||
val capture = ShadingCapture()
|
|
||||||
|
|
||||||
override fun renderFaceXPos(block: Block?, x: Double, y: Double, z: Double, icon: IIcon?) = renderFace(EAST, block, x, y, z, icon)
|
|
||||||
override fun renderFaceXNeg(block: Block?, x: Double, y: Double, z: Double, icon: IIcon?) = renderFace(WEST, block, x, y, z, icon)
|
|
||||||
override fun renderFaceYPos(block: Block?, x: Double, y: Double, z: Double, icon: IIcon?) = renderFace(UP, block, x, y, z, icon)
|
|
||||||
override fun renderFaceYNeg(block: Block?, x: Double, y: Double, z: Double, icon: IIcon?) = renderFace(DOWN, block, x, y, z, icon)
|
|
||||||
override fun renderFaceZPos(block: Block?, x: Double, y: Double, z: Double, icon: IIcon?) = renderFace(SOUTH, block, x, y, z, icon)
|
|
||||||
override fun renderFaceZNeg(block: Block?, x: Double, y: Double, z: Double, icon: IIcon?) = renderFace(NORTH, block, x, y, z, icon)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Render a block face, saving relevant data if appropriate.
|
|
||||||
*/
|
|
||||||
@Suppress("NON_EXHAUSTIVE_WHEN")
|
|
||||||
fun renderFace(face: ForgeDirection, block: Block?, x: Double, y: Double, z: Double, icon: IIcon?) {
|
|
||||||
if (capture.isCorrectPass(face)) {
|
|
||||||
saveAllShading(face); capture.icons[face.ordinal] = icon
|
|
||||||
}
|
|
||||||
if (capture.renderCallback(capture, face, capture.passes[face.ordinal], icon)) when (face) {
|
|
||||||
EAST -> super.renderFaceXPos(block, x, y, z, icon)
|
|
||||||
WEST -> super.renderFaceXNeg(block, x, y, z, icon)
|
|
||||||
UP -> super.renderFaceYPos(block, x, y, z, icon)
|
|
||||||
DOWN -> super.renderFaceYNeg(block, x, y, z, icon)
|
|
||||||
SOUTH -> super.renderFaceZPos(block, x, y, z, icon)
|
|
||||||
NORTH -> super.renderFaceZNeg(block, x, y, z, icon)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun saveTopLeft(face: ForgeDirection, corner: Pair<ForgeDirection, ForgeDirection>) =
|
|
||||||
capture.aoShading(face, corner.first, corner.second)
|
|
||||||
.set(brightnessTopLeft, colorRedTopLeft, colorGreenTopLeft, colorBlueTopLeft)
|
|
||||||
|
|
||||||
fun saveTopRight(face: ForgeDirection, corner: Pair<ForgeDirection, ForgeDirection>) =
|
|
||||||
capture.aoShading(face, corner.first, corner.second)
|
|
||||||
.set(brightnessTopRight, colorRedTopRight, colorGreenTopRight, colorBlueTopRight)
|
|
||||||
|
|
||||||
fun saveBottomLeft(face: ForgeDirection, corner: Pair<ForgeDirection, ForgeDirection>) =
|
|
||||||
capture.aoShading(face, corner.first, corner.second)
|
|
||||||
.set(brightnessBottomLeft, colorRedBottomLeft, colorGreenBottomLeft, colorBlueBottomLeft)
|
|
||||||
|
|
||||||
fun saveBottomRight(face: ForgeDirection, corner: Pair<ForgeDirection, ForgeDirection>) =
|
|
||||||
capture.aoShading(face, corner.first, corner.second)
|
|
||||||
.set(brightnessBottomRight, colorRedBottomRight, colorGreenBottomRight, colorBlueBottomRight)
|
|
||||||
|
|
||||||
fun saveAllShading(face: ForgeDirection) {
|
|
||||||
saveTopLeft(face, faceCorners[face.ordinal].topLeft)
|
|
||||||
saveTopRight(face, faceCorners[face.ordinal].topRight)
|
|
||||||
saveBottomLeft(face, faceCorners[face.ordinal].bottomLeft)
|
|
||||||
saveBottomRight(face, faceCorners[face.ordinal].bottomRight)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Captures the AO values and textures used in a specific rendering pass when rendering a block.
|
|
||||||
*/
|
|
||||||
class ShadingCapture {
|
|
||||||
/** Sparse array of stored AO data. */
|
|
||||||
val aoShadings = arrayOfNulls<AoData>(6 * 6 * 6)
|
|
||||||
|
|
||||||
/** List of stored AO data (only valid instances). */
|
|
||||||
var shadingsList = listOf<AoData>()
|
|
||||||
|
|
||||||
/** List of stored texture data. */
|
|
||||||
val icons = arrayOfNulls<IIcon>(6)
|
|
||||||
|
|
||||||
/** Number of passes to go on a given face. */
|
|
||||||
val passes = Array(6) { 0 }
|
|
||||||
|
|
||||||
/** lambda to determine which faces to render. */
|
|
||||||
var renderCallback = alwaysRender
|
|
||||||
|
|
||||||
init {
|
|
||||||
(0..5).forEach { i1 ->
|
|
||||||
(0..5).forEach { i2 ->
|
|
||||||
(i2..5).forEach { i3 ->
|
|
||||||
aoShadings[cornerId(i1, i2, i3)] = AoData()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
shadingsList = aoShadings.filterNotNull()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the AO data of a specific corner.
|
|
||||||
*
|
|
||||||
* The two corner directions are interchangeable. All 3 parameters must lie on different axes.
|
|
||||||
*
|
|
||||||
* @param[face] block face
|
|
||||||
* @param[corner1] first direction of corner on face
|
|
||||||
* @param[corner2] second direction of corner on face
|
|
||||||
*/
|
|
||||||
fun aoShading(face: ForgeDirection, corner1: ForgeDirection, corner2: ForgeDirection) =
|
|
||||||
aoShadings[cornerId(face, corner1, corner2)]!!
|
|
||||||
|
|
||||||
/** Returns true if the AO and texture data should be saved. Mutates state. */
|
|
||||||
fun isCorrectPass(face: ForgeDirection) = (passes[face.ordinal]-- > 0)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset all data and pass counters.
|
|
||||||
*
|
|
||||||
* @param[targetPass] which render pass to save
|
|
||||||
*/
|
|
||||||
fun reset(targetPass: Int) {
|
|
||||||
shadingsList.forEach { it.reset() }
|
|
||||||
(0..5).forEach { idx -> icons[idx] = null; passes[idx] = targetPass }
|
|
||||||
}
|
|
||||||
|
|
||||||
/** One-dimensional index of a specific corner. */
|
|
||||||
protected fun cornerId(face: Int, corner1: Int, corner2: Int) = when (corner2 > corner1) {
|
|
||||||
true -> 36 * face + 6 * corner1 + corner2
|
|
||||||
false -> 36 * face + 6 * corner2 + corner1
|
|
||||||
}
|
|
||||||
|
|
||||||
/** One-dimensional index of a specific corner. */
|
|
||||||
protected fun cornerId(face: ForgeDirection, corner1: ForgeDirection, corner2: ForgeDirection) =
|
|
||||||
cornerId(face.ordinal, corner1.ordinal, corner2.ordinal)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Lambda to render all faces of a block */
|
|
||||||
val alwaysRender: (ShadingCapture, ForgeDirection, Int, IIcon?) -> Boolean = { ctx, face, pass, icon -> true }
|
|
||||||
|
|
||||||
/** Lambda to render no faces of a block */
|
|
||||||
val neverRender: (ShadingCapture, ForgeDirection, Int, IIcon?) -> Boolean = { ctx, face, pass, icon -> false }
|
|
||||||
|
|
||||||
@@ -1,24 +1,26 @@
|
|||||||
package mods.octarinecore.client.render
|
package mods.octarinecore.client.render
|
||||||
|
|
||||||
import net.minecraftforge.common.util.ForgeDirection
|
import mods.octarinecore.common.*
|
||||||
|
import net.minecraft.util.EnumFacing
|
||||||
|
|
||||||
|
|
||||||
const val defaultCornerDimming = 0.5f
|
const val defaultCornerDimming = 0.5f
|
||||||
const val defaultEdgeDimming = 0.8f
|
const val defaultEdgeDimming = 0.8f
|
||||||
|
|
||||||
// ================================
|
// ================================
|
||||||
// Resolvers for automatic shading
|
// Shader instantiation lambdas
|
||||||
// ================================
|
// ================================
|
||||||
fun cornerAo(fallbackAxis: Axis): (ForgeDirection, ForgeDirection, ForgeDirection)->Shader = { face, dir1, dir2 ->
|
fun cornerAo(fallbackAxis: EnumFacing.Axis): (EnumFacing, EnumFacing, EnumFacing)->Shader = { face, dir1, dir2 ->
|
||||||
val fallbackDir = listOf(face, dir1, dir2).find { it.axis == fallbackAxis }!!
|
val fallbackDir = listOf(face, dir1, dir2).find { it.axis == fallbackAxis }!!
|
||||||
CornerSingleFallback(face, dir1, dir2, fallbackDir)
|
CornerSingleFallback(face, dir1, dir2, fallbackDir)
|
||||||
}
|
}
|
||||||
val cornerFlat = { face: ForgeDirection, dir1: ForgeDirection, dir2: ForgeDirection -> FaceFlat(face) }
|
val cornerFlat = { face: EnumFacing, dir1: EnumFacing, dir2: EnumFacing -> FaceFlat(face) }
|
||||||
fun cornerAoTri(func: (AoData, AoData)-> AoData) = { face: ForgeDirection, dir1: ForgeDirection, dir2: ForgeDirection ->
|
fun cornerAoTri(func: (AoData, AoData)-> AoData) = { face: EnumFacing, dir1: EnumFacing, dir2: EnumFacing ->
|
||||||
CornerTri(face, dir1, dir2, func)
|
CornerTri(face, dir1, dir2, func)
|
||||||
}
|
}
|
||||||
val cornerAoMaxGreen = cornerAoTri { s1, s2 -> if (s1.green > s2.green) s1 else s2 }
|
val cornerAoMaxGreen = cornerAoTri { s1, s2 -> if (s1.green > s2.green) s1 else s2 }
|
||||||
|
|
||||||
fun cornerInterpolate(edgeAxis: Axis, weight: Float, dimming: Float): (ForgeDirection, ForgeDirection, ForgeDirection)->Shader = { dir1, dir2, dir3 ->
|
fun cornerInterpolate(edgeAxis: EnumFacing.Axis, weight: Float, dimming: Float): (EnumFacing, EnumFacing, EnumFacing)->Shader = { dir1, dir2, dir3 ->
|
||||||
val edgeDir = listOf(dir1, dir2, dir3).find { it.axis == edgeAxis }!!
|
val edgeDir = listOf(dir1, dir2, dir3).find { it.axis == edgeAxis }!!
|
||||||
val faceDirs = listOf(dir1, dir2, dir3).filter { it.axis != edgeAxis }
|
val faceDirs = listOf(dir1, dir2, dir3).filter { it.axis != edgeAxis }
|
||||||
CornerInterpolateDimming(faceDirs[0], faceDirs[1], edgeDir, weight, dimming)
|
CornerInterpolateDimming(faceDirs[0], faceDirs[1], edgeDir, weight, dimming)
|
||||||
@@ -32,14 +34,15 @@ object NoShader : Shader {
|
|||||||
override fun rotate(rot: Rotation) = this
|
override fun rotate(rot: Rotation) = this
|
||||||
}
|
}
|
||||||
|
|
||||||
class CornerSingleFallback(val face: ForgeDirection, val dir1: ForgeDirection, val dir2: ForgeDirection, val fallbackDir: ForgeDirection, val fallbackDimming: Float = defaultCornerDimming) : Shader {
|
class CornerSingleFallback(val face: EnumFacing, val dir1: EnumFacing, val dir2: EnumFacing, val fallbackDir: EnumFacing, val fallbackDimming: Float = defaultCornerDimming) : Shader {
|
||||||
val offset = Int3(fallbackDir)
|
val offset = Int3(fallbackDir)
|
||||||
override fun shade(context: ShadingContext, vertex: RenderVertex) {
|
override fun shade(context: ShadingContext, vertex: RenderVertex) {
|
||||||
val shading = context.aoShading(face, dir1, dir2)
|
val shading = context.aoShading(face, dir1, dir2)
|
||||||
if (shading.valid)
|
if (shading.valid)
|
||||||
vertex.shade(shading)
|
vertex.shade(shading)
|
||||||
else
|
else context.blockData(offset).let {
|
||||||
vertex.shade(context.blockBrightness(offset) brMul fallbackDimming, context.blockColor(offset) colorMul fallbackDimming)
|
vertex.shade(it.brightness brMul fallbackDimming, it.color colorMul fallbackDimming)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
override fun rotate(rot: Rotation) = CornerSingleFallback(face.rotate(rot), dir1.rotate(rot), dir2.rotate(rot), fallbackDir.rotate(rot), fallbackDimming)
|
override fun rotate(rot: Rotation) = CornerSingleFallback(face.rotate(rot), dir1.rotate(rot), dir2.rotate(rot), fallbackDir.rotate(rot), fallbackDimming)
|
||||||
}
|
}
|
||||||
@@ -53,7 +56,7 @@ inline fun accumulate(v1: AoData?, v2: AoData?, func: ((AoData, AoData)-> AoData
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
class CornerTri(val face: ForgeDirection, val dir1: ForgeDirection, val dir2: ForgeDirection,
|
class CornerTri(val face: EnumFacing, val dir1: EnumFacing, val dir2: EnumFacing,
|
||||||
val func: ((AoData, AoData)-> AoData)) : Shader {
|
val func: ((AoData, AoData)-> AoData)) : Shader {
|
||||||
override fun shade(context: ShadingContext, vertex: RenderVertex) {
|
override fun shade(context: ShadingContext, vertex: RenderVertex) {
|
||||||
var acc = accumulate(
|
var acc = accumulate(
|
||||||
@@ -69,17 +72,18 @@ class CornerTri(val face: ForgeDirection, val dir1: ForgeDirection, val dir2: Fo
|
|||||||
override fun rotate(rot: Rotation) = CornerTri(face.rotate(rot), dir1.rotate(rot), dir2.rotate(rot), func)
|
override fun rotate(rot: Rotation) = CornerTri(face.rotate(rot), dir1.rotate(rot), dir2.rotate(rot), func)
|
||||||
}
|
}
|
||||||
|
|
||||||
class EdgeInterpolateFallback(val face: ForgeDirection, val edgeDir: ForgeDirection, val pos: Double, val fallbackDimming: Float = defaultEdgeDimming): Shader {
|
class EdgeInterpolateFallback(val face: EnumFacing, val edgeDir: EnumFacing, val pos: Double, val fallbackDimming: Float = defaultEdgeDimming): Shader {
|
||||||
val offset = Int3(edgeDir)
|
val offset = Int3(edgeDir)
|
||||||
val edgeAxis = axes.find { it != face.axis && it != edgeDir.axis }!!
|
val edgeAxis = axes.find { it != face.axis && it != edgeDir.axis }!!
|
||||||
val weightN = (0.5 - pos).toFloat()
|
val weightN = (0.5 - pos).toFloat()
|
||||||
val weightP = (0.5 + pos).toFloat()
|
val weightP = (0.5 + pos).toFloat()
|
||||||
|
|
||||||
override fun shade(context: ShadingContext, vertex: RenderVertex) {
|
override fun shade(context: ShadingContext, vertex: RenderVertex) {
|
||||||
val shadingP = context.aoShading(face, edgeDir, (edgeAxis to Dir.P).face)
|
val shadingP = context.aoShading(face, edgeDir, (edgeAxis to EnumFacing.AxisDirection.POSITIVE).face)
|
||||||
val shadingN = context.aoShading(face, edgeDir, (edgeAxis to Dir.N).face)
|
val shadingN = context.aoShading(face, edgeDir, (edgeAxis to EnumFacing.AxisDirection.NEGATIVE).face)
|
||||||
if (!shadingP.valid && !shadingN.valid)
|
if (!shadingP.valid && !shadingN.valid) context.blockData(offset).let {
|
||||||
return vertex.shade(context.blockBrightness(offset) brMul fallbackDimming, context.blockColor(offset) colorMul fallbackDimming)
|
return vertex.shade(it.brightness brMul fallbackDimming, it.color colorMul fallbackDimming)
|
||||||
|
}
|
||||||
if (!shadingP.valid) return vertex.shade(shadingN)
|
if (!shadingP.valid) return vertex.shade(shadingN)
|
||||||
if (!shadingN.valid) return vertex.shade(shadingP)
|
if (!shadingN.valid) return vertex.shade(shadingP)
|
||||||
vertex.shade(shadingP, shadingN, weightP, weightN)
|
vertex.shade(shadingP, shadingN, weightP, weightN)
|
||||||
@@ -87,7 +91,7 @@ class EdgeInterpolateFallback(val face: ForgeDirection, val edgeDir: ForgeDirect
|
|||||||
override fun rotate(rot: Rotation) = EdgeInterpolateFallback(face.rotate(rot), edgeDir.rotate(rot), pos)
|
override fun rotate(rot: Rotation) = EdgeInterpolateFallback(face.rotate(rot), edgeDir.rotate(rot), pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
class CornerInterpolateDimming(val face1: ForgeDirection, val face2: ForgeDirection, val edgeDir: ForgeDirection,
|
class CornerInterpolateDimming(val face1: EnumFacing, val face2: EnumFacing, val edgeDir: EnumFacing,
|
||||||
val weight: Float, val dimming: Float, val fallbackDimming: Float = defaultCornerDimming) : Shader {
|
val weight: Float, val dimming: Float, val fallbackDimming: Float = defaultCornerDimming) : Shader {
|
||||||
val offset = Int3(edgeDir)
|
val offset = Int3(edgeDir)
|
||||||
override fun shade(context: ShadingContext, vertex: RenderVertex) {
|
override fun shade(context: ShadingContext, vertex: RenderVertex) {
|
||||||
@@ -95,8 +99,9 @@ class CornerInterpolateDimming(val face1: ForgeDirection, val face2: ForgeDirect
|
|||||||
var shading2 = context.aoShading(face2, edgeDir, face1)
|
var shading2 = context.aoShading(face2, edgeDir, face1)
|
||||||
var weight1 = weight
|
var weight1 = weight
|
||||||
var weight2 = 1.0f - weight
|
var weight2 = 1.0f - weight
|
||||||
if (!shading1.valid && !shading2.valid)
|
if (!shading1.valid && !shading2.valid) context.blockData(offset).let {
|
||||||
return vertex.shade(context.blockBrightness(offset) brMul fallbackDimming, context.blockColor(offset) colorMul fallbackDimming)
|
return vertex.shade(it.brightness brMul fallbackDimming, it.color colorMul fallbackDimming)
|
||||||
|
}
|
||||||
if (!shading1.valid) { shading1 = shading2; weight1 *= dimming }
|
if (!shading1.valid) { shading1 = shading2; weight1 *= dimming }
|
||||||
if (!shading2.valid) { shading2 = shading1; weight2 *= dimming }
|
if (!shading2.valid) { shading2 = shading1; weight2 *= dimming }
|
||||||
vertex.shade(shading1, shading2, weight1, weight2)
|
vertex.shade(shading1, shading2, weight1, weight2)
|
||||||
@@ -106,7 +111,7 @@ class CornerInterpolateDimming(val face1: ForgeDirection, val face2: ForgeDirect
|
|||||||
CornerInterpolateDimming(face1.rotate(rot), face2.rotate(rot), edgeDir.rotate(rot), weight, dimming, fallbackDimming)
|
CornerInterpolateDimming(face1.rotate(rot), face2.rotate(rot), edgeDir.rotate(rot), weight, dimming, fallbackDimming)
|
||||||
}
|
}
|
||||||
|
|
||||||
class FaceCenter(val face: ForgeDirection): Shader {
|
class FaceCenter(val face: EnumFacing): Shader {
|
||||||
override fun shade(context: ShadingContext, vertex: RenderVertex) {
|
override fun shade(context: ShadingContext, vertex: RenderVertex) {
|
||||||
vertex.red = 0.0f; vertex.green = 0.0f; vertex.blue = 0.0f;
|
vertex.red = 0.0f; vertex.green = 0.0f; vertex.blue = 0.0f;
|
||||||
val b = IntArray(4)
|
val b = IntArray(4)
|
||||||
@@ -123,25 +128,27 @@ class FaceCenter(val face: ForgeDirection): Shader {
|
|||||||
override fun rotate(rot: Rotation) = FaceCenter(face.rotate(rot))
|
override fun rotate(rot: Rotation) = FaceCenter(face.rotate(rot))
|
||||||
}
|
}
|
||||||
|
|
||||||
class FaceFlat(val face: ForgeDirection): Shader {
|
class FaceFlat(val face: EnumFacing): Shader {
|
||||||
override fun shade(context: ShadingContext, vertex: RenderVertex) {
|
override fun shade(context: ShadingContext, vertex: RenderVertex) {
|
||||||
val color = context.blockColor(Int3.zero)
|
val color = context.blockData(Int3.zero).color
|
||||||
vertex.shade(context.blockBrightness(face.offset), color)
|
vertex.shade(context.blockData(face.offset).brightness, color)
|
||||||
}
|
}
|
||||||
override fun rotate(rot: Rotation): Shader = FaceFlat(face.rotate(rot))
|
override fun rotate(rot: Rotation): Shader = FaceFlat(face.rotate(rot))
|
||||||
}
|
}
|
||||||
|
|
||||||
class FlatOffset(val offset: Int3): Shader {
|
class FlatOffset(val offset: Int3): Shader {
|
||||||
override fun shade(context: ShadingContext, vertex: RenderVertex) {
|
override fun shade(context: ShadingContext, vertex: RenderVertex) {
|
||||||
vertex.brightness = context.blockBrightness(offset)
|
context.blockData(offset).let {
|
||||||
vertex.setColor(context.blockColor(offset))
|
vertex.brightness = it.brightness
|
||||||
|
vertex.setColor(it.color)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
override fun rotate(rot: Rotation): Shader = this
|
override fun rotate(rot: Rotation): Shader = this
|
||||||
}
|
}
|
||||||
|
|
||||||
class FlatOffsetNoColor(val offset: Int3): Shader {
|
class FlatOffsetNoColor(val offset: Int3): Shader {
|
||||||
override fun shade(context: ShadingContext, vertex: RenderVertex) {
|
override fun shade(context: ShadingContext, vertex: RenderVertex) {
|
||||||
vertex.brightness = context.blockBrightness(offset)
|
vertex.brightness = context.blockData(offset).brightness
|
||||||
vertex.red = 1.0f; vertex.green = 1.0f; vertex.blue = 1.0f
|
vertex.red = 1.0f; vertex.green = 1.0f; vertex.blue = 1.0f
|
||||||
}
|
}
|
||||||
override fun rotate(rot: Rotation): Shader = this
|
override fun rotate(rot: Rotation): Shader = this
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
package mods.octarinecore.client.render
|
package mods.octarinecore.client.render
|
||||||
|
|
||||||
import net.minecraftforge.common.util.ForgeDirection
|
import mods.octarinecore.common.*
|
||||||
import java.lang.Math.*
|
import net.minecraft.client.BFBlockModelRenderer
|
||||||
|
import net.minecraft.util.EnumFacing
|
||||||
|
import net.minecraft.util.EnumFacing.*
|
||||||
|
import java.lang.Math.min
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
/** Holds shading values for block corners as calculated by vanilla Minecraft rendering. */
|
/** Holds shading values for block corners as calculated by vanilla Minecraft rendering. */
|
||||||
class AoData() {
|
class AoData() {
|
||||||
@@ -22,11 +26,58 @@ class AoData() {
|
|||||||
this.blue = blue
|
this.blue = blue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun set(brightness: Int, colorMultiplier: Float) {
|
||||||
|
this.valid = true
|
||||||
|
this.brightness = brightness
|
||||||
|
this.red = colorMultiplier
|
||||||
|
this.green = colorMultiplier
|
||||||
|
this.blue = colorMultiplier
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val black = AoData();
|
val black = AoData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AoFaceData(val face: EnumFacing) {
|
||||||
|
val ao = BFBlockModelRenderer.getVanillaAoObject()
|
||||||
|
val top = faceCorners[face.ordinal].topLeft.first
|
||||||
|
val left = faceCorners[face.ordinal].topLeft.second
|
||||||
|
|
||||||
|
val topLeft = AoData()
|
||||||
|
val topRight = AoData()
|
||||||
|
val bottomLeft = AoData()
|
||||||
|
val bottomRight = AoData()
|
||||||
|
val ordered = when(face) {
|
||||||
|
DOWN -> listOf(topLeft, bottomLeft, bottomRight, topRight)
|
||||||
|
UP -> listOf(bottomRight, topRight, topLeft, bottomLeft)
|
||||||
|
NORTH -> listOf(bottomLeft, bottomRight, topRight, topLeft)
|
||||||
|
SOUTH -> listOf(topLeft, bottomLeft, bottomRight, topRight)
|
||||||
|
WEST -> listOf(bottomLeft, bottomRight, topRight, topLeft)
|
||||||
|
EAST -> listOf(topRight, topLeft, bottomLeft, bottomRight)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun update(offset: Int3, useBounds: Boolean = false) {
|
||||||
|
val ctx = blockContext
|
||||||
|
val blockState = ctx.blockState(offset)
|
||||||
|
val quadBounds: FloatArray = FloatArray(12)
|
||||||
|
val flags = BitSet(3).apply { set(0) }
|
||||||
|
|
||||||
|
ao.updateVertexBrightness(ctx.world, blockState.block, ctx.pos + offset, face, quadBounds, flags)
|
||||||
|
ordered.forEachIndexed { idx, aoData -> aoData.set(ao.vertexBrightness[idx], ao.vertexColorMultiplier[idx]) }
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun get(dir1: EnumFacing, dir2: EnumFacing): AoData {
|
||||||
|
val isTop = top == dir1 || top == dir2
|
||||||
|
val isLeft = left == dir1 || left == dir2
|
||||||
|
return if (isTop) {
|
||||||
|
if (isLeft) topLeft else topRight
|
||||||
|
} else {
|
||||||
|
if (isLeft) bottomLeft else bottomRight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instances of this interface are associated with [Model] vertices, and used to apply brightness and color
|
* Instances of this interface are associated with [Model] vertices, and used to apply brightness and color
|
||||||
* values to a [RenderVertex].
|
* values to a [RenderVertex].
|
||||||
@@ -81,9 +132,9 @@ interface Shader {
|
|||||||
* @param[corner] shader instantiation lambda for corner vertices
|
* @param[corner] shader instantiation lambda for corner vertices
|
||||||
* @param[edge] shader instantiation lambda for edge midpoint vertices
|
* @param[edge] shader instantiation lambda for edge midpoint vertices
|
||||||
*/
|
*/
|
||||||
fun faceOrientedAuto(overrideFace: ForgeDirection? = null,
|
fun faceOrientedAuto(overrideFace: EnumFacing? = null,
|
||||||
corner: ((ForgeDirection, ForgeDirection, ForgeDirection)->Shader)? = null,
|
corner: ((EnumFacing, EnumFacing, EnumFacing)->Shader)? = null,
|
||||||
edge: ((ForgeDirection, ForgeDirection)->Shader)? = null) =
|
edge: ((EnumFacing, EnumFacing)->Shader)? = null) =
|
||||||
fun(quad: Quad, vertex: Vertex): Shader {
|
fun(quad: Quad, vertex: Vertex): Shader {
|
||||||
val quadFace = overrideFace ?: quad.normal.nearestCardinal
|
val quadFace = overrideFace ?: quad.normal.nearestCardinal
|
||||||
val nearestCorner = nearestPosition(vertex.xyz, faceCorners[quadFace.ordinal].asList) {
|
val nearestCorner = nearestPosition(vertex.xyz, faceCorners[quadFace.ordinal].asList) {
|
||||||
@@ -108,8 +159,8 @@ fun faceOrientedAuto(overrideFace: ForgeDirection? = null,
|
|||||||
* @param[overrideEdge] assume the given edge instead of going by the _quad_ normal
|
* @param[overrideEdge] assume the given edge instead of going by the _quad_ normal
|
||||||
* @param[corner] shader instantiation lambda
|
* @param[corner] shader instantiation lambda
|
||||||
*/
|
*/
|
||||||
fun edgeOrientedAuto(overrideEdge: Pair<ForgeDirection, ForgeDirection>? = null,
|
fun edgeOrientedAuto(overrideEdge: Pair<EnumFacing, EnumFacing>? = null,
|
||||||
corner: (ForgeDirection, ForgeDirection, ForgeDirection)->Shader) =
|
corner: (EnumFacing, EnumFacing, EnumFacing)->Shader) =
|
||||||
fun(quad: Quad, vertex: Vertex): Shader {
|
fun(quad: Quad, vertex: Vertex): Shader {
|
||||||
val edgeDir = overrideEdge ?: nearestAngle(quad.normal, boxEdges) { it.first.vec + it.second.vec }.first
|
val edgeDir = overrideEdge ?: nearestAngle(quad.normal, boxEdges) { it.first.vec + it.second.vec }.first
|
||||||
val nearestFace = nearestPosition(vertex.xyz, edgeDir.toList()) { it.vec }.first
|
val nearestFace = nearestPosition(vertex.xyz, edgeDir.toList()) { it.vec }.first
|
||||||
@@ -119,11 +170,11 @@ fun edgeOrientedAuto(overrideEdge: Pair<ForgeDirection, ForgeDirection>? = null,
|
|||||||
return corner(nearestFace, nearestCorner.first, nearestCorner.second)
|
return corner(nearestFace, nearestCorner.first, nearestCorner.second)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun faceOrientedInterpolate(overrideFace: ForgeDirection? = null) =
|
fun faceOrientedInterpolate(overrideFace: EnumFacing? = null) =
|
||||||
fun(quad: Quad, vertex: Vertex): Shader {
|
fun(quad: Quad, vertex: Vertex): Shader {
|
||||||
val resolver = faceOrientedAuto(overrideFace, edge = { face, edgeDir ->
|
val resolver = faceOrientedAuto(overrideFace, edge = { face, edgeDir ->
|
||||||
val axis = axes.find { it != face.axis && it != edgeDir.axis }!!
|
val axis = axes.find { it != face.axis && it != edgeDir.axis }!!
|
||||||
val vec = Double3((axis to Dir.P).face)
|
val vec = Double3((axis to EnumFacing.AxisDirection.POSITIVE).face)
|
||||||
val pos = vertex.xyz.dot(vec)
|
val pos = vertex.xyz.dot(vec)
|
||||||
EdgeInterpolateFallback(face, edgeDir, pos)
|
EdgeInterpolateFallback(face, edgeDir, pos)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,124 @@
|
|||||||
|
package mods.octarinecore.client.resource
|
||||||
|
|
||||||
|
import mods.betterfoliage.client.config.BlockMatcher
|
||||||
|
import mods.betterfoliage.loader.Refs
|
||||||
|
import mods.octarinecore.stripStart
|
||||||
|
import net.minecraft.block.Block
|
||||||
|
import net.minecraft.block.state.IBlockState
|
||||||
|
import net.minecraft.client.renderer.block.model.ModelBlock
|
||||||
|
import net.minecraft.client.renderer.block.statemap.DefaultStateMapper
|
||||||
|
import net.minecraft.client.renderer.block.statemap.IStateMapper
|
||||||
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite
|
||||||
|
import net.minecraft.client.renderer.texture.TextureMap
|
||||||
|
import net.minecraft.client.resources.model.ModelResourceLocation
|
||||||
|
import net.minecraft.util.ResourceLocation
|
||||||
|
import net.minecraftforge.client.event.TextureStitchEvent
|
||||||
|
import net.minecraftforge.client.model.IModel
|
||||||
|
import net.minecraftforge.client.model.ModelLoader
|
||||||
|
import net.minecraftforge.common.MinecraftForge
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.Event
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
|
||||||
|
|
||||||
|
class LoadModelDataEvent(val loader: ModelLoader) : Event()
|
||||||
|
|
||||||
|
abstract class ModelDataInspector {
|
||||||
|
|
||||||
|
abstract fun onAfterModelLoad()
|
||||||
|
abstract fun processModelDefinition(state: IBlockState, location: ModelResourceLocation, model: IModel)
|
||||||
|
abstract fun onStitch(atlas: TextureMap)
|
||||||
|
|
||||||
|
init { MinecraftForge.EVENT_BUS.register(this) }
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
@SubscribeEvent
|
||||||
|
fun handleLoadModelData(event: LoadModelDataEvent) {
|
||||||
|
val stateMappings = Block.blockRegistry.flatMap { block ->
|
||||||
|
((event.loader.blockModelShapes.blockStateMapper.blockStateMap[block]as? IStateMapper ?: DefaultStateMapper())
|
||||||
|
.putStateModelLocations(block as Block) as Map<IBlockState, ModelResourceLocation>).entries
|
||||||
|
}
|
||||||
|
val stateModels = Refs.stateModels.get(event.loader) as Map<ModelResourceLocation, IModel>
|
||||||
|
|
||||||
|
onAfterModelLoad()
|
||||||
|
|
||||||
|
stateMappings.forEach { mapping ->
|
||||||
|
val model = stateModels[mapping.value]
|
||||||
|
if (model != null) {
|
||||||
|
val result = processModelDefinition(mapping.key, mapping.value, model)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
fun handleTextureReload(event: TextureStitchEvent.Pre) { onStitch(event.map) }
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class BlockTextureInspector<T> : ModelDataInspector() {
|
||||||
|
|
||||||
|
val state2Names = hashMapOf<IBlockState, Iterable<String>>()
|
||||||
|
val modelMappings = linkedListOf<Pair<(IBlockState, IModel)->Boolean, Iterable<String>>>()
|
||||||
|
val infoMap = hashMapOf<IBlockState, T>()
|
||||||
|
|
||||||
|
fun match(textureNames: Iterable<String>, predicate: (IBlockState, IModel)->Boolean) =
|
||||||
|
modelMappings.add(predicate to textureNames)
|
||||||
|
fun matchClassAndModel(blockClass: BlockMatcher, modelLocation: String, textureNames: Iterable<String>) =
|
||||||
|
match(textureNames) { state, model -> blockClass.matchesClass(state.block) && model.derivesFromModel(modelLocation) }
|
||||||
|
|
||||||
|
operator fun get(state: IBlockState) = infoMap[state]
|
||||||
|
|
||||||
|
override fun onAfterModelLoad() {
|
||||||
|
infoMap.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun processModelDefinition(state: IBlockState, modelDefLoc: ModelResourceLocation, model: IModel) {
|
||||||
|
modelMappings.forEach { mapping ->
|
||||||
|
if (mapping.first(state, model)) {
|
||||||
|
model.modelBlockAndLoc?.first?.let { modelBlock ->
|
||||||
|
val textures = mapping.second.map { modelBlock.resolveTextureName(it) }
|
||||||
|
if (textures.all { it != null && it != "missingno" }) {
|
||||||
|
state2Names.put(state, textures)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStitch(atlas: TextureMap) {
|
||||||
|
val state2Texture = hashMapOf<IBlockState, List<TextureAtlasSprite>>()
|
||||||
|
val texture2Info = hashMapOf<List<TextureAtlasSprite>, T>()
|
||||||
|
state2Names.forEach { state, textureNames ->
|
||||||
|
val textures = textureNames.map { atlas.getTextureExtry(ResourceLocation(it).toString()) }
|
||||||
|
if (textures.all { it != null }) {
|
||||||
|
state2Texture.put(state, textures)
|
||||||
|
if (textures !in texture2Info) texture2Info.put(textures, processTextures(textures, atlas))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state2Texture.forEach { state, texture -> infoMap.put(state, texture2Info[texture]!!) }
|
||||||
|
state2Names.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun processTextures(textures: List<TextureAtlasSprite>, atlas: TextureMap): T
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
val IModel.modelBlockAndLoc: Pair<ModelBlock, ResourceLocation>? get() {
|
||||||
|
if (Refs.VanillaModelWrapper.isInstance(this))
|
||||||
|
return Pair(Refs.model_VMW.get(this) as ModelBlock, Refs.location_VMW.get(this) as ResourceLocation)
|
||||||
|
else if (Refs.WeightedPartWrapper.isInstance(this)) Refs.model_WPW.get(this)?.let {
|
||||||
|
return (it as IModel).modelBlockAndLoc
|
||||||
|
}
|
||||||
|
else if (Refs.WeightedRandomModel.isInstance(this)) Refs.models_WRM.get(this)?.let {
|
||||||
|
(it as List<IModel>).forEach {
|
||||||
|
it.modelBlockAndLoc.let { if (it != null) return it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Pair<ModelBlock, ResourceLocation>.derivesFrom(targetLocation: String): Boolean {
|
||||||
|
if (second.stripStart("models/") == ResourceLocation(targetLocation)) return true
|
||||||
|
if (first.parent != null && first.parentLocation != null)
|
||||||
|
return Pair(first.parent, first.parentLocation).derivesFrom(targetLocation)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IModel.derivesFromModel(modelLocation: String) = modelBlockAndLoc?.derivesFrom(modelLocation) ?: false
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
package mods.octarinecore.client.resource
|
package mods.octarinecore.client.resource
|
||||||
|
|
||||||
import cpw.mods.fml.client.FMLClientHandler
|
|
||||||
import mods.betterfoliage.loader.Refs
|
|
||||||
import mods.octarinecore.metaprog.reflectField
|
import mods.octarinecore.metaprog.reflectField
|
||||||
import net.minecraft.client.resources.IResourcePack
|
import net.minecraft.client.resources.IResourcePack
|
||||||
import net.minecraft.client.resources.data.IMetadataSerializer
|
import net.minecraft.client.resources.data.IMetadataSerializer
|
||||||
import net.minecraft.client.resources.data.PackMetadataSection
|
import net.minecraft.client.resources.data.PackMetadataSection
|
||||||
import net.minecraft.util.ChatComponentText
|
import net.minecraft.util.ChatComponentText
|
||||||
import net.minecraft.util.ResourceLocation
|
import net.minecraft.util.ResourceLocation
|
||||||
|
import net.minecraftforge.fml.client.FMLClientHandler
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@@ -21,7 +20,6 @@ import java.util.*
|
|||||||
class GeneratorPack(val name: String, vararg val generators: GeneratorBase) : IResourcePack {
|
class GeneratorPack(val name: String, vararg val generators: GeneratorBase) : IResourcePack {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// add to the default resource packs
|
|
||||||
FMLClientHandler.instance().reflectField<MutableList<IResourcePack>>("resourcePackList")!!.add(this)
|
FMLClientHandler.instance().reflectField<MutableList<IResourcePack>>("resourcePackList")!!.add(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,16 +105,8 @@ class ParameterList(val params: Map<String, String>, val value: String?) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* [GeneratorBase] returning parametrized generated resources.
|
|
||||||
*
|
|
||||||
* @param[domain] Resource domain of generator.
|
|
||||||
*/
|
|
||||||
abstract class ParameterBasedGenerator(domain: String) : GeneratorBase(domain) {
|
abstract class ParameterBasedGenerator(domain: String) : GeneratorBase(domain) {
|
||||||
/** @see [IResourcePack.resourceExists] */
|
|
||||||
abstract fun resourceExists(params: ParameterList): Boolean
|
abstract fun resourceExists(params: ParameterList): Boolean
|
||||||
|
|
||||||
/** @see [IResourcePack.getInputStream] */
|
|
||||||
abstract fun getInputStream(params: ParameterList): InputStream?
|
abstract fun getInputStream(params: ParameterList): InputStream?
|
||||||
|
|
||||||
override fun resourceExists(location: ResourceLocation?) =
|
override fun resourceExists(location: ResourceLocation?) =
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
package mods.octarinecore.client.resource
|
package mods.octarinecore.client.resource
|
||||||
|
|
||||||
import cpw.mods.fml.client.event.ConfigChangedEvent
|
|
||||||
import cpw.mods.fml.common.FMLCommonHandler
|
|
||||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent
|
|
||||||
import mods.octarinecore.client.render.Double3
|
|
||||||
import mods.octarinecore.client.render.Int3
|
|
||||||
import mods.octarinecore.client.render.Model
|
import mods.octarinecore.client.render.Model
|
||||||
import net.minecraft.client.renderer.texture.IIconRegister
|
import mods.octarinecore.common.Double3
|
||||||
import net.minecraft.util.IIcon
|
import mods.octarinecore.common.Int3
|
||||||
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite
|
||||||
|
import net.minecraft.client.renderer.texture.TextureMap
|
||||||
|
import net.minecraft.util.BlockPos
|
||||||
import net.minecraft.util.MathHelper
|
import net.minecraft.util.MathHelper
|
||||||
import net.minecraft.util.ResourceLocation
|
import net.minecraft.util.ResourceLocation
|
||||||
import net.minecraft.world.World
|
import net.minecraft.world.World
|
||||||
@@ -15,12 +13,15 @@ import net.minecraft.world.gen.NoiseGeneratorSimplex
|
|||||||
import net.minecraftforge.client.event.TextureStitchEvent
|
import net.minecraftforge.client.event.TextureStitchEvent
|
||||||
import net.minecraftforge.common.MinecraftForge
|
import net.minecraftforge.common.MinecraftForge
|
||||||
import net.minecraftforge.event.world.WorldEvent
|
import net.minecraftforge.event.world.WorldEvent
|
||||||
|
import net.minecraftforge.fml.client.event.ConfigChangedEvent
|
||||||
|
import net.minecraftforge.fml.common.FMLCommonHandler
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
// ============================
|
// ============================
|
||||||
// Resource types
|
// Resource types
|
||||||
// ============================
|
// ============================
|
||||||
interface IStitchListener { fun onStitch(atlas: IIconRegister) }
|
interface IStitchListener { fun onStitch(atlas: TextureMap) }
|
||||||
interface IConfigChangeListener { fun onConfigChange() }
|
interface IConfigChangeListener { fun onConfigChange() }
|
||||||
interface IWorldLoadListener { fun onWorldLoad(world: World) }
|
interface IWorldLoadListener { fun onWorldLoad(world: World) }
|
||||||
|
|
||||||
@@ -61,10 +62,8 @@ open class ResourceHandler(val modId: String) {
|
|||||||
// ============================
|
// ============================
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
fun onStitch(event: TextureStitchEvent.Pre) {
|
fun onStitch(event: TextureStitchEvent.Pre) {
|
||||||
if (event.map.textureType == 0) {
|
resources.forEach { (it as? IStitchListener)?.onStitch(event.map) }
|
||||||
resources.forEach { (it as? IStitchListener)?.onStitch(event.map) }
|
afterStitch()
|
||||||
afterStitch()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
@@ -81,8 +80,8 @@ open class ResourceHandler(val modId: String) {
|
|||||||
// Resource container classes
|
// Resource container classes
|
||||||
// ============================
|
// ============================
|
||||||
class IconHolder(val domain: String, val name: String) : IStitchListener {
|
class IconHolder(val domain: String, val name: String) : IStitchListener {
|
||||||
var icon: IIcon? = null
|
var icon: TextureAtlasSprite? = null
|
||||||
override fun onStitch(atlas: IIconRegister) { icon = atlas.registerIcon("$domain:$name") }
|
override fun onStitch(atlas: TextureMap) { icon = atlas.registerSprite(ResourceLocation(domain, name)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
class ModelHolder(val init: Model.()->Unit): IConfigChangeListener {
|
class ModelHolder(val init: Model.()->Unit): IConfigChangeListener {
|
||||||
@@ -91,14 +90,14 @@ class ModelHolder(val init: Model.()->Unit): IConfigChangeListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class IconSet(val domain: String, val namePattern: String) : IStitchListener {
|
class IconSet(val domain: String, val namePattern: String) : IStitchListener {
|
||||||
val icons = arrayOfNulls<IIcon>(16)
|
val icons = arrayOfNulls<TextureAtlasSprite>(16)
|
||||||
var num = 0
|
var num = 0
|
||||||
|
|
||||||
override fun onStitch(atlas: IIconRegister) {
|
override fun onStitch(atlas: TextureMap) {
|
||||||
num = 0;
|
num = 0;
|
||||||
(0..15).forEach { idx ->
|
(0..15).forEach { idx ->
|
||||||
val locReal = ResourceLocation(domain, "textures/blocks/${namePattern.format(idx)}.png")
|
val locReal = ResourceLocation(domain, "textures/${namePattern.format(idx)}.png")
|
||||||
if (resourceManager[locReal] != null) icons[num++] = atlas.registerIcon("$domain:${namePattern.format(idx)}")
|
if (resourceManager[locReal] != null) icons[num++] = atlas.registerSprite(ResourceLocation(domain, namePattern.format(idx)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,4 +122,5 @@ class SimplexNoise() : IWorldLoadListener {
|
|||||||
}
|
}
|
||||||
operator fun get(x: Int, z: Int) = MathHelper.floor_double((noise.func_151605_a(x.toDouble(), z.toDouble()) + 1.0) * 32.0)
|
operator fun get(x: Int, z: Int) = MathHelper.floor_double((noise.func_151605_a(x.toDouble(), z.toDouble()) + 1.0) * 32.0)
|
||||||
operator fun get(pos: Int3) = get(pos.x, pos.z)
|
operator fun get(pos: Int3) = get(pos.x, pos.z)
|
||||||
|
operator fun get(pos: BlockPos) = get(pos.x, pos.z)
|
||||||
}
|
}
|
||||||
@@ -39,9 +39,7 @@ abstract class TextureGenerator(domain: String) : ParameterBasedGenerator(domain
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/** Get the type and location of the texture resource encoded by the given [ParameterList]. */
|
||||||
* Get the type and location of the texture resource encoded by the given [ParameterList].
|
|
||||||
*/
|
|
||||||
fun targetResource(params: ParameterList): Pair<ResourceType, ResourceLocation>? {
|
fun targetResource(params: ParameterList): Pair<ResourceType, ResourceLocation>? {
|
||||||
val baseTexture =
|
val baseTexture =
|
||||||
if (listOf("dom", "path").all { it in params }) ResourceLocation(params["dom"]!!, params["path"]!!)
|
if (listOf("dom", "path").all { it in params }) ResourceLocation(params["dom"]!!, params["path"]!!)
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ import java.lang.Math.*
|
|||||||
import javax.imageio.ImageIO
|
import javax.imageio.ImageIO
|
||||||
|
|
||||||
/** Concise getter for the Minecraft resource manager. */
|
/** Concise getter for the Minecraft resource manager. */
|
||||||
val resourceManager: SimpleReloadableResourceManager get() = Minecraft.getMinecraft().resourceManager as SimpleReloadableResourceManager
|
val resourceManager: SimpleReloadableResourceManager get() =
|
||||||
|
Minecraft.getMinecraft().resourceManager as SimpleReloadableResourceManager
|
||||||
|
|
||||||
/** Append a string to the [ResourceLocation]'s path. */
|
/** Append a string to the [ResourceLocation]'s path. */
|
||||||
operator fun ResourceLocation.plus(str: String) = ResourceLocation(resourceDomain, resourcePath + str)
|
operator fun ResourceLocation.plus(str: String) = ResourceLocation(resourceDomain, resourcePath + str)
|
||||||
@@ -86,5 +87,5 @@ val TextureAtlasSprite.averageColor: Int? get() {
|
|||||||
* Get the actual location of a texture from the name of its [TextureAtlasSprite].
|
* Get the actual location of a texture from the name of its [TextureAtlasSprite].
|
||||||
*/
|
*/
|
||||||
fun textureLocation(iconName: String) = ResourceLocation(iconName).let {
|
fun textureLocation(iconName: String) = ResourceLocation(iconName).let {
|
||||||
ResourceLocation(it.resourceDomain, "textures/blocks/${it.resourcePath}")
|
ResourceLocation(it.resourceDomain, "textures/${it.resourcePath}")
|
||||||
}
|
}
|
||||||
@@ -1,41 +1,52 @@
|
|||||||
package mods.octarinecore.client.render
|
package mods.octarinecore.common
|
||||||
|
|
||||||
import mods.octarinecore.client.render.Axis.*
|
|
||||||
import mods.octarinecore.client.render.Dir.N
|
|
||||||
import mods.octarinecore.client.render.Dir.P
|
|
||||||
import mods.octarinecore.cross
|
import mods.octarinecore.cross
|
||||||
import net.minecraftforge.common.util.ForgeDirection
|
import net.minecraft.util.BlockPos
|
||||||
import net.minecraftforge.common.util.ForgeDirection.*
|
import net.minecraft.util.EnumFacing
|
||||||
|
import net.minecraft.util.EnumFacing.*
|
||||||
|
import net.minecraft.util.EnumFacing.Axis.*
|
||||||
|
import net.minecraft.util.EnumFacing.AxisDirection.*
|
||||||
|
|
||||||
// ================================
|
// ================================
|
||||||
// Axes and directions
|
// Axes and directions
|
||||||
// ================================
|
// ================================
|
||||||
enum class Axis { X, Y, Z }
|
|
||||||
enum class Dir { P, N }
|
|
||||||
val axes = listOf(X, Y, Z)
|
val axes = listOf(X, Y, Z)
|
||||||
val axisDirs = listOf(P, N)
|
val axisDirs = listOf(POSITIVE, NEGATIVE)
|
||||||
val forgeDirs = ForgeDirection.VALID_DIRECTIONS
|
val EnumFacing.dir: AxisDirection get() = axisDirection
|
||||||
|
val AxisDirection.sign: String get() = when(this) { POSITIVE -> "+"; NEGATIVE -> "-" }
|
||||||
|
val forgeDirs = EnumFacing.values()
|
||||||
val forgeDirOffsets = forgeDirs.map { Int3(it) }
|
val forgeDirOffsets = forgeDirs.map { Int3(it) }
|
||||||
val ForgeDirection.axis: Axis get() = when(this) {EAST, WEST -> X; UP, DOWN -> Y; else -> Z }
|
val Pair<Axis, AxisDirection>.face: EnumFacing get() = when(this) {
|
||||||
val ForgeDirection.dir: Dir get() = when(this) {UP, SOUTH, EAST -> P; else -> N }
|
X to POSITIVE -> EAST; X to NEGATIVE -> WEST;
|
||||||
val Pair<Axis, Dir>.face: ForgeDirection get() = when(this) {
|
Y to POSITIVE -> UP; Y to NEGATIVE -> DOWN;
|
||||||
X to P -> EAST; X to N -> WEST; Y to P -> UP; Y to N -> DOWN; Z to P -> SOUTH; Z to N -> NORTH; else -> UNKNOWN
|
Z to POSITIVE -> SOUTH; else -> NORTH;
|
||||||
}
|
}
|
||||||
val ForgeDirection.perpendiculars: List<ForgeDirection> get() =
|
val EnumFacing.perpendiculars: List<EnumFacing> get() =
|
||||||
axes.filter { it != this.axis }.cross(axisDirs).map { it.face }
|
axes.filter { it != this.axis }.cross(axisDirs).map { it.face }
|
||||||
val ForgeDirection.offset: Int3 get() = forgeDirOffsets[ordinal]
|
val EnumFacing.offset: Int3 get() = forgeDirOffsets[ordinal]
|
||||||
|
|
||||||
|
/** Old ForgeDirection rotation matrix yanked from 1.7.10 */
|
||||||
|
val ROTATION_MATRIX: Array<IntArray> get() = arrayOf(
|
||||||
|
intArrayOf(0, 1, 4, 5, 3, 2, 6),
|
||||||
|
intArrayOf(0, 1, 5, 4, 2, 3, 6),
|
||||||
|
intArrayOf(5, 4, 2, 3, 0, 1, 6),
|
||||||
|
intArrayOf(4, 5, 2, 3, 1, 0, 6),
|
||||||
|
intArrayOf(2, 3, 1, 0, 4, 5, 6),
|
||||||
|
intArrayOf(3, 2, 0, 1, 4, 5, 6)
|
||||||
|
)
|
||||||
|
|
||||||
// ================================
|
// ================================
|
||||||
// Vectors
|
// Vectors
|
||||||
// ================================
|
// ================================
|
||||||
operator fun ForgeDirection.times(scale: Double) =
|
operator fun EnumFacing.times(scale: Double) =
|
||||||
Double3(offsetX.toDouble() * scale, offsetY.toDouble() * scale, offsetZ.toDouble() * scale)
|
Double3(directionVec.x.toDouble() * scale, directionVec.y.toDouble() * scale, directionVec.z.toDouble() * scale)
|
||||||
val ForgeDirection.vec: Double3 get() = Double3(offsetX.toDouble(), offsetY.toDouble(), offsetZ.toDouble())
|
val EnumFacing.vec: Double3 get() = Double3(directionVec.x.toDouble(), directionVec.y.toDouble(), directionVec.z.toDouble())
|
||||||
|
operator fun BlockPos.plus(other: Int3) = BlockPos(x + other.x, y + other.y, z + other.z)
|
||||||
|
|
||||||
/** 3D vector of [Double]s. Offers both mutable operations, and immutable operations in operator notation. */
|
/** 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) {
|
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(x: Float, y: Float, z: Float) : this(x.toDouble(), y.toDouble(), z.toDouble())
|
||||||
constructor(dir: ForgeDirection) : this(dir.offsetX.toDouble(), dir.offsetY.toDouble(), dir.offsetZ.toDouble())
|
constructor(dir: EnumFacing) : this(dir.directionVec.x.toDouble(), dir.directionVec.y.toDouble(), dir.directionVec.z.toDouble())
|
||||||
companion object {
|
companion object {
|
||||||
val zero: Double3 get() = Double3(0.0, 0.0, 0.0)
|
val zero: Double3 get() = Double3(0.0, 0.0, 0.0)
|
||||||
fun weight(v1: Double3, weight1: Double, v2: Double3, weight2: Double) =
|
fun weight(v1: Double3, weight1: Double, v2: Double3, weight2: Double) =
|
||||||
@@ -79,16 +90,16 @@ data class Double3(var x: Double, var y: Double, var z: Double) {
|
|||||||
infix fun cross(o: Double3) = Double3(y * o.z - z * o.y, z * o.x - x * o.z, x * o.y - y * o.x)
|
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 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 normalize: Double3 get() = (1.0 / length).let { Double3(x * it, y * it, z * it) }
|
||||||
val nearestCardinal: ForgeDirection get() = nearestAngle(this, forgeDirs.asIterable()) { it.vec }.first
|
val nearestCardinal: EnumFacing get() = nearestAngle(this, forgeDirs.asIterable()) { it.vec }.first
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 3D vector of [Int]s. Offers both mutable operations, and immutable operations in operator notation. */
|
/** 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) {
|
data class Int3(var x: Int, var y: Int, var z: Int) {
|
||||||
constructor(dir: ForgeDirection) : this(dir.offsetX, dir.offsetY, dir.offsetZ)
|
constructor(dir: EnumFacing) : this(dir.directionVec.x, dir.directionVec.y, dir.directionVec.z)
|
||||||
constructor(offset: Pair<Int, ForgeDirection>) : this(
|
constructor(offset: Pair<Int, EnumFacing>) : this(
|
||||||
offset.first * offset.second.offsetX,
|
offset.first * offset.second.directionVec.x,
|
||||||
offset.first * offset.second.offsetY,
|
offset.first * offset.second.directionVec.y,
|
||||||
offset.first * offset.second.offsetZ
|
offset.first * offset.second.directionVec.z
|
||||||
)
|
)
|
||||||
companion object {
|
companion object {
|
||||||
val zero = Int3(0, 0, 0)
|
val zero = Int3(0, 0, 0)
|
||||||
@@ -96,10 +107,10 @@ data class Int3(var x: Int, var y: Int, var z: Int) {
|
|||||||
|
|
||||||
// immutable operations
|
// immutable operations
|
||||||
operator fun plus(other: Int3) = Int3(x + other.x, y + other.y, z + other.z)
|
operator fun plus(other: Int3) = Int3(x + other.x, y + other.y, z + other.z)
|
||||||
operator fun plus(other: Pair<Int, ForgeDirection>) = Int3(
|
operator fun plus(other: Pair<Int, EnumFacing>) = Int3(
|
||||||
x + other.first * other.second.offsetX,
|
x + other.first * other.second.directionVec.x,
|
||||||
y + other.first * other.second.offsetY,
|
y + other.first * other.second.directionVec.y,
|
||||||
z + other.first * other.second.offsetZ
|
z + other.first * other.second.directionVec.z
|
||||||
)
|
)
|
||||||
operator fun unaryMinus() = Int3(-x, -y, -z)
|
operator fun unaryMinus() = Int3(-x, -y, -z)
|
||||||
operator fun minus(other: Int3) = Int3(x - other.x, y - other.y, z - other.z)
|
operator fun minus(other: Int3) = Int3(x - other.x, y - other.y, z - other.z)
|
||||||
@@ -132,17 +143,17 @@ data class Int3(var x: Int, var y: Int, var z: Int) {
|
|||||||
// ================================
|
// ================================
|
||||||
// Rotation
|
// Rotation
|
||||||
// ================================
|
// ================================
|
||||||
val ForgeDirection.rotations: Array<ForgeDirection> get() =
|
val EnumFacing.rotations: Array<EnumFacing> get() =
|
||||||
Array(6) { idx -> ForgeDirection.values()[ForgeDirection.ROTATION_MATRIX[ordinal][idx]] }
|
Array(6) { idx -> EnumFacing.values()[ROTATION_MATRIX[ordinal][idx]] }
|
||||||
fun ForgeDirection.rotate(rot: Rotation) = rot.forward[ordinal]
|
fun EnumFacing.rotate(rot: Rotation) = rot.forward[ordinal]
|
||||||
fun rot(axis: ForgeDirection) = Rotation.rot90[axis.ordinal]
|
fun rot(axis: EnumFacing) = Rotation.rot90[axis.ordinal]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class representing an arbitrary rotation (or combination of rotations) around cardinal axes by 90 degrees.
|
* Class representing an arbitrary rotation (or combination of rotations) around cardinal axes by 90 degrees.
|
||||||
* In effect, a permutation of [ForgeDirection]s.
|
* In effect, a permutation of [ForgeDirection]s.
|
||||||
*/
|
*/
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
class Rotation(val forward: Array<ForgeDirection>, val reverse: Array<ForgeDirection>) {
|
class Rotation(val forward: Array<EnumFacing>, val reverse: Array<EnumFacing>) {
|
||||||
operator fun plus(other: Rotation) = Rotation(
|
operator fun plus(other: Rotation) = Rotation(
|
||||||
Array(6) { idx -> forward[other.forward[idx].ordinal] },
|
Array(6) { idx -> forward[other.forward[idx].ordinal] },
|
||||||
Array(6) { idx -> other.reverse[reverse[idx].ordinal] }
|
Array(6) { idx -> other.reverse[reverse[idx].ordinal] }
|
||||||
@@ -150,9 +161,9 @@ class Rotation(val forward: Array<ForgeDirection>, val reverse: Array<ForgeDirec
|
|||||||
operator fun unaryMinus() = Rotation(reverse, forward)
|
operator fun unaryMinus() = Rotation(reverse, forward)
|
||||||
operator fun times(num: Int) = when(num % 4) { 1 -> this; 2 -> this + this; 3 -> -this; else -> identity }
|
operator fun times(num: Int) = when(num % 4) { 1 -> this; 2 -> this + this; 3 -> -this; else -> identity }
|
||||||
|
|
||||||
inline fun rotatedComponent(dir: ForgeDirection, x: Int, y: Int, z: Int) =
|
inline fun rotatedComponent(dir: EnumFacing, x: Int, y: Int, z: Int) =
|
||||||
when(reverse[dir.ordinal]) { EAST -> x; WEST -> -x; UP -> y; DOWN -> -y; SOUTH -> z; NORTH -> -z; else -> 0 }
|
when(reverse[dir.ordinal]) { EAST -> x; WEST -> -x; UP -> y; DOWN -> -y; SOUTH -> z; NORTH -> -z; else -> 0 }
|
||||||
inline fun rotatedComponent(dir: ForgeDirection, x: Double, y: Double, z: Double) =
|
inline fun rotatedComponent(dir: EnumFacing, x: Double, y: Double, z: Double) =
|
||||||
when(reverse[dir.ordinal]) { EAST -> x; WEST -> -x; UP -> y; DOWN -> -y; SOUTH -> z; NORTH -> -z; else -> 0.0 }
|
when(reverse[dir.ordinal]) { EAST -> x; WEST -> -x; UP -> y; DOWN -> -y; SOUTH -> z; NORTH -> -z; else -> 0.0 }
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -177,7 +188,7 @@ val boxEdges = forgeDirs.flatMap { face1 -> forgeDirs.filter { it.axis > face1.a
|
|||||||
* @param[objPos] lambda to calculate the position of an object
|
* @param[objPos] lambda to calculate the position of an object
|
||||||
* @return [Pair] of (object, distance)
|
* @return [Pair] of (object, distance)
|
||||||
*/
|
*/
|
||||||
fun <T> nearestPosition(vertex: Double3, objs: Iterable<T>, objPos: (T)->Double3): Pair<T, Double> =
|
fun <T> nearestPosition(vertex: Double3, objs: Iterable<T>, objPos: (T)-> Double3): Pair<T, Double> =
|
||||||
objs.map { it to (objPos(it) - vertex).length }.minBy { it.second }!!
|
objs.map { it to (objPos(it) - vertex).length }.minBy { it.second }!!
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -188,14 +199,14 @@ fun <T> nearestPosition(vertex: Double3, objs: Iterable<T>, objPos: (T)->Double3
|
|||||||
* @param[objAngle] lambda to calculate the orientation of an object
|
* @param[objAngle] lambda to calculate the orientation of an object
|
||||||
* @return [Pair] of (object, normalized dot product)
|
* @return [Pair] of (object, normalized dot product)
|
||||||
*/
|
*/
|
||||||
fun <T> nearestAngle(vector: Double3, objs: Iterable<T>, objAngle: (T)->Double3): Pair<T, Double> =
|
fun <T> nearestAngle(vector: Double3, objs: Iterable<T>, objAngle: (T)-> Double3): Pair<T, Double> =
|
||||||
objs.map { it to objAngle(it).dot(vector) }.maxBy { it.second }!!
|
objs.map { it to objAngle(it).dot(vector) }.maxBy { it.second }!!
|
||||||
|
|
||||||
data class FaceCorners(val topLeft: Pair<ForgeDirection, ForgeDirection>,
|
data class FaceCorners(val topLeft: Pair<EnumFacing, EnumFacing>,
|
||||||
val topRight: Pair<ForgeDirection, ForgeDirection>,
|
val topRight: Pair<EnumFacing, EnumFacing>,
|
||||||
val bottomLeft: Pair<ForgeDirection, ForgeDirection>,
|
val bottomLeft: Pair<EnumFacing, EnumFacing>,
|
||||||
val bottomRight: Pair<ForgeDirection, ForgeDirection>) {
|
val bottomRight: Pair<EnumFacing, EnumFacing>) {
|
||||||
constructor(top: ForgeDirection, left: ForgeDirection) :
|
constructor(top: EnumFacing, left: EnumFacing) :
|
||||||
this(top to left, top to left.opposite, top.opposite to left, top.opposite to left.opposite)
|
this(top to left, top to left.opposite, top.opposite to left, top.opposite to left.opposite)
|
||||||
|
|
||||||
val asArray = arrayOf(topLeft, topRight, bottomLeft, bottomRight)
|
val asArray = arrayOf(topLeft, topRight, bottomLeft, bottomRight)
|
||||||
@@ -208,7 +219,5 @@ val faceCorners = forgeDirs.map { when(it) {
|
|||||||
NORTH -> FaceCorners(WEST, UP)
|
NORTH -> FaceCorners(WEST, UP)
|
||||||
SOUTH -> FaceCorners(UP, WEST)
|
SOUTH -> FaceCorners(UP, WEST)
|
||||||
WEST -> FaceCorners(SOUTH, UP)
|
WEST -> FaceCorners(SOUTH, UP)
|
||||||
EAST ->FaceCorners(SOUTH, DOWN)
|
EAST -> FaceCorners(SOUTH, DOWN)
|
||||||
else -> FaceCorners(UNKNOWN, UNKNOWN)
|
|
||||||
}}
|
}}
|
||||||
|
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
package mods.octarinecore.config
|
package mods.octarinecore.common.config
|
||||||
|
|
||||||
import com.google.common.collect.LinkedListMultimap
|
import com.google.common.collect.LinkedListMultimap
|
||||||
import cpw.mods.fml.client.config.GuiConfigEntries
|
|
||||||
import cpw.mods.fml.client.config.IConfigElement
|
|
||||||
import cpw.mods.fml.client.event.ConfigChangedEvent
|
|
||||||
import cpw.mods.fml.common.FMLCommonHandler
|
|
||||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent
|
|
||||||
import mods.octarinecore.metaprog.reflectField
|
import mods.octarinecore.metaprog.reflectField
|
||||||
import mods.octarinecore.metaprog.reflectFieldsOfType
|
import mods.octarinecore.metaprog.reflectFieldsOfType
|
||||||
import mods.octarinecore.metaprog.reflectNestedObjects
|
import mods.octarinecore.metaprog.reflectNestedObjects
|
||||||
import net.minecraftforge.common.config.ConfigElement
|
import net.minecraftforge.common.config.ConfigElement
|
||||||
import net.minecraftforge.common.config.Configuration
|
import net.minecraftforge.common.config.Configuration
|
||||||
import net.minecraftforge.common.config.Property
|
import net.minecraftforge.common.config.Property
|
||||||
|
import net.minecraftforge.fml.client.config.GuiConfigEntries
|
||||||
|
import net.minecraftforge.fml.client.config.IConfigElement
|
||||||
|
import net.minecraftforge.fml.client.event.ConfigChangedEvent
|
||||||
|
import net.minecraftforge.fml.common.FMLCommonHandler
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
// ============================
|
// ============================
|
||||||
@@ -37,7 +37,7 @@ abstract class DelegatingConfig(val modId: String, val langPrefix: String) {
|
|||||||
|
|
||||||
/** The [Configuration] backing this config object. */
|
/** The [Configuration] backing this config object. */
|
||||||
var config: Configuration? = null
|
var config: Configuration? = null
|
||||||
val rootGuiElements = linkedListOf<IConfigElement<*>>()
|
val rootGuiElements = linkedListOf<IConfigElement>()
|
||||||
|
|
||||||
/** Attach this config object to the given [Configuration] and update all properties. */
|
/** Attach this config object to the given [Configuration] and update all properties. */
|
||||||
fun attach(config: Configuration) {
|
fun attach(config: Configuration) {
|
||||||
@@ -50,7 +50,7 @@ abstract class DelegatingConfig(val modId: String, val langPrefix: String) {
|
|||||||
property.attach(config, langPrefix, category, name)
|
property.attach(config, langPrefix, category, name)
|
||||||
property.guiProperties.forEach { guiProperty ->
|
property.guiProperties.forEach { guiProperty ->
|
||||||
property.guiClass?.let { guiProperty.setConfigEntryClass(it) }
|
property.guiClass?.let { guiProperty.setConfigEntryClass(it) }
|
||||||
if (category == "global") rootGuiElements.add(ConfigElement.getTypedElement(guiProperty))
|
if (category == "global") rootGuiElements.add(ConfigElement(guiProperty))
|
||||||
else subProperties.put(category, guiProperty.name)
|
else subProperties.put(category, guiProperty.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,7 +58,7 @@ abstract class DelegatingConfig(val modId: String, val langPrefix: String) {
|
|||||||
val configCategory = config.getCategory(category)
|
val configCategory = config.getCategory(category)
|
||||||
configCategory.setLanguageKey("$langPrefix.$category")
|
configCategory.setLanguageKey("$langPrefix.$category")
|
||||||
configCategory.setPropertyOrder(subProperties[category])
|
configCategory.setPropertyOrder(subProperties[category])
|
||||||
rootGuiElements.add(ConfigElement<String>(configCategory))
|
rootGuiElements.add(ConfigElement(configCategory))
|
||||||
}
|
}
|
||||||
save()
|
save()
|
||||||
}
|
}
|
||||||
@@ -118,7 +118,7 @@ abstract class ConfigPropertyBase {
|
|||||||
var lang: String? = null
|
var lang: String? = null
|
||||||
|
|
||||||
/** GUI class to use. */
|
/** GUI class to use. */
|
||||||
var guiClass: Class<out GuiConfigEntries.IConfigEntry<*>>? = null
|
var guiClass: Class<out GuiConfigEntries.IConfigEntry>? = null
|
||||||
|
|
||||||
/** @return true if the property has changed. */
|
/** @return true if the property has changed. */
|
||||||
abstract val hasChanged: Boolean
|
abstract val hasChanged: Boolean
|
||||||
@@ -64,6 +64,7 @@ open class ClassRef(val mcpName: String, val obfName: String) : Resolvable<Class
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val int = ClassRefPrimitive("I", Int::class.java)
|
val int = ClassRefPrimitive("I", Int::class.java)
|
||||||
|
val long = ClassRefPrimitive("J", Long::class.java)
|
||||||
val float = ClassRefPrimitive("F", Float::class.java)
|
val float = ClassRefPrimitive("F", Float::class.java)
|
||||||
val boolean = ClassRefPrimitive("Z", Boolean::class.java)
|
val boolean = ClassRefPrimitive("Z", Boolean::class.java)
|
||||||
val void = ClassRefPrimitive("V", null)
|
val void = ClassRefPrimitive("V", null)
|
||||||
@@ -73,6 +74,8 @@ open class ClassRef(val mcpName: String, val obfName: String) : Resolvable<Class
|
|||||||
open fun asmDescriptor(namespace: Namespace) = "L${name(namespace).replace(".", "/")};"
|
open fun asmDescriptor(namespace: Namespace) = "L${name(namespace).replace(".", "/")};"
|
||||||
|
|
||||||
override fun resolve() = listOf(mcpName, obfName).map { getJavaClass(it) }.filterNotNull().firstOrNull()
|
override fun resolve() = listOf(mcpName, obfName).map { getJavaClass(it) }.filterNotNull().firstOrNull()
|
||||||
|
|
||||||
|
fun isInstance(obj: Any) = element?.isInstance(obj) ?: false
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
package mods.octarinecore.metaprog
|
package mods.octarinecore.metaprog
|
||||||
|
|
||||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin
|
import mods.octarinecore.metaprog.Namespace.MCP
|
||||||
|
import mods.octarinecore.metaprog.Namespace.OBF
|
||||||
import net.minecraft.launchwrapper.IClassTransformer
|
import net.minecraft.launchwrapper.IClassTransformer
|
||||||
import mods.octarinecore.metaprog.Namespace.*
|
import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin
|
||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
import org.objectweb.asm.ClassReader
|
import org.objectweb.asm.ClassReader
|
||||||
import org.objectweb.asm.ClassWriter
|
import org.objectweb.asm.ClassWriter
|
||||||
@@ -32,14 +33,14 @@ open class Transformer : IClassTransformer {
|
|||||||
var environment: Namespace = MCP
|
var environment: Namespace = MCP
|
||||||
|
|
||||||
/** The list of transformers and targets. */
|
/** The list of transformers and targets. */
|
||||||
var transformers: MutableList<Pair<MethodRef, MethodTransformContext.()->Unit>> = arrayListOf()
|
var methodTransformers: MutableList<Pair<MethodRef, MethodTransformContext.()->Unit>> = arrayListOf()
|
||||||
|
|
||||||
/** Add a transformation to perform. Call this during instance initialization.
|
/** Add a transformation to perform. Call this during instance initialization.
|
||||||
*
|
*
|
||||||
* @param[method] the target method of the transformation
|
* @param[method] the target method of the transformation
|
||||||
* @param[trans] method transformation lambda
|
* @param[trans] method transformation lambda
|
||||||
*/
|
*/
|
||||||
fun transformMethod(method: MethodRef, trans: MethodTransformContext.()->Unit) = transformers.add(method to trans)
|
fun transformMethod(method: MethodRef, trans: MethodTransformContext.()->Unit) = methodTransformers.add(method to trans)
|
||||||
|
|
||||||
override fun transform(name: String?, transformedName: String?, classData: ByteArray?): ByteArray? {
|
override fun transform(name: String?, transformedName: String?, classData: ByteArray?): ByteArray? {
|
||||||
if (classData == null) return null
|
if (classData == null) return null
|
||||||
@@ -48,7 +49,7 @@ open class Transformer : IClassTransformer {
|
|||||||
val classNode = ClassNode().apply { val reader = ClassReader(classData); reader.accept(this, 0) }
|
val classNode = ClassNode().apply { val reader = ClassReader(classData); reader.accept(this, 0) }
|
||||||
var workDone = false
|
var workDone = false
|
||||||
|
|
||||||
val transformations: List<Pair<MethodTransformContext.()->Unit, MethodNode?>> = transformers.map { transformer ->
|
val transformations: List<Pair<MethodTransformContext.()->Unit, MethodNode?>> = methodTransformers.map { transformer ->
|
||||||
if (transformedName != transformer.first.parentClass.mcpName) return@map transformer.second to null
|
if (transformedName != transformer.first.parentClass.mcpName) return@map transformer.second to null
|
||||||
log.debug("Found class: $name -> $transformedName")
|
log.debug("Found class: $name -> $transformedName")
|
||||||
log.debug(" searching: ${transformer.first.name(OBF)} ${transformer.first.asmDescriptor(OBF)} -> ${transformer.first.name(MCP)} ${transformer.first.asmDescriptor(MCP)}")
|
log.debug(" searching: ${transformer.first.name(OBF)} ${transformer.first.asmDescriptor(OBF)} -> ${transformer.first.name(MCP)} ${transformer.first.asmDescriptor(MCP)}")
|
||||||
@@ -72,7 +73,7 @@ open class Transformer : IClassTransformer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return if (!workDone) classData else ClassWriter(0).apply { classNode.accept(this) }.toByteArray()
|
return if (!workDone) classData else ClassWriter(3).apply { classNode.accept(this) }.toByteArray()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,6 +85,11 @@ open class Transformer : IClassTransformer {
|
|||||||
* @param[environment] the type of environment we are in
|
* @param[environment] the type of environment we are in
|
||||||
*/
|
*/
|
||||||
class MethodTransformContext(val method: MethodNode, val environment: Namespace) {
|
class MethodTransformContext(val method: MethodNode, val environment: Namespace) {
|
||||||
|
|
||||||
|
fun makePublic() {
|
||||||
|
method.access = (method.access or Opcodes.ACC_PUBLIC) and (Opcodes.ACC_PRIVATE or Opcodes.ACC_PROTECTED).inv()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the first instruction that matches a predicate.
|
* Find the first instruction that matches a predicate.
|
||||||
*
|
*
|
||||||
@@ -117,9 +123,14 @@ class MethodTransformContext(val method: MethodNode, val environment: Namespace)
|
|||||||
* @param[init] builder-style lambda to assemble instruction list
|
* @param[init] builder-style lambda to assemble instruction list
|
||||||
*/
|
*/
|
||||||
fun AbstractInsnNode.insertBefore(init: InstructionList.()->Unit) = InstructionList(environment).apply{
|
fun AbstractInsnNode.insertBefore(init: InstructionList.()->Unit) = InstructionList(environment).apply{
|
||||||
this.init(); list.forEach { method.instructions.insertBefore(this@insertBefore, it) }
|
val insertBeforeNode = this@insertBefore //.let { if (it.previous is FrameNode) it.previous else it }
|
||||||
|
this.init(); list.forEach { method.instructions.insertBefore(insertBeforeNode, it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun AbstractInsnNode.replace(init: InstructionList.()->Unit) = InstructionList(environment).apply {
|
||||||
|
insertAfter(init)
|
||||||
|
method.instructions.remove(this@replace)
|
||||||
|
}
|
||||||
/** Remove all isntructiuons between the given two (inclusive). */
|
/** Remove all isntructiuons between the given two (inclusive). */
|
||||||
fun Pair<AbstractInsnNode, AbstractInsnNode>.remove() {
|
fun Pair<AbstractInsnNode, AbstractInsnNode>.remove() {
|
||||||
var current: AbstractInsnNode? = first
|
var current: AbstractInsnNode? = first
|
||||||
@@ -151,6 +162,16 @@ class MethodTransformContext(val method: MethodNode, val environment: Namespace)
|
|||||||
fun varinsn(opcode: Int, idx: Int): (AbstractInsnNode)->Boolean = { insn ->
|
fun varinsn(opcode: Int, idx: Int): (AbstractInsnNode)->Boolean = { insn ->
|
||||||
insn.opcode == opcode && insn is VarInsnNode && insn.`var` == idx
|
insn.opcode == opcode && insn is VarInsnNode && insn.`var` == idx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun invokeName(name: String): (AbstractInsnNode)->Boolean = { insn ->
|
||||||
|
(insn as? MethodInsnNode)?.name == name
|
||||||
|
}
|
||||||
|
|
||||||
|
fun invokeRef(ref: MethodRef): (AbstractInsnNode)->Boolean = { insn ->
|
||||||
|
(insn as? MethodInsnNode)?.let {
|
||||||
|
it.name == ref.name(environment) && it.owner == ref.parentClass.name(environment).replace(".", "/")
|
||||||
|
} ?: false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -160,6 +181,8 @@ class MethodTransformContext(val method: MethodNode, val environment: Namespace)
|
|||||||
*/
|
*/
|
||||||
class InstructionList(val environment: Namespace) {
|
class InstructionList(val environment: Namespace) {
|
||||||
|
|
||||||
|
fun insn(opcode: Int) = list.add(InsnNode(opcode))
|
||||||
|
|
||||||
/** The instruction list being assembled. */
|
/** The instruction list being assembled. */
|
||||||
val list: MutableList<AbstractInsnNode> = arrayListOf()
|
val list: MutableList<AbstractInsnNode> = arrayListOf()
|
||||||
|
|
||||||
|
|||||||
28
src/main/resources/META-INF/BetterFoliage_at.cfg
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
public net.minecraft.client.renderer.BlockModelRenderer func_178261_a(Lnet/minecraft/block/Block;[ILnet/minecraft/util/EnumFacing;[FLjava/util/BitSet;)V
|
||||||
|
|
||||||
|
public net.minecraft.client.renderer.BlockModelRenderer$AmbientOcclusionFace
|
||||||
|
public net.minecraft.client.renderer.BlockModelRenderer$AmbientOcclusionFace field_178206_b # vertexColorMultiplier
|
||||||
|
public net.minecraft.client.renderer.BlockModelRenderer$AmbientOcclusionFace field_178207_c # vertexBrightness
|
||||||
|
|
||||||
|
public net.minecraft.client.renderer.BlockModelRenderer$VertexTranslations field_178191_g
|
||||||
|
public net.minecraft.client.renderer.BlockModelRenderer$VertexTranslations field_178200_h
|
||||||
|
public net.minecraft.client.renderer.BlockModelRenderer$VertexTranslations field_178201_i
|
||||||
|
public net.minecraft.client.renderer.BlockModelRenderer$VertexTranslations field_178198_j
|
||||||
|
|
||||||
|
public net.minecraft.client.renderer.WorldRenderer field_179008_i # rawBufferIndex
|
||||||
|
public net.minecraft.client.renderer.WorldRenderer field_179009_s # bufferSize
|
||||||
|
public net.minecraft.client.renderer.WorldRenderer field_179011_q # vertexFormat
|
||||||
|
public net.minecraft.client.renderer.WorldRenderer func_178983_e(I)V # growBuffer()
|
||||||
|
|
||||||
|
public net.minecraft.client.resources.model.ModelBakery field_177612_i # variants
|
||||||
|
public net.minecraft.client.resources.model.ModelBakery field_177611_h # models
|
||||||
|
public net.minecraft.client.resources.model.ModelBakery field_177609_j # textureMap
|
||||||
|
public net.minecraft.client.resources.model.ModelBakery field_177610_k # blockModelShapes
|
||||||
|
|
||||||
|
public net.minecraftforge.client.model.ModelLoader stateModels
|
||||||
|
|
||||||
|
public net.minecraft.client.resources.model.WeightedBakedModel field_177565_b # models
|
||||||
|
|
||||||
|
public net.minecraft.client.renderer.block.statemap.BlockStateMapper field_178450_a # blockStateMap
|
||||||
|
|
||||||
|
public net.minecraft.client.resources.SimpleReloadableResourceManager field_110548_a # domainResourceManagers
|
||||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 377 B |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 414 B |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 491 B |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 610 B |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 859 B |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 519 B |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 590 B |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 434 B |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 505 B |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 464 B |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 369 B |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 379 B |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 345 B |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 739 B |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 711 B |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 571 B |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 501 B |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 507 B |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 490 B |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 483 B |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 453 B |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 756 B |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 1.4 KiB |