Handle annotation exceptions in the helper class

This commit is contained in:
FatherToast 2022-06-23 09:51:14 -05:00
parent 037faab4f0
commit 9c6eb7bbfb
5 changed files with 68 additions and 97 deletions

View file

@ -16,7 +16,6 @@ import net.minecraftforge.fml.RegistryObject;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault; import javax.annotation.ParametersAreNonnullByDefault;
import java.lang.reflect.InvocationTargetException;
import java.util.*; import java.util.*;
/** /**
@ -253,12 +252,12 @@ public class MobFamily<T extends LivingEntity> {
// Below require variant class to be defined // Below require variant class to be defined
final EntityType.Builder<T> entityTypeBuilder = makeEntityTypeBuilder( parentFamily.replaceableTypes[0] ); final EntityType.Builder<T> entityTypeBuilder = makeEntityTypeBuilder( parentFamily.replaceableTypes[0] );
bestiaryInfo = makeBestiaryInfo( entityTypeBuilder ); bestiaryInfo = AnnotationHelper.getBestiaryInfo( this, entityTypeBuilder );
// Initialize deferred registry objects // Initialize deferred registry objects
entityType = SMEntities.register( name.toLowerCase( Locale.ROOT ), entityTypeBuilder ); entityType = SMEntities.register( name.toLowerCase( Locale.ROOT ), entityTypeBuilder );
spawnEgg = SMItems.registerSpawnEgg( entityType, parentFamily.eggBaseColor, bestiaryInfo.eggSpotsColor ); spawnEgg = SMItems.registerSpawnEgg( entityType, parentFamily.eggBaseColor, bestiaryInfo.eggSpotsColor );
injectEntityType(); AnnotationHelper.injectEntityTypeHolder( this );
} }
/** Finds the entity class based on a standard format. */ /** Finds the entity class based on a standard format. */
@ -272,28 +271,12 @@ public class MobFamily<T extends LivingEntity> {
} }
} }
/** Calls on this species' entity class to generate its bestiary info. */
private BestiaryInfo makeBestiaryInfo( EntityType.Builder<T> entityTypeBuilder ) {
try {
return AnnotationHelper.getBestiaryInfo( this, entityTypeBuilder );
}
catch( IllegalAccessException | NoSuchMethodException | InvocationTargetException ex ) {
throw new RuntimeException( "Entity class for " + name + " has invalid bestiary info method", ex );
}
}
/** /**
* Builds a deep copy of an entity type with a different entity constructor. * Builds a deep copy of an entity type with a different entity constructor.
* Leaves the new entity type "un-built" so it can be further modified, if needed. * Leaves the new entity type "un-built" so it can be further modified, if needed.
*/ */
private EntityType.Builder<T> makeEntityTypeBuilder( EntityType<?> original ) { private EntityType.Builder<T> makeEntityTypeBuilder( EntityType<?> original ) {
final EntityType.IFactory<T> factory; final EntityType.IFactory<T> factory = AnnotationHelper.getEntityFactory( this );
try {
factory = AnnotationHelper.getEntityFactory( this );
}
catch( NoSuchMethodException ex ) {
throw new RuntimeException( "Entity class for " + name + " has no valid constructors", ex );
}
final EntityType.Builder<T> clone = EntityType.Builder.of( factory, original.getCategory() ); final EntityType.Builder<T> clone = EntityType.Builder.of( factory, original.getCategory() );
if( !original.canSummon() ) clone.noSummon(); if( !original.canSummon() ) clone.noSummon();
@ -307,15 +290,5 @@ public class MobFamily<T extends LivingEntity> {
.clientTrackingRange( original.clientTrackingRange() ).updateInterval( original.updateInterval() ) .clientTrackingRange( original.clientTrackingRange() ).updateInterval( original.updateInterval() )
.setShouldReceiveVelocityUpdates( original.trackDeltas() ); .setShouldReceiveVelocityUpdates( original.trackDeltas() );
} }
/** Calls on this species' entity class to generate its bestiary info. */
private void injectEntityType() {
try {
AnnotationHelper.injectEntityTypeHolder( this );
}
catch( IllegalAccessException ex ) {
throw new RuntimeException( "Entity class for " + name + " has invalid entity type holder", ex );
}
}
} }
} }

