aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/com/anthonyhilyard/iceberg/registry/AutoRegistry.java
blob: c42a8d008005a209247937315a5c1adf95cfd10e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
package com.anthonyhilyard.iceberg.registry;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;

import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundEvent;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.fml.client.registry.IRenderFactory;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.IForgeRegistry;
import net.minecraftforge.registries.IForgeRegistryEntry;
import net.minecraftforge.event.entity.EntityAttributeCreationEvent;

/**
 * Extend this class to have all registerable fields be automatically registered in Forge.  Easy.
 */
public abstract class AutoRegistry
{
	protected static String MODID = null;

	private static boolean entityCreationRegistered = false;

	private static Map<EntityType<?>, Supplier<AttributeModifierMap.MutableAttribute>> entityAttributes = new HashMap<>();

	private static Map<String, EntityType<? extends Entity>> registeredEntityTypes = new HashMap<>();

	public static void init(String ModID)
	{
		MODID = ModID;
	}

	@SuppressWarnings("unchecked")
	protected AutoRegistry()
	{
		try
		{
			// Iterate through every built-in Forge registry...
			for (Field field : ForgeRegistries.class.getDeclaredFields())
			{
				Object fieldObj = field.get(null);
				if (fieldObj instanceof IForgeRegistry)
				{
					// Grab the registry's supertype and add a generic listener for registry events.
					Class<IForgeRegistryEntry<?>> clazz = (Class<IForgeRegistryEntry<?>>)((IForgeRegistry<?>)fieldObj).getRegistrySuperType();
					FMLJavaModLoadingContext.get().getModEventBus().addGenericListener(clazz, (Consumer<RegistryEvent.Register<? extends IForgeRegistryEntry<?>>>)(e) -> registerAllOfType(clazz, e) );
				}
			}
		}
		catch (Exception e)
		{
			throw new RuntimeException(e);
		}
	}

	public static boolean isEntityTypeRegistered(String name)
	{
		return registeredEntityTypes.containsKey(name);
	}

	@SuppressWarnings("unchecked")
	public static <T extends Entity> EntityType<T> getEntityType(String name)
	{
		return (EntityType<T>) registeredEntityTypes.getOrDefault(name, null);
	}

	@SuppressWarnings("unchecked")
	private final <T extends IForgeRegistryEntry<T>> void registerAllOfType(Class<IForgeRegistryEntry<?>> type, RegistryEvent.Register<T> event)
	{
		try
		{
			// Loop through all fields we've declared and register them.
			for (Field field : this.getClass().getDeclaredFields())
			{
				// Grab the field and check if it is a Forge registry-compatible type.
				Object obj = field.get(this);
				if (type.isAssignableFrom(obj.getClass()))
				{
					// If this is an entity type field and we haven't already registered for the entity creation event, do so now.
					if (obj instanceof EntityType && !entityCreationRegistered)
					{
						FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onEntityCreation);
						entityCreationRegistered = true;
					}

					// If this field has a registry name, register it now.
					T entry = (T)obj;
					if (entry != null && entry.getRegistryName() != null)
					{
						event.getRegistry().register(entry);
					}
				}
			}
		}
		catch (Exception e)
		{
			throw new RuntimeException(e);
		}
	}

	protected static <T extends Entity> EntityType<T> registerEntity(String name, EntityType.Builder<T> builder, IRenderFactory<? super T> renderFactory)
	{
		return registerEntity(name, builder, renderFactory, null);
	}

	@SuppressWarnings("unchecked")
	protected static <T extends Entity> EntityType<T> registerEntity(String name, EntityType.Builder<T> builder, IRenderFactory<? super T> renderFactory, Supplier<AttributeModifierMap.MutableAttribute> attributes)
	{
		if (MODID == null)
		{
			throw new RuntimeException("AutoRegistry was not initialized with mod id!");
		}

		// Build the entity type.
		ResourceLocation resourceLocation = new ResourceLocation(MODID, name);
		EntityType<T> entityType = (EntityType<T>) builder.build(name).setRegistryName(resourceLocation);

		// Add this entity type to the registered hashmap.
		registeredEntityTypes.put(name, entityType);

		// Store mob attributes if provided.  These will be added in the attribute creation event below.
		if (attributes != null)
		{
			entityAttributes.put(entityType, attributes);
		}

		return entityType;
	}

	protected static SoundEvent registerSound(String name)
	{
		if (MODID == null)
		{
			throw new RuntimeException("AutoRegistry was not initialized with mod id!");
		}

		return new SoundEvent(new ResourceLocation(MODID, name));
	}

	@SuppressWarnings("unchecked")
	private void onEntityCreation(EntityAttributeCreationEvent event)
	{
		for (Field field : this.getClass().getDeclaredFields())
		{
			try
			{
				// Grab the field and check if it is a Forge registry-compatible type.
				Object obj = field.get(this);
				if (EntityType.class.isAssignableFrom(obj.getClass()) && entityAttributes.containsKey(obj))
				{
					EntityType<? extends LivingEntity> entityType = (EntityType<? extends LivingEntity>) obj;
					if (entityType != null)
					{
						event.put(entityType, entityAttributes.get(obj).get().build());
					}
				}
			}
			catch (ClassCastException e)
			{
				// The class cast exception likely just means that we tried to convert an EntityType with generic type
				// parameter of something other than a LivingEntity subclass.  This is fine, so continue.
				continue;
			}
			catch (IllegalAccessException e)
			{
				throw new RuntimeException(e);
			}
		}
	}
}