User Tools

Site Tools


tutorial:mixin_accessors

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
Last revisionBoth sides next revision
tutorial:mixin_accessors [2020/08/29 15:18] – Add how to add ores to the end biomes siglongtutorial:mixin_accessors [2021/04/01 17:30] – Make accessor example less icky proudmuslim
Line 1: Line 1:
-====== Adding Ores to Worlds ====== +====== Mixin Accessors ====== 
-A lot of mods add their own ores, and you'll need a way to place them in existing biomes for players to find. In this tutorial, we'll look at adding ores to existing biomes. There are 2 steps that are required to add ores to biomes. +Mixin Accessors allow you to access fields and methods that are not visible (private) or final.
-  * Make a ConfiguredFeatures. This defines how your ore block is spawned. +
-  * Register your feature by using [[tutorial:mixin_introduction|mixin]] into Minecraft class where default features are listed+
  
-We'll assume you've already created your own ore block at this pointQuartz Ore will serve as our replacement throughout this tutorial. Replace references to Quartz Ore with your ore when appropriate.+===== Accessor ===== 
 +''@Accessor'' allows you to access fieldsSuppose we want to access ''itemUseCooldown'' field of ''MinecraftClient'' class.
  
-==== Adding to the overworld ==== +==== Getting a value from the field ==== 
-In this section, our goal will be spawning the ore in the overworld.+<code java> 
 +@Mixin(MinecraftClient.class) 
 +public interface MinecraftClientAccessor { 
 +    @Accessor 
 +    int getItemUseCooldown(); 
 +
 +</code>
  
-=== Making a ConfiguredFeatures === +Usage:
-First we need to create a ConfiguredFeatures. Make sure to register your ConfiguredFeature at ''onInitialize''. Feel free to change the values to suit your mod.+
  
-<code java [enable_line_numbers="true"]+<code java> 
-public class ExampleMod implements ModInitializer { +int itemUseCooldown = ((MinecraftClientAccessorMinecraftClient.getInstance()).getItemUseCooldown(); 
-  public static ConfiguredFeature<?, ?> ORE_QUARTZ_OVERWORLD Feature.ORE +</code>
-      .configure(new OreFeatureConfig( +
-        OreFeatureConfig.Rules.BASE_STONE_OVERWORLD,  +
-        Blocks.NETHER_QUARTZ_ORE.getDefaultState()+
-        9)) // vein size +
-      .decorate(Decorator.RANGE.configure(new RangeDecoratorConfig( +
-        0, // bottom offset +
-        0, // min y level +
-        64))) // max y level +
-      .spreadHorizontally() +
-      .repeat(20); // number of veins per chunk+
  
-  @Override +==== Setting a value to the field ==== 
-  public void onInitialize() { +<code java> 
-    Registry.register(BuiltinRegistries.CONFIGURED_FEATURE, new Identifier("tutorial", "ore_quartz_overworld"), ORE_QUARTZ_OVERWORLD); +@Mixin(MinecraftClient.class) 
-  }+public interface MinecraftClientAccessor 
 +    @Accessor("itemUseCooldown") 
 +    public void setItemUseCooldown(int itemUseCooldown);
 } }
 </code> </code>
  
-=== Registering the feature === +Usage:
-Vanilla ore features that spawn in the overworld biomes are listed in ''DefaultBiomeFeature.addDefaultOres''. We modify this method to add our ore to the overworld via [[tutorial:mixin_introduction|mixin]].+
  
-<code java [enable_line_numbers="true"]+<code java
-@Mixin(DefaultBiomeFeatures.class) +((MinecraftClientAccessor) MinecraftClient.getInstance()).setItemUseCooldown(100); 
-public class DefaultBiomeFeaturesMixin +</code> 
-  @Inject(method = "addDefaultOres(Lnet/minecraft/world/biome/GenerationSettings$Builder;)V", at = @At("TAIL")+ 
-  private static void addDefaultOres(GenerationSettings.Builder builder, CallbackInfo ci) { +===== Accessor for static fields ===== 
-    builder.feature(GenerationStep.Feature.UNDERGROUND_ORES, ExampleMod.ORE_QUARTZ_OVERWORLD);+Suppose we want to access ''BIOMES'' field of ''VanillaLayeredBiomeSource'' class. 
 + 
 +==== Getting a value from the field ==== 
 +<code java
 +@Mixin(VanillaLayeredBiomeSource.class) 
 +public interface VanillaLayeredBiomeSourceAccessor 
 +  @Accessor("BIOMES") 
 +  public static List<RegistryKey<Biome>> getBiomes() { 
 +    throw new AssertionError();
   }   }
 } }
 </code> </code>
  
