Fractal Softworks Forum

Please login or register.

Login with username, password and session length
Advanced search  

News:

Starsector 0.97a is out! (02/02/24); New blog post: Simulator Enhancements (03/13/24)

Author Topic: Methods called on an uninitialized combat plugin when loading the campaign  (Read 2020 times)

LazyWizard

  • Global Moderator
  • Admiral
  • *****
  • Posts: 1363
    • View Profile
    • GitHub Profile

Here's a weird one: when leaving the main menu to the campaign, it looks like new copies of every registered EveryFrameCombatPlugin are created and their advance() and renderInXCoords() methods are called without init() being called first, leading to potential NPEs.

Placing the following script in data/scripts/plugins will cause a crash when entering the campaign:
Code: java
package data.scripts.plugins;

import com.fs.starfarer.api.combat.BaseEveryFrameCombatPlugin;
import com.fs.starfarer.api.combat.CombatEngineAPI;
import com.fs.starfarer.api.combat.ViewportAPI;

import java.util.List;

public class TestMenuCalls extends BaseEveryFrameCombatPlugin
{
    private Object obj;

    @Override
    public void init(CombatEngineAPI engine)
    {
        obj = new Object();
    }

    @Override
    public void advance(float amount, List events)
    {
        obj.toString();
    }

    @Override
    public void renderInUICoords(ViewportAPI view)
    {
        obj.toString();
    }

    @Override
    public void renderInWorldCoords(ViewportAPI view)
    {
        obj.toString();
    }
}

With the stack trace:
Code
22386 [Thread-4] ERROR com.fs.starfarer.combat.CombatMain  - java.lang.NullPointerException
java.lang.NullPointerException
        at data.scripts.plugins.TestMenuCalls.advance(TestMenuCalls.java:23)
        at com.fs.starfarer.title.ooOO.K$Oo.super(Unknown Source)
        at com.fs.starfarer.combat.A.new.o00000(Unknown Source)
        at com.fs.starfarer.combat.CombatEngine.advanceInner(Unknown Source)
        at com.fs.starfarer.combat.CombatEngine.advance(Unknown Source)
        at com.fs.starfarer.title.TitleScreenState.advance(Unknown Source)
        at com.fs.starfarer.BaseGameState.traverse(Unknown Source)
        at com.fs.state.AppDriver.begin(Unknown Source)
        at com.fs.starfarer.combat.CombatMain.main(Unknown Source)
        at com.fs.starfarer.StarfarerLauncher$1.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)
Logged

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 23986
    • View Profile
Re: Methods called on an uninitialized combat plugin when loading the campaign
« Reply #1 on: September 16, 2018, 01:32:12 PM »

Crash reproduced. This is not something I'm comfortable trying to fix at this point due to the risk of introducing other bugs; e.g. an init() call in the wrong place before something else is initialized could cause problems in mod code that depend on that.

Given that, I'd say that any combat plugin just needs to check "if (engine == null) return" in any method that does anything meaningful.
Logged

LazyWizard

  • Global Moderator
  • Admiral
  • *****
  • Posts: 1363
    • View Profile
    • GitHub Profile
Re: Methods called on an uninitialized combat plugin when loading the campaign
« Reply #2 on: September 22, 2018, 02:21:07 PM »

Why is there a plugin being created at this point, though? This isn't a problem with combat plugins on the main menu; those run just fine. This is caused by a combat plugin that's being created and advanced after the campaign has already finished loading:
Code
21849 [Thread-4] INFO  com.fs.starfarer.campaign.save.CampaignGameManager  - Loading stage 37
21850 [Thread-4] INFO  com.fs.starfarer.campaign.save.CampaignGameManager  - Loading stage 38
21850 [Thread-4] INFO  com.fs.starfarer.campaign.save.CampaignGameManager  - Loading stage 39 - last
constructor called for instance #8
advance() called for instance #8
22452 [Thread-4] ERROR com.fs.starfarer.combat.CombatMain  - java.lang.NullPointerException
java.lang.NullPointerException
        at data.scripts.plugins.TestPluginCreation.advance(TestPluginCreation.java:25)
        at com.fs.starfarer.title.ooOO.K$Oo.super(Unknown Source)
        at com.fs.starfarer.combat.A.new.o00000(Unknown Source)
        at com.fs.starfarer.combat.CombatEngine.advanceInner(Unknown Source)
        at com.fs.starfarer.combat.CombatEngine.advance(Unknown Source)
        at com.fs.starfarer.title.TitleScreenState.advance(Unknown Source)
        at com.fs.starfarer.BaseGameState.traverse(Unknown Source)
        at com.fs.state.AppDriver.begin(Unknown Source)
        at com.fs.starfarer.combat.CombatMain.main(Unknown Source)
        at com.fs.starfarer.StarfarerLauncher$1.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)
Logged

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 23986
    • View Profile
Re: Methods called on an uninitialized combat plugin when loading the campaign
« Reply #3 on: September 22, 2018, 09:54:19 PM »

Probably something like the title screen state advance()-ing and rendering once or twice after a campaign game is loaded but before switching to the campaign state. I don't remember exactly why it does this - I *think* it was needed to avoid some graphical glitching related to how the progress bar works.

I mean, you're probably right that it *shouldn't* be doing this in quite this particular way, and that part of the code is definitely a bit of a mess, but defensively-coded plugins should be able to handle it regardless. Any code that relies on state transitions happening just so, unless it absolutely has to, is an error waiting to happen, you know?
Logged