use of net.minecraftforge.fml.common.discovery.ASMDataTable in project Bookshelf by Darkhax-Minecraft.
the class AnnotationUtils method getAnnotations.
/**
* Finds all classes annotated with the annotation class. These classes are then
* instantiated, added to a list, and given to you.
*
* @param table The ASMDataTable created by Forge. You can get this from most of the main
* mod loading stage events.
* @param annotation The class of the annotation you're using to search for.
* @param instance The class of the thing you're trying to construct. This should be a
* shared interface, or parent class.
* @return A list of all classes annotated with the annotation, as instances.
*/
public static <T, A extends Annotation> Map<T, A> getAnnotations(ASMDataTable table, Class<A> annotation, Class<T> instance) {
final Map<T, A> map = new HashMap<>();
for (final ASMDataTable.ASMData asmData : getData(table, annotation)) {
try {
final Class<?> asmClass = Class.forName(asmData.getClassName());
final Class<? extends T> asmInstanceClass = asmClass.asSubclass(instance);
map.put(asmInstanceClass.newInstance(), asmInstanceClass.getAnnotation(annotation));
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
Constants.LOG.warn("Could not load " + asmData.getClassName(), e);
}
}
return map;
}
use of net.minecraftforge.fml.common.discovery.ASMDataTable in project Guide-API by TeamAmeriFrance.
the class AnnotationHandler method registerBooks.
public static void registerBooks(ASMDataTable dataTable) {
for (ASMDataTable.ASMData data : dataTable.getAll(GuideBook.class.getCanonicalName())) {
try {
Class<?> genericClass = Class.forName(data.getClassName());
if (!IGuideBook.class.isAssignableFrom(genericClass))
continue;
IGuideBook guideBook = (IGuideBook) genericClass.newInstance();
Book book = guideBook.buildBook();
if (book == null)
continue;
APISetter.registerBook(book);
BOOK_CLASSES.add(Pair.of(book, guideBook));
} catch (Exception e) {
LogHelper.error("Error registering book for class " + data.getClassName());
e.printStackTrace();
}
}
APISetter.setIndexedBooks(Lists.newArrayList(GuideAPI.getBooks().values()));
}
use of net.minecraftforge.fml.common.discovery.ASMDataTable in project Charset by CharsetMC.
the class ModuleLoader method readDataTable.
@SuppressWarnings("unchecked")
private void readDataTable(ASMDataTable table) {
Multimap<String, String> unmetDependencies = HashMultimap.create();
Set<String> enabledModules = new HashSet<>();
Set<String> compatModules = new HashSet<>();
Map<String, ASMDataTable.ASMData> moduleData = new HashMap<>();
Property baseProfileProp = ModCharset.configGeneral.get("general", "profile", "DEFAULT");
baseProfileProp.setValidValues(new String[] { "DEFAULT", "STABLE", "TESTING", "EXPERIMENTAL" });
baseProfileProp.setLanguageKey("config.charset.profile.name");
baseProfileProp.setRequiresMcRestart(true);
ModuleProfile profile, defaultProfile;
if (ModCharset.INDEV) {
defaultProfile = ModuleProfile.INDEV;
} else if (ModCharset.defaultOptions.containsKey("profile")) {
defaultProfile = getProfileFromString(ModCharset.defaultOptions.get("profile"));
} else {
defaultProfile = ModuleProfile.STABLE;
}
baseProfileProp.setComment("Set the base profile for Charset.\nThis will give you a default set of modules based on stability.\nAllowed values: DEFAULT, STABLE, TESTING, EXPERIMENTAL (DEFAULT means " + defaultProfile.name() + ")\nFor fine-grained configuration, check modules.cfg!");
if ("DEFAULT".equals(baseProfileProp.getString().toUpperCase())) {
profile = defaultProfile;
} else {
profile = getProfileFromString(baseProfileProp.getString());
}
ModCharset.profile = profile;
ModCharset.logger.info("Charset profile is " + ModCharset.profile);
ConfigCategory category = ModCharset.configModules.getCategory("overrides");
category.setComment("Overrides can have one of three values: DEFAULT, ENABLE, DISABLE\nDEFAULT will enable the module based on your profile settings and dependency availability.");
category = ModCharset.configModules.getCategory("categories");
category.setComment("This section allows you to disable certain categories of content, based on a tag system.");
boolean configDirty = false;
Map<String, Boolean> categoryMap = new HashMap<>();
// Initialize categories
for (ASMDataTable.ASMData data : table.getAll(CharsetModule.class.getName())) {
Map<String, Object> info = data.getAnnotationInfo();
List<String> tags = (List<String>) info.getOrDefault("categories", Collections.emptyList());
for (String s : tags) {
if (!categoryMap.containsKey(s)) {
Property prop = ModCharset.configModules.get("categories", s, !CATEGORIES_OFF_BY_DEFAULT.contains(s));
prop.setRequiresMcRestart(true);
categoryMap.put(s, prop.getBoolean());
}
}
}
for (ASMDataTable.ASMData data : table.getAll(CharsetModule.class.getName())) {
Map<String, Object> info = data.getAnnotationInfo();
String name = (String) info.get("name");
String desc = (String) info.get("description");
if (desc == null)
desc = "";
ModuleProfile modProfile = ModuleProfile.valueOf(((ModAnnotation.EnumHolder) info.get("profile")).getValue());
Boolean isDefault = (Boolean) info.getOrDefault("isDefault", true);
Boolean compat = modProfile == ModuleProfile.COMPAT;
Boolean clientOnly = (Boolean) info.getOrDefault("isClientOnly", false);
Boolean serverOnly = (Boolean) info.getOrDefault("isServerOnly", false);
List<String> tags = (List<String>) info.getOrDefault("categories", Collections.emptyList());
String moduleGuiClass = (String) info.getOrDefault("moduleConfigGui", "");
if (moduleGuiClass.length() > 0) {
moduleGuiClasses.put(name, moduleGuiClass);
}
moduleData.put(name, data);
ThreeState override = ThreeState.MAYBE;
if ((Boolean) info.getOrDefault("isVisible", true)) {
if (modProfile == ModuleProfile.INDEV && profile != ModuleProfile.INDEV) {
override = ThreeState.NO;
} else {
if (compat) {
Property prop = ModCharset.configModules.get("compat", name, isDefault);
prop.setRequiresMcRestart(true);
if (!prop.getBoolean())
override = ThreeState.NO;
} else {
Property prop = ModCharset.configModules.get("overrides", name, "DEFAULT");
prop.setValidValues(new String[] { "DEFAULT", "ENABLE", "DISABLE" });
prop.setRequiresMcRestart(true);
if (desc.length() > 0)
desc += " ";
desc += "[Profile: " + modProfile.name().toUpperCase() + "";
if (!isDefault) {
desc += ", off by default!";
}
desc += "]";
if (!desc.equals(prop.getComment())) {
prop.setComment(desc);
configDirty = true;
}
if (prop.getString().toUpperCase().startsWith("ENABLE")) {
override = ThreeState.YES;
} else if (prop.getString().toUpperCase().startsWith("DISABLE")) {
override = ThreeState.NO;
} else if (!"DEFAULT".equals(prop.getString().toUpperCase())) {
ModCharset.logger.warn("Invalid value for '" + name + "' override: '" + prop.getString() + ";");
}
}
}
}
if (clientOnly && !FMLCommonHandler.instance().getSide().isClient()) {
continue;
}
if (serverOnly && !FMLCommonHandler.instance().getSide().isServer()) {
continue;
}
if (compat) {
compatModules.add(name);
}
if (override == ThreeState.MAYBE && isDefault) {
List<String> antideps = (List<String>) info.get("antidependencies");
if (antideps != null) {
for (String dep : antideps) {
if (isDepPresent(dep, enabledModules)) {
ModCharset.logger.info("Antidependency " + dep + " is present - disabling otherwise not forced module " + name + ".");
isDefault = false;
break;
}
}
}
for (String s : tags) {
if (!categoryMap.get(s)) {
ModCharset.logger.info("Category " + s + " is disabled - disabling otherwise not forced module " + name + ".");
isDefault = false;
}
}
}
if (!compat && modProfile != ModuleProfile.FORCED && modProfile.ordinal() > profile.ordinal()) {
isDefault = false;
}
EnableInformation enableInfo = new EnableInformation(isDefault, override);
if (enableInfo.isEnabled()) {
enabledModules.add(name);
enableInfoMap.put(name, enableInfo);
if (!"lib".equals(name))
dependencies.put(name, "lib");
List<String> deps = (List<String>) info.get("dependencies");
if (deps != null) {
dependencies.putAll(name, deps);
}
}
}
if (ModCharset.configGeneral.hasChanged()) {
ModCharset.configGeneral.save();
}
if (ModCharset.configModules.hasChanged() || configDirty) {
ModCharset.configModules.save();
configDirty = false;
}
int removedCount = 1;
while (removedCount > 0) {
removedCount = 0;
for (String name : enabledModules) {
if (dependencies.containsKey(name)) {
for (String dep : dependencies.get(name)) {
boolean optional = false;
if (dep.startsWith("optional:")) {
optional = true;
dep = dep.substring("optional:".length());
}
boolean met = optional || isDepPresent(dep, enabledModules);
if (!met) {
enableInfoMap.get(name).dependenciesMet = false;
unmetDependencies.put(name, dep);
break;
}
}
}
}
Iterator<String> unmetDepKey = unmetDependencies.keySet().iterator();
while (unmetDepKey.hasNext()) {
String depMod = unmetDepKey.next();
EnableInformation enableInfo = enableInfoMap.get(depMod);
if (!enableInfo.isEnabled()) {
if (!compatModules.contains(depMod)) {
ModCharset.logger.info("Module " + depMod + " requires " + joinerComma.join(unmetDependencies.get(depMod)) + ", but is not force-enabled. You can ignore this - it is not an error, just information.");
}
removedCount++;
enabledModules.remove(depMod);
unmetDepKey.remove();
}
}
}
for (String name : enabledModules) {
if (ModCharset.INDEV) {
ModCharset.logger.info("Instantiating module " + name);
}
ASMDataTable.ASMData data = moduleData.get(name);
try {
Object o = getClass(data).newInstance();
loadedModules.put(name, o);
loadedModulesByClass.put(data.getClassName(), o);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
if (unmetDependencies.size() > 0) {
List<String> depStrings = new ArrayList<>(unmetDependencies.size());
for (String depMod : unmetDependencies.keys()) {
depStrings.add(depMod + "<-[" + joinerComma.join(unmetDependencies.get(depMod)) + "]");
}
throw new RuntimeException("The following mandatory dependencies were not met: " + joinerComma.join(depStrings));
}
iterateModules(table, Mod.EventHandler.class.getName(), (data, instance) -> {
String methodName = data.getObjectName().substring(0, data.getObjectName().indexOf('('));
String methodDesc = data.getObjectName().substring(methodName.length());
MethodType methodType = MethodType.fromMethodDescriptorString(methodDesc, classLoader);
if (ModCharset.INDEV) {
if (methodType.parameterCount() != 1) {
throw new RuntimeException("Invalid parameter count " + methodType.parameterCount() + " for EventHandler in " + instance.getClass() + "!");
}
}
try {
MethodHandle methodHandle = MethodHandles.lookup().findVirtual(getClass(data), methodName, methodType);
List<Pair<String, MethodHandle>> list = loaderHandles.computeIfAbsent(methodType.parameterType(0), k -> new ArrayList<>());
list.sort(Comparator.comparing(Pair::getLeft));
list.add(Pair.of(loadedModules.inverse().get(instance), methodHandle));
} catch (NoSuchMethodException e) {
// method has been annotated away, ignore
} catch (Exception e) {
throw new RuntimeException(e);
}
});
iterateModules(table, CharsetModule.Instance.class.getName(), (data, instance) -> {
try {
String instString = (String) data.getAnnotationInfo().get("value");
if (instString == null || instString.equals("")) {
getField(data).set(instance, instance);
} else {
Object inst2 = loadedModules.get(instString);
getField(data).set(instance, inst2);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
});
iterateModules(table, CharsetModule.PacketRegistry.class.getName(), (data, instance) -> {
String id = (String) data.getAnnotationInfo().get("value");
if (id == null)
id = loadedModules.inverse().get(instance);
try {
String channelName = "chrs:" + id.substring(id.lastIndexOf('.') + 1);
getField(data).set(instance, new PacketRegistry(channelName));
} catch (Exception e) {
throw new RuntimeException(e);
}
});
iterateModules(table, CharsetModule.Configuration.class.getName(), (data, instance) -> {
String id = (String) data.getAnnotationInfo().get("value");
if (id == null)
id = loadedModules.inverse().get(instance);
try {
Configuration config = new Configuration(ModCharset.getModuleConfigFile(id));
getField(data).set(instance, config);
moduleConfigs.put(id, config);
} catch (Exception e) {
throw new RuntimeException(e);
}
});
Side side = FMLCommonHandler.instance().getSide();
for (ASMDataTable.ASMData data : table.getAll(CharsetModule.SidedProxy.class.getName())) {
String clientSide = (String) data.getAnnotationInfo().get("clientSide");
String serverSide = (String) data.getAnnotationInfo().get("serverSide");
try {
Field f = getField(data);
f.set(null, Class.forName(side == Side.CLIENT ? clientSide : serverSide).newInstance());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
List<String> sortedModules = new ArrayList<>();
Set<String> remainingModules = Sets.newHashSet(enabledModules);
while (!remainingModules.isEmpty()) {
Iterator<String> remainingIterator = remainingModules.iterator();
boolean added = false;
while (remainingIterator.hasNext()) {
String s = remainingIterator.next();
boolean canAdd = true;
for (String dep : dependencies.get(s)) {
if (!dep.startsWith("mod:") && !dep.startsWith("optional:") && !sortedModules.contains(dep)) {
canAdd = false;
break;
}
}
if (canAdd) {
added = true;
sortedModules.add(s);
remainingIterator.remove();
}
}
if (!added) {
throw new RuntimeException("Cyclic dependency within Charset modules! Report!");
}
}
for (List<Pair<String, MethodHandle>> list : loaderHandles.values()) {
list.sort(Comparator.comparingInt(a -> sortedModules.indexOf(a.getKey())));
}
for (String s : sortedModules) {
MinecraftForge.EVENT_BUS.register(loadedModules.get(s));
}
for (ASMDataTable.ASMData data : table.getAll(CharsetCompatAnnotation.class.getName())) {
String id = (String) data.getAnnotationInfo().get("value");
try {
addClassNames(table, Class.forName(data.getClassName()), id);
} catch (Exception e) {
e.printStackTrace();
}
}
passEvent(new CharsetLoadConfigEvent(true));
if (ModCharset.configModules.hasChanged() || configDirty) {
ModCharset.configModules.save();
configDirty = false;
}
}
use of net.minecraftforge.fml.common.discovery.ASMDataTable in project Charset by CharsetMC.
the class ModuleLoader method addClassNames.
private void addClassNames(ASMDataTable table, Class annotationClass, String confType) {
for (ASMDataTable.ASMData data : table.getAll(annotationClass.getName())) {
String id = (String) data.getAnnotationInfo().get("value");
Property prop = ModCharset.configModules.get("compat", confType + ":" + id, true);
boolean enabled = prop.getBoolean();
if (enabled && loadedModules.containsKey(id)) {
classNames.put(annotationClass, data.getClassName());
}
}
}
use of net.minecraftforge.fml.common.discovery.ASMDataTable in project ClaySoldiersMod by SanAndreasP.
the class ClaySoldiersMod method loadPlugins.
private static void loadPlugins(ASMDataTable dataTable) {
String annotationClassName = CsmPlugin.class.getCanonicalName();
Set<ASMDataTable.ASMData> asmDatas = dataTable.getAll(annotationClassName);
for (ASMDataTable.ASMData asmData : asmDatas) {
try {
Class<?> asmClass = Class.forName(asmData.getClassName());
Class<? extends ICsmPlugin> asmInstanceClass = asmClass.asSubclass(ICsmPlugin.class);
ICsmPlugin instance = asmInstanceClass.getConstructor().newInstance();
PLUGINS.add(instance);
} catch (ClassNotFoundException | IllegalAccessException | ExceptionInInitializerError | InstantiationException | NoSuchMethodException | InvocationTargetException e) {
CsmConstants.LOG.log(Level.ERROR, "Failed to load: {}", asmData.getClassName(), e);
}
}
}
Aggregations