Jump to content

  • Curse Sites
Become a Premium Member! Help
Latest News Article

Minecraft Mod Manager


  • Please log in to reply
155 replies to this topic

#1

RobRendell

Posted 12 December 2010 - 12:29 AM

Minecraft Mod Manager v0.2 for SSP

IMPORTANT: DO NOT simply insert the contents of this zip archive into your minecraft.jar!  That's not how MMM works!

Contents
        [*:1p9dl4bk] Introduction
        
              [*:1p9dl4bk] What is this?
              [*:1p9dl4bk] How does it work?
              [*:1p9dl4bk] What's the catch?
        [*:1p9dl4bk] Information for users
        
              [*:1p9dl4bk] How do I install MMM?
              [*:1p9dl4bk] How do I add a mod to Minecraft using MMM?
              [*:1p9dl4bk] Resolving conflicts
        [*:1p9dl4bk] MMM and ModLoader
        [*:1p9dl4bk] Information for Modders
        
              [*:1p9dl4bk] Regular mods
              [*:1p9dl4bk] MMM mods
              [*:1p9dl4bk] Command Files
              [*:1p9dl4bk] Creating a default command file
        [*:1p9dl4bk] Working Example
        [*:1p9dl4bk] Changelog

Introduction

What is this?

Minecraft Mod Manager (MMM) is an attempt to make modding SSP Minecraft much more convenient.  It allows you to apply mods to your SMP minecraft game without editing your minecraft.jar file.  Instead, you can drop mod files into a specific folder, and MMM will detect them and load them automatically when Minecraft starts up.

MMM can load most regular mods, and makes installing and uninstalling such mods easier.  Where it really shines, however, is when modders create mods that rely on MMM's features.  These features allow modders to create mods that:

    [*:1p9dl4bk] Avoid including any copywrited Mojang code,
    [*:1p9dl4bk] Alter the behaviour of minecraft classes without (necessarily) conflicting with other mods that alter the same classes,
    [*:1p9dl4bk] Auto-unzip resources into Minecraft's resources folder,
    [*:1p9dl4bk] Don't need to be re-built every time Minecraft updates, unless some feature of the code the mod relies on has been altered.

How does it work?

MMM defines a custom java class loader, which allows it to control what is loaded when Java asks for a specific class file.  It also contains code to re-write the java bytecode of classes on the fly, allowing class names, fields and methods to be renamed dynamically.

These features allow MMM to dynamically override classes in minecraft.jar, re-mapping class names across versions and substitute modder-defined classes for Minecraft classes without completely replacing them.

The mapping of classes, fields and methods is controlled from remapping files.  Mods can bundle relevant remappings, so an individual mod-maker can maintain their own mod's dependencies.  Alternatively, a global remapping file is also loaded, and mods can rely on the user updating this to handle updating to new versions of Minecraft.  MMM comes with remappings for beta 1.2_02 and beta 1.3_01 built-in.

What's the catch?

In order for MMM to operate, it needs some extra parameters to be passed in to the Java runtime.  Thus, you will have to run Minecraft from the command line (using the supplied .bat file or shell script) in order to use MMM.

Another catch is that MMM only supports mods that are in .zip format.  Apologies to those who like using better compression algorithms, but .zip is natively supported by Java, and it made the coding of MMM simpler to just use the built-in zip file support.  

If a particular mod you want to use is in a different format (.rar, .7z, .tgz), you can manually uncompress it and re-compress it into a .zip file yourself for your own local copy, without requiring any special knowledge or input from the mod's author.


Information for users

How do I install MMM?

    [*:1p9dl4bk] Download MMM:

            http://dl.dropbox.co... ... anager.zip

         
    [*:1p9dl4bk]  Uncompress the .zip file and put the files in a directory from which you'd like to run Minecraft.

        !!! This should not be your .minecraft/bin folder! !!!

        For example, on Windows XP the MMM files could go into C:\Program Files\Minecraft, on Linux into ~/bin or /usr/local/bin, and so on.

         
    [*:1p9dl4bk] Download the jar version of the Minecraft launcher:

            http://www.minecraft.net/download.jsp

        You want the file for Linux/Other.  Don't worry, this will work for Windows and Mac users too.  MMM v0.2 will work with either the old or new Launcher for Minecraft.

        Confusingly, there are two files you'll need to deal with called minecraft.jar.  One is Minecraft's launcher, downloaded from the above link and used in this and the next step.  The other is the file that automatically downloads when you first play the game or a new version of Minecraft is released, in your .minecraft folder.  This second one is the target of any mod instructions to "open minecraft.jar".
        
        Do not get the two different minecraft.jar-s confused!

         
    [*:1p9dl4bk] Put the launcher minecraft.jar file from step 3. in the folder with the MMM files from step 2.

         
    [*:1p9dl4bk] Windows users should run MMM_minecraft.bat file, while Mac and Unix users should be able to launch MMM_minecraft.sh

That's it!

How do I add a mod to Minecraft using MMM?

When MMM first runs, it creates a folder in your .minecraft folder called "mmm_mods".  If you are unsure where this folder is, click the "Mods and Texture Packs" button on the Minecraft front screen, click "Open texture pack folder", and then navigate up one level from that folder.  If MMM loaded correctly, you will see the mmm_mods folder.

Quit Minecraft (if it is running), and then simply copy mods in zip format into the mmm_mods folder.  When you re-start Minecraft, the mods should load automatically.

Note that not all mods will work out-of-the-box like this.  Aside from the issue of compression formats other than .zip, some mods aren't installed by simply splatting all their contents into minecraft.jar, and as such they shouldn't just be put in mmm_mods.

For instance, a mod might provide several different versions of its .class files, and you're supposed to only copy one set of them into minecraft.jar.  In this case, you will need to select and extract the specific .class files you want, and then zip them up in a new archive by themselves.

Other mods may require audio files be extracted into the resources folder.  MMM actually provides a mechanism for mod-makers to package these resources so that they auto-deploy when the mod is loaded, but that only works for mods built specifically to run under MMM; if you're using a regular style mod, you will have to perform such steps manually.

Basically, follow whatever installation instructions the mod's author has provided, but where you were told to open minecraft.jar and copy class files in, instead put those class files in a separate zip archive and put that file in mmm_mods.

Resolving conflicts

For regular mods that simply replace entire class files, MMM creates a .txt file in the mmm_mods folder whenever it runs, listing all classes that conflict (that is, are replaced by two or more mods).  You can edit this conflicts.txt file when Minecraft is not running, to control which version of the class is used.  As described in the comments at the top of the file, the first mod listed after a given class file is the one whose version of that class will be used.  You can mix and match, taking some classes from one mod and others from another, although this is likely to crash Minecraft unless you know what you are doing.

MMM and ModLoader