View file

@ -10,8 +10,6 @@ import net.minecraftforge.fml.RegistryObject;
import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.ForgeRegistries;
import java.lang.reflect.InvocationTargetException;
public class SMEntities { public class SMEntities {
public static final DeferredRegister<EntityType<?>> REGISTRY = DeferredRegister.create( ForgeRegistries.ENTITIES, SpecialMobs.MOD_ID ); public static final DeferredRegister<EntityType<?>> REGISTRY = DeferredRegister.create( ForgeRegistries.ENTITIES, SpecialMobs.MOD_ID );
@ -24,19 +22,9 @@ public class SMEntities {
/** Sets the default attributes for entity types, such as max health, attack damage etc. */ /** Sets the default attributes for entity types, such as max health, attack damage etc. */
public static void createAttributes( EntityAttributeCreationEvent event ) { public static void createAttributes( EntityAttributeCreationEvent event ) {
// Bestiary-generated entities // Bestiary-generated entities
for( MobFamily.Species<?> variant : MobFamily.getAllSpecies() ) for( MobFamily.Species<?> species : MobFamily.getAllSpecies() )
createSpeciesAttributes( event, variant );
}
/** Builds the attributes for a specific entity species. */
private static void createSpeciesAttributes( EntityAttributeCreationEvent event, MobFamily.Species<?> species ) {
try {
event.put( species.entityType.get(), AnnotationHelper.createAttributes( species ) ); event.put( species.entityType.get(), AnnotationHelper.createAttributes( species ) );
} }
catch( NoSuchMethodException | InvocationTargetException | IllegalAccessException ex ) {
throw new RuntimeException( "Entity class for " + species.name + " has invalid attribute creation method", ex );
}
}
/** Sets the natural spawn placement rules for entity types. */ /** Sets the natural spawn placement rules for entity types. */
public static void registerSpawnPlacements() { public static void registerSpawnPlacements() {

View file

@ -12,20 +12,28 @@ import javax.annotation.ParametersAreNonnullByDefault;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.*; import java.lang.reflect.*;
/**
* Provides helper methods to handle annotation processing through reflection.
*/
@ParametersAreNonnullByDefault @ParametersAreNonnullByDefault
public final class AnnotationHelper { public final class AnnotationHelper {
//--------------- PRETTY HELPER METHODS ---------------- //--------------- PRETTY HELPER METHODS ----------------
/** Creates an entity factory from a special mob species. Throws an exception if anything goes wrong. */ /** Creates an entity factory from a special mob species. Throws an exception if anything goes wrong. */
public static void injectEntityTypeHolder( MobFamily.Species<?> species ) throws IllegalAccessException { public static void injectEntityTypeHolder( MobFamily.Species<?> species ) {
try {
final Field field = getFieldOptional( species.entityClass, SpecialMob.TypeHolder.class ); final Field field = getFieldOptional( species.entityClass, SpecialMob.TypeHolder.class );
if( field != null ) field.set( null, species.entityType ); if( field != null ) field.set( null, species.entityType );
} }
catch( IllegalAccessException ex ) {
throw new RuntimeException( "Entity class for " + species.name + " has invalid entity type holder", ex );
}
}
/** Creates an entity factory from a special mob species. Throws an exception if anything goes wrong. */ /** Creates an entity factory from a special mob species. Throws an exception if anything goes wrong. */
public static <T extends LivingEntity> EntityType.IFactory<T> getEntityFactory( MobFamily.Species<T> species ) public static <T extends LivingEntity> EntityType.IFactory<T> getEntityFactory( MobFamily.Species<T> species ) {
throws NoSuchMethodException { try {
final Constructor<T> constructor = getConstructor( species.entityClass, SpecialMob.Constructor.class ); final Constructor<T> constructor = getConstructor( species.entityClass, SpecialMob.Constructor.class );
return ( entityType, world ) -> { return ( entityType, world ) -> {
try { try {
@ -36,34 +44,54 @@ public final class AnnotationHelper {
} }
}; };
} }
catch( NoSuchMethodException ex ) {
throw new RuntimeException( "Entity class for " + species.name + " has no valid constructors", ex );
}
}
/** Gets bestiary info from a special mob species. Throws an exception if anything goes wrong. */ /** Gets bestiary info from a special mob species. Throws an exception if anything goes wrong. */
public static <T extends LivingEntity> BestiaryInfo getBestiaryInfo( MobFamily.Species<T> species, EntityType.Builder<T> entityType ) public static <T extends LivingEntity> BestiaryInfo getBestiaryInfo( MobFamily.Species<T> species, EntityType.Builder<T> entityType ) {
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { try {
return (BestiaryInfo) getMethod( species.entityClass, SpecialMob.BestiaryInfoSupplier.class ).invoke( null, entityType ); return (BestiaryInfo) getMethod( species.entityClass, SpecialMob.BestiaryInfoSupplier.class ).invoke( null, entityType );
} }
catch( IllegalAccessException | NoSuchMethodException | InvocationTargetException ex ) {
throw new RuntimeException( "Entity class for " + species.name + " has invalid bestiary info method", ex );
}
}
/** Creates an attribute modifier map from a special mob species. Throws an exception if anything goes wrong. */ /** Creates an attribute modifier map from a special mob species. Throws an exception if anything goes wrong. */
public static AttributeModifierMap createAttributes( MobFamily.Species<?> species ) public static AttributeModifierMap createAttributes( MobFamily.Species<?> species ) {
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { try {
return ((AttributeModifierMap.MutableAttribute) getMethod( species.entityClass, SpecialMob.AttributeCreator.class ) return ((AttributeModifierMap.MutableAttribute) getMethod( species.entityClass, SpecialMob.AttributeCreator.class )
.invoke( null )).build(); .invoke( null )).build();
} }
catch( NoSuchMethodException | InvocationTargetException | IllegalAccessException ex ) {
throw new RuntimeException( "Entity class for " + species.name + " has invalid attribute creation method", ex );
}
}
/** Gets the translations from a special mob species. Throws an exception if anything goes wrong. */ /** Gets the translations from a special mob species. Throws an exception if anything goes wrong. */
public static String[] getTranslations( MobFamily.Species<?> species ) public static String[] getTranslations( MobFamily.Species<?> species ) {
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { try {
return (String[]) getMethod( species.entityClass, SpecialMob.LanguageProvider.class ) return (String[]) getMethod( species.entityClass, SpecialMob.LanguageProvider.class )
.invoke( null, species.entityType.get().getDescriptionId() ); .invoke( null, species.entityType.get().getDescriptionId() );
} }
catch( NoSuchMethodException | InvocationTargetException | IllegalAccessException ex ) {
throw new RuntimeException( "Entity class for " + species.name + " has invalid language provider method", ex );
}
}
/** Builds a loot table from a special mob species. Throws an exception if anything goes wrong. */ /** Builds a loot table from a special mob species. Throws an exception if anything goes wrong. */
public static LootTableBuilder buildLootTable( MobFamily.Species<?> species ) public static LootTableBuilder buildLootTable( MobFamily.Species<?> species ) {
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { try {
final LootTableBuilder builder = new LootTableBuilder(); final LootTableBuilder builder = new LootTableBuilder();
getMethod( species.entityClass, SpecialMob.LootTableProvider.class ).invoke( null, builder ); getMethod( species.entityClass, SpecialMob.LootTableProvider.class ).invoke( null, builder );
return builder; return builder;
} }
catch( NoSuchMethodException | InvocationTargetException | IllegalAccessException ex ) {
throw new RuntimeException( "Entity class for " + species.name + " has invalid loot table builder method", ex );
}
}
//--------------- RAW ANNOTATION METHODS ---------------- //--------------- RAW ANNOTATION METHODS ----------------

View file

@ -7,7 +7,6 @@ import fathertoast.specialmobs.common.util.References;
import net.minecraft.data.DataGenerator; import net.minecraft.data.DataGenerator;
import net.minecraftforge.common.data.LanguageProvider; import net.minecraftforge.common.data.LanguageProvider;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -45,7 +44,7 @@ public class SMLanguageProvider extends LanguageProvider {
// Bestiary-generated translations // Bestiary-generated translations
for( MobFamily.Species<?> species : MobFamily.getAllSpecies() ) { for( MobFamily.Species<?> species : MobFamily.getAllSpecies() ) {
final String[] speciesTranslations = getTranslations( species ); final String[] speciesTranslations = AnnotationHelper.getTranslations( species );
String[] spawnEggTranslations = format( spawnEggTranslationPattern, speciesTranslations ); String[] spawnEggTranslations = format( spawnEggTranslationPattern, speciesTranslations );
spawnEggTranslations[0] = species.spawnEgg.get().getDescriptionId(); spawnEggTranslations[0] = species.spawnEgg.get().getDescriptionId();
@ -81,16 +80,6 @@ public class SMLanguageProvider extends LanguageProvider {
SpecialMobs.LOG.info( "Translation key verification complete!" ); SpecialMobs.LOG.info( "Translation key verification complete!" );
} }
/** Gets the translations for a specific entity species. */
private static String[] getTranslations( MobFamily.Species<?> species ) {
try {
return AnnotationHelper.getTranslations( species );
}
catch( NoSuchMethodException | InvocationTargetException | IllegalAccessException ex ) {
throw new RuntimeException( "Entity class for " + species.name + " has invalid language provider method", ex );
}
}
/** Applies single argument string formats 1:1 given an array of formats and an array of arguments. */ /** Applies single argument string formats 1:1 given an array of formats and an array of arguments. */
private static String[] format( String[] formats, String[] args ) { private static String[] format( String[] formats, String[] args ) {
final String[] formatted = new String[formats.length]; final String[] formatted = new String[formats.length];

View file

@ -11,12 +11,14 @@ import net.minecraft.data.DataGenerator;
import net.minecraft.data.LootTableProvider; import net.minecraft.data.LootTableProvider;
import net.minecraft.data.loot.EntityLootTables; import net.minecraft.data.loot.EntityLootTables;
import net.minecraft.entity.EntityType; import net.minecraft.entity.EntityType;
import net.minecraft.loot.*; import net.minecraft.loot.LootParameterSet;
import net.minecraft.loot.LootParameterSets;
import net.minecraft.loot.LootTable;
import net.minecraft.loot.ValidationTracker;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.RegistryObject; import net.minecraftforge.fml.RegistryObject;
import javax.annotation.ParametersAreNonnullByDefault; import javax.annotation.ParametersAreNonnullByDefault;
import java.lang.reflect.InvocationTargetException;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
@ -54,18 +56,9 @@ public class SMLootTableProvider extends LootTableProvider {
@Override @Override
protected void addTables() { protected void addTables() {
// Bestiary-generated tables // Bestiary-generated tables
for( MobFamily.Species<?> variant : MobFamily.getAllSpecies() ) addTable( variant ); for( MobFamily.Species<?> species : MobFamily.getAllSpecies() )
}
/** Builds the loot table for a specific entity species. */
private void addTable( MobFamily.Species<?> species ) {
try {
add( species.entityType.get(), AnnotationHelper.buildLootTable( species ).toLootTable() ); add( species.entityType.get(), AnnotationHelper.buildLootTable( species ).toLootTable() );
} }
catch( NoSuchMethodException | InvocationTargetException | IllegalAccessException ex ) {
throw new RuntimeException( "Entity class for " + species.name + " has invalid loot table builder method", ex );
}
}
/** Supplies the entity types this loot table provider will be used for. */ /** Supplies the entity types this loot table provider will be used for. */
@Override @Override