/* * Minecraft Forge * Copyright (c) 2016-2019. * * 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.fml; import net.minecraftforge.fml.config.ModConfig; import net.minecraftforge.forgespi.language.IModInfo; import java.util.*; import java.util.function.Consumer; import java.util.function.Supplier; /** * The container that wraps around mods in the system. *

* The philosophy is that individual mod implementation technologies should not * impact the actual loading and management of mod code. This class provides * a mechanism by which we can wrap actual mod code so that the loader and other * facilities can treat mods at arms length. *

* * @author cpw * */ public abstract class ModContainer { protected final String modId; protected final String namespace; protected final IModInfo modInfo; protected ModLoadingStage modLoadingStage; protected Supplier contextExtension; protected final Map> triggerMap; protected final Map> extensionPoints = new IdentityHashMap<>(); protected final EnumMap configs = new EnumMap<>(ModConfig.Type.class); @SuppressWarnings("OptionalUsedAsFieldOrParameterType") protected Optional> configHandler = Optional.empty(); public ModContainer(IModInfo info) { this.modId = info.getModId(); // TODO: Currently not reading namespace from configuration.. this.namespace = this.modId; this.modInfo = info; this.triggerMap = new HashMap<>(); this.modLoadingStage = ModLoadingStage.CONSTRUCT; } /** * @return the modid for this mod */ public final String getModId() { return modId; } /** * @return the resource prefix for the mod */ public final String getNamespace() { return namespace; } /** * @return The current loading stage for this mod */ public ModLoadingStage getCurrentState() { return modLoadingStage; } /** * Transition the mod to this event if possible. * @param event to transition to */ public final void transitionState(LifecycleEventProvider.LifecycleEvent event, Consumer> errorHandler) { if (modLoadingStage == event.fromStage()) { try { ModLoadingContext.get().setActiveContainer(this, contextExtension.get()); triggerMap.getOrDefault(modLoadingStage, e->{}).accept(event); modLoadingStage = event.toStage(); ModLoadingContext.get().setActiveContainer(null, null); } catch (ModLoadingException e) { modLoadingStage = ModLoadingStage.ERROR; errorHandler.accept(Collections.singletonList(e)); } } } /** * @return the modinfo used to create this mod instance */ public IModInfo getModInfo() { return modInfo; } @SuppressWarnings("unchecked") public Optional getCustomExtension(ExtensionPoint point) { return Optional.ofNullable((T)extensionPoints.getOrDefault(point,()-> null).get()); } public void registerExtensionPoint(ExtensionPoint point, Supplier extension) { extensionPoints.put(point, extension); } public void addConfig(final ModConfig modConfig) { configs.put(modConfig.getType(), modConfig); } public void dispatchConfigEvent(ModConfig.ModConfigEvent event) { configHandler.ifPresent(configHandler->configHandler.accept(event)); } /** * Does this mod match the supplied mod? * * @param mod to compare * @return if the mod matches */ public abstract boolean matches(Object mod); /** * @return the mod object instance */ public abstract Object getMod(); }