danielyxie / bitburner

Bitburner Game
https://danielyxie.github.io/bitburner/
2.8k stars 778 forks source link

Screen goes black #2768

Closed uhhhclem closed 2 years ago

uhhhclem commented 2 years ago

Bitburner v1.4.0 [49de4a28]

Can't seem to find any specific cause or trigger for this: Sometimes the whole screen goes black and I have to refresh to continue playing.

Tried to upload a recent save file, but https://github.com/github/hub/issues/1479 appears to be blocking.

kotenok2000 commented 2 years ago

Put it in zip archive with 7zip it works for me test.zip

uhhhclem commented 2 years ago

For what it's worth, it seems that this is happening when the game is saving. I have the game set to save every 10 minutes, because whenever it saves, it stops the world for 10-15 seconds, or longer. Every few times, I get the popup message suggesting that hey, maybe I have an infinite loop in my script and do I want to restart? (I cancel and let the save complete.)

I believe (from looking deeper into github/hub#1479, that I can't upload my save file because it's too large - it's 55mb zipped. So I uploaded it to my Google Drive - https://drive.google.com/file/d/1CfX-r5yVWu_AU-QKKS119Dk2n9Gw0ybc/view?usp=sharing

uhhhclem commented 2 years ago

Also, I should say that by "sometimes the screen goes black" I mean "reliably, several times a day."

upsided commented 2 years ago

I got this too on the steam client & chrome (firefox worked fine, though). Thinking it was memory related, I recently tried --js-flags="--max_old_space_size=8192” as run arguments and haven’t gotten the black screen yet. (steam client, approx 1 hr of playing)

phyzical commented 2 years ago

@uhhhclem can you confirm if this flag helps at all?

gholub commented 2 years ago

I have been seeing a similar issue for several days now. I tried adding the js-flags to the run arguments for the steam client, but it did not solve the issue. Attached is my save file as well as main.log.

This exception appears to be causing the issue:

[2022-02-17 18:46:14.933] [error] Unhandled Exception UnhandledRejection Error: Render frame was disposed before WebFrameMain could be accessed
    at Object._send (<anonymous>)
    at Object.n._sendInternal (electron/js2c/browser_init.js:165:558)
    at Object.b._sendInternal (electron/js2c/browser_init.js:161:2571)
    at electron/js2c/browser_init.js:201:729
    at new Promise (<anonymous>)
    at Object.invokeInWebContents (electron/js2c/browser_init.js:201:477)
    at Object.b.executeJavaScript (electron/js2c/browser_init.js:161:3265)
    at processTicksAndRejections (internal/process/task_queues.js:95:5)
[2022-02-17 18:46:15.143] [warn]  Forcefully crashing the renderer process

bb1.4.0(49de4a28)_blackscreen_17022022.zip

zigdon commented 2 years ago

Running into this too, with the steam client. My theory is that it's happening when an auto-save is triggering while a manual save is already running. My saves are now taking a few seconds to run, so it's not that uncommon that auto-save would try to happen while I'm in the middle of saving via the editor

zigdon commented 2 years ago

Nope - disabling 'save game on file save' didn't make this go away, so it's not (only) concurrent save games.

zigdon commented 2 years ago

From discord, someone suggested clearing out large files in my safe, and doing so did get rid of the problem.

OriginalRobotWizard commented 2 years ago

I am using the Steam version and this happens to me frequently, multiple times during the day, in different intervals. It can happen anywhere between 0.5 to 8 hours.

It started to happen when I started to use singularity functions to automate crimes, and work for factions. I saw the screen go black a single time with my eyes. A crime was about to be finished, but then the game went black before displaying the crime selection screen. All other times I come back to a black game window, the game is pretty much in the background, or on another screen, so it's not easy to point down when it happens.

It is not related to saving, as it also happens when auto save is off.

Adding the js-flags argument does not prevent the behaviour.

The largest file I have is 200kb, with a total unkompressed save of 4 MB.

phyzical commented 2 years ago

@OriginalRobotWizard could you please try the beta branch "development" in steam to see if it still occurs? (backup your save just incase) there has been some changes around save corruption fixes

OriginalRobotWizard commented 2 years ago

Using Steam version beta "development" ec44c9d2, the game window went black after about 7 hours.

OriginalRobotWizard commented 2 years ago

Steam version beta bc952147 still has the issue.

phyzical commented 2 years ago

@OriginalRobotWizard thx for keeping the ticket up to date, did you happen to maybe be working/ commiting crimes and then your script tried to install augmentations by chance?

phyzical commented 2 years ago

i have a pr (https://github.com/danielyxie/bitburner/pull/3101) open to fixe a crash related to augmenting when working, and there was a stale reference to the player object when commiting crimes too so fingers crossed that miight be it

OriginalRobotWizard commented 2 years ago

I noticed that after the black game window, and then reloading the game, that then the API Server stopped working. And it can not be made working again by simply disabling and enabling it. The game has to be closed and reopened for the API Server to work again.

phyzical commented 2 years ago

changes look to be merged @OriginalRobotWizard hopefully itll work this time (whenever the dev branch build is updated next)

OriginalRobotWizard commented 2 years ago

Steam version beta ca19e151 still has the issue. Let me know when your changes are live and I will keep this ticket up to date.

OriginalRobotWizard commented 2 years ago

Steam version beat b265d7ba still has the issue. It is happening unrelated to installing augmentations. The script is just working for factions and committing crimes.

phyzical commented 2 years ago

damn.... okay lets try this again.

so before you said it happens right before crimes finish, is this always the case or does it occur at random times too?

how do you handle your scripts are they just simple scripts that loop and wait for conditions or are you using like the more magical methods tail, exec, onExit ect?

OriginalRobotWizard commented 2 years ago

Still happened on the update before f17e6857 (I did not take note which commit that was). Not happened on f17e6857 for now, presumably because I only installed it a few hours ago.

Up until now, I was unable to exactly determine the point of my controller, of what it is actually doing, since when I reload, the last save is loaded and thus logging in gone. So I made an external logging server using NodeJS and ns.wget() to have live external logging. Black screen happened 2 times, since then. Both at the same log entry ("Start do-Faction-Work"). I have extended the logging in that particular part now.

So, how do I handle my scripts in that part of my controller? As with any other part where I use singularity, I am using all kind of magical methods to save on RAM on the controller. In this case in particular:

In the controller:

let pid = ns.run("appSingularityWorkForFaction.js", 1, targetFaction);
    while (ns.ps().filter(process => process.pid == pid).length)
        await ns.sleep(100);

In appSingularityWorkForFaction.js:

export async function main(ns) {
    let targetFaction = ns.args[0];

    if (ns.workForFaction(targetFaction, "hacking contracts")) {
        while (ns.isBusy()) {
            await ns.sleep(9000);
            ns.stopAction();
        }
    }

    if (ns.workForFaction(targetFaction, "field work")) {
        while (ns.isBusy()) {
            await ns.sleep(9000);
            ns.stopAction();
        }
    }

    if (ns.workForFaction(targetFaction, "security work")) {
        while (ns.isBusy()) {
            await ns.sleep(9000);
            ns.stopAction();
        }
    }

    await ns.sleep(100);
}

As I said, I have extended the logging now, so that I may be able to determine further, which of the lines causes the issue. Its worth noting, that the black screen appearance has hours of working game in between, where this particular function called over and over.

As I said, I am doing similar things for committing crimes, and all other singularity functions that just do stuff, instead of returning data. I have now extended logging in all those cases and may be able to point down on the ns calls that are made before back screens happen. (Or it magically disappears now, be it by timing of logging, or a new version of this absolutely fantstic game).

OriginalRobotWizard commented 2 years ago

bitburnerSave_1648101328_BN4x2.zip Hello, I have new insight. It seems to be a memory leaking issue. I have closely watched what happens over time, and it is the RAM usage of BitBurner Steam and Browser version slowly climbing up over time. When it reaches about 8 GB, the screen goes black and RAM usage drops to about 125 MB.

Please find attached a minimal setup save that reproduces the issue.

All the save does is, using 2 Scripts:

It will take hours to reach the point of black screen (like in the normal save), but already after a short time the RAM increase is visible in the Task Manager.

JesseFL commented 2 years ago

I just started to experience this on Steam version 1.7.0 (00adc2ff). I am still early in the game on the first bitnode, no singularity. I was focusing on working for a faction when the screen just went black for no reason. I go to Reloads -> Reload (F5) to reload the game, and it hangs until it tells me I might have an infinite loop and I have to reload and kill scripts to get it back.

It has happened 3-4 times now in the past two days. It was stable for me before last week.

JesseFL commented 2 years ago

I am observing the same behavior reported by @OriginalRobotWizard , except in my case when Bitburner hits about 4150mb the screen goes black and RAM usage drops down to about 140mb.

DoctorPolski commented 2 years ago

@phyzical I'm seeing this issue and I have a very simple case to demonstrate it.

I only started playing a couple of days ago and am using the Steam version @ 1.7.0.

I have a created a simple environment that autoscales player purchased servers to hack/weaken/grow commercial servers. Each player server runs many copies of 1 single-threaded script that in turn will hack/weaken/grow a single target. When there is enough money to buy a new player server it does so. If we are at the player server limit it will delete a single, smaller server if one exists and replace it with a new, bigger server.

As you can imagine this scales very quickly and was great fun to watch... until it wasn't. From a completely cold start, with no active scripts I run my initiator script and RAM usage climbs very quickly. Within a couple of minutes the screen goes black and hitting F5 eventually gives the "did you not wait for an async fn?" pop-up. This is not the case.

As observed by others in this issue thread the RAM usage of the exe drops right down to around 150MB when the screen goes black.

I have done nothing else in game so far. No factions, no jobs, no gangs. Just NUKE'd all the immediate scan targets and set an autoscaling bot army after them...

I can no longer play the game for more than a few minutes.

Would a save file help here? My system specs etc?

UPDATE: I have just made an interesting observation. Once the game is loaded and the game window remains focused the game runs. But, within 3 - 4 seconds of the window losing focus the game crashes to black screen.

UPDATE 2: After more digging it seems I'm hitting the infamous 4GB V8 garbage collection limit. I've tried everything to increase that limt with every --max-old-space-size variation I can think of but it's still only allocating 4GB. Has anyone used a variation of that and actually seen the memory usage increase past the 4GB default limit in a 64-bit environment?

phyzical commented 2 years ago

i want to say i have seen it get above 4gb but this was probably 6 months ago, you could also try googling electron + default limit as it might be an electron specific adjustment.

the other option is to just make some calculations to use multi threaded scripts instead of a bazzillion single thread scripts, as you will probably hit the limits again even if you did increase it

DoctorPolski commented 2 years ago

Multi-threading was definitely the way to go. It'll be a while before I hit RAM limits again... 😁

ElFisho2 commented 2 years ago

Hello, A script I was writing started crashing with a black screen immediately after running it so I started deleting stuff to find the problem. I'm not sure that this will help solve the issues that the other people have, but I found a way to black screen instantly by running the following script:

/** @param {NS} ns */
export async function main(ns) {
    Object.prototype.a = function(){}
}

For me this crashes on both google chrome and steam even in a new save. I hope this helps : )

Ok. I thought I was done, but in the middle of writing this I changed Object.prototype.a to Object.prototype.aa (or anything with more characters) and it brought me to a recovery screen instead of a black screen, so... I'm not sure if this should be submitted separately or something, but because it's related I will include the report here.

TypeError: Cannot read properties of undefined (reading 'format') (at "Terminal")

How did this happen?

I ran crash.js which is:

/** @param {NS} ns */
export async function main(ns) {
    Object.prototype.aa = function(){}
}

Environment

Save

happens on a fresh save file but here aa bitburnerSave_1658432341_BN1x1.txt

P.S. I've also been recently getting the random black screen every so often (probably the memory reasons discussed in earlier comments)

ElFisho2 commented 2 years ago

@hydroflame It looks like you closed this issue while I was writing my last comment. I was 8 minutes too late (what a coincidence!) and I think the issue should be reopened. (I don't have the reopen button) : )

HoveringGoat commented 2 years ago

I dont think this is resolved. I'm getting this on 1.7. I spent a few trillion on upgrading my home ram and now loading my main hacking script it spawns too many scripts and crashes the game.

powiedl commented 4 weeks ago

I'm on v2.6.2 and experiencing the black screen problem too. In my case it seems to be related with a script I wrote (to automate blackburner). The script is still a WIP - but I can't figure out, what could be the reason for the black screens when the script is running.

Here is the script - maybe someone gets an idea where the problem with the black screen is coming from. Without running the script I get no black screens at all (so at least in my case it seems heavily related). Some times the black screen comes within a few minutes, some times it takes more than an hour:

`

const TRAINING_SECONDS = 5 * 60;
let startTrainingTime = 0; // unix epoch, wann das Training gestartet ist
const minChance = 100;
const minStamina = 50;
const actions = [GENERAL, CONTRACTS, OPERATIONS, BLACKOPS];
const doDebug = true;
const doDeepDebug = false;
export async function main(ns) {
    async function log(info) {
        // during this post I've commented the following two lines out
                const f = "/log-meinBladeburner.txt"; 
        await ns.write(f, info + "``n", "a")
    }
    function tlog(info, print = doDebug) {
        print && ns.tprint(new Date().toLocaleTimeString() + ' ' + info);
    }
    async function getAllActionInfos() {
        log('getAllActionInfos');
        await ns.run('/Temp/bladeburner-getAllActionInfos.js');
        const f = "/Temp/bladeburner-getAllActionInfos.json";
        return JSON.parse(await ns.read(f));
    }
    function getCurrentActionSuccessChance(name) {
        const currentActionInfo = actionInfos.infos.find(el => el.name.toLowerCase() === name.toLowerCase());
        if (currentActionInfo) {
            return { curSuccessChance: currentActionInfo.successChance, maxSuccessChance: currentActionInfo.maxSuccessChance };
        } else return 0;
    }
    async function getCurrentCityInfos() {
        log('getCurrentCityInfos');
        await ns.run('/Temp/bladeburner-getCurrentCityInfos.js');
        const f = "/Temp/bladeburner-getCurrentCityInfos.json";
        const o = JSON.parse(await ns.read(f));
        log('o.info=', o.info);
        if (o.status.toUpperCase() === 'OK') return o.info; else throw new Error('Unable to getCurrentCityInfos');
    }
    async function getMiscInfos() {
        log('getMiscInfos');
        await ns.run('/Temp/bladeburner-getMiscInfos.js');
        const f = "/Temp/bladeburner-getMiscInfos.json";
        const o = JSON.parse(await ns.read(f));
        if (o.status.toUpperCase() === 'OK') return o.info; else throw new Error('Unable to getMiscInfos');
    }
    async function footer() {
        ns.print(new Date().toLocaleTimeString() + ' - Running ...');
        await ns.sleep(sleepMs);
    }
    function getNextBlackOp(blackOpNames, currentRank) {
        if (!blackOpNames) return null;
        let tmp;
        for (let b of blackOpNames) {
            tmp = ns.bladeburner.getActionCountRemaining('black operation', b);
            if (tmp === 1) {
                let neededRank = ns.bladeburner.getBlackOpRank(b);
                if (neededRank < currentRank) return b;
            }
        }
        return null;
    }
    function stopTraining(cAct) {
        if (!cAct) return;
        if (!(cAct?.name === 'Training')) return;
        ns.bladeburner.stopBladeburnerAction();
        tlog('Stoppe Training');
        startTrainingTime = 0;
    }
ns.disableLog('ALL');
ns.tail();
const sleepMs = 2000;
const sleepShortMs = 200;
let actionInfos = {};
let allowedActions = {};
var nextBlackOp = {};
var desiredSkill = 'Hyperdrive';
var neededSkillPoints = 0;
var ownedSkillPoints = 0;
let trainingTimer = 0;
const blackOpNames = ns.bladeburner.getBlackOpNames();

while (true) {
    tlog('Starte Schleife', doDeepDebug);
    const currentMs = (new Date()).getTime();
    ns.clearLog();
    const { hp: { current: hp }, hp: { max: maxHp } } = ns.getPlayer();
    log('ns.player:' + JSON.stringify(ns.getPlayer()));
    ns.print(`Training-Timer:${trainingTimer}`);
    ns.print(`hp: ${hp} / ${maxHp}`);
    actionInfos = await getAllActionInfos();
    allowedActions = actionInfos.infos.filter(i => i.successChance >= minChance / 100 && i.remaining >= 2);
    const { city, cityChaos } = await getCurrentCityInfos();
    let { curStamina, maxStamina, curAction, curRank } = await getMiscInfos();
    log(`curStamina:${curStamina},maxStamina:${maxStamina}`);
    nextBlackOp.name = getNextBlackOp(blackOpNames, curRank);
    if (nextBlackOp.name) {
        nextBlackOp.successChance = ns.bladeburner.getActionEstimatedSuccessChance('black operation', nextBlackOp.name)[0];
    }
    ns.print(`allowed actions:${allowedActions && allowedActions.length}`);
    if (nextBlackOp?.successChance) {
        ns.print(`next possible BlackOp: ${nextBlackOp.name} (${ns.nFormat(nextBlackOp.successChance * 100, '0.0a')})`);
    }
    ns.print('Rank:', ns.nFormat(curRank, '0.000a'));
    ns.print('city (chaos):', city, ' (', ns.nFormat(cityChaos, '0.00a'), ')');
    ns.print('stamina:', ns.nFormat(curStamina, '0.000a'), '/', ns.nFormat(maxStamina, '0.000a'));
    if (startTrainingTime) {
        // es laeuft gerade ein Training
        if (startTrainingTime + TRAINING_SECONDS * 1000 < currentMs) {
            // Trainingsende erreicht
            stopTraining(curAction);
            startTrainingTime = 0;
        } else if (!curAction) {
            tlog('Start Training');
            ns.print('Start Training');
            ns.bladeburner.startAction(GENERAL, 'Training')
        };
        ns.print('0Current Action: Training (for ' + ns.nFormat((startTrainingTime + TRAINING_SECONDS * 1000 - currentMs)/1000,'0a') + ' seconds)');
        await footer();
        continue;
    }
    // wenn möglich Bladeburner machen
    if (nextBlackOp?.name && nextBlackOp?.successChance >= 1.0) {
        if (curAction && curAction.type != 'Black Operations') {
            ns.bladeburner.stopBladeburnerAction();
            curAction = ns.bladeburner.getCurrentAction();
        }
        if (!curAction || curAction === '---') { // man macht gerade keine Bladeburner-Aktion
            tlog('Bladeburner Operation machen');
            ns.bladeburner.startAction('black operation', nextBlackOp.name);
            curAction = ns.bladeburner.getCurrentAction();
            ns.print('1Current Action:', curAction?.name ? `${curAction.name}, (${curAction.type})` : '---');
        }
        await footer();
        continue;
    }
    // wenn curHealth<maxHealth Health wieder herstellen ...
    if (hp < maxHp) {
        ns.print("Regenerieren! (", curAction, ")");
        // gegebenenfalls current Action stoppen ...
        if (!curAction) {
            ns.bladeburner.startAction(GENERAL, "Hyperbolic Regeneration Chamber")
        } else if (curAction.name !== 'Hyperbolic Regeneration Chamber') {
            tlog('Starte Regenerieren');
            ns.print("Stoppe ", curAction);
            ns.bladeburner.stopBladeburnerAction();
            ns.bladeburner.startAction(GENERAL, "Hyperbolic Regeneration Chamber");
        }
        curAction = ns.bladeburner.getCurrentAction();
        await footer();
        continue;
    } else {
        if (curAction?.type?.toLowerCase() === 'general' && curAction?.name === 'Hyperbolic Regeneration Chamber') {
            tlog('Health OK - Regenerieren beenden');
            ns.bladeburner.stopBladeburnerAction();
            curAction = ns.bladeburner.getCurrentAction();
        }
    }
    // successChance < minChance - ACTION abbrechen
    let curSuccessChance = 0;
    let maxSuccessChance = 0;
    if (curAction && curAction.name) {
        let tmp = getCurrentActionSuccessChance(curAction.name);
        curSuccessChance = tmp.curSuccessChance;
        maxSuccessChance = tmp.maxSuccessChance;
    }
    ns.print(`current success chance: ${curSuccessChance * 100}`);
    if (curAction?.name === 'Field Analysis' && allowedActions.length > 0) {
        tlog("Stoppe 'Field Analysis' weil wieder etwas anderes gemacht werden kann");
        ns.bladeburner.stopBladeburnerAction();
    }
    if (curAction?.name === 'Raid' && allowedActions.length > 1) {
        tlog("Stoppe 'Raid' weil das will ich nicht machen");
        ns.bladeburner.stopBladeburnerAction();
    }
    if (curAction && curSuccessChance < minChance / 100) {
        ns.print(`Successchance too low (${curSuccessChance}), stopping...`);
        tlog('Successchance too low - stop');
        ns.bladeburner.stopBladeburnerAction();
        if (maxSuccessChance >= minChance / 100) {
            // maxSuccessChance >= minChance - Field Analysis starten (es gibt eine Schwankungsbreite bei der Successchance)
            tlog('max Successchance ok - Field Analysis');
            ns.bladeburner.startAction(GENERAL, 'Field Analysis');
        }
        curAction = ns.bladeburner.getCurrentAction();
    }
    if (curAction?.name === 'Training' && allowedActions.length > 0) stopTraining(curAction);
    if ((!curAction || curAction === '---') && allowedActions && allowedActions.length) {
        // man macht nichts, aber man darf was machen - neue Action starten
        const newAction = Math.floor(Math.random() * allowedActions.length);
        ns.print("Starting new action...");
        tlog(`Starte neue Action '${allowedActions[newAction].name}'`);
        ns.bladeburner.startAction(allowedActions[newAction].type, allowedActions[newAction].name);
        curAction = ns.bladeburner.getCurrentAction();
        await footer();
        continue;
    }
    if (curAction?.type !== 'idle' && curAction) {
        ns.print('2Current Action:', curAction?.name ? `${curAction.name}, (${curAction.type})` : '---');
    } else {
        ns.bladeburner.startAction(GENERAL, 'Training');
        tlog('Starte Trainingtimer');
        startTrainingTime = currentMs;
        curAction = ns.bladeburner.getCurrentAction();
        ns.print('3Current Action:', curAction?.name ? `${curAction.name}, (${curAction.type})` : '---');
    }

    //ns.print('blackOpNames:',blackOpNames);
    /*
                var count=0;
                if (desiredSkill) {
                        neededSkillPoints=ns.bladeburner.getSkillUpgradeCost(desiredSkill);
                        ownedSkillPoints=ns.bladeburner.getSkillPoints();
                        while (ownedSkillPoints >= neededSkillPoints) {
                                count++;
                                neededSkillPoints=ns.bladeburner.getSkillUpgradeCost(desiredSkill,count);
                                ownedSkillPoints=ns.bladeburner.getSkillPoints();
                        }
                        count--;
                        if (count>0) {
                                ns.bladeburner.upgradeSkill(desiredSkill,count);
                                ns.print(new Date().toLocaleTimeString() + 'bought Skill:',desiredSkill,' (',count,' times)');
                        }
                }
    */
    // Zur Sicherheit warten - eigentlich sollte man nie hier ankommen ...
    await footer();
}
}

` Sorry for the multiple updates - I haven't realized the preview function ... (intention of the script is not 100% correct)

As the time of the writing of this post I got the suspection, that it is related with the log function, because it happened two times when I tried to cat the log-file from the Terminal while the script was running. So - as this log isn't very useful at all I've commented out the content of the log function and will check if this resolves the black screen issue (for me). And til now (round about 30 minutes no black screen appeared, but it's a too short period of time to be really sure about it).

The issue is NOT completely gone, but in my opinion it is far better. The second part which could lead to a black screen seems to have to do with start Training or stop Training (because the "Offline" timer fits quite well with one of these events). What is strange in my opinion is the fact, that I've clicked around in bitburner "multiple" times and it was quite responsive and some seconds later I got a black screen and after reload it said, that it was offline for more than a minute (so it was still responsive after being offline).

And there is also a connection with saving of the game - like others earlier in this post stated too - (but not with if I try to save the game during a automatic save or if an automatic save kicks in during a manual save is running). But right now I was able to reproduce the issue four times in a row (and at the last attempt my above script wasn't even running - so I guess it only increases the chance for the black screen to happen, but it is not the root cause).