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
tutorial:mixin_accessors [2020/08/29 15:18] – Add how to add ores to the end biomes siglongtutorial:mixin_accessors [2022/04/29 09:54] (current) – [Mixin Accessors] solidblock
Line 1: Line 1:
-====== Adding Ores to Worlds ====== +====== Mixin Accessors & Invokers ====== 
-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 and invokers allow you to access fields or invoke 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.1598714307.txt.gz · Last modified: 2020/08/29 15:18 by siglong