Reputation: 9
I am writing an addon to the minecraft mod Thaumcraft, specifically one that adds aspects to blocks based on the contents of a file. This is for Minecraft 1.7.10
The code runs the preInit method, everything goes fine. However, the game crashes on the postInit method. I cannot figure out why it crashes
Here is the stacktrace from the crash report:
---- Minecraft Crash Report ----
// I'm sorry, Dave.
Time: 6/10/15 5:40 PM
Description: Initializing game
java.lang.StringIndexOutOfBoundsException: String index out of range:
-1
at java.lang.String.substring(Unknown Source)
at polymer.aspectadder.AspectAdder.decodeValues(AspectAdder.java:105)
at polymer.aspectadder.AspectAdder.postInit(AspectAdder.java:64)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at cpw.mods.fml.common.FMLModContainer.
handleModStateEvent(FMLModContainer.java:513)
at sun.reflect.GeneratedMethodAccessor3.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.google.common.eventbus.EventSubscriber.
handleEvent(EventSubscriber.java:74)
at com.google.common.eventbus.SynchronizedEventSubscriber.
handleEvent(SynchronizedEventSubscriber.java:47)
at com.google.common.eventbus.EventBus.dispatch(EventBus.java:322)
at com.google.common.eventbus.EventBus.
dispatchQueuedEvents(EventBus.java:304)
at com.google.common.eventbus.EventBus.post(EventBus.java:275)
at cpw.mods.fml.common.LoadController.
sendEventToModContainer(LoadController.java:208)
at cpw.mods.fml.common.LoadController.
propogateStateMessage(LoadController.java:187)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.google.common.eventbus.EventSubscriber.
handleEvent(EventSubscriber.java:74)
at com.google.common.eventbus.SynchronizedEventSubscriber
.handleEvent(SynchronizedEventSubscriber.java:47)
at com.google.common.eventbus.EventBus.dispatch(EventBus.java:322)
at com.google.common.eventbus.EventBus.
dispatchQueuedEvents(EventBus.java:304)
at com.google.common.eventbus.EventBus.post(EventBus.java:275)
at cpw.mods.fml.common.LoadController.
distributeStateMessage(LoadController.java:118)
at cpw.mods.fml.common.Loader.initializeMods(Loader.java:694)
at cpw.mods.fml.client.FMLClientHandler.
finishMinecraftLoading(FMLClientHandler.java:288)
at net.minecraft.client.Minecraft.func_71384_a(Minecraft.java:541)
at net.minecraft.client.Minecraft.func_99999_d(Minecraft.java:867)
at net.minecraft.client.main.Main.main(SourceFile:148)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at net.minecraft.launchwrapper.Launch.launch(Launch.java:135)
at net.minecraft.launchwrapper.Launch.main(Launch.java:28)
A detailed walkthrough of the error, its code path and all known details
is as follows:
---------------------------------------------------------------------------
------------
-- Head --
Stacktrace:
at java.lang.String.substring(Unknown Source)
at polymer.aspectadder.AspectAdder.decodeValues(AspectAdder.java:105)
at polymer.aspectadder.AspectAdder.postInit(AspectAdder.java:64)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at cpw.mods.fml.common.FMLModContainer.
handleModStateEvent(FMLModContainer.java:513)
at sun.reflect.GeneratedMethodAccessor3.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.google.common.eventbus.EventSubscriber.
handleEvent(EventSubscriber.java:74)
at com.google.common.eventbus.SynchronizedEventSubscriber.
handleEvent(SynchronizedEventSubscriber.java:47)
at com.google.common.eventbus.EventBus.dispatch(EventBus.java:322)
at com.google.common.eventbus.EventBus.
dispatchQueuedEvents(EventBus.java:304)
at com.google.common.eventbus.EventBus.post(EventBus.java:275)
at cpw.mods.fml.common.LoadController.
sendEventToModContainer(LoadController.java:208)
at cpw.mods.fml.common.LoadController.
propogateStateMessage(LoadController.java:187)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.google.common.eventbus.EventSubscriber.
handleEvent(EventSubscriber.java:74)
at com.google.common.eventbus.SynchronizedEventSubscriber.
handleEvent(SynchronizedEventSubscriber.java:47)
at com.google.common.eventbus.EventBus.dispatch(EventBus.java:322)
at com.google.common.eventbus.EventBus.
dispatchQueuedEvents(EventBus.java:304)
at com.google.common.eventbus.EventBus.post(EventBus.java:275)
at cpw.mods.fml.common.LoadController.
distributeStateMessage(LoadController.java:118)
at cpw.mods.fml.common.Loader.initializeMods(Loader.java:694)
at cpw.mods.fml.client.FMLClientHandler.
finishMinecraftLoading(FMLClientHandler.java:288)
at net.minecraft.client.Minecraft.func_71384_a(Minecraft.java:541)
-- Initialization --
Details:
Stacktrace:
at net.minecraft.client.Minecraft.func_99999_d(Minecraft.java:867)
at net.minecraft.client.main.Main.main(SourceFile:148)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at net.minecraft.launchwrapper.Launch.launch(Launch.java:135)
at net.minecraft.launchwrapper.Launch.main(Launch.java:28)
The file had the following line in it:
minecraft:sponge=WATER,WATER,WATER,VOID,VOID,CROP
This should add 3 WATER aspects, 2 VOID aspects, and 1 CROP aspect.
Here is my code:
package polymer.aspectadder;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Logger;
import net.minecraft.item.Item;
import thaumcraft.api.ThaumcraftApi;
import thaumcraft.api.aspects.Aspect;
import thaumcraft.api.aspects.AspectList;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.registry.GameRegistry;
@Mod(modid = "aspectadder", name = "Aspect Adder",
version = "1.0,minecraft 1.7.10",
dependencies="required-after:Thaumcraft")
public class AspectAdder {
/*
* A mod that allows the adding of Thaumcraft aspects to items, blocks,
* or entities (enchantments may be added one day :D)
* This is done through a config file.
*
* This is an example of how to add an aspect to something, in this case
* adding 3 telum and 2 instrumentum to a Tinker's Construct Battleaxe
*
* tconstruct:battleaxe=WEAPON,WEAPON,WEAPON,TOOL,TOOL
*/
public static Logger log = Logger.getLogger("Aspect Adder");
static String pathOfClass =
AspectAdder.class.getProtectionDomain()
.getCodeSource().getLocation().getPath();
static String pathOfInstall = pathOfClass.substring(0,
pathOfClass.indexOf("mods")); //back up to the install folder
static String path =
pathOfInstall.concat("config/aspectadder").substring(6);
@EventHandler
public void preInit(FMLPreInitializationEvent event){
if(System.getProperty("os.name").startsWith("Windows")){
path.replaceAll("/", "\\\\");
}
log.info("Creating a file at " + path + " if one does not exist.");
try {
new File(path).mkdirs();
new File(path + File.separator + "entries.txt").createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
@EventHandler
public void init(FMLInitializationEvent event){
}
@EventHandler
public void postInit(FMLPostInitializationEvent event){
decodeValues(readFile());
}
static Properties readFile(){
Properties p = new Properties();
File f = new File(path + File.separator + "entries.txt");
FileInputStream inStream;
try {
inStream = new FileInputStream(f);
p.load(inStream);
inStream.close();
} catch (FileNotFoundException fnfe) {
try {
f.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
// do nothing, since we handled this at lines 39-44
// this catch clause is just here so the code runs
// plus, the file is blank anyways if it wasn't there
} catch (IOException ioe) {
ioe.printStackTrace();
}
return p;
}
static void decodeValues(Properties p){
Set<Object> keySet= p.keySet();
Object[] keys = new Object[p.size()];
int dex = 0;
for(Object o : keySet){
keys[dex] = o;
dex++;
}
for(int i = 0; i < keys.length; i++){
String key = keys[i].toString();
Item item = GameRegistry.findItem(
key.toString().substring(0, key.indexOf(":")),
key.toString().substring(key.indexOf(":") + 1));
//these are modID and item name, without the colon
addAspects(item, p.getProperty(key));
}
}
static void addAspects(Item item, String aspects) {
log.info("Adding Aspects: " + aspects + " to " +
item.getUnlocalizedName());
AspectList list = new AspectList();
int commaIndex = 0;
int i = 0;
do{
String aspect = aspects.substring(commaIndex + 1, aspects.substring(commaIndex + 1).indexOf(","));
commaIndex = aspects.substring(commaIndex + 1).indexOf(",");
list.add(Aspect.getAspect(aspect), 1);
i++;
log.info("Attempting to add " + Aspect.getAspect(aspect).getTag() + " (" + aspect.toLowerCase() + ") to " + item.getUnlocalizedName());
}while(commaIndex < aspects.lastIndexOf(","));
ThaumcraftApi.registerObjectTag(item.getUnlocalizedName(), list);
}
}
So you don't have to count all those lines, the crash seems to be caused by this section of the code:
for(int i = 0; i < keys.length; i++){
String key = keys[i].toString();
Item item = GameRegistry.findItem(
//the following line is the one in the crash report
key.toString().substring(0, key.indexOf(":")),
key.toString().substring(key.indexOf(":") + 1));
//these are modID and item name, without the colon
addAspects(item, p.getProperty(key));
}
Upvotes: 0
Views: 315
Reputation: 28722
You are looking for minecraft:sponge
in the item registry. Sponge is a block and not an item. The BlockItem has a whole different id and won't appear in the item registry under minecraft:sponge.
So instead of:
Item item = GameRegistry.findItem(
//the following line is the one in the crash report
key.toString().substring(0, key.indexOf(":")),
key.toString().substring(key.indexOf(":") + 1));
//these are modID and item name, without the colon
you should do
Item item = GameRegistry.findItem(
//the following line is the one in the crash report
key.toString().substring(0, key.indexOf(":")),
key.toString().substring(key.indexOf(":") + 1));
//these are modID and item name, without the colon
// nothing found, assume it's a block
if(item == null) {
Block block = GameRegistry.findBlock(key.toString().substring(0,key.indexOf(":")),
key.toString().substring(key.indexOf(":") + 1));
if(block != null) {
item = Block.getItemFromBlock(block);// You should probaly also do something with metadata here...
}
}
if(item != null) {
addAspects(item, p.getProperty(key));
}
EDIT I noticed a simple blatant grab fromt he item registry without any checks, so i added the stuff above. but the stuff below is also important to keep in mind. I did not add the below steps in the code above.
You should learn how to process strings. Always check if something exists(index not -1, returned value not null) Then proceed.
Simple if then else. Especially with user custom input. you must always assume they will enter it wrong. And since this is only done at startup you can affor to make it "expensive" in checks.
int pos = str.indexOf(":");
if(pos > -1) {
String[] contents = str.split(":");
if(contents.length == 2) {
String modname = contents[0];
String itemid = contents[2];
if(modname != null && itemid != null && modname.length() > 0 && itemid.length > 0
}
}
Upvotes: 0
Reputation: 6478
One of your key
does not contain any ":" during execution, so
key.toString().substring(0, key.indexOf(":"))
is evaluated as key.substring(0, -1)
which cause the error.
Check for presence of ":" before using substring()
Upvotes: 1
Reputation: 5948
Most likely it's crashing on an empty line, because it can't find a :
character in it. Add this line above the one that creates an Item:
if (key.length() == 0) continue;
Also, you shouldn't need to call key.toString()
: just key
should be fine. It is already a String.
Upvotes: 1