Skip to content

Commit

Permalink
PreLaunch: Add ModifyVariable generator
Browse files Browse the repository at this point in the history
  • Loading branch information
mattco98 committed Jun 22, 2023
1 parent 8a7ff40 commit 18ea997
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 7 deletions.
17 changes: 17 additions & 0 deletions src/main/kotlin/com/chattriggers/ctjs/launch/annotations.kt
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,23 @@ data class ModifyReturnValue(
val allow: Int?,
) : IInjector

data class ModifyVariable(
val method: String,
val at: At,
val slice: Slice?,
val print: Boolean?,
val ordinal: Int?,
val index: Int?,
val type: String?,
val parameterName: String?,
val locals: List<Local>?,
val remap: Boolean?,
val require: Int?,
val expect: Int?,
val allow: Int?,
val constraints: String?,
) : IInjector

data class WrapOperation(
val method: String,
val at: At?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ internal class DynamicMixinGenerator(private val ctx: GenerationContext, private
is ModifyExpressionValue -> ModifyExpressionValueGenerator(ctx, id, injector).generate()
is ModifyReceiver -> ModifyReceiverGenerator(ctx, id, injector).generate()
is ModifyReturnValue -> ModifyReturnValueInjector(ctx, id, injector).generate()
is ModifyVariable -> ModifyVariableGenerator(ctx, id, injector).generate()
is WrapOperation -> WrapOperationGenerator(ctx, id, injector).generate()
is WrapWithCondition -> WrapWithConditionGenerator(ctx, id, injector).generate()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.chattriggers.ctjs.launch.generation

import com.chattriggers.ctjs.launch.Local
import com.chattriggers.ctjs.launch.ModifyVariable
import com.chattriggers.ctjs.utils.descriptorString
import org.objectweb.asm.tree.MethodNode
import org.spongepowered.asm.mixin.injection.ModifyVariable as SPModifyVariable

internal class ModifyVariableGenerator(
ctx: GenerationContext,
id: Int,
private var modifyVariable: ModifyVariable,
) : InjectorGenerator(ctx, id) {
override val type = "modifyVariable"

override fun getInjectionSignature(): InjectionSignature {
val (mappedMethod, method) = ctx.findMethod(modifyVariable.method)

// Construct a temporary local so we can call Utils.getParameterFromLocal
val tempLocal = Local(
modifyVariable.print,
modifyVariable.parameterName,
modifyVariable.index,
modifyVariable.ordinal,
modifyVariable.type,
mutable = false,
)

val parameter = Utils.getParameterFromLocal(tempLocal, mappedMethod, name = "ModifyVariable")

// Update our ModifyVariable annotation since we may have changed the index
modifyVariable = modifyVariable.copy(
index = parameter.local?.index ?: modifyVariable.index,
)

return InjectionSignature(
mappedMethod,
listOf(parameter.copy(local = null)),
parameter.descriptor,
method.isStatic,
)
}

override fun attachAnnotation(node: MethodNode, signature: InjectionSignature) {
node.visitAnnotation(SPModifyVariable::class.descriptorString(), true).apply {
visit("method", listOf(signature.targetMethod.toFullDescriptor()))
visit("at", Utils.createAtAnnotation(modifyVariable.at))
if (modifyVariable.slice != null)
visit("slice", Utils.createSliceAnnotation(modifyVariable.slice!!))
if (modifyVariable.print != null)
visit("print", modifyVariable.print)
if (modifyVariable.ordinal != null)
visit("ordinal", modifyVariable.ordinal)
if (modifyVariable.index != null)
visit("index", modifyVariable.index)
if (modifyVariable.remap != null)
visit("remap", modifyVariable.remap)
if (modifyVariable.require != null)
visit("require", modifyVariable.require)
if (modifyVariable.expect != null)
visit("expect", modifyVariable.expect)
if (modifyVariable.allow != null)
visit("allow", modifyVariable.allow)
if (modifyVariable.constraints != null)
visit("constraints", modifyVariable.constraints)
visitEnd()
}
}
}
16 changes: 10 additions & 6 deletions src/main/kotlin/com/chattriggers/ctjs/launch/generation/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,11 @@ internal object Utils {
error("Unable to match method $descriptor in class ${mappedClass.name.original}")
}

fun getParameterFromLocal(local: Local, method: Mappings.MappedMethod): InjectorGenerator.Parameter {
fun getParameterFromLocal(
local: Local,
method: Mappings.MappedMethod,
name: String = "Local",
): InjectorGenerator.Parameter {
var modifiedLocal = local

val descriptor = when {
Expand All @@ -183,7 +187,7 @@ internal object Utils {
}
local.parameterName != null -> {
require(local.type == null && local.index == null && local.ordinal == null) {
"Local that specifies parameterName cannot specify type, index, or ordinal"
"$name that specifies parameterName cannot specify type, index, or ordinal"
}

val parameter = method.parameters.find { p -> p.name.original == local.parameterName }
Expand All @@ -194,16 +198,16 @@ internal object Utils {
local.type != null -> {
if (local.index != null) {
require(local.ordinal == null) {
"Local that specifies a type and index cannot specify an ordinal"
"$name that specifies a type and index cannot specify an ordinal"
}
} else {
require(local.ordinal != null) {
"Local that specifies a type must also specify an index or ordinal"
"$name that specifies a type must also specify an index or ordinal"
}
}
Descriptor.Object(local.type)
Descriptor.Parser(local.type).parseType(full = true)
}
else -> error("Local must specify one of the following options: \"print\"; \"parameterName\"; " +
else -> error("$name must specify one of the following options: \"print\"; \"parameterName\"; " +
"\"type\" and either \"ordinal\" or \"index\"")
}

Expand Down
63 changes: 62 additions & 1 deletion src/main/resources/assets/chattriggers/js/mixinProvidedLibs.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
const ModifyExpressionValueObj = Java.type('com.chattriggers.ctjs.launch.ModifyExpressionValue');
const ModifyReceiverObj = Java.type('com.chattriggers.ctjs.launch.ModifyReceiver');
const ModifyReturnValueObj = Java.type('com.chattriggers.ctjs.launch.ModifyReturnValue');
const ModifyVariableObj = Java.type('com.chattriggers.ctjs.launch.ModifyVariable');
const WrapOperationObj = Java.type('com.chattriggers.ctjs.launch.WrapOperation');
const WrapWithConditionObj = Java.type('com.chattriggers.ctjs.launch.WrapWithCondition');

Expand Down Expand Up @@ -297,6 +298,12 @@
return this._createModifyReturnValue(obj);
}

modifyVariable(obj) {
if (typeof obj != 'object')
throw new Error('Mixin.modifyVariable() expects an object as its first argument');
return this._createModifyVariable(obj);
}

wrapOperation(obj) {
if (typeof obj != 'object')
throw new Error('Mixin.wrapOperation() expects an object as its first argument');
Expand Down Expand Up @@ -641,11 +648,65 @@
require,
expect,
allow,
)
);

return JSLoader.registerInjector(this.mixinObj, modifyReturnValueObj);
}

_createModifyVariable(obj) {
const method = obj.method ?? throw new Error('ModifyVariable.method must be specified');
const at = obj.at ?? throw new Error('ModifyVariable.at must be specified');
const slice = obj.slice;
const print = obj.print;
const ordinal = obj.ordinal;
const index = obj.index;
const type = obj.type;
const parameterName = obj.parameterName;
let locals = obj.locals;
if (locals instanceof Local)
locals = [locals];
const remap = obj.remap;
const require = obj.require;
const expect = obj.expect;
const allow = obj.allow;
const constraints = obj.constraints;

assertType(method, 'string', 'ModifyVariable.method');
assertType(at, At, 'ModifyVariable.at');
assertType(slice, Slice, 'ModifyVariable.slice');
assertType(remap, 'boolean', 'ModifyVariable.remap');
assertType(print, 'boolean', 'ModifyVariable.print');
assertType(ordinal, 'number', 'ModifyVariable.ordinal');
assertType(index, 'number', 'ModifyVariable.index');
assertType(type, 'string', 'ModifyVariable.type');
assertType(parameterName, 'string', 'ModifyVariable.type');
assertArrayType(locals, Local, 'ModifyVariable.locals');
assertType(remap, 'number', 'ModifyVariable.remap');
assertType(require, 'number', 'ModifyVariable.require');
assertType(expect, 'number', 'ModifyVariable.expect');
assertType(allow, 'number', 'ModifyVariable.allow');
assertType(constraints, 'string', 'ModifyVariable.constraints');

const modifyVariableObj = new ModifyVariableObj(
method,
at?.atObj,
slice?.sliceObj,
print,
ordinal,
index,
type,
parameterName,
locals?.map(l => l.localObj),
remap,
require,
expect,
allow,
constraints,
);

return JSLoader.registerInjector(this.mixinObj, modifyVariableObj);
}

_createWrapOperation(obj) {
const method = obj.method ?? throw new Error('WrapOperation.method must be specified');
const at = obj.at;
Expand Down

0 comments on commit 18ea997

Please sign in to comment.