Fractal Softworks Forum

Please login or register.

Login with username, password and session length

Author Topic: Horror Stories About Bugs From Hell (And How To Slay Them)  (Read 7859 times)

Sundog

  • Admiral
  • *****
  • Posts: 1727
    • View Profile
Horror Stories About Bugs From Hell (And How To Slay Them)
« on: February 03, 2014, 03:26:44 PM »

Some bugs are easy to kill. Once they're dead you think to yourself; 'Golly, how did I miss that?' This thread isn't about those bugs. This thread is about the bugs that take five hours to kill and sap every ounce of your sanity in the process. Bugs that boggle the mind even after they're dead at your feet.

My hope is that by sharing these stories, painful as they are, we can help our fellow modders overcome the tribulations we once struggled with. If we warn each other about the hidden dangers of our craft we'll all be better off.

Sundog

  • Admiral
  • *****
  • Posts: 1727
    • View Profile
Re: Horror Stories About Bugs From Hell (And How To Slay Them)
« Reply #1 on: February 03, 2014, 03:27:11 PM »

Once upon a time (approx. 25 minutes ago), I was writing an EveryFrameWeaponEffectPlugin, when lo! A vicious bug did crash my game upon startup. Frantically I searched about for the beast and found these clues three:
1. A popup dialogue box with a familiar message: 'Fatal: Index: 0, Size: 0'
2. A starsector.log with an epitaph at the end reading thusly;
Code
22188 [Thread-5] WARN  com.fs.starfarer.title.ooOO.D  - Error loading mission preview
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at com.fs.starfarer.loading.scripts.ScriptStore.o00000(Unknown Source)
at com.fs.starfarer.settings.StarfarerSettings.Ó00000(Unknown Source)
at com.fs.starfarer.campaign.fleet.FleetMember.updateStatsBasedOnCrew(Unknown Source)
at com.fs.starfarer.campaign.fleet.FleetMember.updateOnlyStatsThatCanRelyOnCROrCrew(Unknown Source)
at com.fs.starfarer.campaign.fleet.FleetMember.updateStats(Unknown Source)
at com.fs.starfarer.campaign.fleet.FleetMember.<init>(Unknown Source)
at com.fs.starfarer.combat.super.o00000(Unknown Source)
at com.fs.starfarer.title.ooOO.K.addToFleet(Unknown Source)
at com.fs.starfarer.title.ooOO.K.addToFleet(Unknown Source)
at data.missions.turningthetables.MissionDefinition.defineMission(MissionDefinition.java:37)
at com.fs.starfarer.title.ooOO.K.<init>(Unknown Source)
at com.fs.starfarer.title.ooOO.D.o00000(Unknown Source)
at com.fs.starfarer.title.ooOO.J.o00000(Unknown Source)
at com.fs.starfarer.title.ooOO.J.<init>(Unknown Source)
at com.fs.starfarer.title.ooOO.E.<init>(Unknown Source)
at com.fs.starfarer.title.OoOO.ÖôÒ000(Unknown Source)
at com.fs.starfarer.title.OoOO.class.for$super(Unknown Source)
at com.fs.starfarer.B.ØÓÒ000(Unknown Source)
at com.fs.oOOO.A.Ò00000(Unknown Source)
at com.fs.starfarer.combat.O0OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO.o00000(Unknown Source)
at com.fs.starfarer.StarfarerLauncher$2.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
22227 [Thread-5] DEBUG com.fs.graphics.TextureLoader  - Loading [graphics/backgrounds/background4.jpg] as texture with id [graphics/backgrounds/background4.jpg]
23571 [Thread-5] ERROR com.fs.starfarer.combat.O0OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO  - java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at com.fs.starfarer.loading.scripts.ScriptStore.o00000(Unknown Source)
at com.fs.starfarer.settings.StarfarerSettings.Ó00000(Unknown Source)
at com.fs.starfarer.combat.entities.Ship.<init>(Unknown Source)
at com.fs.starfarer.loading.specs.oo0OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO.o00000(Unknown Source)
at com.fs.starfarer.loading.specs.oo0OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO.o00000(Unknown Source)
at com.fs.starfarer.loading.specs.oo0OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO.o00000(Unknown Source)
at com.fs.starfarer.title.A.Ó00000(Unknown Source)
at com.fs.starfarer.title.A.class(Unknown Source)
at com.fs.starfarer.title.A.o00000(Unknown Source)
at com.fs.starfarer.combat.oOOO.new.super(Unknown Source)
at com.fs.starfarer.combat.CombatEngine.advance(Unknown Source)
at com.fs.starfarer.title.OoOO.o00000(Unknown Source)
at com.fs.starfarer.B.ØÓÒ000(Unknown Source)
at com.fs.oOOO.A.Ò00000(Unknown Source)
at com.fs.starfarer.combat.O0OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO.o00000(Unknown Source)
at com.fs.starfarer.StarfarerLauncher$2.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
3. That's all. It had to be three though. 'Answer me these riddles two' doesn't exactly have a ring to it.