ModLoader is very useful and widely used, but it won't work out of the box with MMM.  This is due to ModLoader's (perfectly reasonable!) assumption that all of the mods it might be trying to load are stored in minecraft.jar.  With MMM, this is not the case - minecraft.jar is untouched, and all the mods reside in the mmm_mods folder.  In order to get ModLoader to load ModLoader mods under MMM, you can add a global command file (called, say, "ModLoader.mmm") to the mmm_mods folder with the following contents:

callback ModLoader init
callback ModLoader readFromClassPath

This causes ModLoader to initialise, and then its readFromClassPath method will be invoked repeatedly with each of the mods loaded by MMM (see the section "Command Files" for details on the "callback" command).  ModLoader will then know about any classes defined in the mods in the mmm_mods folder.

Information for Modders

Hopefully, MMM can grow to be a useful tool for modders, as well as a convenience for users.

Regular mods

The simplest option is for modders to carry on as before, releasing mods that replace entire class files using the current Minecraft version's obfuscation mapping.  Users have the convenience of dropping a single zip file into a folder, instead of injecting classes into minecraft.jar, but the mods remain just as conflict-prone as they are currently, and will be invalidated by Minecraft updates.

MMM mods

If a mod is written to be run under MMM, it can take advantage of various features.

    [*:1p9dl4bk] Command file.  Each MMM mod must include a text file with the suffix ".mmm" (instead of ".txt") in the .zip file.  The presence of a .mmm file is what MMM uses to flag mods as MMM-native.  This file can contain MMM commands that can set the mod's name and version, list other mods that it relies upon, nominates which classes should replace base Minecraft classes in a controlled fashion, and other commands.  See the section below for MMM commands.

    [*:1p9dl4bk] Not obfuscated.  MMM mods can be built using MCP, and compiled without re-obfuscation (simply zip up the .class files generated from your MCP sources).  MMM will remap thes un-obfuscated names at run-time, based on the remappings in the loaded command files (see below).

    [*:1p9dl4bk] Dynamically remapped.  The not-obfuscated class, method and field names in MMM mods are remapped at run-time by MMM to the current Minecraft version's particular set of mappings.  This means that as long as mappings are updated and none of the functionality a mod relies on actually changes, it can continue to run over multiple updates of Minecraft.

    [*:1p9dl4bk] Auto-deployment of resources.  MMM mods that contain a "resources" folder at the top level of the .zip file will auto-unzip the contents of that folder.  Note that this process won't overwrite existing files (since they are not versioned, MMM can't tell if the files already in the resources folder are the ones you want or not).  Thus, once your mod has unzipped its resources once, they will only be re-deployed if the user manually deletes them, or you release an update for your mod with additional files.

    [*:1p9dl4bk] Modifying classes without replacing them.  When an MMM mod wishes to modify the behaviour of a Minecraft class, the modder can extend the class they wish to modify using Java inheritance, and put a "substitute" command (see below) in the .mmm file.  They can then override only the method or methods they wish to change, allowing the inheritance mechanism to pass everything else through to the base class.  Each method's super() should also be called.  MMM will re-write things on the fly so that the augmented class is substituted for the base class when Minecraft is running.  As a result, mods can avoid including any of Mojang's code.

    [*:1p9dl4bk] Reduced mod conflicts.  The above mechansim for modifying Minecraft's behaviour through inheritance has another benefit: multiple mods can modify the same base class.  Each one inherits the base class independently and declares that it should be substituted for the base.  Once they are all loaded, MMM "chains" the classes' inheritance relationships, making each one inherit from the next.  Whichever class ends up at the "top" of the inheritance chain is the one ultimately substituted for the base minecraft class.  As long as the different mods override different methods, and/or ensure they call the method's super(), every mods' code will get to execute.

    [*:1p9dl4bk] Minecraft data dir property.  MMM assigns a Java system property, "minecraft.data", to the path to the Minecraft data directory (.minecraft).  Modders can access this value by calling System.getProperty("minecraft.data"), allowing them to easily create paths to preferences files and suchlike.

Command Files

When MMM starts, it loads .mmm files and executes the commands within.  These "command files" are simply regular text files with a suffix of ".mmm" instead of ".txt".  The commands executed from command files change the behaviour of MMM and assign values to a given mod.

Lines within the command file starting with # symbols are treated as comments, and are ignored.  Any non-comment lines should contain MMM commands.  The commands understood by MMM are:

    [*:1p9dl4bk] name (mod name): sets the mod's name (by default, the mod's file name is used as the mod's name).  Note that the mod name cannot contain spaces.  Only valid in a command file contained in a mod.

    [*:1p9dl4bk] version (version string): sets this mod's version string.  Note that the version string cannot contain spaces.  Only valid in a command file contained in a mod.

    [*:1p9dl4bk] requires (other mod name) [(another mod name) ...]: indicates that this mod requires the nominated other mod or mods. An error will be displayed and Minecraft not started if any are missing. The mod names can optinally be followed by a ":" and a version string, giving the minimum version of the required mod that must be present. Only valid in a command file contained in a mod.

    [*:1p9dl4bk] substitute (mod class name): informs MMM that the given mod class should be used to replace whichever minecraft class it extends (i.e. inherits from), and should be substituted for it everywhere. Only valid in a command file contained in a mod.

    [*:1p9dl4bk] exclude (class name): lists a single class in the zip to ignore. Only valid in a command file contained in a mod.

    [*:1p9dl4bk] callback (class name) (method name): the parameters are a class name in the mod and a static method on that class, which MMM will invoke when the mod is loaded. This method can take no parameters, or accept a single parameter of type File, String, File[] or String[], in which case it is called (multiple times in the case of non-array versions) with all the mods MMM has loaded.

    [*:1p9dl4bk] minecraftVersion (version timestamp): indicates that the following part of the command file is relevant only for a specific version of Minecraft. If the version timestamp (from the .minecraft/bin/version file) does not match, subsequent commands in the file up to the next minecraftVersion command will be ignored.

    [*:1p9dl4bk] remapClass (from class name) (to class name): inform MMM that the given "from" class name should be treated as the nominated "to" class name, overriding/supplimenting the mappings loaded from the mapping file.

    [*:1p9dl4bk] remapMethod (class name) (from method name) (method signature) (to method name): inform MMM that in the given (un-obfuscated) class, the given "from" method name should be treated as the nominated "to" method name. The method signature should also be un-obfuscated, if it contains any class references.

    [*:1p9dl4bk] remapField (class name) (from field name) (to field name): inform MMM that in the given class (un-obfuscated), the given "from" field name should be treated as the nominated "to" field name.