-=== Result === +Usage:
-You should see quartz ore spawning in the overworld. You can use fill command to remove stone blocks surrounding you like this''/fill ~-4 0 ~-4 ~4 ~ ~4 minecraft:air replace minecraft:stone''.+
  
-{{tutorial:ores.png?800}}+<code java> 
 +List<RegistryKey<Biome>> biomes = VanillaLayeredBiomeSourceAccessor.getBiomes(); 
 +</code>
  
-==== Adding to the end ==== +==== Setting a value to the field ==== 
-In this section, based on the code in the previous section, we will add the ore to the end biomes.+<code java> 
 +@Mixin(VanillaLayeredBiomeSource.class) 
 +public interface VanillaLayeredBiomeSourceAccessor { 
 +  @Accessor("BIOMES"
 +  public static void setBiomes(List<RegistryKey<Biome>> biomes) { 
 +    throw new AssertionError(); 
 +  } 
 +
 +</code>
  
-=== Making a ConfiguredFeatures === +Usage:
-We replace '' OreFeatureConfig.Rules.BASE_STONE_OVERWORLD'' with ''new BlockMatchRuleTest(Blocks.END_STONE)'' because endstone is used as a base block in the end biomes.+
  
-<code java [enable_line_numbers="true"]+<code java> 
-public class ExampleMod implements ModInitializer { +VanillaLayeredBiomeSourceAccessor.setBiomes(biomes); 
-  public static ConfiguredFeature<?, ?> ORE_QUARTZ_END = Feature.ORE +</code>
-      .configure(new OreFeatureConfig+
-        new BlockMatchRuleTest(Blocks.END_STONE), /* We use endstone! */ +
-        Blocks.NETHER_QUARTZ_ORE.getDefaultState(), +
-        9)) +
-      .decorate(Decorator.RANGE.configure(new RangeDecoratorConfig( +
-        0, +
-        0, +
-        64))) +
-      .spreadHorizontally() +
-      .repeat(20);+
  
-  @Override +===== Invoker ===== 
-  public void onInitialize() { +''@Invoker'' allows you to access methods. Suppose we want to invoke ''teleportTo'' method of ''EndermanEntity'' class. 
-    Registry.register(BuiltinRegistries.CONFIGURED_FEATURE, new Identifier("tutorial", "ore_quartz_end"), ORE_QUARTZ_END); + 
-  }+<code java> 
 +@Mixin(EndermanEntity.class) 
 +public interface EndermanEntityInvoker 
 +  @Invoker("teleportTo") 
 +  public boolean invokeTeleportTo(double x, double ydouble z);
 } }
 </code> </code>
  
-=== Registering the feature === +Usage:
-Considering that no ore is generated in the end biomes on vanilla minecraft, ''DefaultBiomeFeature.addDefaultOres'' can't be used for adding an ore to the end biomes. Instead, we inject into ''DefaultBiomeCreator.method_31065'' because this method is used to create every end biomes.+
  
-<code java [enable_line_numbers="true"]+<code java
-@Mixin(DefaultBiomeCreator.class) +EndermanEntity enderman ...; 
-public class DefaultBiomeCreatorMixin +((EndermanEntityInvoker) enderman).invokeTeleportTo(0.0D, 70.0D, 0.0D); 
-  @Inject(method = "method_31065(Lnet/minecraft/world/biome/GenerationSettings$Builder;)Lnet/minecraft/world/biome/Biome;", at = @At("HEAD")+</code> 
-  private static void addEndOres(GenerationSettings.Builder builder, CallbackInfoReturnable<Biome> cir) { + 
-    builder.feature(GenerationStep.Feature.UNDERGROUND_ORES, ExampleMod.ORE_QUARTZ_END);+===== Invoker for static methods ===== 
 +Suppose we want to invoke ''registerPotionType'' method of ''BrewingRecipeRegistry'' class. 
 + 
 +<code java
 +@Mixin(BrewingRecipeRegistry.class) 
 +public interface BrewingRecipeRegistryInvoker 
 +  @Invoker("registerPotionType") 
 +  public static void invokeRegisterPotionType(Item item) { 
 +    throw new AssertionError();
   }   }
 } }
 </code> </code>
  
 +Usage:
 +
 +<code java>
 +BrewingRecipeRegistryInvoker.invokeRegisterPotionType(item);
 +</code>
tutorial/mixin_accessors.txt · Last modified: 2022/04/29 09:54 by solidblock