Notice how the exception is thrown in the mission definition for Turning the Tables. What? How?

The bug and I proceeded to do glorious battle. I was eviscerated, decapitated, and incinerated, but I kept respawning. When at last the bug succumbed to oblivion a had learned a valuable lesson about the runtime compiler that is Janino. It is intolerant of redundancy and I, in my youthful ignorance, had been redundant. This line, and this line alone, had created the fell beast;
Code
static final float SNAP_DISTANCE = 100;
All I had to do to kill the bug was remove the static keyword*. I still find this kinda baffling as I've used 'static final' for non primitive types without issue, and NetBeans doesn't flag it as an error, or even a warning. It certainly didn't help that all my 'clues' pointed in the wrong directions.
*Edit: OR I could have solved this by assigning a float value to the attribute instead of an integer. Like so:
Code
static final float SNAP_DISTANCE = 100f;
Notice the 'f' suffix at the end that transforms the int into a float. This, I believe, is the preferred method.

tl;dr - don't use 'static final' to modify a variable. It's redundant and Janino can't handle it when it's used for primitive types. Instead just use 'final'
Edit: NOPE! I was wrong. While this will fix the issue I had, it's not the best way. 'static final' can be used for attributes, but you should be sure to assign the proper value type (e.i.  1 for int, 1.0f for float, and 1.0 for double)
« Last Edit: February 03, 2014, 04:11:59 PM by Sundog »
Logged

xenoargh

  • Admiral
  • *****
  • Posts: 5078
  • naively breaking things!
    • View Profile
Re: Horror Stories About Bugs From Hell (And How To Slay Them)
« Reply #2 on: February 03, 2014, 03:30:13 PM »

Static and final don't have the same meaning, in Java.  It's not redundant; they're used for different purposes :)
Logged
Please check out my SS projects :)
Xeno's Mod Pack

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 24123
    • View Profile
Re: Horror Stories About Bugs From Hell (And How To Slay Them)
« Reply #3 on: February 03, 2014, 03:40:59 PM »

Hmm, this is weird - the hullmod scripts use "static final" all over the place, and they're compiled with Janino. Wonder what magic combination of factors caused it to crap out, although if it did, you'd see an error about it somewhere earlier in the log.

From the stack trace, it looks like it's failing to find the combatReadinessPlugin specified in settings.json. Is that the file that your static final was in, by chance?
Logged

Sundog

  • Admiral
  • *****
  • Posts: 1727
    • View Profile
Re: Horror Stories About Bugs From Hell (And How To Slay Them)
« Reply #4 on: February 03, 2014, 03:59:41 PM »

@xenoargh: Huh. You're right. It's not redundant. I know the difference between final and static, but I was thinking using 'final' would make it static as well (after all, if it can't be changed it doesn't need to be attached to an instance). However, I just tried accessing a 'final' variable through the class name and it doesn't work, so the 'static final' combo does seem to have a purpose. So why the nads does it cause this crash? *sigh* I miss C#...

