User Tools

Site Tools


tutorial:mixin_injects

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
tutorial:mixin_injects [2025/12/02 17:51] – Added section on shifting gauntreclusetutorial:mixin_injects [2025/12/15 16:52] (current) – Added an extra bracket to show that it has to be inside @At more clearly mcgambingpro
Line 17: Line 17:
   * Adding a consistent operation at a part of a target method, without the intent of replacing any of the existing operations.   * Adding a consistent operation at a part of a target method, without the intent of replacing any of the existing operations.
   * Populating fields added by a Mixin class, via an injection at the tail of the target class's constructor.   * Populating fields added by a Mixin class, via an injection at the tail of the target class's constructor.
 +  * Adding new operations at the head or tail of a method body.
  
-It is important to not use ''@Inject'', and in particular its cancelling, if the goal can be achieved with a more precise and less intrusive changes. For instance, injectors such as ''[[https://github.com/LlamaLad7/MixinExtras/wiki/WrapOperation|@WrapOperation]]'' are better suited for preventing or diverting individual calls or operations, without cancelling the entire method. 
  
 +==== Limitations and Alternatives ====
 +
 +=== Cancelling, Modifying or Diverting individual operations ===
 +It is important to not use ''@Inject'', and in particular its cancelling, if the goal can be achieved with a more precise and less intrusive changes. Injectors such as ''[[https://github.com/LlamaLad7/MixinExtras/wiki/WrapOperation|@WrapOperation]]'', [[https://github.com/LlamaLad7/MixinExtras/wiki/ModifyExpressionValue|@ModifyExpressionValue]], [[https://github.com/LlamaLad7/MixinExtras/wiki/ModifyReturnValue|@ModifyReturnValue]] or ''@ModifyArg'' are better-suited for preventing, modifying or diverting individual calls or operations, without cancelling the entire method; or applying modifications to a return value.
 +
 +=== Context-Sensitive Injections ===
 +FIXME //This section should use a more concrete example.//
 +
 +''@Inject'' lacks context when injecting relative to a specific operation.\\
 +For example, say we had the following code snippet:
 +<code java>
 +public void calculateSlap(int quantity, Person haykam) {
 +    /*...*/
 +    float force = complexCalculation(quantity);
 +    haykam.slap(quantity, force / haykam.resistance);
 +    
 +    /*...*/
 +}
 +</code>
 +if we wished to inject right after the ''slap'' call, we could use a [[#shifting|Shift]] to inject after the call with ''@Inject''. However, if we needed to also get the ''force / haykam.resistance'' value, it would be instead preferable to use a ''@WrapOperation'' to get it without needing to use ''@Local'' on ''force'' to then recalculate it.\\
 +For the sake of showing how to appropriately add our new operations after the original method call outside of void returns, we'll say ''slap'' has a ''boolean'' return value.
 +<code java>
 +@WrapOperation(method = "calculateSlap", at = @At(value = "INVOKE", target = "Lnet/fabricmc/haykam_slapper/people/Person;slap(IF)Z;"))
 +private boolean onHaykamSlapped(Person instance, int quantity, float forceOverResistance, Operation<Boolean> original) {
 +    boolean originalValue = original.call(instance, quantity, forceOverResistance);
 +    newOperations(forceOverResistance, instance);
 +    return originalValue;
 +}
 +</code>
 +This allows us to get the returned value of the ''force / haykam.resistance'' expression without needing to separately recalculate it via capturing the ''force'' variable, which may be especially brittle if there are other ''float'' variables earlier in the method body.
 +
 +:!: Note that ''@Local'' capture is particularly brittle specifically in the context of obfuscated code, mainly Minecraft code. However unofbuscated code such as other mods or as Minecraft will be starting on version 26.1, where obfuscation will be removed from the game does not imply the same level of brittleness for local capture. This is because unobfuscated code will allow to target and capture locals by name rather than needing to only rely on type, ordinal or index which can often be brittle.
 +
 +In summary of this subsection, ''@Inject'' should be avoided when it may lack in the context it can naturally about variables or operations it is injecting relative to, or when the intention is to modify individual operations within a method, as there are more precise and expressive injectors for those situations.
 ===== Structure ===== ===== Structure =====
 A barebones structure of ''@Inject'' would look as follows: A barebones structure of ''@Inject'' would look as follows:
Line 100: Line 134:
 The only common form of shifting comes in the form of using ''shift = At.Shift.AFTER'' within the ''@At''. This shifts the injection point to after the target. The syntax for shifting looks as follows: The only common form of shifting comes in the form of using ''shift = At.Shift.AFTER'' within the ''@At''. This shifts the injection point to after the target. The syntax for shifting looks as follows:
 <code java> <code java>
-@Inject(method = "...", at = @At(value = "...", target = "...", shift = At.Shift.AFTER)+@Inject(method = "...", at = @At(value = "...", target = "...", shift = At.Shift.AFTER))
 </code> </code>
tutorial/mixin_injects.1764697880.txt.gz · Last modified: 2025/12/02 17:51 by gauntrecluse