Skip to content
LlamaLad7 edited this page Jan 14, 2024 · 7 revisions

Allows you to capture local variables wherever you need them. Targeting the variables works in exactly the same way as explained here, so I encourage you to read that.

Possible parameters could look like:

  • @Local double fov (captures the only local of type double and throws an error if there is more than one)
  • @Local(ordinal = 1) BlockPos pos (captures the second local of type BlockPos)
  • @Local(index = 3) int x (captures the local with LVT index 3)

Example

When targeting code such as the following:

boolean bl1 = complexThing1() && complexThing2() || complexThing3();
boolean bl2 = !complexThing4() || complexThing5();

you may wish to change bl2 in such a way that requires the value of bl1.

This could be done like so:

@ModifyVariable(method = "targetMethod", at = @At("STORE"), ordinal = 1)
private boolean modifybl2ForReasons(boolean original, @Local(ordinal = 0) boolean bl1) {
	return original && YourMod.anotherComplexThing(bl1);
}

Your ModifyVariable would work as normal, modifying bl2, but you also receive the value of bl1.

Code Diff

  boolean bl2 = !complexThing4() || complexThing5();
+ bl2 = modifybl2ForReasons(bl2, bl1);

Mutability

@Local also allows you to capture mutable references to local variables. Targeting the locals works in exactly the same way as above, but instead of the local's type, you use the corresponding reference type.

Possible parameters could look like:

  • @Local LocalDoubleRef fov (captures a reference to the only local of type double and throws an error if there is more than one)
  • @Local(ordinal = 1) LocalRef<BlockPos> pos (captures a reference to the second local of type BlockPos)
  • @Local(index = 3) LocalIntRef x (captures a reference to the local with LVT index 3).

These reference types have get and set methods providing both read and write access to the variable in question.

Example

When targeting code such as the following:

String playerName = player.getName();
int color = 0xFFFFFFFF;

if (player.isSneaking()) {
	// ...
}
// ...

you may wish to modify both variables at the same time.

This could be done like so:

@Inject(method = "targetMethod", at = @At(value = "INVOKE", target = "Lsome/package/Player;isSneaking()Z"))
private void changeNameAndColor(CallbackInfo ci, @Local LocalRef<String> name, @Local LocalIntRef color) {
	if (name.get().equals("LlamaLad7")) {
		name.set("Herobrine");
		color.set(0xFFFF0000);
	}
}

Your Inject would be passed references to both variables, and your new values would be assigned to the actual variables when your handler method finishes.

Code Diff

  String playerName = player.getName();
  int color = 0xFFFFFFFF;

+ LocalRef ref1 = new LocalRefImpl(playerName);
+ LocalIntRef ref2 = new LocalIntRefImpl(color);
+ changeNameAndColor(null, ref1, ref2);
+ color = ref2.get();
+ playerName = ref1.get();
  if (player.isSneaking()) {
   	  // ...
  }
  // ...