@Alex: Nope. I haven't implemented CombatReadinessPlugin. I think I just figured it out thanks to your hint about the hullmod scripts. The only differences between the hullmod 'static final' attributes and mine are that the hullmod attributes are public and have the 'f' suffix after the value. Turns out my attribute works just fine with the 'f' suffix too. The public keyword doesn't seem to matter. What silliness.

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 24123
    • View Profile
Re: Horror Stories About Bugs From Hell (And How To Slay Them)
« Reply #5 on: February 03, 2014, 04:01:16 PM »

Oh, that's fun stuff. Good to know!
Logged

Sundog

  • Admiral
  • *****
  • Posts: 1727
    • View Profile
Re: Horror Stories About Bugs From Hell (And How To Slay Them)
« Reply #6 on: February 03, 2014, 04:29:50 PM »

More Janino fun. This one's from a month or two ago. I've been meaning to warn you guys about it for a while.

Step 1. Create this very simple class and put it in your plugins folder.
Code
package data.scripts.plugins;

public class Foo {
    public Foo(int myArg) { }
}
Step 2. Start Starsector.
Step 3. Crash and enjoy.

Popup Text:
   Fatal: Error compiling [data.scripts.plugins.Foo]
   Cause: Problem loading class [data.scripts.Foo]

starsector.log:
Code
26905 [Thread-5] ERROR com.fs.starfarer.combat.O0OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO  - java.lang.RuntimeException: Error compiling [data.scripts.plugins.Foo]
java.lang.RuntimeException: Error compiling [data.scripts.plugins.Foo]
at com.fs.starfarer.loading.scripts.ScriptStore$3.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.RuntimeException: Problem loading class [data.scripts.plugins.Foo]
at com.fs.starfarer.loading.scripts.ScriptStore.Ó00000(Unknown Source)
... 2 more
Caused by: java.lang.InstantiationException: data.scripts.plugins.Foo
at java.lang.Class.newInstance(Unknown Source)
... 3 more

To rectify this you can simply add a default constructor like so:
Code
package data.scripts.plugins;

public class Foo {
    public Foo() { }
    public Foo(int myArg) { }
}

Anyone who can explain to me why this is necessary has my everlasting gratitude.

tl;dr - If you need to make a parameterized constructor, make a default one too.

Zaphide

  • Admiral
  • *****
  • Posts: 799
    • View Profile
Re: Horror Stories About Bugs From Hell (And How To Slay Them)
« Reply #7 on: February 03, 2014, 04:54:11 PM »

It's because of java.lang.Class.newInstance, which is called to instantiate a class (rather than say directly calling a specific constructor). It requires a 0-parameter or default constructor.

I assume this is a requirement of the ClassLoader (as I imagine it just 'by default' calls the default constructor :)).

You can check some of the doco here: http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html.

A C# example would be serializable objects; they (can) need a default constructor for a similar(ish) reason.  :)
« Last Edit: February 03, 2014, 04:57:56 PM by Zaphide »
Logged

Zaphide

  • Admiral
  • *****
  • Posts: 799
    • View Profile
Re: Horror Stories About Bugs From Hell (And How To Slay Them)
« Reply #8 on: February 03, 2014, 04:56:56 PM »

... double post... :P
Logged

Sundog

  • Admiral
  • *****
  • Posts: 1727
    • View Profile
Re: Horror Stories About Bugs From Hell (And How To Slay Them)
« Reply #9 on: February 03, 2014, 07:00:33 PM »

Zaphide, I hereby award you another one of my everlasting gratitudes! (the first one was for Exerelin)

Debido

  • Admiral
  • *****
  • Posts: 1183
    • View Profile
Re: Horror Stories About Bugs From Hell (And How To Slay Them)
« Reply #10 on: April 08, 2014, 02:33:06 AM »

Hey Sundog,

I KILLED IT



