Merge branch 'kotlin-1.10' into kotlin-1.11.2

This commit is contained in:
octarine-noise
2017-04-09 12:07:25 +02:00
24 changed files with 150 additions and 163 deletions

View File

@@ -2,11 +2,11 @@ apply plugin: "net.minecraftforge.gradle.forge"
apply plugin: 'kotlin'
group = 'com.github.octarine-noise'
version = "2.1.3"
version = "2.1.4"
archivesBaseName = rootProject.name + '-MC1.11.2'
buildscript {
ext.kotlin_version = '1.0.3'
ext.kotlin_version = '1.1.1'
repositories {
mavenCentral()
maven {

View File

@@ -20,9 +20,9 @@ import net.minecraftforge.fml.relauncher.SideOnly
@SideOnly(Side.CLIENT)
interface IColumnTextureInfo {
val axis: Axis?
val top: (ShadingContext, Int, Quad)->TextureAtlasSprite?
val bottom: (ShadingContext, Int, Quad)->TextureAtlasSprite?
val side: (ShadingContext, Int, Quad)->TextureAtlasSprite?
val top: QuadIconResolver
val bottom: QuadIconResolver
val side: QuadIconResolver
}
@SideOnly(Side.CLIENT)
@@ -35,13 +35,13 @@ data class StaticColumnInfo(override val axis: Axis?,
val topTexture: TextureAtlasSprite,
val bottomTexture: TextureAtlasSprite,
val sideTexture: TextureAtlasSprite) : IColumnTextureInfo {
override val top = { ctx: ShadingContext, idx: Int, quad: Quad ->
override val top: QuadIconResolver = { ctx, _, _ ->
OptifineCTM.override(topTexture, blockContext, UP.rotate(ctx.rotation))
}
override val bottom = { ctx: ShadingContext, idx: Int, quad: Quad ->
override val bottom: QuadIconResolver = { ctx, _, _ ->
OptifineCTM.override(bottomTexture, blockContext, DOWN.rotate(ctx.rotation))
}
override val side = { ctx: ShadingContext, idx: Int, quad: Quad ->
override val side: QuadIconResolver = { ctx, idx, _ ->
OptifineCTM.override(sideTexture, blockContext, (if ((idx and 1) == 0) SOUTH else EAST).rotate(ctx.rotation))
}
}
@@ -129,7 +129,7 @@ abstract class AbstractRenderColumn(modId: String) : AbstractBlockRenderingHandl
val transitionTop = model { mix(sideRoundLarge.model, sideRoundSmall.model) { it > 1 } }
val transitionBottom = model { mix(sideRoundSmall.model, sideRoundLarge.model) { it > 1 } }
inline fun continous(q1: QuadrantType, q2: QuadrantType) =
inline fun continuous(q1: QuadrantType, q2: QuadrantType) =
q1 == q2 || ((q1 == SQUARE || q1 == INVISIBLE) && (q2 == SQUARE || q2 == INVISIBLE))
abstract val blockPredicate: (IBlockState)->Boolean
@@ -185,7 +185,6 @@ abstract class AbstractRenderColumn(modId: String) : AbstractBlockRenderingHandl
renderer,
sideModel,
rotation,
blockContext.blockCenter,
icon = columnTextures.side,
postProcess = noPost
)
@@ -210,7 +209,7 @@ abstract class AbstractRenderColumn(modId: String) : AbstractBlockRenderingHandl
}
}
PARALLEL -> {
if (!continous(quadrants[idx], quadrantsTop[idx])) {
if (!continuous(quadrants[idx], quadrantsTop[idx])) {
if (quadrants[idx] == SQUARE || quadrants[idx] == INVISIBLE) {
upModel = topSquare.model
}
@@ -229,7 +228,7 @@ abstract class AbstractRenderColumn(modId: String) : AbstractBlockRenderingHandl
}
}
PARALLEL -> {
if (!continous(quadrants[idx], quadrantsBottom[idx]) &&
if (!continuous(quadrants[idx], quadrantsBottom[idx]) &&
(quadrants[idx] == SQUARE || quadrants[idx] == INVISIBLE)) {
downModel = bottomSquare.model
}
@@ -240,9 +239,8 @@ abstract class AbstractRenderColumn(modId: String) : AbstractBlockRenderingHandl
renderer,
upModel,
rotation,
blockContext.blockCenter,
icon = upIcon,
postProcess = { ctx, qi, q, vi, v ->
postProcess = { _, _, _, _, _ ->
if (isLidUp) {
rotateUV(idx + if (logAxis == Axis.X) 1 else 0)
if (logAxis == Axis.X) mirrorUV(true, true)
@@ -253,9 +251,8 @@ abstract class AbstractRenderColumn(modId: String) : AbstractBlockRenderingHandl
renderer,
downModel,
rotation,
blockContext.blockCenter,
icon = downIcon,
postProcess = { ctx, qi, q, vi, v ->
postProcess = { _, _, _, _, _ ->
if (isLidDown) {
rotateUV((if (logAxis == Axis.X) 0 else 3) - idx)
if (logAxis != Axis.Y) mirrorUV(true, true)

View File

@@ -47,7 +47,7 @@ class RenderAlgae : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
renderer,
algaeModels[rand[2]],
Rotation.identity,
icon = { ctx, qi, q -> algaeIcons[rand[qi and 1]]!! },
icon = { _, qi, _ -> algaeIcons[rand[qi and 1]]!! },
postProcess = noPost
)
}

View File

@@ -110,14 +110,14 @@ class RenderCactus : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
renderer,
modelCross[ctx.random(0)],
Rotation.identity,
icon = { ctx, qi, q -> iconCross.icon!!},
icon = { _, _, _ -> iconCross.icon!!},
postProcess = noPost
)
modelRenderer.render(
renderer,
modelArm[ctx.random(1)],
cactusArmRotation[ctx.random(2) % 4],
icon = { ctx2, qi, q -> iconArm[ctx.random(3)]!!},
icon = { _, _, _ -> iconArm[ctx.random(3)]!!},
postProcess = noPost
)
return true

View File

@@ -6,6 +6,8 @@ import mods.octarinecore.client.render.AbstractBlockRenderingHandler
import mods.octarinecore.client.render.BlockContext
import mods.octarinecore.client.render.withOffset
import mods.octarinecore.common.Int3
import mods.octarinecore.common.forgeDirsHorizontal
import mods.octarinecore.common.offset
import net.minecraft.client.renderer.BlockRendererDispatcher
import net.minecraft.client.renderer.VertexBuffer
import net.minecraft.util.BlockRenderLayer
@@ -21,6 +23,10 @@ class RenderConnectedGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_
(Config.connectedGrass.snowEnabled || !ctx.blockState(up2).isSnow)
override fun render(ctx: BlockContext, dispatcher: BlockRendererDispatcher, renderer: VertexBuffer, layer: BlockRenderLayer): Boolean {
// if the block sides are not visible anyway, render normally
if (forgeDirsHorizontal.all { ctx.blockState(it.offset).isOpaqueCube }) return renderWorldBlockBase(ctx, dispatcher, renderer, null)
if (ctx.isSurroundedBy { it.isOpaqueCube } ) return false
return ctx.withOffset(Int3.zero, up1) {
ctx.withOffset(up1, up2) {
renderWorldBlockBase(ctx, dispatcher, renderer, null)

View File

@@ -65,7 +65,7 @@ class RenderCoral : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
renderer,
coralModels[variation++],
rotationFromUp[idx],
icon = { ctx, qi, q -> if (qi == 4) crustIcons[variation]!! else coralIcons[variation + (qi and 1)]!!},
icon = { _, qi, _ -> if (qi == 4) crustIcons[variation]!! else coralIcons[variation + (qi and 1)]!!},
postProcess = noPost
)
}

View File

@@ -6,9 +6,7 @@ import mods.betterfoliage.client.config.Config
import mods.betterfoliage.client.integration.ShadersModIntegration
import mods.betterfoliage.client.texture.GrassRegistry
import mods.octarinecore.client.render.*
import mods.octarinecore.common.Double3
import mods.octarinecore.common.Int3
import mods.octarinecore.common.Rotation
import mods.octarinecore.common.*
import mods.octarinecore.random
import net.minecraft.client.renderer.BlockRendererDispatcher
import net.minecraft.client.renderer.VertexBuffer
@@ -66,15 +64,17 @@ class RenderGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
// get full AO data
modelRenderer.updateShading(Int3.zero, allFaces)
// check occlusion
val isHidden = forgeDirs.map { ctx.blockState(it.offset).isOpaqueCube }
// render full grass block
ShadersModIntegration.renderAs(ctx.blockState(Int3.zero), renderer) {
modelRenderer.render(
renderer,
fullCube,
Rotation.identity,
ctx.blockCenter,
icon = { ctx, qi, q -> grassInfo.grassTopTexture },
postProcess = { ctx, qi, q, vi, v ->
quadFilter = { qi, _ -> !isHidden[qi] },
icon = { _, _, _ -> grassInfo.grassTopTexture },
postProcess = { ctx, _, _, _, _ ->
rotateUV(2)
if (isSnowed) {
if (!ctx.aoEnabled) setGrey(1.4f)
@@ -104,10 +104,8 @@ class RenderGrass : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
grassModels[rand[0]],
Rotation.identity,
ctx.blockCenter + (if (isSnowed) snowOffset else Double3.zero),
icon = { ctx: ShadingContext, qi: Int, q: Quad ->
if (Config.shortGrass.useGenerated) iconGen.icon!! else iconset[rand[qi and 1]]!!
},
postProcess = { ctx, qi, q, vi, v -> if (isSnowed) setGrey(1.0f) else multiplyColor(grassInfo.overrideColor ?: blockColor) }
icon = { _, qi, _ -> if (Config.shortGrass.useGenerated) iconGen.icon!! else iconset[rand[qi and 1]]!! },
postProcess = { _, _, _, _, _ -> if (isSnowed) setGrey(1.0f) else multiplyColor(grassInfo.overrideColor ?: blockColor) }
)
}

View File

@@ -64,8 +64,8 @@ class RenderLeaves : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
leavesModel.model,
rotation,
ctx.blockCenter + perturbs[rand[0]],
icon = { ctx, qi, q -> leafInfo.roundLeafTexture },
postProcess = { ctx, qi, q, vi, v ->
icon = { _, _, _ -> leafInfo.roundLeafTexture },
postProcess = { _, _, _, _, _ ->
rotateUV(rand[1])
multiplyColor(blockColor)
}
@@ -76,7 +76,7 @@ class RenderLeaves : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
leavesModel.model,
Rotation.identity,
ctx.blockCenter + perturbs[rand[0]],
icon = { ctx, qi, q -> snowedIcon[rand[1]]!! },
icon = { _, _, _ -> snowedIcon[rand[1]]!! },
postProcess = whitewash
)
}

View File

@@ -68,7 +68,7 @@ class RenderLilypad : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
Rotation.identity,
ctx.blockCenter.add(perturbs[rand[4]]),
forceFlat = true,
icon = { ctx, qi, q -> flowerIcon[rand[0]]!! },
icon = { _, _, _ -> flowerIcon[rand[0]]!! },
postProcess = noPost
)

View File

@@ -73,7 +73,7 @@ object StandardLogSupport : TextureListModelProcessor<IColumnTextureInfo>, IColu
fun getAxis(state: IBlockState): Axis? {
val axis = tryDefault(null) { state.getValue(BlockLog.LOG_AXIS).toString() } ?:
state.properties.entries.find { it.key.getName().toLowerCase() == "axis" }?.let { it.value.toString() }
state.properties.entries.find { it.key.getName().toLowerCase() == "axis" }?.value?.toString()
return when (axis) {
"x" -> Axis.X
"y" -> Axis.Y

View File

@@ -47,7 +47,7 @@ class RenderMycelium : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
myceliumModel[rand[0]],
Rotation.identity,
ctx.blockCenter + (if (isSnowed) snowOffset else Double3.zero),
icon = { ctx, qi, q -> myceliumIcon[rand[qi and 1]]!! },
icon = { _, qi, _ -> myceliumIcon[rand[qi and 1]]!! },
postProcess = if (isSnowed) whitewash else noPost
)

View File

@@ -49,7 +49,7 @@ class RenderNetherrack : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID)
renderer,
netherrackModel[rand[0]],
Rotation.identity,
icon = { ctx, qi, q -> netherrackIcon[rand[qi and 1]]!! },
icon = { _, qi, _ -> netherrackIcon[rand[qi and 1]]!! },
postProcess = noPost
)

View File

@@ -64,7 +64,7 @@ class RenderReeds : AbstractBlockRenderingHandler(BetterFoliageMod.MOD_ID) {
reedModels[ctx.random(0)],
Rotation.identity,
forceFlat = true,
icon = { ctx, qi, q -> reedIcons[iconVar]!! },
icon = { _, _, _ -> reedIcons[iconVar]!! },
postProcess = noPost
)
}

View File

@@ -21,8 +21,8 @@ val snowOffset = UP * 0.0625
val normalLeavesRot = arrayOf(Rotation.identity)
val denseLeavesRot = arrayOf(Rotation.identity, Rotation.rot90[EAST.ordinal], Rotation.rot90[SOUTH.ordinal])
val whitewash: RenderVertex.(ShadingContext, Int, Quad, Int, Vertex)->Unit = { ctx, qi, q, vi, v -> setGrey(1.4f) }
val greywash: RenderVertex.(ShadingContext, Int, Quad, Int, Vertex)->Unit = { ctx, qi, q, vi, v -> setGrey(1.0f) }
val whitewash: PostProcessLambda = { _, _, _, _, _ -> setGrey(1.4f) }
val greywash: PostProcessLambda = { _, _, _, _, _ -> setGrey(1.0f) }
val IBlockState.isSnow: Boolean get() = material.let { it == Material.SNOW || it == Material.CRAFTED_SNOW }

View File

@@ -14,6 +14,7 @@ import org.objectweb.asm.Opcodes.*
"mods.octarinecore.kotlin"
)
@IFMLLoadingPlugin.MCVersion("1.11.2")
@IFMLLoadingPlugin.SortingIndex(1400)
class BetterFoliageLoader : ASMPlugin(BetterFoliageTransformer::class.java)
class BetterFoliageTransformer : Transformer() {

View File

@@ -16,53 +16,50 @@ object Refs {
val Random = ClassRef("java.util.Random")
// Minecraft
val IBlockAccess = ClassRef("net.minecraft.world.IBlockAccess", "ajw")
val IBlockState = ClassRef("net.minecraft.block.state.IBlockState", "atl")
val BlockStateBase = ClassRef("net.minecraft.block.state.BlockStateBase", "ati")
val BlockPos = ClassRef("net.minecraft.util.math.BlockPos", "co")
val MutableBlockPos = ClassRef("net.minecraft.util.math.BlockPos\$MutableBlockPos", "co\$a")
val BlockRenderLayer = ClassRef("net.minecraft.util.BlockRenderLayer", "ajk")
val EnumFacing = ClassRef("net.minecraft.util.EnumFacing", "cv")
val IBlockAccess = ClassRef("net.minecraft.world.IBlockAccess")
val IBlockState = ClassRef("net.minecraft.block.state.IBlockState")
val BlockStateBase = ClassRef("net.minecraft.block.state.BlockStateBase")
val BlockPos = ClassRef("net.minecraft.util.math.BlockPos")
val MutableBlockPos = ClassRef("net.minecraft.util.math.BlockPos\$MutableBlockPos")
val BlockRenderLayer = ClassRef("net.minecraft.util.BlockRenderLayer")
val EnumFacing = ClassRef("net.minecraft.util.EnumFacing")
val World = ClassRef("net.minecraft.world.World", "ajs")
val WorldClient = ClassRef("net.minecraft.client.multiplayer.WorldClient", "bnq")
val showBarrierParticles = MethodRef(WorldClient, "showBarrierParticles", "func_184153_a", "a", ClassRef.void, ClassRef.int, ClassRef.int, ClassRef.int, ClassRef.int, Random, ClassRef.boolean, MutableBlockPos)
val World = ClassRef("net.minecraft.world.World")
val WorldClient = ClassRef("net.minecraft.client.multiplayer.WorldClient")
val showBarrierParticles = MethodRef(WorldClient, "showBarrierParticles", "func_184153_a", ClassRef.void, ClassRef.int, ClassRef.int, ClassRef.int, ClassRef.int, Random, ClassRef.boolean, MutableBlockPos)
val Block = ClassRef("net.minecraft.block.Block", "alu")
val StateImplementation = ClassRef("net.minecraft.block.state.BlockStateContainer\$StateImplementation", "atm\$a")
val Block = ClassRef("net.minecraft.block.Block")
val StateImplementation = ClassRef("net.minecraft.block.state.BlockStateContainer\$StateImplementation")
val canRenderInLayer = MethodRef(Block, "canRenderInLayer", ClassRef.boolean, IBlockState, BlockRenderLayer)
val getAmbientOcclusionLightValue = MethodRef(StateImplementation, "getAmbientOcclusionLightValue", "func_185892_j", "k", ClassRef.float)
val useNeighborBrightness = MethodRef(StateImplementation, "useNeighborBrightness", "func_185916_f", "f", ClassRef.boolean)
val getAmbientOcclusionLightValue = MethodRef(StateImplementation, "getAmbientOcclusionLightValue", "func_185892_j", ClassRef.float)
val useNeighborBrightness = MethodRef(StateImplementation, "useNeighborBrightness", "func_185916_f", ClassRef.boolean)
val doesSideBlockRendering = MethodRef(StateImplementation, "doesSideBlockRendering", ClassRef.boolean, IBlockAccess, BlockPos, EnumFacing)
val isOpaqueCube = MethodRef(StateImplementation, "isOpaqueCube", "func_185914_p", "q", ClassRef.boolean)
val randomDisplayTick = MethodRef(Block, "randomDisplayTick", "func_180655_c", "a", ClassRef.void, IBlockState, World, BlockPos, Random)
val isOpaqueCube = MethodRef(StateImplementation, "isOpaqueCube", "func_185914_p", ClassRef.boolean)
val randomDisplayTick = MethodRef(Block, "randomDisplayTick", "func_180655_c", ClassRef.void, IBlockState, World, BlockPos, Random)
val BlockModelRenderer = ClassRef("net.minecraft.client.renderer.BlockModelRenderer", "brc")
val AmbientOcclusionFace = ClassRef("net.minecraft.client.renderer.BlockModelRenderer\$AmbientOcclusionFace", "brc\$b")
val ChunkCompileTaskGenerator = ClassRef("net.minecraft.client.renderer.chunk.ChunkCompileTaskGenerator", "bsy")
val VertexBuffer = ClassRef("net.minecraft.client.renderer.VertexBuffer", "bpy")
val BlockModelRenderer = ClassRef("net.minecraft.client.renderer.BlockModelRenderer")
val AmbientOcclusionFace = ClassRef("net.minecraft.client.renderer.BlockModelRenderer\$AmbientOcclusionFace")
val ChunkCompileTaskGenerator = ClassRef("net.minecraft.client.renderer.chunk.ChunkCompileTaskGenerator")
val VertexBuffer = ClassRef("net.minecraft.client.renderer.VertexBuffer")
val AOF_constructor = MethodRef(AmbientOcclusionFace, "<init>", ClassRef.void, BlockModelRenderer)
val RenderChunk = ClassRef("net.minecraft.client.renderer.chunk.RenderChunk", "bte")
val rebuildChunk = MethodRef(RenderChunk, "rebuildChunk", "func_178581_b", "b", ClassRef.void, ClassRef.float, ClassRef.float, ClassRef.float, ChunkCompileTaskGenerator)
val RenderChunk = ClassRef("net.minecraft.client.renderer.chunk.RenderChunk")
val rebuildChunk = MethodRef(RenderChunk, "rebuildChunk", "func_178581_b", ClassRef.void, ClassRef.float, ClassRef.float, ClassRef.float, ChunkCompileTaskGenerator)
val BlockRendererDispatcher = ClassRef("net.minecraft.client.renderer.BlockRendererDispatcher", "bra")
val renderBlock = MethodRef(BlockRendererDispatcher, "renderBlock", "func_175018_a", "a", ClassRef.boolean, IBlockState, BlockPos, IBlockAccess, VertexBuffer)
val BlockRendererDispatcher = ClassRef("net.minecraft.client.renderer.BlockRendererDispatcher")
val renderBlock = MethodRef(BlockRendererDispatcher, "renderBlock", "func_175018_a", ClassRef.boolean, IBlockState, BlockPos, IBlockAccess, VertexBuffer)
val TextureAtlasSprite = ClassRef("net.minecraft.client.renderer.texture.TextureAtlasSprite", "byz")
val TextureMap = ClassRef("net.minecraft.client.renderer.texture.TextureMap", "byy")
val IResourceManager = ClassRef("net.minecraft.client.resources.IResourceManager", "bzy")
val loadTextureAtlas = MethodRef(TextureMap, "loadTextureAtlas", "func_110571_b", "b", ClassRef.void, IResourceManager)
val TextureAtlasSprite = ClassRef("net.minecraft.client.renderer.texture.TextureAtlasSprite")
val IRegistry = ClassRef("net.minecraft.util.registry.IRegistry", "dh")
val IRegistry = ClassRef("net.minecraft.util.registry.IRegistry")
val ModelLoader = ClassRef("net.minecraftforge.client.model.ModelLoader")
val stateModels = FieldRef(ModelLoader, "stateModels", Map)
val setupModelRegistry = MethodRef(ModelLoader, "setupModelRegistry", "func_177570_a", "a", IRegistry)
val setupModelRegistry = MethodRef(ModelLoader, "setupModelRegistry", "func_177570_a", IRegistry)
val IModel = ClassRef("net.minecraftforge.client.model.IModel")
val ModelBlock = ClassRef("net.minecraft.client.renderer.block.model.ModelBlock", "bri")
val ResourceLocation = ClassRef("net.minecraft.util.ResourceLocation", "kq")
val ModelResourceLocation = ClassRef("net.minecraft.client.renderer.block.model.ModelResourceLocation", "cbm")
val ModelBlock = ClassRef("net.minecraft.client.renderer.block.model.ModelBlock")
val ResourceLocation = ClassRef("net.minecraft.util.ResourceLocation")
val ModelResourceLocation = ClassRef("net.minecraft.client.renderer.block.model.ModelResourceLocation")
val VanillaModelWrapper = ClassRef("net.minecraftforge.client.model.ModelLoader\$VanillaModelWrapper")
val model_VMW = FieldRef(VanillaModelWrapper, "model", ModelBlock)
val location_VMW = FieldRef(VanillaModelWrapper, "location", ModelBlock)
@@ -88,7 +85,6 @@ object Refs {
val onAfterBakeModels = MethodRef(BetterFoliageHooks, "onAfterBakeModels", ClassRef.void, Map)
val renderWorldBlock = MethodRef(BetterFoliageHooks, "renderWorldBlock", ClassRef.boolean, BlockRendererDispatcher, IBlockState, BlockPos, IBlockAccess, VertexBuffer, BlockRenderLayer)
val canRenderBlockInLayer = MethodRef(BetterFoliageHooks, "canRenderBlockInLayer", ClassRef.boolean, Block, IBlockState, BlockRenderLayer)
val onLoadAtlasPre = MethodRef(BetterFoliageHooks, "onLoadAtlasPre", ClassRef.void, TextureMap)
// Optifine
val OptifineClassTransformer = ClassRef("optifine.OptiFineClassTransformer")

View File

@@ -70,13 +70,13 @@ data class Quad(val v1: Vertex, val v2: Vertex, val v3: Vertex, val v4: Vertex)
fun clampUV(minU: Double = -0.5, maxU: Double = 0.5, minV: Double = -0.5, maxV: Double = 0.5) =
transformV { it.copy(uv = it.uv.clamp(minU, maxU, minV, maxV)) }
fun mirrorUV(mirrorU: Boolean, mirrorV: Boolean) = transformV { it.copy(uv = it.uv.mirror(mirrorU, mirrorV)) }
fun setAoShader(resolver: (Quad, Vertex)->Shader, predicate: (Vertex, Int)->Boolean = { v, vi -> true }) =
fun setAoShader(factory: ShaderFactory, predicate: (Vertex, Int)->Boolean = { v, vi -> true }) =
transformVI { vertex, idx ->
if (!predicate(vertex, idx)) vertex else vertex.copy(aoShader = resolver(this@Quad, vertex))
if (!predicate(vertex, idx)) vertex else vertex.copy(aoShader = factory(this@Quad, vertex))
}
fun setFlatShader(resolver: (Quad, Vertex)->Shader, predicate: (Vertex, Int)->Boolean = { v, vi -> true }) =
fun setFlatShader(factory: ShaderFactory, predicate: (Vertex, Int)->Boolean = { v, vi -> true }) =
transformVI { vertex, idx ->
if (!predicate(vertex, idx)) vertex else vertex.copy(flatShader = resolver(this@Quad, vertex))
if (!predicate(vertex, idx)) vertex else vertex.copy(flatShader = factory(this@Quad, vertex))
}
fun setFlatShader(shader: Shader) = transformVI { vertex, idx -> vertex.copy(flatShader = shader) }
val flipped: Quad get() = Quad(v4, v3, v2, v1)

View File

@@ -7,7 +7,10 @@ import net.minecraft.client.renderer.texture.TextureAtlasSprite
import net.minecraft.util.EnumFacing
import net.minecraft.util.EnumFacing.*
class ModelRenderer() : ShadingContext() {
typealias QuadIconResolver = (ShadingContext, Int, Quad) -> TextureAtlasSprite?
typealias PostProcessLambda = RenderVertex.(ShadingContext, Int, Quad, Int, Vertex) -> Unit
class ModelRenderer : ShadingContext() {
/** Holds final vertex data before it goes to the [Tessellator]. */
val temp = RenderVertex()
@@ -25,14 +28,15 @@ class ModelRenderer() : ShadingContext() {
* @param[rotateUV] lambda to get amount of UV rotation for each quad
* @param[postProcess] lambda to perform arbitrary modifications on the [RenderVertex] just before it goes to the [Tessellator]
*/
inline fun render(
fun render(
worldRenderer: VertexBuffer,
model: Model,
rot: Rotation,
rot: Rotation = Rotation.identity,
trans: Double3 = blockContext.blockCenter,
forceFlat: Boolean = false,
icon: (ShadingContext, Int, Quad) -> TextureAtlasSprite?,
postProcess: RenderVertex.(ShadingContext, Int, Quad, Int, Vertex) -> Unit
quadFilter: (Int, Quad) -> Boolean = { _, _ -> true },
icon: QuadIconResolver,
postProcess: PostProcessLambda
) {
rotation = rot
aoEnabled = Minecraft.isAmbientOcclusionEnabled()
@@ -41,21 +45,23 @@ class ModelRenderer() : ShadingContext() {
worldRenderer.ensureSpaceForQuads(model.quads.size + 1)
model.quads.forEachIndexed { quadIdx, quad ->
val drawIcon = icon(this, quadIdx, quad)
if (drawIcon != null) {
quad.verts.forEachIndexed { vertIdx, vert ->
temp.init(vert).rotate(rotation).translate(trans)
val shader = if (aoEnabled && !forceFlat) vert.aoShader else vert.flatShader
shader.shade(this, temp)
temp.postProcess(this, quadIdx, quad, vertIdx, vert)
temp.setIcon(drawIcon)
if (quadFilter(quadIdx, quad)) {
val drawIcon = icon(this, quadIdx, quad)
if (drawIcon != null) {
quad.verts.forEachIndexed { vertIdx, vert ->
temp.init(vert).rotate(rotation).translate(trans)
val shader = if (aoEnabled && !forceFlat) vert.aoShader else vert.flatShader
shader.shade(this, temp)
temp.postProcess(this, quadIdx, quad, vertIdx, vert)
temp.setIcon(drawIcon)
worldRenderer
.pos(temp.x, temp.y, temp.z)
.color(temp.red, temp.green, temp.blue, 1.0f)
.tex(temp.u, temp.v)
.lightmap(temp.brightness shr 16 and 65535, temp.brightness and 65535)
.endVertex()
worldRenderer
.pos(temp.x, temp.y, temp.z)
.color(temp.red, temp.green, temp.blue, 1.0f)
.tex(temp.u, temp.v)
.lightmap(temp.brightness shr 16 and 65535, temp.brightness and 65535)
.endVertex()
}
}
}
}
@@ -167,4 +173,4 @@ val allFaces: (EnumFacing) -> Boolean = { true }
val topOnly: (EnumFacing) -> Boolean = { it == UP }
/** Perform no post-processing */
val noPost: RenderVertex.(ShadingContext, Int, Quad, Int, Vertex) -> Unit = { ctx, qi, q, vi, v -> }
val noPost: PostProcessLambda = { _, _, _, _, _ -> }

View File

@@ -10,7 +10,7 @@ const val defaultEdgeDimming = 0.8f
// ================================
// Shader instantiation lambdas
// ================================
fun cornerAo(fallbackAxis: EnumFacing.Axis): (EnumFacing, EnumFacing, EnumFacing)->Shader = { face, dir1, dir2 ->
fun cornerAo(fallbackAxis: EnumFacing.Axis): CornerShaderFactory = { face, dir1, dir2 ->
val fallbackDir = listOf(face, dir1, dir2).find { it.axis == fallbackAxis }!!
CornerSingleFallback(face, dir1, dir2, fallbackDir)
}
@@ -20,7 +20,7 @@ fun cornerAoTri(func: (AoData, AoData)-> AoData) = { face: EnumFacing, dir1: Enu
}
val cornerAoMaxGreen = cornerAoTri { s1, s2 -> if (s1.green > s2.green) s1 else s2 }
fun cornerInterpolate(edgeAxis: EnumFacing.Axis, weight: Float, dimming: Float): (EnumFacing, EnumFacing, EnumFacing)->Shader = { dir1, dir2, dir3 ->
fun cornerInterpolate(edgeAxis: EnumFacing.Axis, weight: Float, dimming: Float): CornerShaderFactory = { dir1, dir2, dir3 ->
val edgeDir = listOf(dir1, dir2, dir3).find { it.axis == edgeAxis }!!
val faceDirs = listOf(dir1, dir2, dir3).filter { it.axis != edgeAxis }
CornerInterpolateDimming(faceDirs[0], faceDirs[1], edgeDir, weight, dimming)

View File

@@ -10,6 +10,10 @@ import net.minecraft.util.EnumFacing.*
import java.lang.Math.min
import java.util.*
typealias EdgeShaderFactory = (EnumFacing, EnumFacing) -> Shader
typealias CornerShaderFactory = (EnumFacing, EnumFacing, EnumFacing) -> Shader
typealias ShaderFactory = (Quad, Vertex) -> Shader
/** Holds shading values for block corners as calculated by vanilla Minecraft rendering. */
class AoData() {
var valid = false
@@ -140,8 +144,8 @@ interface Shader {
* @param[edge] shader instantiation lambda for edge midpoint vertices
*/
fun faceOrientedAuto(overrideFace: EnumFacing? = null,
corner: ((EnumFacing, EnumFacing, EnumFacing)->Shader)? = null,
edge: ((EnumFacing, EnumFacing)->Shader)? = null) =
corner: CornerShaderFactory? = null,
edge: EdgeShaderFactory? = null) =
fun(quad: Quad, vertex: Vertex): Shader {
val quadFace = overrideFace ?: quad.normal.nearestCardinal
val nearestCorner = nearestPosition(vertex.xyz, faceCorners[quadFace.ordinal].asList) {
@@ -167,7 +171,7 @@ fun faceOrientedAuto(overrideFace: EnumFacing? = null,
* @param[corner] shader instantiation lambda
*/
fun edgeOrientedAuto(overrideEdge: Pair<EnumFacing, EnumFacing>? = null,
corner: (EnumFacing, EnumFacing, EnumFacing)->Shader) =
corner: CornerShaderFactory) =
fun(quad: Quad, vertex: Vertex): Shader {
val edgeDir = overrideEdge ?: nearestAngle(quad.normal, boxEdges) { it.first.vec + it.second.vec }.first
val nearestFace = nearestPosition(vertex.xyz, edgeDir.toList()) { it.vec }.first

View File

@@ -16,6 +16,7 @@ val axisDirs = listOf(POSITIVE, NEGATIVE)
val EnumFacing.dir: AxisDirection get() = axisDirection
val AxisDirection.sign: String get() = when(this) { POSITIVE -> "+"; NEGATIVE -> "-" }
val forgeDirs = EnumFacing.values()
val forgeDirsHorizontal = listOf(NORTH, SOUTH, EAST, WEST)
val forgeDirOffsets = forgeDirs.map { Int3(it) }
val Pair<Axis, AxisDirection>.face: EnumFacing get() = when(this) {
X to POSITIVE -> EAST; X to NEGATIVE -> WEST;

View File

@@ -43,7 +43,7 @@ fun Any.reflectFieldsOfType(vararg types: Class<*>) = this.javaClass.declaredFie
.map { field -> field.name to field.let { it.isAccessible = true; it.get(this) } }
.filterNotNull()
enum class Namespace { OBF, SRG, MCP }
enum class Namespace { MCP, SRG }
abstract class Resolvable<T> {
abstract fun resolve(): T?
@@ -56,11 +56,9 @@ fun allAvailable(vararg codeElement: Resolvable<*>) = codeElement.all { it.eleme
/**
* Reference to a class.
*
* @param[mcpName] MCP name of the class
* @param[obfName] obfuscated name of the class
* @param[name] MCP name of the class
*/
open class ClassRef(val mcpName: String, val obfName: String) : Resolvable<Class<*>>() {
constructor(mcpName: String) : this(mcpName, mcpName)
open class ClassRef(val name: String) : Resolvable<Class<*>>() {
companion object {
val int = ClassRefPrimitive("I", Int::class.java)
@@ -70,10 +68,9 @@ open class ClassRef(val mcpName: String, val obfName: String) : Resolvable<Class
val void = ClassRefPrimitive("V", null)
}
fun name(namespace: Namespace) = if (namespace == Namespace.OBF) obfName else mcpName
open fun asmDescriptor(namespace: Namespace) = "L${name(namespace).replace(".", "/")};"
open fun asmDescriptor(namespace: Namespace) = "L${name.replace(".", "/")};"
override fun resolve() = listOf(mcpName, obfName).map { getJavaClass(it) }.filterNotNull().firstOrNull()
override fun resolve() = getJavaClass(name)
fun isInstance(obj: Any) = element?.isInstance(obj) ?: false
}
@@ -85,17 +82,16 @@ open class ClassRef(val mcpName: String, val obfName: String) : Resolvable<Class
* @param[clazz] class of this primitive type
*/
class ClassRefPrimitive(name: String, val clazz: Class<*>?) : ClassRef(name) {
override fun asmDescriptor(namespace: Namespace) = mcpName
override fun asmDescriptor(namespace: Namespace) = name
override fun resolve() = clazz
}
class ClassRefArray(mcpName: String, obfName: String) : ClassRef(mcpName, obfName) {
constructor(mcpName: String) : this(mcpName, mcpName)
class ClassRefArray(name: String) : ClassRef(name) {
override fun asmDescriptor(namespace: Namespace) = "[" + super.asmDescriptor(namespace)
override fun resolve() = listOf(mcpName, obfName).map { getJavaClass("[L$it;") }.filterNotNull().firstOrNull()
override fun resolve() = getJavaClass("[L$name;")
}
fun ClassRef.array() = ClassRefArray(mcpName, obfName)
fun ClassRef.array() = ClassRefArray(name)
/**
* Reference to a method.
@@ -103,30 +99,26 @@ fun ClassRef.array() = ClassRefArray(mcpName, obfName)
* @param[parentClass] reference to the class containing the method
* @param[mcpName] MCP name of the method
* @param[srgName] SRG name of the method
* @param[obfName] obfuscated name of the method
* @param[returnType] reference to the return type
* @param[returnType] references to the argument types
*/
class MethodRef(val parentClass: ClassRef,
val mcpName: String,
val srgName: String?,
val obfName: String?,
val srgName: String,
val returnType: ClassRef,
vararg argTypes: ClassRef
vararg val argTypes: ClassRef
) : Resolvable<Method>() {
constructor(parentClass: ClassRef, mcpName: String, returnType: ClassRef, vararg argTypes: ClassRef) :
this(parentClass, mcpName, mcpName, mcpName, returnType, *argTypes)
this(parentClass, mcpName, mcpName, returnType, *argTypes)
val argTypes = argTypes
fun name(namespace: Namespace) = when(namespace) { OBF -> obfName!!; SRG -> srgName!!; MCP -> mcpName }
fun name(namespace: Namespace) = when(namespace) { SRG -> srgName; MCP -> mcpName }
fun asmDescriptor(namespace: Namespace) = "(${argTypes.map { it.asmDescriptor(namespace) }.fold(""){ s1, s2 -> s1 + s2 } })${returnType.asmDescriptor(namespace)}"
override fun resolve(): Method? =
if (parentClass.element == null || argTypes.any { it.element == null }) null
else {
val args = argTypes.map { it.element!! }.toTypedArray()
listOf(srgName!!, mcpName).map { tryDefault(null) {
listOf(srgName, mcpName).map { tryDefault(null) {
parentClass.element!!.getDeclaredMethod(it, *args)
}}.filterNotNull().firstOrNull()
?.apply { isAccessible = true }
@@ -146,24 +138,22 @@ class MethodRef(val parentClass: ClassRef,
* @param[parentClass] reference to the class containing the field
* @param[mcpName] MCP name of the field
* @param[srgName] SRG name of the field
* @param[obfName] obfuscated name of the field
* @param[type] reference to the field type
*/
class FieldRef(val parentClass: ClassRef,
val mcpName: String,
val srgName: String?,
val obfName: String?,
val srgName: String,
val type: ClassRef?
) : Resolvable<Field>() {
constructor(parentClass: ClassRef, mcpName: String, type: ClassRef?) : this(parentClass, mcpName, mcpName, mcpName, type)
constructor(parentClass: ClassRef, mcpName: String, type: ClassRef?) : this(parentClass, mcpName, mcpName, type)
fun name(namespace: Namespace) = when(namespace) { OBF -> obfName!!; SRG -> srgName!!; MCP -> mcpName }
fun name(namespace: Namespace) = when(namespace) { SRG -> srgName; MCP -> mcpName }
fun asmDescriptor(namespace: Namespace) = type!!.asmDescriptor(namespace)
override fun resolve(): Field? =
if (parentClass.element == null) null
else {
listOf(srgName!!, mcpName).map { tryDefault(null) {
listOf(srgName, mcpName).map { tryDefault(null) {
parentClass.element!!.getDeclaredField(it)
}}.filterNotNull().firstOrNull()
?.apply{ isAccessible = true }

View File

@@ -1,7 +1,6 @@
package mods.octarinecore.metaprog
import mods.octarinecore.metaprog.Namespace.MCP
import mods.octarinecore.metaprog.Namespace.OBF
import mods.octarinecore.metaprog.Namespace.*
import net.minecraft.launchwrapper.IClassTransformer
import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin
import org.apache.logging.log4j.LogManager
@@ -29,9 +28,6 @@ open class Transformer : IClassTransformer {
val log = LogManager.getLogger(this)
/** The type of environment we are in. Assume MCP until proven otherwise. */
var environment: Namespace = MCP
/** The list of transformers and targets. */
var methodTransformers: MutableList<Pair<MethodRef, MethodTransformContext.()->Unit>> = arrayListOf()
@@ -44,36 +40,28 @@ open class Transformer : IClassTransformer {
override fun transform(name: String?, transformedName: String?, classData: ByteArray?): ByteArray? {
if (classData == null) return null
if (name != transformedName) environment = OBF
val classNode = ClassNode().apply { val reader = ClassReader(classData); reader.accept(this, 0) }
var workDone = false
val transformations: List<Pair<MethodTransformContext.()->Unit, MethodNode?>> = methodTransformers.map { transformer ->
if (transformedName != transformer.first.parentClass.mcpName) return@map transformer.second to null
log.debug("Found class: $name -> $transformedName")
log.debug(" searching: ${transformer.first.name(OBF)} ${transformer.first.asmDescriptor(OBF)} -> ${transformer.first.name(MCP)} ${transformer.first.asmDescriptor(MCP)}")
transformer.second to classNode.methods.find {
log.debug(" ${it.name} ${it.desc}")
synchronized(this) {
methodTransformers.forEach { (targetMethod, transform) ->
if (transformedName != targetMethod.parentClass.name) return@forEach
it.name == transformer.first.name(MCP) && it.desc == transformer.first.asmDescriptor(MCP) ||
it.name == transformer.first.name(OBF) && it.desc == transformer.first.asmDescriptor(OBF)
}
}
transformations.filter { it.second != null }.forEach {
synchronized(it.second!!) {
try {
val trans = it.first
MethodTransformContext(it.second!!, environment).trans()
for (method in classNode.methods) {
val namespace = Namespace.values().find {
method.name == targetMethod.name(it) && method.desc == targetMethod.asmDescriptor(it)
} ?: continue
when (namespace) {
MCP -> log.info("Found method ${targetMethod.parentClass.name}.${targetMethod.name(MCP)} ${targetMethod.asmDescriptor(MCP)}")
SRG -> log.info("Found method ${targetMethod.parentClass.name}.${targetMethod.name(namespace)} ${targetMethod.asmDescriptor(namespace)} (matching ${targetMethod.name(MCP)})")
}
MethodTransformContext(method, namespace).transform()
workDone = true
} catch (e: Throwable) {
log.warn("Error transforming method ${it.second!!.name} ${it.second!!.desc}")
}
}
}
return if (!workDone) classData else ClassWriter(3).apply { classNode.accept(this) }.toByteArray()
return if (!workDone) classData else ClassWriter(0).apply { classNode.accept(this) }.toByteArray()
}
}
@@ -169,7 +157,7 @@ class MethodTransformContext(val method: MethodNode, val environment: Namespace)
fun invokeRef(ref: MethodRef): (AbstractInsnNode)->Boolean = { insn ->
(insn as? MethodInsnNode)?.let {
it.name == ref.name(environment) && it.owner == ref.parentClass.name(environment).replace(".", "/")
it.name == ref.name(environment) && it.owner == ref.parentClass.name.replace(".", "/")
} ?: false
}
}
@@ -202,7 +190,7 @@ class InstructionList(val environment: Namespace) {
*/
fun invokeStatic(target: MethodRef, isInterface: Boolean = false) = list.add(MethodInsnNode(
Opcodes.INVOKESTATIC,
target.parentClass.name(environment).replace(".", "/"),
target.parentClass.name.replace(".", "/"),
target.name(environment),
target.asmDescriptor(environment),
isInterface
@@ -215,7 +203,7 @@ class InstructionList(val environment: Namespace) {
*/
fun getField(target: FieldRef) = list.add(FieldInsnNode(
Opcodes.GETFIELD,
target.parentClass.name(environment).replace(".", "/"),
target.parentClass.name.replace(".", "/"),
target.name(environment),
target.asmDescriptor(environment)
))

View File

@@ -1,8 +1,8 @@
// Vanilla
net.minecraft.block.BlockTallGrass
net.minecraft.block.BlockCrops
net.minecraft.block.BlockReed
net.minecraft.block.BlockDoublePlant
-net.minecraft.block.BlockReed
-net.minecraft.block.BlockDoublePlant
-net.minecraft.block.BlockCarrot
-net.minecraft.block.BlockPotato