Any files which end with the suffix ".mmm" is interpreted as a command file by MMM.  These files are typically stored in the mod's zip file, but "global" command files can be added to the mmm_mods folder to configure additional things.  Only some of the above commands are valid in global command files; it cannot contain those that the documentation above indicates are only valid when they appear in command files contained in mods.

Whenever Minecraft updates, any remapClass, remapMethod and remapField commands will become incorrect.  They should thus appear only after a relevant minecraftVersion command.  If MMM detects that a mod uses unmapped values, a warning will be printed to the text console and the mod is disabled.

Because the remap* commands can appear in a mod's command file, individual modders can update their mappings and release an update of their mod when Minecraft updates.  This is much the same situation as Minecraft mods currently suffer from, except that a single set of mappings need to be updated rather than all of the mod's code.  Alternatively, a modder can wait for an updated global remapping file to released, which will happen after the next MCP update.  The global remapping file should cover all known MCP classes, methods and fields, and once it is updated all MMM mods should resume working again.

Creating a default command file

It would be painful for a modder to manually go through their mod and write down all the different minecraft classes, methods and fields they access.  MMM can generate a skeleton command file for a given mod, listing all the remappings that need to be assigned for that mod.

MMM_minecraft.bat or MMM_minecraft.sh can take a command-line parameter:
	MMM_minecraft.bat -DwriteUsages=(mod name)
The mod name is the value specified in the mod's current command file, or the raw file name if no command file is present.  When this parameter is specified, the mappings for the nominated mod are written to the console, where they can be redirected into a file using >.  This output is preceeded with a valid "minecraftVersion" line, and the actual mappings are written in the form of "remapClass", "remapMethod" and "remapField" commands, ready to drop into a command file.  Any unknown mappings are specified as mapping to the string "???".


Working Example

I really liked Seronis' ToolRepair mod.  Unfortunately, with the update to beta 1.2, Minecraft stopped allowing damaged items to be used in recipes, so using crafting to repair tools stopped working.  Here's an MMM mod that re-implements this mod.

First, the biggest problem is that recipes now require undamaged items to work.  Using MMM's replacement mechanism, we can intercept the recipe code at the point it decides which recipies are valid.  The classes CraftingInventoryPlayerCB and CraftingInventoryWorkbenchCB are where this happens; let's just look at the Player one for now.

First, we can define a new class that extends from the Minecraft class we want to modify.  I'm going to put it in a "toolRepair" package, so the code doesn't get mixed up with the code in net.minecraft.src.

package toolRepair;

import net.minecraft.src.CraftingInventoryPlayerCB;
import net.minecraft.src.InventoryPlayer;

public class RepairingCraftingInventoryPlayerCB
				extends CraftingInventoryPlayerCB
{
		public RepairingCraftingInventoryPlayerCB(InventoryPlayer inventoryplayer, boolean flag)
		{
				super(inventoryplayer, flag);
		}

		public RepairingCraftingInventoryPlayerCB(InventoryPlayer inventoryplayer)
		{
				super(inventoryplayer);
		}
}

In the above, we need to delegate all the constructors to the original class, since that isn't done automatically for us by Java inheritance.

Now, we want to change the onCraftMatrixChanged method.

		@Override
		public void onCraftMatrixChanged(IInventory iinventory)
		{
				super.onCraftMatrixChanged(iinventory);
		}

The above just reproduces the functionality of original method, unchanged.  Undamaged items can be used in recipes, but damaged ones can't.  To work around this, we can change our overridden onCraftMatrixChanged method to temporarily repair all the items before calling the super method, and then restore the damage on the way out:


		private static final int cacheSize = 4;

		private Integer damageCache[] = new Integer[cacheSize];


		@Override
		public void onCraftMatrixChanged(IInventory iinventory)
		{
				for (int index = 0; index < cacheSize; ++index)
				{
						ItemStack item = iinventory.getStackInSlot(index);
						if (item != null)
						{
								damageCache[index] = item.getItemDamage();
								item.damageItem(-damageCache[index]);
						}
				}
				super.onCraftMatrixChanged(iinventory);
				for (int index = 0; index < cacheSize; ++index)
				{
						ItemStack item = iinventory.getStackInSlot(index);
						if (item != null)
						{
								item.damageItem(damageCache[index]);
						}
				}
		}

We can do the same for the CraftingInventoryWorkbenchCB class, with a cacheSize of 9 instead of 4.  Now, we just need to tell MMM to use our modified versions instead of the originals, by creating a .mmm file:

name ToolRepair
version 1.0
substitute toolRepair.RepairingCraftingInventoryPlayerCB
substitute toolRepair.RepairingCraftingInventoryWorkbenchCB

MMM knows which Minecraft classes to replace with the nominated Repairing version because it can inspect the bytecode and see which class each one extends.

At this point, we could zip up toolRepair/RepairingCraftingInventoryPlayerCB.class, toolRepair/RepairingCraftingInventoryWorkbenchCB.class and the toolRepair.mmm command file, and we'd have an MMM mod that allows damaged items to be used in crafting recipes.

To make it an actual replacement for Seronis' original ToolRepair mod, we also need to add the repairing recipes.  The original used a ModLoader class, and we can do that too.  Note that Java forbids importing classes in the default package into classes in explicit packages, and ModLoader's classes ModLoader and BaseMod are in the default package, so ModLoader classes also have to live in the default package (i.e. not in any subdirectory).  We'll create a single class, mod_toolrepair, in the base package:


import net.minecraft.src.Block;
import net.minecraft.src.CraftingManager;
import net.minecraft.src.Item;
import net.minecraft.src.ItemStack;

/**
 * Seronis' tool repair mod
 */
public class mod_toolrepair extends BaseMod
{
		@Override
		public void AddRecipes(CraftingManager craftingManager) {
				
				craftingManager.addRecipe(new ItemStack(Item.fishingRod, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.silk, Character.valueOf('#'), Item.fishingRod });
				craftingManager.addRecipe(new ItemStack(Item.fishingRod, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.stick, Character.valueOf('#'), Item.fishingRod });
				craftingManager.addRecipe(new ItemStack(Item.fishingRod, 1), new Object[] { "#", "#", Character.valueOf('#'), Item.fishingRod });

				//handles
				craftingManager.addRecipe(new ItemStack(Item.shovelWood, 1), new Object[] { " X", "#X", Character.valueOf('X'), Item.stick, Character.valueOf('#'), Item.shovelWood });
				craftingManager.addRecipe(new ItemStack(Item.hoeWood, 1), new Object[] { " X", "#X", Character.valueOf('X'), Item.stick, Character.valueOf('#'), Item.hoeWood });
				craftingManager.addRecipe(new ItemStack(Item.shovelStone, 1), new Object[] { " X", "#X", Character.valueOf('X'), Item.stick, Character.valueOf('#'), Item.shovelStone });
				craftingManager.addRecipe(new ItemStack(Item.hoeStone, 1), new Object[] { " X", "#X", Character.valueOf('X'), Item.stick, Character.valueOf('#'), Item.hoeStone });
				craftingManager.addRecipe(new ItemStack(Item.shovelDiamond, 1), new Object[] { " X", "#X", Character.valueOf('X'), Item.stick, Character.valueOf('#'), Item.shovelDiamond });
				craftingManager.addRecipe(new ItemStack(Item.hoeDiamond, 1), new Object[] { " X", "#X", Character.valueOf('X'), Item.stick, Character.valueOf('#'), Item.hoeDiamond });
				craftingManager.addRecipe(new ItemStack(Item.shovelGold, 1), new Object[] { " X", "#X", Character.valueOf('X'), Item.stick, Character.valueOf('#'), Item.shovelGold });
				craftingManager.addRecipe(new ItemStack(Item.hoeGold, 1), new Object[] { " X", "#X", Character.valueOf('X'), Item.stick, Character.valueOf('#'), Item.hoeGold });
				
				//tools
				craftingManager.addRecipe(new ItemStack(Item.swordWood, 1), new Object[] { "X", "#", Character.valueOf('X'), Block.wood, Character.valueOf('#'), Item.swordWood });
				craftingManager.addRecipe(new ItemStack(Item.swordWood, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.swordWood, Character.valueOf('#'), Item.swordWood });
				craftingManager.addRecipe(new ItemStack(Item.pickaxeWood, 1), new Object[] { "X", "#", Character.valueOf('X'), Block.wood, Character.valueOf('#'), Item.pickaxeWood });
				craftingManager.addRecipe(new ItemStack(Item.pickaxeWood, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.pickaxeWood, Character.valueOf('#'), Item.pickaxeWood });
				craftingManager.addRecipe(new ItemStack(Item.shovelWood, 1), new Object[] { "X", "#", Character.valueOf('X'), Block.wood, Character.valueOf('#'), Item.shovelWood });
				craftingManager.addRecipe(new ItemStack(Item.shovelWood, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.shovelWood, Character.valueOf('#'), Item.shovelWood });
				craftingManager.addRecipe(new ItemStack(Item.axeWood, 1), new Object[] { "X", "#", Character.valueOf('X'), Block.wood, Character.valueOf('#'), Item.axeWood });
				craftingManager.addRecipe(new ItemStack(Item.axeWood, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.axeWood, Character.valueOf('#'), Item.axeWood });
				craftingManager.addRecipe(new ItemStack(Item.hoeWood, 1), new Object[] { "X", "#", Character.valueOf('X'), Block.wood, Character.valueOf('#'), Item.hoeWood });
				craftingManager.addRecipe(new ItemStack(Item.hoeWood, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.hoeWood, Character.valueOf('#'), Item.hoeWood });

				craftingManager.addRecipe(new ItemStack(Item.swordStone, 1), new Object[] { "X", "#", Character.valueOf('X'), Block.cobblestone, Character.valueOf('#'), Item.swordStone });
				craftingManager.addRecipe(new ItemStack(Item.swordStone, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.swordStone, Character.valueOf('#'), Item.swordStone });
				craftingManager.addRecipe(new ItemStack(Item.pickaxeStone, 1), new Object[] { "X", "#", Character.valueOf('X'), Block.cobblestone, Character.valueOf('#'), Item.pickaxeStone });
				craftingManager.addRecipe(new ItemStack(Item.pickaxeStone, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.pickaxeStone, Character.valueOf('#'), Item.pickaxeStone });
				craftingManager.addRecipe(new ItemStack(Item.shovelStone, 1), new Object[] { "X", "#", Character.valueOf('X'), Block.cobblestone, Character.valueOf('#'), Item.shovelStone });
				craftingManager.addRecipe(new ItemStack(Item.shovelStone, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.shovelStone, Character.valueOf('#'), Item.shovelStone });
				craftingManager.addRecipe(new ItemStack(Item.axeStone, 1), new Object[] { "X", "#", Character.valueOf('X'), Block.cobblestone, Character.valueOf('#'), Item.axeStone });
				craftingManager.addRecipe(new ItemStack(Item.axeStone, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.axeStone, Character.valueOf('#'), Item.axeStone });
				craftingManager.addRecipe(new ItemStack(Item.hoeStone, 1), new Object[] { "X", "#", Character.valueOf('X'), Block.cobblestone, Character.valueOf('#'), Item.hoeStone });
				craftingManager.addRecipe(new ItemStack(Item.hoeStone, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.hoeStone, Character.valueOf('#'), Item.hoeStone });

				craftingManager.addRecipe(new ItemStack(Item.swordSteel, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.ingotIron, Character.valueOf('#'), Item.swordSteel });
				craftingManager.addRecipe(new ItemStack(Item.swordSteel, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.swordSteel, Character.valueOf('#'), Item.swordSteel });
				craftingManager.addRecipe(new ItemStack(Item.pickaxeSteel, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.ingotIron, Character.valueOf('#'), Item.pickaxeSteel });
				craftingManager.addRecipe(new ItemStack(Item.pickaxeSteel, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.pickaxeSteel, Character.valueOf('#'), Item.pickaxeSteel });
				craftingManager.addRecipe(new ItemStack(Item.shovelSteel, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.ingotIron, Character.valueOf('#'), Item.shovelSteel });
				craftingManager.addRecipe(new ItemStack(Item.shovelSteel, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.shovelSteel, Character.valueOf('#'), Item.shovelSteel });
				craftingManager.addRecipe(new ItemStack(Item.axeSteel, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.ingotIron, Character.valueOf('#'), Item.axeSteel });
				craftingManager.addRecipe(new ItemStack(Item.axeSteel, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.axeSteel, Character.valueOf('#'), Item.axeSteel });
				craftingManager.addRecipe(new ItemStack(Item.hoeSteel, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.ingotIron, Character.valueOf('#'), Item.hoeSteel });
				craftingManager.addRecipe(new ItemStack(Item.hoeSteel, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.hoeSteel, Character.valueOf('#'), Item.hoeSteel });

				craftingManager.addRecipe(new ItemStack(Item.swordDiamond, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.diamond, Character.valueOf('#'), Item.swordDiamond });
				craftingManager.addRecipe(new ItemStack(Item.swordDiamond, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.swordDiamond, Character.valueOf('#'), Item.swordDiamond });
				craftingManager.addRecipe(new ItemStack(Item.pickaxeDiamond, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.diamond, Character.valueOf('#'), Item.pickaxeDiamond });
				craftingManager.addRecipe(new ItemStack(Item.pickaxeDiamond, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.pickaxeDiamond, Character.valueOf('#'), Item.pickaxeDiamond });
				craftingManager.addRecipe(new ItemStack(Item.shovelDiamond, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.diamond, Character.valueOf('#'), Item.shovelDiamond });
				craftingManager.addRecipe(new ItemStack(Item.shovelDiamond, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.shovelDiamond, Character.valueOf('#'), Item.shovelDiamond });
				craftingManager.addRecipe(new ItemStack(Item.axeDiamond, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.diamond, Character.valueOf('#'), Item.axeDiamond });
				craftingManager.addRecipe(new ItemStack(Item.axeDiamond, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.axeDiamond, Character.valueOf('#'), Item.axeDiamond });
				craftingManager.addRecipe(new ItemStack(Item.hoeDiamond, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.diamond, Character.valueOf('#'), Item.hoeDiamond });
				craftingManager.addRecipe(new ItemStack(Item.hoeDiamond, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.hoeDiamond, Character.valueOf('#'), Item.hoeDiamond });

				craftingManager.addRecipe(new ItemStack(Item.swordGold, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.ingotGold, Character.valueOf('#'), Item.swordGold });
				craftingManager.addRecipe(new ItemStack(Item.swordGold, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.swordGold, Character.valueOf('#'), Item.swordGold });
				craftingManager.addRecipe(new ItemStack(Item.pickaxeGold, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.ingotGold, Character.valueOf('#'), Item.pickaxeGold });
				craftingManager.addRecipe(new ItemStack(Item.pickaxeGold, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.pickaxeGold, Character.valueOf('#'), Item.pickaxeGold });
				craftingManager.addRecipe(new ItemStack(Item.shovelGold, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.ingotGold, Character.valueOf('#'), Item.shovelGold });
				craftingManager.addRecipe(new ItemStack(Item.shovelGold, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.shovelGold, Character.valueOf('#'), Item.shovelGold });
				craftingManager.addRecipe(new ItemStack(Item.axeGold, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.ingotGold, Character.valueOf('#'), Item.axeGold });
				craftingManager.addRecipe(new ItemStack(Item.axeGold, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.axeGold, Character.valueOf('#'), Item.axeGold });
				craftingManager.addRecipe(new ItemStack(Item.hoeGold, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.ingotGold, Character.valueOf('#'), Item.hoeGold });
				craftingManager.addRecipe(new ItemStack(Item.hoeGold, 1), new Object[] { "X", "#", Character.valueOf('X'), Item.hoeGold, Character.valueOf('#'), Item.hoeGold });

				
				//armor repair
				craftingManager.addRecipe(new ItemStack(Item.helmetLeather, 1), new Object[] { "X", "X", "#", Character.valueOf('X'), Item.leather, Character.valueOf('#'), Item.helmetLeather });
				craftingManager.addRecipe(new ItemStack(Item.helmetLeather, 1), new Object[] { "X", "#",	  Character.valueOf('X'), Item.helmetLeather,  Character.valueOf('#'), Item.helmetLeather });
				craftingManager.addRecipe(new ItemStack(Item.plateLeather, 1), new Object[] { "XXX", " # ",  Character.valueOf('X'), Item.leather, Character.valueOf('#'), Item.plateLeather });
				craftingManager.addRecipe(new ItemStack(Item.plateLeather, 1), new Object[] { "X", "#",	  Character.valueOf('X'), Item.plateLeather,  Character.valueOf('#'), Item.plateLeather });
				craftingManager.addRecipe(new ItemStack(Item.legsLeather, 1), new Object[] { "XXX", " # ",  Character.valueOf('X'), Item.leather, Character.valueOf('#'), Item.legsLeather });
				craftingManager.addRecipe(new ItemStack(Item.legsLeather, 1), new Object[] { "X", "#",	  Character.valueOf('X'), Item.legsLeather,  Character.valueOf('#'), Item.legsLeather });
				craftingManager.addRecipe(new ItemStack(Item.bootsLeather, 1), new Object[] { "X", "X", "#", Character.valueOf('X'), Item.leather, Character.valueOf('#'), Item.bootsLeather });
				craftingManager.addRecipe(new ItemStack(Item.bootsLeather, 1), new Object[] { "X", "#",	  Character.valueOf('X'), Item.bootsLeather,  Character.valueOf('#'), Item.bootsLeather });

				craftingManager.addRecipe(new ItemStack(Item.helmetChain, 1), new Object[] { "X", "X", "#", Character.valueOf('X'), Item.ingotIron, Character.valueOf('#'), Item.helmetChain });
				craftingManager.addRecipe(new ItemStack(Item.helmetChain, 1), new Object[] { "X", "#",	  Character.valueOf('X'), Item.helmetChain,  Character.valueOf('#'), Item.helmetChain });
				craftingManager.addRecipe(new ItemStack(Item.plateChain, 1), new Object[] { "XXX", " # ",  Character.valueOf('X'), Item.ingotIron, Character.valueOf('#'), Item.plateChain });
				craftingManager.addRecipe(new ItemStack(Item.plateChain, 1), new Object[] { "X", "#",	  Character.valueOf('X'), Item.plateChain,  Character.valueOf('#'), Item.plateChain });
				craftingManager.addRecipe(new ItemStack(Item.legsChain, 1), new Object[] { "XXX", " # ",  Character.valueOf('X'), Item.ingotIron, Character.valueOf('#'), Item.legsChain });
				craftingManager.addRecipe(new ItemStack(Item.legsChain, 1), new Object[] { "X", "#",	  Character.valueOf('X'), Item.legsChain,  Character.valueOf('#'), Item.legsChain });
				craftingManager.addRecipe(new ItemStack(Item.bootsChain, 1), new Object[] { "X", "X", "#", Character.valueOf('X'), Item.ingotIron, Character.valueOf('#'), Item.bootsChain });
				craftingManager.addRecipe(new ItemStack(Item.bootsChain, 1), new Object[] { "X", "#",	  Character.valueOf('X'), Item.bootsChain,  Character.valueOf('#'), Item.bootsChain });

				craftingManager.addRecipe(new ItemStack(Item.helmetSteel, 1), new Object[] { "X", "X", "#", Character.valueOf('X'), Item.ingotIron, Character.valueOf('#'), Item.helmetSteel });
				craftingManager.addRecipe(new ItemStack(Item.helmetSteel, 1), new Object[] { "X", "#",	  Character.valueOf('X'), Item.helmetSteel,  Character.valueOf('#'), Item.helmetSteel });
				craftingManager.addRecipe(new ItemStack(Item.plateSteel, 1), new Object[] { "XXX", " # ",  Character.valueOf('X'), Item.ingotIron, Character.valueOf('#'), Item.plateSteel });
				craftingManager.addRecipe(new ItemStack(Item.plateSteel, 1), new Object[] { "X", "#",	  Character.valueOf('X'), Item.plateSteel,  Character.valueOf('#'), Item.plateSteel });
				craftingManager.addRecipe(new ItemStack(Item.legsSteel, 1), new Object[] { "XXX", " # ",  Character.valueOf('X'), Item.ingotIron, Character.valueOf('#'), Item.legsSteel });
				craftingManager.addRecipe(new ItemStack(Item.legsSteel, 1), new Object[] { "X", "#",	  Character.valueOf('X'), Item.legsSteel,  Character.valueOf('#'), Item.legsSteel });
				craftingManager.addRecipe(new ItemStack(Item.bootsSteel, 1), new Object[] { "X", "X", "#", Character.valueOf('X'), Item.ingotIron, Character.valueOf('#'), Item.bootsSteel });
				craftingManager.addRecipe(new ItemStack(Item.bootsSteel, 1), new Object[] { "X", "#",	  Character.valueOf('X'), Item.bootsSteel,  Character.valueOf('#'), Item.bootsSteel });

				craftingManager.addRecipe(new ItemStack(Item.helmetDiamond, 1), new Object[] { "X", "X", "#", Character.valueOf('X'), Item.diamond, Character.valueOf('#'), Item.helmetDiamond });
				craftingManager.addRecipe(new ItemStack(Item.helmetDiamond, 1), new Object[] { "X", "#",	  Character.valueOf('X'), Item.helmetDiamond,  Character.valueOf('#'), Item.helmetDiamond });
				craftingManager.addRecipe(new ItemStack(Item.plateDiamond, 1), new Object[] { "XXX", " # ",  Character.valueOf('X'), Item.diamond, Character.valueOf('#'), Item.plateDiamond });
				craftingManager.addRecipe(new ItemStack(Item.plateDiamond, 1), new Object[] { "X", "#",	  Character.valueOf('X'), Item.plateDiamond,  Character.valueOf('#'), Item.plateDiamond });
				craftingManager.addRecipe(new ItemStack(Item.legsDiamond, 1), new Object[] { "XXX", " # ",  Character.valueOf('X'), Item.diamond, Character.valueOf('#'), Item.legsDiamond });
				craftingManager.addRecipe(new ItemStack(Item.legsDiamond, 1), new Object[] { "X", "#",	  Character.valueOf('X'), Item.legsDiamond,  Character.valueOf('#'), Item.legsDiamond });
				craftingManager.addRecipe(new ItemStack(Item.bootsDiamond, 1), new Object[] { "X", "X", "#", Character.valueOf('X'), Item.diamond, Character.valueOf('#'), Item.bootsDiamond });
				craftingManager.addRecipe(new ItemStack(Item.bootsDiamond, 1), new Object[] { "X", "#",	  Character.valueOf('X'), Item.bootsDiamond,  Character.valueOf('#'), Item.bootsDiamond });

				craftingManager.addRecipe(new ItemStack(Item.helmetGold, 1), new Object[] { "X", "X", "#", Character.valueOf('X'), Item.ingotGold, Character.valueOf('#'), Item.helmetGold });
				craftingManager.addRecipe(new ItemStack(Item.helmetGold, 1), new Object[] { "X", "#",	  Character.valueOf('X'), Item.helmetGold,  Character.valueOf('#'), Item.helmetGold });
				craftingManager.addRecipe(new ItemStack(Item.plateGold, 1), new Object[] { "XXX", " # ",  Character.valueOf('X'), Item.ingotGold, Character.valueOf('#'), Item.plateGold });
				craftingManager.addRecipe(new ItemStack(Item.plateGold, 1), new Object[] { "X", "#",	  Character.valueOf('X'), Item.plateGold,  Character.valueOf('#'), Item.plateGold });
				craftingManager.addRecipe(new ItemStack(Item.legsGold, 1), new Object[] { "XXX", " # ",  Character.valueOf('X'), Item.ingotGold, Character.valueOf('#'), Item.legsGold });
				craftingManager.addRecipe(new ItemStack(Item.legsGold, 1), new Object[] { "X", "#",	  Character.valueOf('X'), Item.legsGold,  Character.valueOf('#'), Item.legsGold });
				craftingManager.addRecipe(new ItemStack(Item.bootsGold, 1), new Object[] { "X", "X", "#", Character.valueOf('X'), Item.ingotGold, Character.valueOf('#'), Item.bootsGold });
				craftingManager.addRecipe(new ItemStack(Item.bootsGold, 1), new Object[] { "X", "#",	  Character.valueOf('X'), Item.bootsGold,  Character.valueOf('#'), Item.bootsGold });

		}

		@Override
		public String Version()
		{
				return "MMM-0.1";
		}

}

We can rely on MMM's remappings to fix up all the references to Minecraft classes such as Item.fishingRod, Block.wood and suchlike.

And that's it!  Zip up the three .class files and the .mmm file, preserving the directory structure (so mod_toolrepair.class goes at the top level, the two Repairing*CB classes go in toolRepair, and the .mmm file goes anywhere).

If you are using Eclipse, you can create the final .zip by right-clicking on the source, selecting "Export", choosing "General/Archive File", and then ticking the checkboxes for the files you want.  The advantage of putting most of the tool repair files in their own subdirectory comes up here too; you can just tick that entire subdirectory.  Click the "Save in zip format" radiobutton.  You might also need to experiment with the "Create directory structure for files" vs. "Create only selected directories" radiobuttons, to see which one gives you the directory structure you want.

You can download the final sources here: http://dl.dropbox.co...pair_Source.zip

And the zipped-up mod here: http://dl.dropbox.co...lRepair_MMM.zip

Changelog

0.1     Initial release of MMM

0.2     Support for remapping fields and methods; Auto-deployed resources; Inheritance chaining.
Check out my Minecraft Mod Manager, before official modding support makes it redundant in a few weeks.  Better late than never!

Register or log in to remove.

#2

lahwran
    lahwran

    Diamond Miner

  • Members
  • 773 posts
  • Location: Around the World

Posted 12 December 2010 - 12:34 AM

this isn't really a mod *manager*, you know. it's a cool idea, I might code to it, but for it to be a manager it #1 wouldn't have any change in how modders would code (as far as I can tell this does) and would have a GUI.

howabout a gui that allows you to choose which mods you want from the minecraft launcher?

edit: also, could you remove the zip requirement? and what happens if there are files in the loading dir that are not zip or are zipped but are not .class?

Posted Image
Stupidity on the rise with a 40% chance of shitstorms.


#3

Smiley96L

Posted 12 December 2010 - 12:37 AM

One question: Dose this cut down on conflicts?
| CPU: AMD Phenom II X6 1100T @ 4 Ghz | GPU 1: EVGA GTX 680 SC Signature | GPU 2: PNY GTX 560 Dedicated PhysX | RAM: 4GB Corsair XMS3 @ 1600Mhz | Mobo: Asus Corsshair V Formula | PSU: XFX Pro 850w | Hard Drive: Samsung F3 @ 7200 RPM | OS: Windows 7 Proffesional 64-Bit | CPU Cooler: Noctua NH-D14 | Case: Antec Twelve Hundred |

#4

