Merge branch 'kotlin-1.10' into kotlin-1.11.2
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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 = { _, _, _, _, _ -> }
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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)
|
||||
))
|
||||
|
||||
Reference in New Issue
Block a user