Reimplement @ObjectHolder scanning, and expose system for others to add handlers.
Fix forgedev and userdev run configs. Fix issue in log functions assuming String arguments.
This commit is contained in:
parent
34568a0a74
commit
36d2e67b07
21
build.gradle
21
build.gradle
|
@ -161,7 +161,7 @@ project(':forge') {
|
||||||
exc = file("$rootDir/src/main/resources/forge.exc")
|
exc = file("$rootDir/src/main/resources/forge.exc")
|
||||||
srgPatches = true
|
srgPatches = true
|
||||||
runs {
|
runs {
|
||||||
client = {
|
forge_client = {
|
||||||
main 'net.minecraftforge.fml.LaunchTesting'
|
main 'net.minecraftforge.fml.LaunchTesting'
|
||||||
environment = [
|
environment = [
|
||||||
target: 'fmldevclient',
|
target: 'fmldevclient',
|
||||||
|
@ -180,7 +180,7 @@ project(':forge') {
|
||||||
'fmllauncher.version': SPEC_VERSION
|
'fmllauncher.version': SPEC_VERSION
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
server = {
|
forge_server = {
|
||||||
main 'net.minecraftforge.fml.LaunchTesting'
|
main 'net.minecraftforge.fml.LaunchTesting'
|
||||||
environment = [
|
environment = [
|
||||||
target: 'fmldevserver'
|
target: 'fmldevserver'
|
||||||
|
@ -190,7 +190,8 @@ project(':forge') {
|
||||||
'mcp.version': MCP_VERSION,
|
'mcp.version': MCP_VERSION,
|
||||||
'forge.version': "${project.version.substring(MC_VERSION.length() + 1)}".toString(),
|
'forge.version': "${project.version.substring(MC_VERSION.length() + 1)}".toString(),
|
||||||
'forge.spec': SPEC_VERSION,
|
'forge.spec': SPEC_VERSION,
|
||||||
'forge.group': project.group
|
'forge.group': project.group,
|
||||||
|
'fmllauncher.version': SPEC_VERSION
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -285,9 +286,9 @@ project(':forge') {
|
||||||
}
|
}
|
||||||
//jvmArgs = ['-verbose:class']
|
//jvmArgs = ['-verbose:class']
|
||||||
classpath sourceSets.main.runtimeClasspath
|
classpath sourceSets.main.runtimeClasspath
|
||||||
main patcher.runs.client.main
|
main patcher.runs.forge_client.main
|
||||||
systemProperties = patcher.runs.client.properties
|
systemProperties = patcher.runs.forge_client.properties
|
||||||
environment += patcher.runs.client.environment
|
environment += patcher.runs.forge_client.environment
|
||||||
workingDir 'runclient'
|
workingDir 'runclient'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,10 +303,10 @@ project(':forge') {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
classpath sourceSets.main.runtimeClasspath
|
classpath sourceSets.main.runtimeClasspath
|
||||||
main patcher.runs.server.main
|
main patcher.runs.forge_server.main
|
||||||
args 'nogui'
|
args 'nogui'
|
||||||
systemProperties = patcher.runs.server.properties
|
systemProperties = patcher.runs.forge_server.properties
|
||||||
environment += patcher.runs.server.environment
|
environment += patcher.runs.forge_server.environment
|
||||||
workingDir 'runserver'
|
workingDir 'runserver'
|
||||||
standardInput = System.in
|
standardInput = System.in
|
||||||
}
|
}
|
||||||
|
@ -808,7 +809,7 @@ project(':forge') {
|
||||||
}
|
}
|
||||||
server = {
|
server = {
|
||||||
main 'net.minecraftforge.userdev.UserdevLauncher'
|
main 'net.minecraftforge.userdev.UserdevLauncher'
|
||||||
environment 'target', 'fmldevserver'
|
environment 'target', 'fmluserdevserver'
|
||||||
environment 'FORGE_VERSION', project.version.substring(MC_VERSION.length() + 1)
|
environment 'FORGE_VERSION', project.version.substring(MC_VERSION.length() + 1)
|
||||||
environment 'FORGE_GROUP', project.group
|
environment 'FORGE_GROUP', project.group
|
||||||
environment 'MCP_VERSION', MCP_VERSION
|
environment 'MCP_VERSION', MCP_VERSION
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
--- a/net/minecraft/init/Fluids.java
|
|
||||||
+++ b/net/minecraft/init/Fluids.java
|
|
||||||
@@ -6,6 +6,7 @@
|
|
||||||
import net.minecraft.fluid.Fluid;
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
|
||||||
|
|
||||||
+@net.minecraftforge.registries.ObjectHolder("minecraft")
|
|
||||||
public class Fluids {
|
|
||||||
private static final Set<Fluid> field_207214_f;
|
|
||||||
public static final Fluid field_204541_a;
|
|
|
@ -22,6 +22,7 @@ package net.minecraftforge.fml.language;
|
||||||
|
|
||||||
import org.objectweb.asm.Type;
|
import org.objectweb.asm.Type;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -71,13 +72,15 @@ public class ModFileScanData
|
||||||
}
|
}
|
||||||
public static class AnnotationData {
|
public static class AnnotationData {
|
||||||
private final Type annotationType;
|
private final Type annotationType;
|
||||||
|
private final ElementType targetType;
|
||||||
private final Type clazz;
|
private final Type clazz;
|
||||||
private final String memberName;
|
private final String memberName;
|
||||||
private final Map<String,Object> annotationData;
|
private final Map<String,Object> annotationData;
|
||||||
|
|
||||||
|
|
||||||
public AnnotationData(final Type annotationType, final Type clazz, final String memberName, final Map<String, Object> annotationData) {
|
public AnnotationData(final Type annotationType, final ElementType targetType, final Type clazz, final String memberName, final Map<String, Object> annotationData) {
|
||||||
this.annotationType = annotationType;
|
this.annotationType = annotationType;
|
||||||
|
this.targetType = targetType;
|
||||||
this.clazz = clazz;
|
this.clazz = clazz;
|
||||||
this.memberName = memberName;
|
this.memberName = memberName;
|
||||||
this.annotationData = annotationData;
|
this.annotationData = annotationData;
|
||||||
|
@ -87,6 +90,10 @@ public class ModFileScanData
|
||||||
return annotationType;
|
return annotationType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ElementType getTargetType() {
|
||||||
|
return targetType;
|
||||||
|
}
|
||||||
|
|
||||||
public Type getClassType() {
|
public Type getClassType() {
|
||||||
return clazz;
|
return clazz;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,9 +26,6 @@ import java.net.URL;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by cpw on 05/06/17.
|
|
||||||
*/
|
|
||||||
public class StringUtils
|
public class StringUtils
|
||||||
{
|
{
|
||||||
public static String toLowerCase(final String str) {
|
public static String toLowerCase(final String str) {
|
||||||
|
|
|
@ -33,7 +33,7 @@ import com.google.common.collect.Maps;
|
||||||
public class ModAnnotation
|
public class ModAnnotation
|
||||||
{
|
{
|
||||||
public static ModFileScanData.AnnotationData fromModAnnotation(final Type clazz, final ModAnnotation annotation) {
|
public static ModFileScanData.AnnotationData fromModAnnotation(final Type clazz, final ModAnnotation annotation) {
|
||||||
return new ModFileScanData.AnnotationData(annotation.asmType, clazz, annotation.member, annotation.values);
|
return new ModFileScanData.AnnotationData(annotation.asmType, annotation.type, clazz, annotation.member, annotation.values);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class EnumHolder
|
public static class EnumHolder
|
||||||
|
|
|
@ -44,9 +44,9 @@ public class ForgeI18n {
|
||||||
// {0,modinfo,id} -> modid from ModInfo object; {0,modinfo,name} -> displayname from ModInfo object
|
// {0,modinfo,id} -> modid from ModInfo object; {0,modinfo,name} -> displayname from ModInfo object
|
||||||
customFactories.put("modinfo", (name, formatString, locale) -> new CustomReadOnlyFormat((stringBuffer, objectToParse) -> parseModInfo(formatString, stringBuffer, objectToParse)));
|
customFactories.put("modinfo", (name, formatString, locale) -> new CustomReadOnlyFormat((stringBuffer, objectToParse) -> parseModInfo(formatString, stringBuffer, objectToParse)));
|
||||||
// {0,lower} -> lowercase supplied string
|
// {0,lower} -> lowercase supplied string
|
||||||
customFactories.put("lower", (name, formatString, locale) -> new CustomReadOnlyFormat((stringBuffer, objectToParse) -> stringBuffer.append(StringUtils.toLowerCase((String)objectToParse))));
|
customFactories.put("lower", (name, formatString, locale) -> new CustomReadOnlyFormat((stringBuffer, objectToParse) -> stringBuffer.append(StringUtils.toLowerCase(String.valueOf(objectToParse)))));
|
||||||
// {0,upper> -> uppercase supplied string
|
// {0,upper> -> uppercase supplied string
|
||||||
customFactories.put("upper", (name, formatString, locale) -> new CustomReadOnlyFormat((stringBuffer, objectToParse) -> stringBuffer.append(StringUtils.toUpperCase((String)objectToParse))));
|
customFactories.put("upper", (name, formatString, locale) -> new CustomReadOnlyFormat((stringBuffer, objectToParse) -> stringBuffer.append(StringUtils.toUpperCase(String.valueOf(objectToParse)))));
|
||||||
// {0,exc,class} -> class of exception; {0,exc,msg} -> message from exception
|
// {0,exc,class} -> class of exception; {0,exc,msg} -> message from exception
|
||||||
customFactories.put("exc", (name, formatString, locale) -> new CustomReadOnlyFormat((stringBuffer, objectToParse) -> parseException(formatString, stringBuffer, objectToParse)));
|
customFactories.put("exc", (name, formatString, locale) -> new CustomReadOnlyFormat((stringBuffer, objectToParse) -> parseException(formatString, stringBuffer, objectToParse)));
|
||||||
// {0,vr} -> transform VersionRange into cleartext string using fml.messages.version.restriction.* strings
|
// {0,vr} -> transform VersionRange into cleartext string using fml.messages.version.restriction.* strings
|
||||||
|
@ -112,4 +112,4 @@ public class ForgeI18n {
|
||||||
throw new UnsupportedOperationException("Parsing is not supported");
|
throw new UnsupportedOperationException("Parsing is not supported");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,8 @@ import net.minecraftforge.fml.loading.LoadingModList;
|
||||||
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
|
||||||
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
|
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
|
||||||
import net.minecraftforge.registries.GameData;
|
import net.minecraftforge.registries.GameData;
|
||||||
|
import net.minecraftforge.registries.ObjectHolderRegistry;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
@ -86,6 +88,7 @@ public class ModLoader
|
||||||
modList.setLoadedMods(modContainerStream.collect(Collectors.toList()));
|
modList.setLoadedMods(modContainerStream.collect(Collectors.toList()));
|
||||||
dispatchAndHandleError(LifecycleEventProvider.CONSTRUCT);
|
dispatchAndHandleError(LifecycleEventProvider.CONSTRUCT);
|
||||||
GameData.fireCreateRegistryEvents();
|
GameData.fireCreateRegistryEvents();
|
||||||
|
ObjectHolderRegistry.findObjectHolders();
|
||||||
CapabilityManager.INSTANCE.injectCapabilities(modList.getAllScanData());
|
CapabilityManager.INSTANCE.injectCapabilities(modList.getAllScanData());
|
||||||
GameData.fireRegistryEvents();
|
GameData.fireRegistryEvents();
|
||||||
dispatchAndHandleError(LifecycleEventProvider.PREINIT);
|
dispatchAndHandleError(LifecycleEventProvider.PREINIT);
|
||||||
|
|
|
@ -695,7 +695,7 @@ public class GameData
|
||||||
//Loader.instance().fireRemapEvent(remaps, false);
|
//Loader.instance().fireRemapEvent(remaps, false);
|
||||||
|
|
||||||
// The id map changed, ensure we apply object holders
|
// The id map changed, ensure we apply object holders
|
||||||
ObjectHolderRegistry.INSTANCE.applyObjectHolders();
|
ObjectHolderRegistry.applyObjectHolders();
|
||||||
|
|
||||||
// Return an empty list, because we're good
|
// Return an empty list, because we're good
|
||||||
return ArrayListMultimap.create();
|
return ArrayListMultimap.create();
|
||||||
|
|
|
@ -26,17 +26,15 @@ import java.util.LinkedList;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
import net.minecraft.util.ResourceLocationException;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal class used in tracking {@link ObjectHolder} references
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
class ObjectHolderRef
|
public class ObjectHolderRef implements Runnable
|
||||||
{
|
{
|
||||||
private static final Logger LOGGER = LogManager.getLogger();
|
private static final Logger LOGGER = LogManager.getLogger();
|
||||||
private Field field;
|
private Field field;
|
||||||
|
@ -44,19 +42,24 @@ class ObjectHolderRef
|
||||||
private boolean isValid;
|
private boolean isValid;
|
||||||
private ForgeRegistry<?> registry;
|
private ForgeRegistry<?> registry;
|
||||||
|
|
||||||
ObjectHolderRef(Field field, ResourceLocation injectedObject, boolean extractFromExistingValues)
|
public ObjectHolderRef(Field field, ResourceLocation injectedObject)
|
||||||
{
|
{
|
||||||
registry = getRegistryForType(field);
|
this(field, injectedObject.toString(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectHolderRef(Field field, String injectedObject, boolean extractFromExistingValues)
|
||||||
|
{
|
||||||
|
this.registry = getRegistryForType(field);
|
||||||
this.field = field;
|
this.field = field;
|
||||||
this.isValid = registry != null;
|
this.isValid = registry != null;
|
||||||
|
|
||||||
if (extractFromExistingValues)
|
if (extractFromExistingValues)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Object existing = field.get(null);
|
Object existing = field.get(null);
|
||||||
// nothing is ever allowed to replace AIR
|
// nothing is ever allowed to replace AIR
|
||||||
if (existing == null || existing == registry.getDefault())
|
if (!isValid || (existing == null || existing == registry.getDefault()))
|
||||||
{
|
{
|
||||||
this.injectedObject = null;
|
this.injectedObject = null;
|
||||||
this.field = null;
|
this.field = null;
|
||||||
|
@ -75,7 +78,14 @@ class ObjectHolderRef
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.injectedObject = injectedObject;
|
try
|
||||||
|
{
|
||||||
|
this.injectedObject = new ResourceLocation(injectedObject);
|
||||||
|
}
|
||||||
|
catch (ResourceLocationException e)
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Invalid @ObjectHolder annotation on \"" + field.toString() + "\"", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.injectedObject == null || !isValid())
|
if (this.injectedObject == null || !isValid())
|
||||||
|
@ -103,9 +113,9 @@ class ObjectHolderRef
|
||||||
{
|
{
|
||||||
Class<?> type = typesToExamine.remove();
|
Class<?> type = typesToExamine.remove();
|
||||||
Collections.addAll(typesToExamine, type.getInterfaces());
|
Collections.addAll(typesToExamine, type.getInterfaces());
|
||||||
if (ForgeRegistryEntry.class.isAssignableFrom(type))
|
if (IForgeRegistryEntry.class.isAssignableFrom(type))
|
||||||
{
|
{
|
||||||
registry = (ForgeRegistry<?>)RegistryManager.ACTIVE.getRegistry((Class<ForgeRegistryEntry>)type);
|
registry = (ForgeRegistry<?>)RegistryManager.ACTIVE.getRegistry((Class<IForgeRegistryEntry>)type);
|
||||||
final Class<?> parentType = type.getSuperclass();
|
final Class<?> parentType = type.getSuperclass();
|
||||||
if (parentType != null)
|
if (parentType != null)
|
||||||
{
|
{
|
||||||
|
@ -121,7 +131,8 @@ class ObjectHolderRef
|
||||||
return isValid;
|
return isValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void apply()
|
@Override
|
||||||
|
public void run()
|
||||||
{
|
{
|
||||||
Object thing;
|
Object thing;
|
||||||
if (isValid && registry.containsKey(injectedObject) && !registry.isDummied(injectedObject))
|
if (isValid && registry.containsKey(injectedObject) && !registry.isDummied(injectedObject))
|
||||||
|
@ -147,4 +158,19 @@ class ObjectHolderRef
|
||||||
LOGGER.warn("Unable to set {} with value {} ({})", this.field, thing, this.injectedObject, e);
|
LOGGER.warn("Unable to set {} with value {} ({})", this.field, thing, this.injectedObject, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return field.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object other)
|
||||||
|
{
|
||||||
|
if (!(other instanceof ObjectHolderRef))
|
||||||
|
return false;
|
||||||
|
ObjectHolderRef o = (ObjectHolderRef)other;
|
||||||
|
return this.field.equals(o.field);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,17 +19,20 @@
|
||||||
|
|
||||||
package net.minecraftforge.registries;
|
package net.minecraftforge.registries;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Modifier;
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraftforge.fml.ModList;
|
||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
import net.minecraftforge.fml.common.registry.GameRegistry;
|
import net.minecraftforge.fml.language.ModFileScanData;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
@ -37,52 +40,85 @@ import javax.annotation.Nullable;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal registry for tracking {@link ObjectHolder} references
|
* Internal registry for tracking {@link ObjectHolder} references
|
||||||
*/
|
*/
|
||||||
public enum ObjectHolderRegistry
|
public class ObjectHolderRegistry
|
||||||
{
|
{
|
||||||
INSTANCE;
|
/**
|
||||||
|
* Exposed to allow modders to register their own notification handlers.
|
||||||
|
* This runnable will be called after a registry snapshot has been injected and finalized.
|
||||||
|
* The internal list is backed by a HashSet so it is HIGHLY recommended you implement a proper equals
|
||||||
|
* and hashCode function to de-duplicate callers here.
|
||||||
|
* The default @ObjectHolder implementation uses the hashCode/equals for the field the annotation is on.
|
||||||
|
*/
|
||||||
|
public static void addHandler(Runnable ref)
|
||||||
|
{
|
||||||
|
objectHolders.add(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removed the specified handler from the notification list.
|
||||||
|
*
|
||||||
|
* The internal list is backed by a hash set, and so proper hashCode and equals operations are required for success.
|
||||||
|
*
|
||||||
|
* The default @ObjectHolder implementation uses the hashCode/equals for the field the annotation is on.
|
||||||
|
*
|
||||||
|
* @return true if handler was matched and removed.
|
||||||
|
*/
|
||||||
|
public static boolean removeHandler(Runnable ref)
|
||||||
|
{
|
||||||
|
return objectHolders.remove(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================
|
||||||
|
// Everything below is internal, do not use.
|
||||||
|
//==============================================================
|
||||||
|
|
||||||
private static final Logger LOGGER = LogManager.getLogger();
|
private static final Logger LOGGER = LogManager.getLogger();
|
||||||
private List<ObjectHolderRef> objectHolders = Lists.newArrayList();
|
private static final Set<Runnable> objectHolders = new HashSet<>();
|
||||||
/* TODO annotation data
|
private static final Type OBJECT_HOLDER = Type.getType(ObjectHolder.class);
|
||||||
public void findObjectHolders(ASMDataTable table)
|
private static final Type MOD = Type.getType(Mod.class);
|
||||||
|
|
||||||
|
public static void findObjectHolders()
|
||||||
{
|
{
|
||||||
LOGGER.info("Processing ObjectHolder annotations");
|
LOGGER.info("Processing ObjectHolder annotations");
|
||||||
Set<ASMData> allObjectHolders = table.getAll(ObjectHolder.class.getName());
|
final List<ModFileScanData.AnnotationData> annotations = ModList.get().getAllScanData().stream()
|
||||||
Map<String, String> classModIds = Maps.newHashMap();
|
.map(ModFileScanData::getAnnotations)
|
||||||
Map<String, Class<?>> classCache = Maps.newHashMap();
|
.flatMap(Collection::stream)
|
||||||
|
.filter(a -> OBJECT_HOLDER.equals(a.getAnnotationType()) || MOD.equals(a.getAnnotationType()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
table.getAll(Mod.class.getName()).forEach(data -> classModIds.put(data.getClassName(), (String)data.getAnnotationInfo().get("value")));
|
Map<Type, String> classModIds = Maps.newHashMap();
|
||||||
|
Map<Type, Class<?>> classCache = Maps.newHashMap();
|
||||||
|
|
||||||
|
// Gather all @Mod classes, so that @ObjectHolder's in those classes don't need to specify the mod id, Modder convince
|
||||||
|
annotations.stream().filter(a -> MOD.equals(a.getAnnotationType())).forEach(data -> classModIds.put(data.getClassType(), (String)data.getAnnotationData().get("value")));
|
||||||
|
|
||||||
// double pass - get all the class level annotations first, then the field level annotations
|
// double pass - get all the class level annotations first, then the field level annotations
|
||||||
allObjectHolders.stream().filter(data -> data.getObjectName().equals(data.getClassName())).forEach(data ->
|
annotations.stream().filter(a -> OBJECT_HOLDER.equals(a.getAnnotationType())).filter(a -> a.getTargetType() == ElementType.TYPE)
|
||||||
{
|
.forEach(data -> scanTarget(classModIds, classCache, data.getClassType(), null, (String)data.getAnnotationData().get("value"), true, data.getClassType().getClassName().startsWith("net.minecraft.init")));
|
||||||
String value = (String)data.getAnnotationInfo().get("value");
|
|
||||||
scanTarget(classModIds, classCache, data.getClassName(), data.getObjectName(), value, true, data.getClassName().startsWith("net.minecraft.init"));
|
annotations.stream().filter(a -> OBJECT_HOLDER.equals(a.getAnnotationType())).filter(a -> a.getTargetType() == ElementType.FIELD)
|
||||||
});
|
.forEach(data -> scanTarget(classModIds, classCache, data.getClassType(), data.getMemberName(), (String)data.getAnnotationData().get("value"), false, false));
|
||||||
allObjectHolders.stream().filter(data -> !data.getObjectName().equals(data.getClassName())).forEach(data ->
|
|
||||||
{
|
|
||||||
String value = (String)data.getAnnotationInfo().get("value");
|
|
||||||
scanTarget(classModIds, classCache, data.getClassName(), data.getObjectName(), value, false, false);
|
|
||||||
});
|
|
||||||
LOGGER.info("Found {} ObjectHolder annotations", objectHolders.size());
|
LOGGER.info("Found {} ObjectHolder annotations", objectHolders.size());
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
private void scanTarget(Map<String, String> classModIds, Map<String, Class<?>> classCache, String className, @Nullable String annotationTarget, String value, boolean isClass, boolean extractFromValue)
|
private static void scanTarget(Map<Type, String> classModIds, Map<Type, Class<?>> classCache, Type type, @Nullable String annotationTarget, String value, boolean isClass, boolean extractFromValue)
|
||||||
{
|
{
|
||||||
Class<?> clazz;
|
Class<?> clazz;
|
||||||
if (classCache.containsKey(className))
|
if (classCache.containsKey(type))
|
||||||
{
|
{
|
||||||
clazz = classCache.get(className);
|
clazz = classCache.get(type);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
clazz = Class.forName(className, extractFromValue, getClass().getClassLoader());
|
clazz = Class.forName(type.getClassName(), extractFromValue, ObjectHolderRegistry.class.getClassLoader());
|
||||||
classCache.put(className, clazz);
|
classCache.put(type, clazz);
|
||||||
}
|
}
|
||||||
catch (ClassNotFoundException ex)
|
catch (ClassNotFoundException ex)
|
||||||
{
|
{
|
||||||
|
@ -92,24 +128,26 @@ public enum ObjectHolderRegistry
|
||||||
}
|
}
|
||||||
if (isClass)
|
if (isClass)
|
||||||
{
|
{
|
||||||
scanClassForFields(classModIds, className, value, clazz, extractFromValue);
|
scanClassForFields(classModIds, type, value, clazz, extractFromValue);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (value.indexOf(':') == -1)
|
if (value.indexOf(':') == -1)
|
||||||
{
|
{
|
||||||
String prefix = classModIds.get(className);
|
String prefix = classModIds.get(type);
|
||||||
if (prefix == null)
|
if (prefix == null)
|
||||||
{
|
{
|
||||||
LOGGER.warn("Found an unqualified ObjectHolder annotation ({}) without a modid context at {}.{}, ignoring", value, className, annotationTarget);
|
LOGGER.warn("Found an unqualified ObjectHolder annotation ({}) without a modid context at {}.{}, ignoring", value, type, annotationTarget);
|
||||||
throw new IllegalStateException("Unqualified reference to ObjectHolder");
|
throw new IllegalStateException("Unqualified reference to ObjectHolder");
|
||||||
}
|
}
|
||||||
value = prefix + ":" + value;
|
value = prefix + ':' + value;
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Field f = clazz.getDeclaredField(annotationTarget);
|
Field f = clazz.getDeclaredField(annotationTarget);
|
||||||
addHolderReference(new ObjectHolderRef(f, new ResourceLocation(value), extractFromValue));
|
ObjectHolderRef ref = new ObjectHolderRef(f, value, extractFromValue);
|
||||||
|
if (ref.isValid())
|
||||||
|
addHandler(ref);
|
||||||
}
|
}
|
||||||
catch (NoSuchFieldException ex)
|
catch (NoSuchFieldException ex)
|
||||||
{
|
{
|
||||||
|
@ -119,32 +157,24 @@ public enum ObjectHolderRegistry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scanClassForFields(Map<String, String> classModIds, String className, String value, Class<?> clazz, boolean extractFromExistingValues)
|
private static void scanClassForFields(Map<Type, String> classModIds, Type targetClass, String value, Class<?> clazz, boolean extractFromExistingValues)
|
||||||
{
|
{
|
||||||
classModIds.put(className, value);
|
classModIds.put(targetClass, value);
|
||||||
final int flags = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC;
|
final int flags = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC;
|
||||||
for (Field f : clazz.getFields())
|
for (Field f : clazz.getFields())
|
||||||
{
|
{
|
||||||
if (((f.getModifiers() & flags) != flags) || f.isAnnotationPresent(ObjectHolder.class))
|
if (((f.getModifiers() & flags) != flags) || f.isAnnotationPresent(ObjectHolder.class))
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
ObjectHolderRef ref = new ObjectHolderRef(f, value + ':' + f.getName().toLowerCase(Locale.ENGLISH), extractFromExistingValues);
|
||||||
addHolderReference(new ObjectHolderRef(f, new ResourceLocation(value, f.getName()), extractFromExistingValues));
|
if (ref.isValid())
|
||||||
|
addHandler(ref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addHolderReference(ObjectHolderRef ref)
|
public static void applyObjectHolders()
|
||||||
{
|
|
||||||
if (ref.isValid())
|
|
||||||
{
|
|
||||||
objectHolders.add(ref);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void applyObjectHolders()
|
|
||||||
{
|
{
|
||||||
LOGGER.info("Applying holder lookups");
|
LOGGER.info("Applying holder lookups");
|
||||||
objectHolders.forEach(ObjectHolderRef::apply);
|
objectHolders.forEach(Runnable::run);
|
||||||
LOGGER.info("Holder lookups applied");
|
LOGGER.info("Holder lookups applied");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue