tutorial:mixin_your_first_mixin
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| tutorial:mixin_your_first_mixin [2025/10/16 10:08] – Extra tweaks; Likely soon exiting drafting; Remove tutorial repo links gauntrecluse | tutorial:mixin_your_first_mixin [2025/11/16 13:35] (current) – Minor fixes to try and simplify wordings and fix typos gauntrecluse | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | :!: //This page is currently a draft! It is not intended to be read by users of the wiki yet. Feedback will be appreciated but trust this page's information at your own risk!//\\ | + | ====== Tutorial: Making your first Mixin ====== |
| - | //Contact GauntRecluse (paleintrovert) on Discord to give feedback and suggestions on this draft// | + | |
| - | + | ||
| - | ====== Tutorial: Making your first Mixin (DRAFT) | + | |
| ===== Preamble ===== | ===== Preamble ===== | ||
| - | This is meant to be complementary to the [[tutorial: | + | This is meant to be complementary to the [[tutorial: |
| See [[tutorial: | See [[tutorial: | ||
| Line 18: | Line 15: | ||
| For this task, we'll use the injector '' | For this task, we'll use the injector '' | ||
| - | It is important to note that we use '' | + | It is important to note that we use '' |
| The reason '' | The reason '' | ||
| Line 24: | Line 21: | ||
| < | < | ||
| @Mixin(MinecraftServer.class) | @Mixin(MinecraftServer.class) | ||
| - | public | + | abstract class TutorialFirstMixin { |
| } | } | ||
| </ | </ | ||
| - | It is conventional practice to name your Mixin classes the target class with '' | + | It is conventional practice to name your Mixin classes the target class with '' |
| - | You'll notice we made the Mixin class '' | + | You'll notice we made the Mixin class '' |
| Accordingly, | Accordingly, | ||
| Line 55: | Line 52: | ||
| < | < | ||
| @Mixin(MinecraftServer.class) | @Mixin(MinecraftServer.class) | ||
| - | public | + | abstract class TutorialFirstMixin { |
| - | private void addLoggerAtHead() { | + | private void logOnWorldLoad() { |
| } | } | ||
| } | } | ||
| </ | </ | ||
| - | Your Mixin injectors' | + | Your Mixin injectors' |
| Next, we add the annotation: | Next, we add the annotation: | ||
| < | < | ||
| - | public | + | abstract class TutorialFirstMixin { |
| @Inject(method = " | @Inject(method = " | ||
| - | private void addLoggerAtHead() { | + | private void logOnWorldLoad() { |
| | | ||
| } | } | ||
| Line 75: | Line 72: | ||
| </ | </ | ||
| - | This now specifies to Mixin that, when this method gets merged into '' | + | This now specifies to Mixin that, when this method gets merged into '' |
| Now, to specify where in the targeted method we want our injection to happen, we add something that may be a bit counterintuitive to some, an '' | Now, to specify where in the targeted method we want our injection to happen, we add something that may be a bit counterintuitive to some, an '' | ||
| < | < | ||
| - | public | + | abstract class TutorialFirstMixin { |
| - | @Inject(method = " | + | @Inject(method = " |
| - | | + | private void logOnWorldLoad() { |
| - | | + | |
| - | private void addLoggerAtHead() { | + | |
| } | } | ||
| } | } | ||
| </ | </ | ||
| - | |||
| - | It is not necessary to put the different fields on different lines in your code, but it may become useful when the individual arguments are very long or if you prefer it for organization purposes. | ||
| Now, let's look closer at the annotations we have thus far. Think of them as holding a series of hierarchized instructions. A very simplified explanation would be: | Now, let's look closer at the annotations we have thus far. Think of them as holding a series of hierarchized instructions. A very simplified explanation would be: | ||
| Line 95: | Line 88: | ||
| * '' | * '' | ||
| * '' | * '' | ||
| - | * '' | + | * '' |
| //Sidenote: one does not need to put '' | //Sidenote: one does not need to put '' | ||
| - | Now, if you're following along with MCDev you'll likely notice that our handler method, '' | + | Now, if you're following along with MCDev you'll likely notice that our handler method, '' |
| If we fix the signature and add a call to our mod's logger, the full class becomes: | If we fix the signature and add a call to our mod's logger, the full class becomes: | ||
| < | < | ||
| @Mixin(MinecraftServer.class) | @Mixin(MinecraftServer.class) | ||
| - | public | + | abstract class TutorialFirstMixin { |
| - | @Inject(method = " | + | @Inject(method = " |
| - | | + | private void logOnWorldLoad(CallbackInfo ci) { |
| - | | + | |
| - | private void addLoggerAtHead(CallbackInfo ci) { | + | |
| ExampleMod.LOGGER.info(" | ExampleMod.LOGGER.info(" | ||
| } | } | ||
| Line 124: | Line 115: | ||
| When the class you're targeting extends and/or implements parents, mimicking that on your Mixin class is an overall benefit, as it allows you to get all of the parent methods directly. For our example Mixin it'll look like: | When the class you're targeting extends and/or implements parents, mimicking that on your Mixin class is an overall benefit, as it allows you to get all of the parent methods directly. For our example Mixin it'll look like: | ||
| < | < | ||
| - | public | + | abstract class TutorialFirstMixin extends class_4093< |
| public TutorialFirstMixin(String string) { | public TutorialFirstMixin(String string) { | ||
| super(string) | super(string) | ||
| } | } | ||
| - | @Inject(method = " | + | @Inject(method = " |
| - | | + | private void logOnWorldLoad(CallbackInfo ci) { |
| - | | + | |
| - | private void addLoggerAtHead(CallbackInfo ci) { | + | |
| - | | + | |
| } | } | ||
| } | } | ||
| </ | </ | ||
| - | The constructor | + | The constructor |
| ==== Debugging Mixins ==== | ==== Debugging Mixins ==== | ||
| Line 150: | Line 139: | ||
| @Debug(export = true) | @Debug(export = true) | ||
| @Mixin(MinecraftServer.class) | @Mixin(MinecraftServer.class) | ||
| - | public | + | abstract class TutorialFirstMixin extends class_4093< |
| - | @Inject(method = " | + | @Inject(method = " |
| - | | + | private void logOnWorldLoad(CallbackInfo ci) { |
| - | | + | |
| - | private void addLoggerAtHead(CallbackInfo ci) { | + | |
| - | | + | |
| } | } | ||
| } | } | ||
| </ | </ | ||
| - | Setting a Mixin to be exported makes it so that once the targeted class has been transformed and has loaded (which could be anytime between the client starting and a world loading) Mixin will export a version of that now transformed class. It should be exported to the directory '' | + | Setting a Mixin to be exported makes it so that once the targeted class has been transformed and has loaded (which could be anytime between the client starting and a world loading) Mixin will export a version of that now transformed class. It should be exported to the directory '' |
| :!: If you use the '' | :!: If you use the '' | ||
tutorial/mixin_your_first_mixin.1760609321.txt.gz · Last modified: 2025/10/16 10:08 by gauntrecluse