Config GUIs in the modlist now work.

This commit is contained in:
Christian committed 2014-01-02 11:51:16 -05:00
1 parent 7a62801209
commit aa963c5df6
10 files changed
+292 -3

No files matched your search

@@ -36,7 +36,10 @@ import net.minecraft.network.INetHandler;
import net.minecraft.network.NetworkManager;
import net.minecraft.server.MinecraftServer;
import org.apache.logging.log4j.Level;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
@@ -119,6 +122,8 @@ public class FMLClientHandler implements IFMLSidedHandler
private Map<String, IResourcePack> resourcePackMap;
private BiMap<ModContainer, IModGuiFactory> guiFactories;
/**
* Called to start the whole game off
*
@@ -239,6 +244,26 @@ public class FMLClientHandler implements IFMLSidedHandler
// Reload resources
// client.func_110436_a();
RenderingRegistry.instance().loadEntityRenderers((Map<Class<? extends Entity>, Render>)RenderManager.field_78727_a.field_78729_o);
guiFactories = HashBiMap.create();
for (ModContainer mc : Loader.instance().getActiveModList())
{
String className = mc.getGuiClassName();
if (Strings.isNullOrEmpty(className))
{
continue;
}
try
{
Class<?> clazz = Class.forName(className, true, Loader.instance().getModClassLoader());
Class<? extends IModGuiFactory> guiClassFactory = clazz.asSubclass(IModGuiFactory.class);
IModGuiFactory guiFactory = guiClassFactory.newInstance();
guiFactory.initialize(client);
guiFactories.put(mc, guiFactory);
} catch (Exception e)
{
FMLLog.log(Level.ERROR, e, "A critical error occurred instantiating the gui factory for mod %s", mc.getModId());
}
}
loading = false;
}
@@ -514,4 +539,9 @@ public class FMLClientHandler implements IFMLSidedHandler
{
showGuiScreen(new GuiIngameModOptions(guiIngameMenu));
}
public IModGuiFactory getGuiFactoryFor(ModContainer selectedMod)
{
return guiFactories.get(selectedMod);
}
}
@@ -0,0 +1,70 @@
package cpw.mods.fml.client;
import java.util.Set;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
public class FMLConfigGuiFactory implements IModGuiFactory {
public static class FMLConfigGuiScreen extends GuiScreen {
private GuiScreen parent;
public FMLConfigGuiScreen(GuiScreen parent)
{
this.parent = parent;
}
@SuppressWarnings("unchecked")
@Override
public void func_73866_w_()
{
this.field_146292_n.add(new GuiButton(1, this.field_146294_l / 2 - 75, this.field_146295_m - 38, I18n.func_135052_a("gui.done")));
}
@Override
protected void func_146284_a(GuiButton p_73875_1_)
{
if (p_73875_1_.field_146124_l && p_73875_1_.field_146127_k == 1)
{
FMLClientHandler.instance().showGuiScreen(parent);
}
}
@Override
public void func_73863_a(int p_73863_1_, int p_73863_2_, float p_73863_3_)
{
this.func_146276_q_();
this.func_73732_a(this.field_146289_q, "Forge Mod Loader test config screen", this.field_146294_l / 2, 40, 0xFFFFFF);
super.func_73863_a(p_73863_1_, p_73863_2_, p_73863_3_);
}
}
private Minecraft minecraft;
@Override
public void initialize(Minecraft minecraftInstance)
{
this.minecraft = minecraftInstance;
}
@Override
public Class<? extends GuiScreen> mainConfigGuiClass()
{
return FMLConfigGuiScreen.class;
}
@Override
public Set<RuntimeOptionCategoryElement> runtimeGuiCategories()
{
// TODO Auto-generated method stub
return null;
}
@Override
public RuntimeOptionGuiHandler getHandlerFor(RuntimeOptionCategoryElement element)
{
// TODO Auto-generated method stub
return null;
}
}
@@ -33,10 +33,12 @@ import net.minecraft.client.resources.I18n;
import net.minecraft.client.resources.IResourcePack;
import net.minecraft.util.ResourceLocation;
import org.apache.logging.log4j.Level;
import org.lwjgl.opengl.GL11;
import com.google.common.base.Strings;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.common.ModContainer.Disableable;
@@ -93,8 +95,8 @@ public class GuiModList extends GuiScreen
}
listWidth=Math.min(listWidth, 150);
this.field_146292_n.add(new GuiButton(6, this.field_146294_l / 2 - 75, this.field_146295_m - 38, I18n.func_135052_a("gui.done")));
configModButton = new GuiButton(7, 10, this.field_146295_m - 60, this.listWidth, 20, "Config");
disableModButton = new GuiButton(8, 10, this.field_146295_m - 38, this.listWidth, 20, "Disable");
configModButton = new GuiButton(20, 10, this.field_146295_m - 60, this.listWidth, 20, "Config");
disableModButton = new GuiButton(21, 10, this.field_146295_m - 38, this.listWidth, 20, "Disable");
this.field_146292_n.add(configModButton);
this.field_146292_n.add(disableModButton);
this.modList=new GuiSlotModList(this, mods, listWidth);
@@ -110,6 +112,18 @@ public class GuiModList extends GuiScreen
case 6:
this.field_146297_k.func_147108_a(this.mainMenu);
return;
case 20:
try
{
IModGuiFactory guiFactory = FMLClientHandler.instance().getGuiFactoryFor(selectedMod);
GuiScreen newScreen = guiFactory.mainConfigGuiClass().getConstructor(GuiScreen.class).newInstance(this);
this.field_146297_k.func_147108_a(newScreen);
}
catch (Exception e)
{
FMLLog.log(Level.ERROR, e, "There was a critical issue trying to build the config GUI for %s", selectedMod.getModId());
}
return;
}
}
super.func_146284_a(button);
@@ -222,6 +236,17 @@ public class GuiModList extends GuiScreen
disableModButton.field_146125_m = true;
disableModButton.field_146124_l = false;
}
IModGuiFactory guiFactory = FMLClientHandler.instance().getGuiFactoryFor(selectedMod);
if (guiFactory == null || guiFactory.mainConfigGuiClass() == null)
{
configModButton.field_146125_m = true;
configModButton.field_146124_l = false;
}
else
{
configModButton.field_146125_m = true;
configModButton.field_146124_l = true;
}
} else {
offset = ( this.listWidth + this.field_146294_l ) / 2;
this.func_73732_a(this.field_146289_q, selectedMod.getName(), offset, 35, 0xFFFFFF);
@@ -0,0 +1,127 @@
package cpw.mods.fml.client;
import java.util.Set;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
public interface IModGuiFactory {
/**
* Called when instantiated to initialize with the active minecraft instance.
*
* @param minecraftInstance the instance
*/
public void initialize(Minecraft minecraftInstance);
/**
* Return the name of a class extending {@link GuiScreen}. This class will
* be instantiated when the "config" button is pressed in the mod list. It will
* have a single argument constructor - the "parent" screen, the same as all
* Minecraft GUIs. The expected behaviour is that this screen will replace the
* "mod list" screen completely, and will return to the mod list screen through
* the parent link, once the appropriate action is taken from the config screen.
*
* A null from this method indicates that the mod does not provide a "config"
* button GUI screen, and the config button will be hidden/disabled.
*
* This config GUI is anticipated to provide configuration to the mod in a friendly
* visual way. It should not be abused to set internals such as IDs (they're gonna
* keep disappearing anyway), but rather, interesting behaviours. This config GUI
* is never run when a server game is running, and should be used to configure
* desired behaviours that affect server state. Costs, mod game modes, stuff like that
* can be changed here.
*
* @return A class that will be instantiated on clicks on the config button
* or null if no GUI is desired.
*/
public Class<? extends GuiScreen> mainConfigGuiClass();
/**
* Return a list of the "runtime" categories this mod wishes to populate with
* GUI elements.
*
* Runtime categories are created on demand and organized in a 'lite' tree format.
* The parent represents the parent node in the tree. There is one special parent
* 'Help' that will always list first, and is generally meant to provide Help type
* content for mods. The remaining parents will sort alphabetically, though
* this may change if there is a lot of alphabetic abuse. "AAA" is probably never a valid
* category parent.
*
* Runtime configuration itself falls into two flavours: in-game help, which is
* generally non interactive except for the text it wishes to show, and client-only
* affecting behaviours. This would include things like toggling minimaps, or cheat modes
* or anything NOT affecting the behaviour of the server. Please don't abuse this to
* change the state of the server in any way, this is intended to behave identically
* when the server is local or remote.
*
* @return the set of options this mod wishes to have available, or empty if none
*/
public Set<RuntimeOptionCategoryElement> runtimeGuiCategories();
/**
* Return an instance of a {@link RuntimeOptionGuiHandler} that handles painting the
* right hand side option screen for the specified {@link RuntimeOptionCategoryElement}.
*
* @param element The element we wish to paint for
* @return The Handler for painting it
*/
public RuntimeOptionGuiHandler getHandlerFor(RuntimeOptionCategoryElement element);
/**
* Represents an option category and entry in the runtime gui options list.
*
* @author cpw
*
*/
public static class RuntimeOptionCategoryElement {
public final String parent;
public final String child;
public RuntimeOptionCategoryElement(String parent, String child)
{
this.parent = parent;
this.child = child;
}
}
/**
* Responsible for painting the mod specific section of runtime options GUI for a particular category
*
* @author cpw
*
*/
public interface RuntimeOptionGuiHandler {
/**
* Called to add widgets to the screen, such as buttons.
* GUI identifier numbers should start at 100 and increase.
* The callback will be through {@link #actionCallback(int)}
*
* @param x X
* @param y Y
* @param w width
* @param h height
*/
public void addWidgets(int x, int y, int w, int h);
/**
* Called to paint the rectangle specified.
* @param x X
* @param y Y
* @param w width
* @param h height
*/
public void paint(int x, int y, int w, int h);
/**
* Called if a widget with id >= 100 is fired.
*
* @param actionId the actionId of the firing widget
*/
public void actionCallback(int actionId);
/**
* Called when this handler is about to go away (probably replaced by another one, or closing the
* option screen)
*/
public void close();
}
}
@@ -186,4 +186,10 @@ public class DummyModContainer implements ModContainer
{
return Disableable.NEVER;
}
@Override
public String getGuiClassName()
{
return null;
}
}
@@ -215,4 +215,10 @@ public class FMLContainer extends DummyModContainer implements WorldAccessContai
{
return getSource().isDirectory() ? FMLFolderResourcePack.class : FMLFileResourcePack.class;
}
@Override
public String getGuiClassName()
{
return "cpw.mods.fml.client.FMLConfigGuiFactory";
}
}
@@ -616,4 +616,10 @@ public class FMLModContainer implements ModContainer
{
return disableability;
}
@Override
public String getGuiClassName()
{
return (String) descriptor.get("guiFactory");
}
}
@@ -174,4 +174,10 @@ public class InjectedModContainer implements ModContainer
{
return wrappedContainer.canBeDisabled();
}
@Override
public String getGuiClassName()
{
return wrappedContainer.getGuiClassName();
}
}
+12 -1
View File
@@ -17,6 +17,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import cpw.mods.fml.client.IModGuiFactory;
import cpw.mods.fml.common.event.FMLEvent;
import cpw.mods.fml.common.event.FMLFingerprintViolationEvent;
import cpw.mods.fml.common.event.FMLInitializationEvent;
@@ -149,10 +150,20 @@ public @interface Mod
* (minimap mods, graphical tweak mods) then you can set true here and receive the FMLDeactivationEvent to perform deactivation
* tasks.
* This does not affect administrative disabling through the system property fml.modStates or the config file fmlModState.properties.
* The mod will only be deactivated outside of a running game world - FML will never allow mod deactivation whilst a game server
* is running.
*
* @return if I can be deactivated whilst the game is running.
* @return if this mod can be deactivated whilst the game is open.
*/
boolean canBeDeactivated() default false;
/**
* An optional GUI factory for this mod. This is the name of a class implementing {@link IModGuiFactory} that will be instantiated
* on the client side, and will have certain configuration/options guis requested from it.
*
* @return The name of a class implementing {@link IModGuiFactory}
*/
String guiFactory() default "";
/**
* A list of custom properties for this mod. Completely up to the mod author if/when they
* want to put anything in here.
@@ -143,4 +143,6 @@ public interface ModContainer
Map<String, String> getSharedModDescriptor();
Disableable canBeDisabled();
String getGuiClassName();
}