tutorial:mixin_injects
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
tutorial:mixin_injects [2020/02/07 01:45] – clean up example draylar | tutorial:mixin_injects [2022/03/08 18:56] – Added interface inection section. salvopelux | ||
---|---|---|---|
Line 2: | Line 2: | ||
===== Introduction ===== | ===== Introduction ===== | ||
- | Injects allows you to place custom code at a specified position inside an existing method. For a functional | + | Injects allows you to place custom code at a specified position inside an existing method. For a working |
<code java> | <code java> | ||
Line 19: | Line 19: | ||
| TAIL | Before the final return statement | | | TAIL | Before the final return statement | | ||
- | In the case of injection points that reference statements or members, the target value can be set inside //@At//. | + | In the case of injection points that reference statements or members, the target value can be set inside //@At//. Target value is specified using JVM bytecode descriptors. |
+ | |||
+ | Oracle defines the following [[https:// | ||
+ | |||
+ | ^ Descriptor ^ Primitive ^ Description ^ | ||
+ | | B | byte | signed byte | | ||
+ | | C | char | Unicode character code point in the Basic Multilingual Plane, encoded with UTF-16 | | ||
+ | | D | double | double-precision floating-point value | | ||
+ | | F | float | single-precision floating-point value | | ||
+ | | I | int | integer | | ||
+ | | J | long | long integer | | ||
+ | | L// | ||
+ | | S | short | signed short | | ||
+ | | Z | boolean | '' | ||
+ | | [ | reference | one array dimension | | ||
+ | |||
+ | A method descriptor is comprised of the method name, followed by a set of parentheses containing the input types, followed by the output type. A method defined in Java as '' | ||
+ | |||
+ | Generics' | ||
//@Inject// methods always have a void return type. The method name does not matter; using something that describes what the inject does is best. The target method' | //@Inject// methods always have a void return type. The method name does not matter; using something that describes what the inject does is best. The target method' | ||
=== Returning & Cancelling from Inject === | === Returning & Cancelling from Inject === | ||
- | To cancel or return early inside a method, use '' | + | To cancel or return early inside a method, use '' |
<code java> | <code java> | ||
@Inject(method = " | @Inject(method = " | ||
</ | </ | ||
+ | |||
+ | |||
+ | === Injecting into Constructors === | ||
+ | To inject into a constructor, | ||
+ | |||
+ | To inject into a static constructor, | ||
===== Practical Example ===== | ===== Practical Example ===== | ||
- | The following example injects a print statement at the top of '' | + | The following example injects a print statement at the top of '' |
<code java [enable_line_numbers=" | <code java [enable_line_numbers=" | ||
Line 42: | Line 66: | ||
</ | </ | ||
- | For more information on this particular example, view its usage in the [[Fabric Example Mod repo]]. | + | For more information on this particular example, view its usage in the [[https:// |
+ | |||
+ | ====== Inject an interface ====== | ||
+ | |||
+ | This is a new tecnique introduced by Loom 0.11 to add methods into a specific existing class. | ||
+ | More specifically, | ||
+ | As result the target class will acquire all the methods of the interface, as if it always had them. | ||
+ | Interface injection is a compile time only feature, this means that a Mixin should also be used to implement the interface into the target class. | ||
+ | |||
+ | This is particulatly useful for libraries, with this you can add new methods to existing classes and use them without the need of casting or reimplementing the interface every time. | ||
+ | |||
+ | Let's explain better with an example: | ||
+ | |||
+ | The scope of this example is to add the following method into FlowableFluid to get the sound of the bucket when emptied. | ||
+ | This, normally, is not possible because FlowableFluid does not has a similar method. | ||
+ | |||
+ | <code java [enable_line_numbers=" | ||
+ | Optional< | ||
+ | </ | ||
+ | |||
+ | To add the method into the class, first of all you need to create an interface with it: | ||
+ | |||
+ | <code java [enable_line_numbers=" | ||
+ | package net.fabricmc.example; | ||
+ | |||
+ | public interface BucketEmptySoundGetter { | ||
+ | Optional< | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Now you need to implement this interface into FlowableFluid with a mixin implementing the interface: | ||
+ | |||
+ | <code java [enable_line_numbers=" | ||
+ | @Mixin(FlowableFluid.class) | ||
+ | public class MixinFlowableFluid implements BucketEmptySoundGetter { | ||
+ | @Override | ||
+ | public Optional< | ||
+ | |||
+ | return Optional.of(((FlowableFluid) (Object) this).isIn(FluidTags.LAVA) ? SoundEvents.ITEM_BUCKET_EMPTY_LAVA : SoundEvents.ITEM_BUCKET_EMPTY); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Lastly you need to inject the interface into FabricFluid. | ||
+ | The following snippet can be added to your fabric.mod.json file to add one or more interfaces to the net/ | ||
+ | |||
+ | <code json [enable_line_numbers=" | ||
+ | { | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Now you can use the new method: | ||
+ | |||
+ | <code java [enable_line_numbers=" | ||
+ | Optional< | ||
+ | </ | ||
+ | |||
+ | You could also override this method in classes extending FlowableFluid to implement custom behaviours. |
tutorial/mixin_injects.txt · Last modified: 2022/08/05 19:19 by clomclem