simo_415
    simo_415

    Glowstone Miner

  • Members
  • 3046 posts

Posted 12 December 2010 - 12:47 AM

Sounds like a much needed tool. A helloworld example for modders would be nice..

#5

RobRendell

Posted 12 December 2010 - 09:35 AM

@lahwran: yes, I agree, "manager" isn't the ideal word.  A better name would have been "mod loader", but that's taken :P  It doesn't require modders to change how they code (it'll happily load current-style mods - see "version 0"), but if modders do change their coding style to take advantage of its features, they can get some benefits.

Re: the zip thing: as I said, support for that format is built in to Java, and so I can make it load that without having to include lots of library code to load other formats.  Given that Notch has announced that he plans to deliver Beta in 8 days, and one of his first priorities in Beta will be getting a proper modding API in place, MMM's format support probably isn't going to be relevant - modders will be moving to whatever the official system is, and MMM will become redundant.  I posted it today, even though it still requires some work, because I figured it might be of interest now, but will not be of any interest in the new year.

Files that don't end with .zip or .jar in the mmm_mods folder are ignored.  All files ending with .zip or .jar are loaded, but only .class and .mmm files within those archives are actively loaded (although if resources are included in the archives such as .pngs or whatever, MMM is able to locate them when the mod code loads them.  So, for instance I can run "Mo' Creatures" through MMM and the lions, ogres etc. all appear properly (although Mo' Creatures requires you to unzip the sound files into the resources dir, and has a specific sub-directory you're supposed to inject into minecraft.jar, so I had to extract it and then zip up that sub-directory as a stand-alone zip).

@Smiley96L: it has the potential to reduce conflicts, if it got to the point of allowing modders to make "version 2" mods.  Assuming I can do it before official API support comes through, I'll be concentrating on getting "version 2" support working next, because I feel that it's probably the only element of MMM that might actually be of interest to Mojang.

@simo_415: in its current form, there's nothing that modders can really do with it - without full support for "Version 1" or "Version 2" mods, they're probably better off just sticking to their current system and waiting for the official API to come out.  If/when I get that stuff working, I'll follow up with examples.
Check out my Minecraft Mod Manager, before official modding support makes it redundant in a few weeks.  Better late than never!

#6

Valance
    Valance

    Coal Miner

  • Members
  • 125 posts
  • Location: Germany

Posted 16 December 2010 - 12:50 AM

I tried MMM with my singleplayer mod collection (ModLoader, AudioMod, BiomeTerrainMod, BunnyMod, DoubleDoor_Fix, ElevationGradient, FancyPack, Recall_1.6, Shears, TorchUnleashed) and it worked great! Just applied HD texture fix to my minecraft.jar.

ModLoader gives an error:
java.lang.NullPointerException
	at ModLoader.(ModLoader.java:92)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at not.minecraft.MMM.invokeInitCallbacks(MMM.java:699)
	at net.minecraft.GameUpdater.createApplet(MMMGameUpdaterWrapper.java:32)
	at net.minecraft.Launcher$1.run(Launcher.java:76)

But all ModLoader dependend mods working fine :D

BiomeTerrainMod isn't loading it's plugins:
java.lang.NullPointerException
	at BiomeTerrain.(BiomeTerrain.java:65)
	at px.(px.java:47)
	at oz.c(oz.java:35)
	at cy.a(SourceFile:248)
	at cy.(SourceFile:228)
	at cy.(SourceFile:165)
	at cy.(SourceFile:132)
	at net.minecraft.client.Minecraft.b(SourceFile:1165)
	at le.c(SourceFile:68)
	at le.a(SourceFile:54)
	at bp.a(SourceFile:69)
	at bp.e(SourceFile:116)
	at bp.d(SourceFile:104)
	at net.minecraft.client.Minecraft.i(SourceFile:1003)
	at net.minecraft.client.Minecraft.run(SourceFile:595)
	at java.lang.Thread.run(Thread.java:662)

I really like the way MMM makes organizing mods easier. Great work!
Posted Image

#7

RobRendell

Posted 16 December 2010 - 09:38 AM

Thanks!  I'm really glad you like it :D

The NullPointerException ModLoader prints is when it first starts up.  It expects the normal URLClassLoader to be in place, and gets thrown by the fact that it finds my classloader instead.  It also goes scanning minecraft.jar for mod class files, but with MMM they're not there.  I have a callback system for mods to register something to call when they're loaded by MMM, and I explicitly added a callback for ModLoader "out of the box" so that it gets fed all the MMM mod zips.

Unfortunately, I have found one problem with MMM using ModLoader - if won't work currently with mods that create custom blocks.  When the game goes to render that block in an "item" form (in your hand or dropped on the ground, i.e. not built), Minecraft crashes.  I've posted to Risugami's ModLoader thread requesting a minor code change to ModLoader that will fix this, and in the meantime I've thought of a workaround that MMM could use, but haven't quite got it working yet.

I'll have a look at BiomeTerrainMod and see if I can work out what's going on.
Check out my Minecraft Mod Manager, before official modding support makes it redundant in a few weeks.  Better late than never!

#8

Valance
    Valance

    Coal Miner

  • Members
  • 125 posts
  • Location: Germany

Posted 18 December 2010 - 12:08 PM

I found out the problem with custom blocks the hard way xD Wasted the last hours to find out what the hell is wrong with my custom block class, but at last I remembered you warned about this... before I was totally getting mad^^

While working on my mod MMM made checking for problems between different mod combinations really easy. Just moving around mod archives :SSSS:
Posted Image

#9

RobRendell

Posted 22 December 2010 - 08:13 PM

Ha!  The Minecraft Forums finally let me log back in!

Valance said:

While working on my mod MMM made checking for problems between different mod combinations really easy. Just moving around mod archives :D
I'm glad it's proving useful! :)  Did you find the conflicts.txt file in the mmm_mods folder?

I've worked around the problem with ModLoader and custom blocks, but unfortunately it requires Minecraft-version-specific knowledge to work (the 0.1 version of MMM has no reliance on the current obfuscated Minecraft class/method/field names, so it should keep running across multiple versions).  The Right Way to solve ModLoader's problem is for Risugami to change ModLoader's startup slightly to be MMM-compatible, but I can't expect him to do that when MMM is still so new.

So, the upshot of that is that now Beta versions are coming out every few hours, I'll need to get the mappings sorted out before I can release MMM v0.2, with the ModLoader fix.

