151 lines
4.8 KiB
Java
151 lines
4.8 KiB
Java
/*
|
|
* Minecraft Forge
|
|
* Copyright (c) 2016-2018.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation version 2.1
|
|
* of the License.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
package net.minecraftforge.registries;
|
|
|
|
import java.lang.reflect.Field;
|
|
import java.lang.reflect.Modifier;
|
|
import java.util.Collections;
|
|
import java.util.LinkedList;
|
|
import java.util.Queue;
|
|
|
|
import net.minecraft.util.ResourceLocation;
|
|
|
|
import javax.annotation.Nullable;
|
|
|
|
import org.apache.logging.log4j.LogManager;
|
|
import org.apache.logging.log4j.Logger;
|
|
|
|
/**
|
|
* Internal class used in tracking {@link ObjectHolder} references
|
|
*/
|
|
@SuppressWarnings("rawtypes")
|
|
class ObjectHolderRef
|
|
{
|
|
private static final Logger LOGGER = LogManager.getLogger();
|
|
private Field field;
|
|
private ResourceLocation injectedObject;
|
|
private boolean isValid;
|
|
private ForgeRegistry<?> registry;
|
|
|
|
ObjectHolderRef(Field field, ResourceLocation injectedObject, boolean extractFromExistingValues)
|
|
{
|
|
registry = getRegistryForType(field);
|
|
|
|
this.field = field;
|
|
this.isValid = registry != null;
|
|
if (extractFromExistingValues)
|
|
{
|
|
try
|
|
{
|
|
Object existing = field.get(null);
|
|
// nothing is ever allowed to replace AIR
|
|
if (existing == null || existing == registry.getDefault())
|
|
{
|
|
this.injectedObject = null;
|
|
this.field = null;
|
|
this.isValid = false;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
this.injectedObject = ((IForgeRegistryEntry)existing).getRegistryName();
|
|
}
|
|
}
|
|
catch (IllegalAccessException e)
|
|
{
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this.injectedObject = injectedObject;
|
|
}
|
|
|
|
if (this.injectedObject == null || !isValid())
|
|
{
|
|
throw new IllegalStateException(String.format("The ObjectHolder annotation cannot apply to a field that does not map to a registry. Ensure the registry was created during the RegistryEvent.NewRegistry event. (found : %s at %s.%s)", field.getType().getName(), field.getClass().getName(), field.getName()));
|
|
}
|
|
|
|
field.setAccessible(true);
|
|
|
|
if (Modifier.isFinal(field.getModifiers()))
|
|
{
|
|
throw new RuntimeException("@ObjectHolder on final field, our transformer did not run? " + field.getDeclaringClass().getName() + "/" + field.getName());
|
|
}
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
@Nullable
|
|
private ForgeRegistry<?> getRegistryForType(Field field)
|
|
{
|
|
Queue<Class<?>> typesToExamine = new LinkedList<Class<?>>();
|
|
typesToExamine.add(field.getType());
|
|
|
|
ForgeRegistry<?> registry = null;
|
|
while (!typesToExamine.isEmpty() && registry == null)
|
|
{
|
|
Class<?> type = typesToExamine.remove();
|
|
Collections.addAll(typesToExamine, type.getInterfaces());
|
|
if (ForgeRegistryEntry.class.isAssignableFrom(type))
|
|
{
|
|
registry = (ForgeRegistry<?>)RegistryManager.ACTIVE.getRegistry((Class<ForgeRegistryEntry>)type);
|
|
final Class<?> parentType = type.getSuperclass();
|
|
if (parentType != null)
|
|
{
|
|
typesToExamine.add(parentType);
|
|
}
|
|
}
|
|
}
|
|
return registry;
|
|
}
|
|
|
|
public boolean isValid()
|
|
{
|
|
return isValid;
|
|
}
|
|
|
|
public void apply()
|
|
{
|
|
Object thing;
|
|
if (isValid && registry.containsKey(injectedObject) && !registry.isDummied(injectedObject))
|
|
{
|
|
thing = registry.getValue(injectedObject);
|
|
}
|
|
else
|
|
{
|
|
thing = null;
|
|
}
|
|
|
|
if (thing == null)
|
|
{
|
|
LOGGER.debug("Unable to lookup {} for {}. This means the object wasn't registered. It's likely just mod options.", injectedObject, field);
|
|
return;
|
|
}
|
|
try
|
|
{
|
|
field.set(null, thing);
|
|
}
|
|
catch (IllegalArgumentException | ReflectiveOperationException e)
|
|
{
|
|
LOGGER.warn("Unable to set {} with value {} ({})", this.field, thing, this.injectedObject, e);
|
|
}
|
|
}
|
|
}
|