User Tools

Site Tools


tutorial:enum_adding

Differences

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

Link to this comparison view

Next revision
Previous revision
tutorial:enum_adding [2021/07/22 14:55] – created mattidragontutorial:enum_adding [2022/08/17 21:22] (current) – removed clomclem
Line 1: Line 1:
-====== Adding to Enums ====== 
  
-===== Introduction ===== 
-To properly add to enums we have to edit some internal fields. There is no guarantee that this will work on all java versions. Due to this it's important to make sure adding to a enum is the correct thing to do. eg. if you need to make armor you shouldn't add to ''ArmorMaterials'' but instead make your own class ([[armor]]). You also need to careful if your target enum is used in a switch and stop it from creating problems (you should anyways make sure that all uses are covered). If this stops working for some reason don't be surprised. It might be a small thing or the whole concept could be changed. I will be using adding a axolotl variant as an example here, but the concept should work on any enum you can mixin into. 
- 
-===== Creating a Container Class ===== 
-The purpose of this is to contain all of your custom enum entries. The entries will be contained in static **non** final fields.  
-<code java> 
-public class CustomAxolotlVariant { 
-    static { 
-        AxolotlEntity.Variant.values(); // Ensure class is loaded before the variant is accessed 
-    } 
-     
-    public static AxolotlEntity.Variant PURPLE; // You can add as many of these fields as you like 
-} 
-</code> 
- 
-===== Mixing Into the Target ===== 
-If you're adding to enum I'm going to expect you know the basics of mixin.  
- 
-==== Accessing the Constructor ==== 
-We need an invoker for the constructor. The first two arguments should always be the internal name and id. After that we have the arguments of the visible constructor. 
-<code java> 
-@SuppressWarnings("InvokerTarget") 
-@Invoker("<init>") 
-private static AxolotlEntity.Variant newVariant(String internalName, int internalId, int id, String name, boolean natural) { 
-    throw new AssertionError(); 
-} 
-</code> 
- 
-==== Accessing the Values Field ==== 
-If we are dealing with a minecraft class then the field name will be in intermediary mappings. To find the name of the filed we have to look at bytecode. This can be done in IntelliJ by placing the cursor in the class and going to View -> Show Bytecode. Scroll down until you see a line a bit like this: 
-<code java> 
-private final static synthetic [Lnet/minecraft/entity/passive/AxolotlEntity$Variant; field_28350 
-</code> 
-That means that in our case the field name is ''field_28350''. Next we shadow it as such: 
-<code java> 
-@SuppressWarnings("ShadowTarget") 
-@Shadow 
-@Mutable 
-private static @FinalAxolotlEntity.Variant[] field_28350; 
-</code> 
- 
-==== Injecting the Entries ==== 
-We are going inject after the values field is assigned. To do this we need the correct target for the for the ''INVOKE'' injection point. We can't use MCDev since we are dealing with internals so we need to type it ourselves as such: 
-''<classname><fieldname>:[<classname>'' 
-In our case it would be ''Lnet/minecraft/entity/passive/AxolotlEntity$Variant;field_28350:[Lnet/minecraft/entity/passive/AxolotlEntity$Variant;'' 
-Now we can create the inject: 
-<code java> 
-@SuppressWarnings("UnresolvedMixinReference") 
-@Inject(method = "<clinit>", at = @At(value = "FIELD",  
-        opcode = Opcodes.PUTSTATIC,  
-        target = "Lnet/minecraft/entity/passive/AxolotlEntity$Variant;field_28350:[Lnet/minecraft/entity/passive/AxolotlEntity$Variant;",  
-        shift = At.Shift.AFTER)) 
-private static void addCustomVariant(CallbackInfo ci) { 
- 
-} 
-</code> 
-Now finally we can add our entries: 
-<code java> 
-var variants = new ArrayList<>(Arrays.asList(field_28350)); 
-var last = variants.get(variants.size() - 1); 
- 
-// This means our code will still work if other mods or Mojang add more variants! 
-// Repeat this section if you need more than one entry. Just remember to have unique ordinals! 
-var purple = newVariant("PURPLE", last.ordinal() + 1, last.getId() + 1, "purple", true); 
-CustomAxolotlVariant.PURPLE = purple; 
-variants.add(purple); 
- 
-field_28350 = variants.toArray(new AxolotlEntity.Variant[0]); 
-</code> 
- 
-===== Accessing Your Entries ===== 
-To access your enum entries simply get the field from your container class. For example  
-<code java> 
-System.out.println(CustomAxolotlVariant.PURPLE); 
-</code> 
- 
- 
-This tutorial is based on [[https://gist.github.com/LlamaLad7/0b553d5ae04e4eb44d3a1e8558be9151|this gist]] by lamalad. 
tutorial/enum_adding.1626965749.txt.gz · Last modified: 2021/07/22 14:55 by mattidragon