diff --git a/src/main/java/gregtech/api/modules/IGregTechModule.java b/src/main/java/gregtech/api/modules/IGregTechModule.java
index 75208d8dce9..d8c156c8bf9 100644
--- a/src/main/java/gregtech/api/modules/IGregTechModule.java
+++ b/src/main/java/gregtech/api/modules/IGregTechModule.java
@@ -21,7 +21,7 @@ public interface IGregTechModule {
/**
* What other modules this module depends on.
*
- * e.g. new ResourceLocation("gregtech", "foo_module") represents a dependency on the module
+ * e.g. {@code new ResourceLocation("gregtech", "foo_module")} represents a dependency on the module
* "foo_module" in the container "gregtech"
*/
@NotNull
@@ -29,25 +29,25 @@ default Set getDependencyUids() {
return Collections.emptySet();
}
- default void construction(FMLConstructionEvent event) {}
+ default void construction(@NotNull FMLConstructionEvent event) {}
- default void preInit(FMLPreInitializationEvent event) {}
+ default void preInit(@NotNull FMLPreInitializationEvent event) {}
- default void init(FMLInitializationEvent event) {}
+ default void init(@NotNull FMLInitializationEvent event) {}
- default void postInit(FMLPostInitializationEvent event) {}
+ default void postInit(@NotNull FMLPostInitializationEvent event) {}
- default void loadComplete(FMLLoadCompleteEvent event) {}
+ default void loadComplete(@NotNull FMLLoadCompleteEvent event) {}
- default void serverAboutToStart(FMLServerAboutToStartEvent event) {}
+ default void serverAboutToStart(@NotNull FMLServerAboutToStartEvent event) {}
- default void serverStarting(FMLServerStartingEvent event) {}
+ default void serverStarting(@NotNull FMLServerStartingEvent event) {}
- default void serverStarted(FMLServerStartedEvent event) {}
+ default void serverStarted(@NotNull FMLServerStartedEvent event) {}
- default void serverStopping(FMLServerStoppingEvent event) {}
+ default void serverStopping(@NotNull FMLServerStoppingEvent event) {}
- default void serverStopped(FMLServerStoppedEvent event) {}
+ default void serverStopped(@NotNull FMLServerStoppedEvent event) {}
/**
* Register packets using GregTech's packet handling API here.
@@ -87,7 +87,11 @@ default void registerPackets() {}
return Collections.emptyList();
}
- default boolean processIMC(FMLInterModComms.IMCMessage message) {
+ /**
+ * @param message the message to process
+ * @return if the message was processed, stopping all other modules from processing it
+ */
+ default boolean processIMC(@NotNull FMLInterModComms.IMCMessage message) {
return false;
}
diff --git a/src/main/java/gregtech/api/modules/IModuleManager.java b/src/main/java/gregtech/api/modules/IModuleManager.java
index e6a04f62075..a2dd5048cd7 100644
--- a/src/main/java/gregtech/api/modules/IModuleManager.java
+++ b/src/main/java/gregtech/api/modules/IModuleManager.java
@@ -4,23 +4,28 @@
import net.minecraft.util.ResourceLocation;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
public interface IModuleManager {
- default boolean isModuleEnabled(String containerID, String moduleID) {
+ default boolean isModuleEnabled(@NotNull String containerID, @NotNull String moduleID) {
return isModuleEnabled(new ResourceLocation(containerID, moduleID));
}
- default boolean isModuleEnabled(String moduleID) {
+ default boolean isModuleEnabled(@NotNull String moduleID) {
return isModuleEnabled(GTUtility.gregtechId(moduleID));
}
- boolean isModuleEnabled(ResourceLocation id);
+ boolean isModuleEnabled(@NotNull ResourceLocation id);
- void registerContainer(IModuleContainer container);
+ void registerContainer(@NotNull IModuleContainer container);
+ @Nullable
IModuleContainer getLoadedContainer();
+ @NotNull
ModuleStage getStage();
- boolean hasPassedStage(ModuleStage stage);
+ boolean hasPassedStage(@NotNull ModuleStage stage);
}
diff --git a/src/main/java/gregtech/modules/ModuleManager.java b/src/main/java/gregtech/modules/ModuleManager.java
index 768d44e95b6..b65ff4938ff 100644
--- a/src/main/java/gregtech/modules/ModuleManager.java
+++ b/src/main/java/gregtech/modules/ModuleManager.java
@@ -12,29 +12,35 @@
import net.minecraftforge.fml.common.event.*;
import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
+import it.unimi.dsi.fastutil.objects.Object2ReferenceLinkedOpenHashMap;
+import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet;
+import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.Unmodifiable;
import java.io.File;
+import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.stream.Collectors;
-public class ModuleManager implements IModuleManager {
+public final class ModuleManager implements IModuleManager {
private static final ModuleManager INSTANCE = new ModuleManager();
private static final String MODULE_CFG_FILE_NAME = "modules.cfg";
private static final String MODULE_CFG_CATEGORY_NAME = "modules";
private static File configFolder;
- private Map containers = new LinkedHashMap<>();
- private final Map sortedModules = new LinkedHashMap<>();
- private final Set loadedModules = new LinkedHashSet<>();
+ private Map containers = new Object2ReferenceLinkedOpenHashMap<>();
+ private final Map sortedModules = new Object2ReferenceLinkedOpenHashMap<>();
+ private final Set loadedModules = new ReferenceLinkedOpenHashSet<>();
- private IModuleContainer currentContainer;
+ private @Nullable IModuleContainer currentContainer;
private ModuleStage currentStage = ModuleStage.C_SETUP;
- private final Logger logger = LogManager.getLogger("GregTech Module Loader");
+ private static final Logger logger = LogManager.getLogger("GregTech Module Loader");
private Configuration config;
private ModuleManager() {}
@@ -44,11 +50,11 @@ public static ModuleManager getInstance() {
}
@Override
- public boolean isModuleEnabled(ResourceLocation id) {
+ public boolean isModuleEnabled(@NotNull ResourceLocation id) {
return sortedModules.containsKey(id);
}
- public boolean isModuleEnabled(IGregTechModule module) {
+ private boolean isModuleEnabled(@NotNull IGregTechModule module) {
GregTechModule annotation = module.getClass().getAnnotation(GregTechModule.class);
String comment = getComment(module);
Property prop = getConfiguration().get(MODULE_CFG_CATEGORY_NAME,
@@ -57,22 +63,22 @@ public boolean isModuleEnabled(IGregTechModule module) {
}
@Override
- public IModuleContainer getLoadedContainer() {
+ public @Nullable IModuleContainer getLoadedContainer() {
return currentContainer;
}
@Override
- public ModuleStage getStage() {
+ public @NotNull ModuleStage getStage() {
return currentStage;
}
@Override
- public boolean hasPassedStage(ModuleStage stage) {
+ public boolean hasPassedStage(@NotNull ModuleStage stage) {
return currentStage.ordinal() > stage.ordinal();
}
@Override
- public void registerContainer(IModuleContainer container) {
+ public void registerContainer(@NotNull IModuleContainer container) {
if (currentStage != ModuleStage.C_SETUP) {
logger.error("Failed to register module container {}, as module loading has already begun", container);
return;
@@ -81,14 +87,21 @@ public void registerContainer(IModuleContainer container) {
containers.put(container.getID(), container);
}
- public void setup(ASMDataTable asmDataTable, File configDirectory) {
- // find and register all containers registered with the @ModuleContainer annotation, then sort them by container
- // name
+ /**
+ * Set up the Module Manager
+ *
+ * @param asmDataTable the data table containing all of the Module Container and Module classes
+ * @param configDirectory the directory containing the GT config directory
+ */
+ public void setup(@NotNull ASMDataTable asmDataTable, @NotNull File configDirectory) {
+ // find and register all containers registered with the @ModuleContainer annotation
discoverContainers(asmDataTable);
+ // then sort them by container name
containers = containers.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.collect(Collectors.toMap(
- Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a, LinkedHashMap::new));
+ Map.Entry::getKey, Map.Entry::getValue,
+ (a, b) -> a, Object2ReferenceLinkedOpenHashMap::new));
currentStage = ModuleStage.M_SETUP;
configFolder = new File(configDirectory, GTValues.MODID);
@@ -108,9 +121,10 @@ public void setup(ASMDataTable asmDataTable, File configDirectory) {
MinecraftForge.ORE_GEN_BUS.register(clazz);
}
}
+ currentContainer = null;
}
- public void onConstruction(FMLConstructionEvent event) {
+ public void onConstruction(@NotNull FMLConstructionEvent event) {
currentStage = ModuleStage.CONSTRUCTION;
for (IGregTechModule module : loadedModules) {
currentContainer = containers.get(getContainerID(module));
@@ -118,9 +132,10 @@ public void onConstruction(FMLConstructionEvent event) {
module.construction(event);
module.getLogger().debug("Construction complete");
}
+ currentContainer = null;
}
- public void onPreInit(FMLPreInitializationEvent event) {
+ public void onPreInit(@NotNull FMLPreInitializationEvent event) {
currentStage = ModuleStage.PRE_INIT;
// Separate loops for strict ordering
for (IGregTechModule module : loadedModules) {
@@ -134,9 +149,10 @@ public void onPreInit(FMLPreInitializationEvent event) {
module.preInit(event);
module.getLogger().debug("Pre-init complete");
}
+ currentContainer = null;
}
- public void onInit(FMLInitializationEvent event) {
+ public void onInit(@NotNull FMLInitializationEvent event) {
currentStage = ModuleStage.INIT;
for (IGregTechModule module : loadedModules) {
currentContainer = containers.get(getContainerID(module));
@@ -144,9 +160,10 @@ public void onInit(FMLInitializationEvent event) {
module.init(event);
module.getLogger().debug("Init complete");
}
+ currentContainer = null;
}
- public void onPostInit(FMLPostInitializationEvent event) {
+ public void onPostInit(@NotNull FMLPostInitializationEvent event) {
currentStage = ModuleStage.POST_INIT;
for (IGregTechModule module : loadedModules) {
currentContainer = containers.get(getContainerID(module));
@@ -154,9 +171,10 @@ public void onPostInit(FMLPostInitializationEvent event) {
module.postInit(event);
module.getLogger().debug("Post-init complete");
}
+ currentContainer = null;
}
- public void onLoadComplete(FMLLoadCompleteEvent event) {
+ public void onLoadComplete(@NotNull FMLLoadCompleteEvent event) {
currentStage = ModuleStage.FINISHED;
for (IGregTechModule module : loadedModules) {
currentContainer = containers.get(getContainerID(module));
@@ -164,9 +182,10 @@ public void onLoadComplete(FMLLoadCompleteEvent event) {
module.loadComplete(event);
module.getLogger().debug("Load-complete complete");
}
+ currentContainer = null;
}
- public void onServerAboutToStart(FMLServerAboutToStartEvent event) {
+ public void onServerAboutToStart(@NotNull FMLServerAboutToStartEvent event) {
currentStage = ModuleStage.SERVER_ABOUT_TO_START;
for (IGregTechModule module : loadedModules) {
currentContainer = containers.get(getContainerID(module));
@@ -174,9 +193,10 @@ public void onServerAboutToStart(FMLServerAboutToStartEvent event) {
module.serverAboutToStart(event);
module.getLogger().debug("Server-about-to-start complete");
}
+ currentContainer = null;
}
- public void onServerStarting(FMLServerStartingEvent event) {
+ public void onServerStarting(@NotNull FMLServerStartingEvent event) {
currentStage = ModuleStage.SERVER_STARTING;
for (IGregTechModule module : loadedModules) {
currentContainer = containers.get(getContainerID(module));
@@ -184,9 +204,10 @@ public void onServerStarting(FMLServerStartingEvent event) {
module.serverStarting(event);
module.getLogger().debug("Server-starting complete");
}
+ currentContainer = null;
}
- public void onServerStarted(FMLServerStartedEvent event) {
+ public void onServerStarted(@NotNull FMLServerStartedEvent event) {
currentStage = ModuleStage.SERVER_STARTED;
for (IGregTechModule module : loadedModules) {
currentContainer = containers.get(getContainerID(module));
@@ -194,23 +215,31 @@ public void onServerStarted(FMLServerStartedEvent event) {
module.serverStarted(event);
module.getLogger().debug("Server-started complete");
}
+ currentContainer = null;
}
- public void onServerStopping(FMLServerStoppingEvent event) {
+ public void onServerStopping(@NotNull FMLServerStoppingEvent event) {
for (IGregTechModule module : loadedModules) {
currentContainer = containers.get(getContainerID(module));
module.serverStopping(event);
}
+ currentContainer = null;
}
- public void onServerStopped(FMLServerStoppedEvent event) {
+ public void onServerStopped(@NotNull FMLServerStoppedEvent event) {
for (IGregTechModule module : loadedModules) {
currentContainer = containers.get(getContainerID(module));
module.serverStopped(event);
}
+ currentContainer = null;
}
- public void processIMC(ImmutableList messages) {
+ /**
+ * Forward incoming IMC messages to each loaded module
+ *
+ * @param messages the messages to forward
+ */
+ public void processIMC(@NotNull @Unmodifiable List messages) {
for (FMLInterModComms.IMCMessage message : messages) {
for (IGregTechModule module : loadedModules) {
if (module.processIMC(message)) {
@@ -220,11 +249,16 @@ public void processIMC(ImmutableList messages) {
}
}
- private void configureModules(Map> modules) {
+ /**
+ * Configure the modules according to the module Configuration
+ *
+ * @param modules the modules to configure
+ */
+ private void configureModules(@NotNull Map> modules) {
Locale locale = Locale.getDefault();
Locale.setDefault(Locale.ENGLISH);
- Set toLoad = new LinkedHashSet<>();
- Set modulesToLoad = new LinkedHashSet<>();
+ Set toLoad = new ObjectLinkedOpenHashSet<>();
+ Set modulesToLoad = new ReferenceLinkedOpenHashSet<>();
Configuration config = getConfiguration();
config.load();
config.addCustomCategoryComment(MODULE_CFG_CATEGORY_NAME,
@@ -303,7 +337,11 @@ private void configureModules(Map> modules) {
Locale.setDefault(locale);
}
- private static IGregTechModule getCoreModule(List modules) {
+ /**
+ * @param modules the list of modules possibly containing a Core Module
+ * @return the first found Core Module found
+ */
+ private static @Nullable IGregTechModule getCoreModule(@NotNull Iterable modules) {
for (IGregTechModule module : modules) {
GregTechModule annotation = module.getClass().getAnnotation(GregTechModule.class);
if (annotation.coreModule()) {
@@ -313,14 +351,22 @@ private static IGregTechModule getCoreModule(List modules) {
return null;
}
- private static String getContainerID(IGregTechModule module) {
+ /**
+ * @param module the module to get the container ID for
+ * @return the container ID
+ */
+ private static @NotNull String getContainerID(@NotNull IGregTechModule module) {
GregTechModule annotation = module.getClass().getAnnotation(GregTechModule.class);
return annotation.containerID();
}
- private Map> getModules(ASMDataTable table) {
+ /**
+ * @param table the ASM Data Table containing the module data
+ * @return a map of Container ID to list of associated modules sorted by Module ID
+ */
+ private static @NotNull Map> getModules(@NotNull ASMDataTable table) {
List instances = getInstances(table);
- Map> modules = new LinkedHashMap<>();
+ Map> modules = new Object2ReferenceLinkedOpenHashMap<>();
for (IGregTechModule module : instances) {
GregTechModule info = module.getClass().getAnnotation(GregTechModule.class);
modules.computeIfAbsent(info.containerID(), k -> new ArrayList<>()).add(module);
@@ -328,45 +374,70 @@ private Map> getModules(ASMDataTable table) {
return modules;
}
+ /**
+ * @param table the ASM Data Table containing the module data
+ * @return all IGregTechModule instances in sorted order by Container and Module ID
+ */
@SuppressWarnings("unchecked")
- private List getInstances(ASMDataTable table) {
+ private static @NotNull List getInstances(@NotNull ASMDataTable table) {
Set dataSet = table.getAll(GregTechModule.class.getCanonicalName());
List instances = new ArrayList<>();
for (ASMDataTable.ASMData data : dataSet) {
String moduleID = (String) data.getAnnotationInfo().get("moduleID");
- List modDependencies = (ArrayList) data.getAnnotationInfo().get("modDependencies");
+ List modDependencies = (List) data.getAnnotationInfo().get("modDependencies");
if (modDependencies == null || modDependencies.stream().allMatch(Loader::isModLoaded)) {
try {
Class> clazz = Class.forName(data.getClassName());
- instances.add((IGregTechModule) clazz.newInstance());
- } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
- logger.error("Could not initialize module " + moduleID, e);
+ if (IGregTechModule.class.isAssignableFrom(clazz)) {
+ instances.add((IGregTechModule) clazz.getConstructor().newInstance());
+ } else {
+ logger.error("Module of class {} with id {} is not an instanceof IGregTechModule",
+ clazz.getName(), moduleID);
+ }
+ } catch (ClassNotFoundException | IllegalAccessException | InstantiationException |
+ NoSuchMethodException | InvocationTargetException e) {
+ logger.error("Could not initialize module {}", moduleID, e);
}
} else {
logger.info("Module {} is missing at least one of mod dependencies: {}, skipping loading...", moduleID,
modDependencies);
}
}
- return instances.stream().sorted((m1, m2) -> {
- GregTechModule m1a = m1.getClass().getAnnotation(GregTechModule.class);
- GregTechModule m2a = m2.getClass().getAnnotation(GregTechModule.class);
- return (m1a.containerID() + ":" + m1a.moduleID()).compareTo(m2a.containerID() + ":" + m2a.moduleID());
- }).collect(Collectors.toCollection(ArrayList::new));
+ return instances.stream()
+ .sorted(Comparator.comparing((m) -> m.getClass()
+ .getAnnotation(GregTechModule.class),
+ Comparator.comparing(GregTechModule::containerID)
+ .thenComparing(GregTechModule::moduleID)))
+ .collect(Collectors.toList());
}
- private void discoverContainers(ASMDataTable table) {
+ /**
+ * Discovers ModuleContainers and registers them
+ *
+ * @param table the table containing the ModuleContainer data
+ */
+ private void discoverContainers(@NotNull ASMDataTable table) {
Set dataSet = table.getAll(ModuleContainer.class.getCanonicalName());
for (ASMDataTable.ASMData data : dataSet) {
try {
Class> clazz = Class.forName(data.getClassName());
- registerContainer((IModuleContainer) clazz.newInstance());
- } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
- logger.error("Could not initialize module container " + data.getClassName(), e);
+ if (IGregTechModule.class.isAssignableFrom(clazz)) {
+ registerContainer((IModuleContainer) clazz.getConstructor().newInstance());
+ } else {
+ logger.error("Module Container Class {} is not an instanceof IModuleContainer", clazz.getName());
+ }
+ } catch (ClassNotFoundException | IllegalAccessException | InstantiationException | NoSuchMethodException |
+ InvocationTargetException e) {
+ logger.error("Could not initialize module container {}", data.getClassName(), e);
}
}
}
- private String getComment(IGregTechModule module) {
+ /**
+ * @param module the module to get the comment for
+ * @return the comment for the module's configuration
+ */
+ private static String getComment(@NotNull IGregTechModule module) {
GregTechModule annotation = module.getClass().getAnnotation(GregTechModule.class);
String comment = annotation.description();
@@ -399,7 +470,10 @@ private String getComment(IGregTechModule module) {
return comment;
}
- private Configuration getConfiguration() {
+ /**
+ * @return the module configuration instance
+ */
+ private @NotNull Configuration getConfiguration() {
if (config == null) {
config = new Configuration(new File(configFolder, MODULE_CFG_FILE_NAME));
}