So this guy

13247 [Thread-5] WARN  com.fs.starfarer.title.ooOO.D  - Error loading mission preview
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
   at java.util.ArrayList.rangeCheck(Unknown Source)
   at java.util.ArrayList.get(Unknown Source)

Was caused by...

The BGEAIPicker.java was in data.scripts
The AdrenalineToggleTracker.java file that calls the BGEAIPicker.java was in data.scripts.plugins.

As soon as I moved the BGEAIPicker.java from data.scripts into the same package/folder as AdrenalineToggleTracker.java

Well the game started running...now to see if the AI picking script is working.

Logged

Debido

  • Admiral
  • *****
  • Posts: 1183
    • View Profile
Re: Horror Stories About Bugs From Hell (And How To Slay Them)
« Reply #11 on: April 08, 2014, 04:01:48 AM »

This does not evaluate correctly:
Code: java
        if (weaponIDCheck.getId() == "lrg_scythe_right"
                    || weaponIDCheck.getId() == "lrg_scythe_left"
                    || weaponIDCheck.getId() == "med_scythe_left"
                    || weaponIDCheck.getId() == "med_scythe_right"
                    || weaponIDCheck.getId() == "lrg_pincer_right"
                    || weaponIDCheck.getId() == "lrg_pincer_left"
                    || weaponIDCheck.getId() == "med_pincer_right"
                    || weaponIDCheck.getId() == "med_pincer_left")

This does:

Code: java
            if (weaponIDCheck.getId().contentEquals("lrg_scythe_right") 
                    || weaponIDCheck.getId().contentEquals("lrg_scythe_left")
                    || weaponIDCheck.getId().contentEquals("med_scythe_left")
                    || weaponIDCheck.getId().contentEquals("med_scythe_right")
                    || weaponIDCheck.getId().contentEquals("lrg_pincer_right")
                    || weaponIDCheck.getId().contentEquals("lrg_pincer_left")
                    || weaponIDCheck.getId().contentEquals("med_pincer_right")
                    || weaponIDCheck.getId().contentEquals("med_pincer_left"))
Logged

Sundog

  • Admiral
  • *****
  • Posts: 1727
    • View Profile
Re: Horror Stories About Bugs From Hell (And How To Slay Them)
« Reply #12 on: April 08, 2014, 01:05:12 PM »

So this guy

13247 [Thread-5] WARN  com.fs.starfarer.title.ooOO.D  - Error loading mission preview
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
   at java.util.ArrayList.rangeCheck(Unknown Source)
   at java.util.ArrayList.get(Unknown Source)

Was caused by...

The BGEAIPicker.java was in data.scripts
The AdrenalineToggleTracker.java file that calls the BGEAIPicker.java was in data.scripts.plugins.

As soon as I moved the BGEAIPicker.java from data.scripts into the same package/folder as AdrenalineToggleTracker.java

Well the game started running...now to see if the AI picking script is working.
Very strange! I wonder what the root cause of that exception is.

Debido

  • Admiral
  • *****
  • Posts: 1183
    • View Profile
Re: Horror Stories About Bugs From Hell (And How To Slay Them)
« Reply #13 on: April 08, 2014, 01:23:31 PM »

Hm, indeed it is strange when you get pretty much the same exact error code for 2 completely unrelated and different causes. You're right it does suggest there is a root cause. But what? Wish I knew.
Logged

xenoargh

  • Admiral
  • *****
  • Posts: 5078
  • naively breaking things!
    • View Profile
Re: Horror Stories About Bugs From Hell (And How To Slay Them)
« Reply #14 on: April 08, 2014, 04:59:25 PM »

Never use == to evaluate Strings.

Use myFooString.equals("foo") or myFooString.contains("foo") depending on the use case. 

This is a common Java newbie mistake; basically, string comparators are their own special thing, and just because it'll compile doesn't mean it'll operate properly :)
Logged
Please check out my SS projects :)
Xeno's Mod Pack