WRT BiomeTerrainMod, I had a look.  The code is modelled on an earlier implementation of ModLoader, and suffers from similar problems (i.e. that it searches minecraft.jar for its plugins, and when running under MMM they're not there).  However, I'm afraid I can't even work around the problems there in the way I did with ModLoader; it does more work in its static block, meaning I can't hook into it.  Again, if MMM was more fully featured and useful the mod's author might have some incentive to change his code to hook into MMM (the callback mechanism in MMM means he'd just need to include a .mmm text file in his .zip with a line to say which method to call, and it would be invoked with the list of mod files to scan), but for now I'm going to have to say BiomeTerrainMod and MMM are incompatible.
Check out my Minecraft Mod Manager, before official modding support makes it redundant in a few weeks.  Better late than never!

#10

SHARK12
    SHARK12

    Out of the Water

  • Members
  • 3 posts

Posted 05 January 2011 - 04:28 PM

HALP cant install were is the minecraft folder ?   :)  :)  :Zombie:  :Sheep:  :Notch:
                                                                         :SSSS:  :Pig:  :(  :tnt:  :tnt:

#11

seronis
    seronis

    Lapis Lazuli Collector

  • Members
  • 1120 posts
  • Location: Ohio, USA
  • Minecraft: seronis

Posted 05 January 2011 - 05:01 PM

Next version of this you should change its load operation so that when looking in the zip anything inside a  'jar' subfolder is placed into the jar, and anything in any OTHER folder is placed in a folder of the same name in  .minecraft.    That way i can package up a mod that inside it has 2 main folders,   jar and resources,  and those will all get properly copied where they need to be.   Alternatively people with configuration could have a  config/  or  mod/mymodname/config.txt  etc and those will get placed where needed.

Its a very simple requirement for modders to then make mods that are MMM compliant.  Then only root level files that are not in a folder would need to be scanned for the administrative stuff.   given mods 'readme' files for manual install would be properly ignored etc.

#12

Gachl
    Gachl

    Forum/Wiki Sponsor

  • Members
  • 754 posts
  • Location: Manehattan, MLP:FIM Server
  • Minecraft: Gachl

Posted 09 January 2011 - 11:53 AM

C:\Path\To\MinecraftModManager>java -Xmx1024M -Xms512M -cp "C
:\Users\myName\AppData\Roaming\.minecraft\bin\Minecraft.jar;mmm.jar" -Djav
a.system.class.loader=not.minecraft.MMM -noverify net.minecraft.LauncherFrame
MMM: No class mappings file found - not translating.
MMM: Loading mods from directory C:\Users\myName\AppData\Roaming\.minecraf
t\mmm_mods\
MMM: Loading mod MineColony0.12.zip
MMM: Loading mod mmm.jar
MMM: ===========================
MMM: Minecraft Mod Manager encountered a problem loading mmm.jar.  It will be di
sabled.
java.io.IOException: Unable to extend original class net/minecraft/GameUpdater
		at not.minecraft.MMM.initialiseMod(MMM.java:362)
		at not.minecraft.MMM.initialiseAllMods(MMM.java:414)
		at not.minecraft.MMM.initialise(MMM.java:485)
		at not.minecraft.MMM.loadClass(MMM.java:812)
Caused by: java.lang.ClassNotFoundException: Unable to custom-load class
		at not.minecraft.MMM.findClassBytes(MMM.java:563)
		at not.minecraft.MMM.initialiseMod(MMM.java:342)
		... 3 more
Caused by: java.lang.NullPointerException
		at not.minecraft.MMM.findClassBytes(MMM.java:557)
		... 4 more
MMM: ===========================
Exception in thread "main" java.lang.NoClassDefFoundError: net/minecraft/Launche
rFrame
Caused by: java.lang.ClassNotFoundException: Unable to custom-load class
		at not.minecraft.MMM.findClassBytes(MMM.java:563)
		at not.minecraft.MMM.findClass(MMM.java:578)
		at not.minecraft.MMM.loadClass(MMM.java:829)
Caused by: java.lang.NullPointerException
		at not.minecraft.MMM.findClassBytes(MMM.java:557)
		... 2 more
Could not find the main class: net.minecraft.LauncherFrame.  Program will exit.
mmm.jar crashes, what do?
Everypony join the Pony Minecraft Server!
Posted Image

#13

Phongishere

Posted 10 January 2011 - 04:17 AM

I'm having trouble installing MMM. I followed the steps and run the minecraft.bat. I do not see a "mmm_mods" folder in the .minecraft folder. Please inform me what might I be doing wrong.

Please and Thank you.

#14

snowninja13

Posted 12 January 2011 - 05:04 AM

Hai, this may seem pretty lame of me, but I dont understand how to work this, I download the files, extract to the place I want the, but what after that!!

#15

MajorWubba
  • Minecraft: MajorWubba

Posted 31 January 2011 - 12:03 AM

Ermmm... im on a mac, and there is no .zip file. My minecraft.sh is a text file, too. Is it supposed to be like that?

#16

danielc1
    danielc1

    Tree Puncher

  • Members
  • 13 posts

Posted 01 February 2011 - 11:49 AM

shit doesnt work

#17

Temragon
    Temragon

    Stone Miner

  • Curse Premium
  • Curse Premium
  • 84 posts

Posted 01 February 2011 - 12:36 PM

I... I think I love you for working on this.  :)

Bonus points if you define a .mm format (minecraft mod) def for authors so they can distribute patch-based mods directly, and your mod manager will handle it.

It's what the Heroes of Newerth community did, and works quite well.

#18

lahwran
    lahwran

    Diamond Miner

  • Members
  • 773 posts
  • Location: Around the World

Posted 03 February 2011 - 03:43 PM

found this again. will merge it into my package manager eventually; not a super high priority, much higher is to get the damn thing released.

btw, I meant that reading from the filesystem should be supported. but now I've written my own patcher and it doesn't support it. good going, me ...

Posted Image
Stupidity on the rise with a 40% chance of shitstorms.


#19

dragonkeyblade
  • Location: Under Notch's bed, stealin' his beard.
  • Minecraft: dragonkeyblade

Posted 09 February 2011 - 06:07 AM

I have gotten multiple errors when minecraft starts that class modloader was not found. What is happening?
Mods will not work.
Don't you hate it when people are?

Posted Image


#20

lahwran
    lahwran

    Diamond Miner

  • Members
  • 773 posts
  • Location: Around the World

Posted 09 February 2011 - 06:13 AM

dragonkeyblade said:

I have gotten multiple errors when minecraft starts that class modloader was not found. What is happening?
Mods will not work.
*facepalm*

Posted Image
Stupidity on the rise with a 40% chance of shitstorms.