Giter VIP home page Giter VIP logo

bitburner-src's People

Contributors

bezrodnov avatar borisflagell avatar bzihnali avatar caldwell-74 avatar catloversg avatar d0sboots avatar danielyxie avatar ficocelliguy avatar hoekstraa avatar hydroflame avatar jaguilar avatar jjclark1982 avatar kopelli avatar ljneon avatar martinfournier avatar mughur avatar ornedan avatar phyzical avatar pigalot avatar quacksouls avatar rderfler avatar snarling avatar stalefishies avatar theaimman avatar theit8514 avatar themas3212 avatar threehams avatar tyasuh avatar undeemiss avatar zeddrak avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bitburner-src's Issues

Inconsistent thousands separator (locale related?)

[Jakob002]
Bitburner v2.1.0 (8f4636c)
Browser
OS and browser set to German (locale de_DE)

Hi devs,
I noticed an inconsistency in the use of the thousands separator (and possibly the decimal separator).
Most of the game uses the notation used in English speaking countries (dot for decimal separator, comma for thousands separator, i.e. 1M=1,000,000 and pi=3.14159). However on the stats page the skill levels seem to use my local notation (dot for thousands separator, i.e. 1M=1.000.000, and possibly comma for decimal separator, i.e. pi=3,14159).

Here is a screenshot. On the left hand my Hacking level shows as "1.000". In the overview on the right my Hacking level shows as "1,000".

locale

I'll also attach a savegame. If both levels show up as "1,000" on an English system, then it looks like the left number is locale dependent.

bitburnerSave_1666172962_BN1x1.json.gz

command line parser bugs on processing `-t` and `--tail`

[vladtepesch]
According to documentation the run command arguments -t and --tail have to be following directly to the script name. ( --> https://bitburner.readthedocs.io/en/latest/basicgameplay/terminal.html#run - at least -t is mentioned there)
But the parser also interprets them as special arguments if they are later in the arg list. this prevents them to be passed to the executed script.

for example starting a runon script (that is supposed to start a script on a remote server)

run runon.js pserv-5 somescript.js -t 500 --tail omnitek

where the script itself is supposed to process the -t and --tail parameter did not see them and itself gets executed with 500 threads

Comments From Original Issue

[mbrannen]

I believe this might be a misunderstanding of the command and intended usage.

From the docs
run [file name] [-t] [num threads] [args…]

Translating that to the command you wrote looks like this
run [file name = runon.js ] [-t] [num threads = 500] [args… = {'pserv-5', 'somescript.js', '--tail','omnitek'}]

I would suggest somescript.js having arguments that you can then pass when exec() is run from runon.js
Try taking out the -t 500 and using just 500 instead.

So in runon.js you might find something like this:

//exec(script, hostname[, numThreads=1[, args...]])
exec(scriptToRun, serverToRunOn, threads,  serverToHack)

[vladtepesch]

I believe this might be a misunderstanding of the command and intended usage.

From the docs run [file name] [-t] [num threads] [args…]

Translating that to the command you wrote looks like this run [file name = runon.js ] [-t] [num threads = 500] [args… = {'pserv-5', 'somescript.js', '--tail','omnitek'}]

I would suggest somescript.js having arguments that you can then pass when exec() is run from runon.js Try taking out the -t 500 and using just 500 instead.

So in runon.js you might find something like this:

//exec(script, hostname[, numThreads=1[, args...]])
exec(scriptToRun, serverToRunOn, threads,  serverToHack)

according to the docs the -t argument has to be passed right after the script name to be processed by the command line interpreter (I would expect the same for --tail). This implies that if I pass -t not as the second argument it should be visible within the ns.args array but that is not the case.

I wanted my runon.js to parse for the optional -t number parameter and pass its number to the ns.exec call.

so at the end according to the docs the following should happen:
(this obviously works)

> run script.js -t 1000 123 foo bar

should run the script script.js with 1000 threads and the arg array [123, 'foo', 'bar']

but this does not work as described:

> run script.js 123 foo bar -t 1000 

should (according to the docs) run the script script.js with 1 threads and the arg array [123, 'foo', 'bar', '-t', 1000].
But instead it has the same result as the first command.

Spoiler Warning Documentation

[tmajibon]
In part request, in part ask for guidance so I can possibly do it myself.

In the markdown can we put the endgame functions under a spoiler warning or such?

I went to edit it myself but a comment in the markdown says it's auto-generated, and I don't know the tool and how it's set up to run/correct it?

At the very least, we could put "Spoiler for Endgame" into the descriptions of the relevant parts?

Comments From Original Issue

[zeddrak]

I don't know the exact process (so not sure how/if spoiler is handled), but here's the documentation on contributing as a documentor. (I have used this information to make several successful documentation submissions myself, but none exactly like you are asking to do.)
contributing to documentation

RAM usage/ report of share() is incorrect (Except for Home)

[HandyGold75]
share() function report to use 2.40 GiB but only uses 0.10 GiB when not running on home.

To reproduce:

  1. Connect to a purchase server or a server that is not home
  2. Create a script with this line while (true) { share() }
  3. Open the script and check what the ram usage should be (1.60 GiB for base cost and 2.40 Gib for share() to a total of 4 GiB)
  4. Run the script with 1 tread (More works too but this is easier to see)
  5. Check Ram usage with free (This should be 1.70 GiB, where I suspect 1.60 GiB is of the base cost)
  6. If the server the script is on has only 4 GiB it should only allow this to be run with 1 tread but because of this bug, it is possible to run with 2 threads.

Version: Bitburner v1.4.0 (49de4a28)

Comments From Original Issue

[HandyGold75]

The above also seems to be the case with this script (This script is run on bought servers).

while (true) { cacheFiles = ls("home", "/Automation/Cache/Hosts/"); for (i = cacheFiles.length - 1; i > 0; i--) { j = Math.floor(Math.random() * i); k = cacheFiles[i]; cacheFiles[i] = cacheFiles[j]; cacheFiles[j] = k } arrayRootedHosts = []; for (i = 0; i < cacheFiles.length; i++) { currentCacheFile = read(cacheFiles[i]).split(","); if (currentCacheFile[5] == "true") { arrayRootedHosts.push(currentCacheFile[1], currentCacheFile[13], currentCacheFile[15]) } } for (i = 0; i < arrayRootedHosts.length; i += 3) { hack(arrayRootedHosts[i]) } }

While this script is a bit more complicated than before it only uses the ls and hack functions that have a ram requirement, with the base cost it should only add up to 1.90 GiB per tread, but when run it requires 2.40 GiB per tread. it seems to be the same case as before but instead of a real lower requirement then meant it takes more than meant.

This is also the case with the script below (This script is run on non bought servers, except for n00dles and foodnstuff).

while (true) { hack("CSEC") }

Should require 1.70 GiB per tread but uses 2.00 GiB

[HandyGold75]

Here is an export of my save file (bitburnerSave_1647685808_BN5x0.json) as I can't upload the file directly I uploaded it to my g drive: https://drive.google.com/drive/folders/1Aa8MIhnIq2XtzT7GDnS6Rjk8L2FeerlM?usp=sharing

cannot access file dir c:/

[k4zter]
wasn't able to access c:/ and had to use a script to remove all contents in the file to get rid of the folder even tho the game fully recognizes that there is a file there with c:/

bitburner_MtzGpkFVIv

Bitburner v1.4.0 (49de4a28)(steam)

Comments From Original Issue

[phyzical]

just to confirm (this is obviously windows right?)

or have you created a folder called c:/?

didn't relise we give bitburner access to the hardrive..
i assume we dont otherwise thats pretty scarey....

[k4zter]

yeah it was a folder i pushed from VSC and it took the file dir of my folder on my pc...

[phyzical]

hmm might be something to ask in the discord channel for VS code. (but we can try to repo it and see what happens) 👍

[k4zter]

Yeah I fixed it by changing the settings in vsc to not push my PC Dir but the people that I was asking help to fix this told me to issue it anyways

[phyzical]

@lordducky hey thought i would tag you on this one, any chance this can be added as part of your webserver updates :). tldr we just need to make sure that we cant save invalid directory names i.e c:\ and / as these cannot be cd into once they are copied across via the webserver

Coding contract window lost due to singularity function

[macdjord]
I had a coding contract window open when a script I had running in the background called the exercise-at-gym singularity function. This caused the game to switch to the gym training screen and the contract window to vanish. When I went back to the terminal and tried to reopen the contract by running it again, I got an error message saying "There's already a Coding Contract in Progress". I had to reload the game to get the contract open again.

Version: Bitburner v1.3.0 (9fdc3ac5)

Comments From Original Issue

[SagePtr]

Also contract window disappears when you return your focus to faction job (hacking contracts for instance) when coding contract window is opened. You cannot programmatically solve contracts after this (the game thinks contract is running) until you reload the game.

[nulflux]

This also happens when triggering a DOM click() on a menu option like City as the contract window is open. The coding contract is forever in progress and there is no way to return to it. There are two potential solutions for this: 1) instead of an error the run command could default to cancel and re-open the contract or 2) make available a command to cancel the current contract. Solution 1 solves the problem universally; solution 2 allows the users to solve the problem themselves. Since there is no special mechanic preventing players pre-singularity from running a coding contract programmatically I don't believe it should be a singularity function but rather a function available by default.

[phyzical]

idk if this should be fixed, by changing focus is it not expected to close windows?

or is it more of a the window should be there when you go back to the terminal?

[macdjord]

@phyzical The problem isn't that the window closes. The problem is you can't reopen it because the game thinks its still open.

[BrianLDev]

This bug happened to me today too in the way @SagePtr described.

If you have a contract open and change focus to Faction work, the coding contract UI disappears but the game incorrectly thinks that it's still open. Doesn't look like there's a way to get the UI to pop back up again, and trying to run the contract again gives an error message. There's already a Coding Contract in Progress. The only way to fix it is to close and reopen the game.

image

[BrianLDev]

So I'm guessing the fix would be in the code that handles focus. It should check for any open coding contracts and simply close them before changing focus.

[macdjord]

@BrianLDev That seems like treating the symptom rather than the problem to me. A better solution would be to change the 'is a coding contract in progress' check so it actually checks whether there is a contract window open - as in, examine the DOM - rather than depend on finding every possible way that the contract window could get closed and ensuring each one marks the window as closed first.

[holgero]

Why is there a guard against opening the contract again, anyway? Perhaps just delete that?

[rayanth]

@holgero it was likely intended in order to prevent two different coding contracts from being opened at the same time. I agree with @macdjord that the better fix would be in the check for a coding contract in progress, but rather than simply check if a window is open, check if a different contract's window is open. If the same coding contract's window is thought to be open, just display it again.

[YoshiRulz]

Just hit this on 2.0.2 via Steam.

Folder refactor

[hydroflame]
Every file in the game should match [a-zA-Z0-9\-_](/[a-zA-Z0-9\-_])*\.(js|script|txt). Note the lack is leading slash in ALL files. Foldered or not.

Make a function to sanitize filename (convert // to /, remove leading slash, etc, take a look at electron.tsx)
Make another function that validates a filename (to catch weird extension and other invalid characters like spaces)
Write a save file migration that sanitizes all txt and scripts.
Make the txt and scripts array on server private, will narrow down everything that uses them.
Write a function called like BaseServer.prototype.findFile so that nothing needs read access to the private arrays

Comments From Original Issue

[daanflore]

Do not know if my issue is related to my "problem" in the game:
Bug reports that I was making:
Seems like when you ns.exec command contains a script in a sub folder when you do not start it with / the system does not detect that it is already running and start the script as a new process
image

Would the new match logic prevent the problem with ns.exec I notices?
Or are they not related.

[phyzical]

@daanflore yeah it basically is 👍

also danielyxie/bitburner#1935 may be related

Hacking server with low money results in "Hack successful on 'foodnstuff'! Gained $0.000"

[davidpa9708]
Last section of danielyxie/bitburner#2783

Description

Hacking server with low amounts of money results in no money stolen

test with server: 'foodnstuff', no extra security and around 3000 hack skill

Expected behavior

to hack some money, at least 1$

steps

  • hack server until 0 money on the server. (foodnstuff)
  • connect to the server
  • run grow from terminal
  • run hack from terminal
  • still same money
output for foodnstuff
    Bitburner v1.4.0 (a3c599e6)
    [home ~/]> connect foodnstuff 
    Connected to foodnstuff
    [foodnstuff ~/]> analyze 
    Analyzing system...
    [||||||||||||||||||||||||||||||||||||||||||||||||||]
    foodnstuff: 
    Organization name: FoodNStuff
    Root Access: YES
    Can run scripts on this host: YES
    Backdoor: YES
    Required hacking skill for hack() and backdoor: 1
    Server security level: 3.000
    Chance to hack: 100.00%
    Time to hack: 0.333 seconds
    Total money available on server: $0.000
    Required number of open ports for NUKE: 0
    SSH port: Open
    FTP port: Closed
    SMTP port: Closed
    HTTP port: Closed
    SQL port: Closed
    [foodnstuff ~/]> grow 
    [||||||||||||||||||||||||||||||||||||||||||||||||||]
    Available money on 'foodnstuff' grown by NaN%. Gained 19.916 hacking exp.
    Security increased on 'foodnstuff' from 3.000 to 3.100
    [foodnstuff ~/]> analyze 
    Analyzing system...
    [||||||||||||||||||||||||||||||||||||||||||||||||||]
    foodnstuff: 
    Organization name: FoodNStuff
    Root Access: YES
    Can run scripts on this host: YES
    Backdoor: YES
    Required hacking skill for hack() and backdoor: 1
    Server security level: 3.100
    Chance to hack: 100.00%
    Time to hack: 0.333 seconds
    Total money available on server: $25.470
    Required number of open ports for NUKE: 0
    SSH port: Open
    FTP port: Closed
    SMTP port: Closed
    HTTP port: Closed
    SQL port: Closed
    [foodnstuff ~/]> hack 
    [||||||||||||||||||||||||||||||||||||||||||||||||||]
    Hack successful on 'foodnstuff'! Gained $0.000 and 19.916 hacking exp
    Security increased on 'foodnstuff' from 3.100 to 3.102
    [foodnstuff ~/]> analyze 
    Analyzing system...
    [||||||||||||||||||||||||||||||||||||||||||||||||||]
    foodnstuff: 
    Organization name: FoodNStuff
    Root Access: YES
    Can run scripts on this host: YES
    Backdoor: YES
    Required hacking skill for hack() and backdoor: 1
    Server security level: 3.102
    Chance to hack: 100.00%
    Time to hack: 0.333 seconds
    Total money available on server: $25.470
    Required number of open ports for NUKE: 0
    SSH port: Open
    FTP port: Closed
    SMTP port: Closed
    HTTP port: Closed
    SQL port: Closed

Comments From Original Issue

[davidpa9708]

we could show a message like not enough money on server to gain money

[zeddrak]

Since hack is a percentage of remaining money, it is entirely possible you can hacking $0.000001 per hack, and it's only a display issue... '_'

[davidpa9708]

it is entirely possible you can hacking $0.000001 per hack

@zeddrak I would expect that to happen, but I think we are currently flooring the money stolen when hacking

https://github.com/danielyxie/bitburner/blob/9ddb1c43796d2c020655bae1052e8ed67075c9e9/src/NetscriptFunctions.ts#L360

[phyzical]

to be fair though do we reaaaaaaaally want to se that we hack 0.0000001 $ it would have such little effect that someone else would complain that they dont get their fraction of a cent in the total because it probably does something similar for display

imo its not worth it

[Bug?] tryWritePort cannot write arrays in NS1 but can in NS2

[BinarySpike]
Using bitburner v1.4.0 (steam edition?)

You cannot write arrays to ports with tryWritePort using a .script file, but you can with a .js file.

// portsTest.script
var i = 0;

clearPort(1);

var values = ["SOMETHING REALLY LONG", "SOMETHINGE ELSE REALLY LONG TOO"];

while (tryWritePort(1, values)) {
	i++;
	var input = readPort(1);
	print('portsLength ' + i + " peek: " + input[0] + " " + input[1]);
}

tprint('portLength ' + i);

fails by printing portsLength xxx peek: undefined undefined

// portsTest.js

/** @param {NS} ns **/
export async function main(ns) {
	var i = 0;

	ns.clearPort(1);

	var values = ["SOMETHING REALLY LONG", "SOMETHINGE ELSE REALLY LONG TOO"];

	while (await ns.tryWritePort(1, values)) {
		i++;
		var input = await ns.readPort(1);
		await ns.print('portsLength ' + i + " peek: " + input[0] + " " + input[1]);
		await ns.sleep(0);
	}

	await ns.tprint('portLength ' + i);
}

Works successfully with portsLength 1145 peek: SOMETHING REALLY LONG SOMETHINGE ELSE REALLY LONG TOO

Comments From Original Issue

[zeddrak]

because your script version isn't waiting for the port read maybe?
var input = readPort(1); //<-- no await... so is the readPort returning a promise?
print('portsLength ' + i + " peek: " + input[0] + " " + input[1]);

[zeddrak]

It's been so long since I used ns1 scripts I don't even remember if it can be waited for?

[BinarySpike]

await is a syntax error in ns1 scripts:

Error processing Imports in test.script:
SyntaxError: Unexpected token (1:17)

It's an issue with ns1. I'm not sure how it gets translated, but the type definition is String | Number and the implementation is any. AFAIK ns2 uses the implementation directly, so it's not an issue.

[phyzical]

is ns1 still supported? i thought i remember reading somewhere it is not

Find All Valid Math Expressions allows leading zeros

[sjauld]
According to the contract instructions,

NOTE: Numbers in the expression cannot have leading 0's. In other words, "1+01" is not a valid expression

However, for the question ["51655173017", -55], the following term was accepted in the solution.

"51-6551-7+3017"

It seems like the "no leading zeros" rule has not been implemented.

Comments From Original Issue

[Phlarx]

(as the formatting seems to have gone awry, here is the actual formula from the above report)

51-6*5*5*1-7+3*017

[heap-underflow]

I haven't tried adding random wrong answers to my answer arrays, but it seems like a few of the solution validators would have this issue, since the logic turns into correct := expectedAnswerSet is-subset-of playerAnswerSet. I guess that you'd really want to ensure the symmetric difference was empty.

Barrel File: Dynamic RAM usage error

[Darren-Gannon]
This is a MINOR issue. I have a work around for it, its just not clean.

Issue

Dynamic RAM usage calculations fail to account for barrel files. In my /lib/index.js I want to roll up all the modules in my lib folder, but in order to avoid the dynamic ram error I need call the imported variable.

Version

v1.4.0(49de4a28)

Files


/lib/get-all-hosts.js (1.8GB)

/** @param {NS} ns **/
export async function main(ns) {
	ns.tprint(getAllHosts(ns));
}

/** 
 * @param {NS} ns 
 **/
export function getAllHosts(ns) {
	const hosts = ns.scan();

	for(const host of hosts) {
		const newHosts = ns.scan(host)
		const additionalHosts = newHosts.filter(newHost => !hosts.includes(newHost))
		hosts.push(...additionalHosts);
	}

	return hosts;
}

/lib/index.js(1.6GB)

export { getAllHosts } from '/lib/get-all-hosts.js'

test.js(1.6GB)

import { getAllHosts } from '/lib/index.js'

/** @param {NS} ns **/
export async function main(ns) {
	ns.tprint(getAllHosts(ns))
}

Temp Fix

In the barrel file (/lib/index.js) read the imported VARIABLE

import { getAllHosts } from '/lib/get-all-hosts.js';
getAllHosts;
export { getAllHosts }

add third layer reset, "load" reset or "base" reset

[hydroflame]
Which does stuff like make sure your programs are in order.

Comments From Original Issue

[phyzical]

need more info to infer this one 😄

[Master-Guy]

What would be the difference between the "base" reset, and the reset while killing all scripts?
(Novice in the game, hope I'm not asking stupid questions)

Bladeburner Synthoid Population UI

[macdjord]
There are several issues with the current bladeburner UI for synthoid population and community counts:

  • We are given an estimated synthoid population count and estimated(?) number of synthoid communities for the current city. We're given a number of actions that we're told will improve the accuracy of these estimates, and a skill which will make these actions more effective. However, we're given no feedback for how accurate these estimates are to start with, or how much our actions are improving them.
  • There is no way to check the populations of other cities except by switching to them one by one.
  • We are given occasional intelligence updates hinting at changes to populations - migrations and such - but these don't update our estimated populations, nor is there any good way to track them over time.

I propose that the UI be changed to display synthoid population and community counts as a chart like so:

City Est. Synth. Pop. Pop. Error Est. Communities Coms. Error
Sector-12 1.2b +20% / -8% 123 +2 / -4
Aevum 1.8b +1% / -12% 87 +5 / -4
Volhaven 123m +30% / -30% 17 +1 / -0
  • 'Aevum' is highlighted because its the player's active city
  • Every time the player completes an action which improves their estimates, the error boundaries are reduced and the estimates are updated
  • When the player gets an intelligence update about a migration, the estimates do not change, but the error bars do, and in the appropriate direction (e.g. if the player is notified about a migration from Sector-12 to Aevum, then the negative error boundary of Sector-12 and the positive error boundary of Aevum increase)

Version: a3c599e

Comments From Original Issue

[zeddrak]

We're given a number of actions that we're told will improve the accuracy of these estimates, and a skill which will make these actions more effective. However, we're given no feedback for how accurate these estimates are to start with, or how much our actions are improving them.

Every time the player completes an action which improves their estimates, the error boundaries are reduced and the estimates are updated

Isn't that what the range of the error tells you? If the error is +10 / -12, then your estimate isn't very good. Increasing the accuracy should reduce the range of the error, to something more like +5 / -6 (this is an estimate that's "twice" as accurate as the previous one, for example). So completing those actions means the "estimate" is now more closely bounded to the error range (ie, your estimate is more accurate and the range of error is reduced.).

We are given occasional intelligence updates hinting at changes to populations - migrations and such - but these don't update our estimated populations, nor is there any good way to track them over time.

When the player gets an intelligence update about a migration, the estimates do not change, but the error bars do, and in the appropriate direction (e.g. if the player is notified about a migration from Sector-12 to Aevum, then the negative error boundary of Sector-12 and the positive error boundary of Aevum increase)

I'm assuming this is because we don't know how many actually migrated (ie we have an unconfirmed report, so we know what we started with - our unchanged estimations - and we know how many were reported as having moved - our updated error bars - but we haven't confirmed how many actually arrived, nor how many gave up and went back, etc, so our estimates have become less accurate.)

Essentially, migrations make estimates less accurate over time (as more migrations occur), while the actions we take make them more accurate - this is the dance (basically, if you do nothing, then the migrations will eventually make the estimates near useless)...

[macdjord]

Isn't that what the range of the error tells you? If the error is +10 / -12, then your estimate isn't very good.

That's the problem - right now, we don't get to see the error range. It isn't displayed anywhere.

[phyzical]

related danielyxie/bitburner#2861

Request(/Bug?): Documentation on how offline earnings is inherited between processes

[Knyffen]
My current hacking setup works in three layers:

  1. A top level process that determines which servers are most profitable to hack. Runs on home. Dynamically spawns/kills hacking handlers.
  2. A hacking handler. Runs on home. It is given a server to manage as an argument and then it automatically calls actual hacking processes on various servers.
  3. The actual hacking process. Only runs the ns.hackServer/ns.growServer/ns.weakenServer commands.

I have noticed that whenever a layer 3. processes finish (by reaching the end of the function), the layer 2. process that started it has an increase in earnings and experience. However, when the layer 2 process ends (either via ns.exit, return, or when another process kills it with ns.kill), the layer 1 process remains at zero earnings and zero experience.

This behavior prevents me from having any substantial offline earnings.

I am currently using the steam version on windows, but it should be platform-agnostic.

I don't know if it is a bug, as it might very well just be that there is an undocumented requirement for when earnings and experience is inherited between processes. My request is therefore for that requirement to be documented. If it turns out to be a bug, tell me, and I will prepare a MWE script.

Thank you for your time. :-)

Comments From Original Issue

[phyzical]

is this not valid? layer 1 doesnt do any actions and thus earns nothing

unless we expect these sort of stats to trickle up?
higher powers question

[Knyffen]

The layer 2 process doesn't do any actions either, yet when the layer 3 process finishes the layer 2 process inherits its earnings/hour number.

Just to be clear: I don't know how its supposed to work (which is the entire point of the ticket), but I have just noticed the inconsistency in that the layer 2 process inherits the earnings of the layer 3 process (once it finishes), yet the layer 1 process doesn't inherit the earnings of the layer 2 process.

Personally, I think it makes sense to have the stats trickle up, since it allows the player to write more modular (often cleaner) scripts without being punished by having practically no offline earnings.

[phyzical]

ah yep the fact it trickles up one layer, i agree it should probably bubble up all the way and is probably a bug, thanks or the reply.

[phyzical]

@Knyffen quick one where is the "total earnings per script actually found" having a hard time finding the right place to workout how it works

[Snarling]

It looks like this was fixed during one of the major edits to launching scripts. Here is a test script and test output I used to verify:

//testLayers.js
/** @param {NS} ns */
export async function main(ns) {
	const layer = ns.args[0] || 1;
	const lastLayer = layer === 5;
	ns.tprintf(`${"  ".repeat(layer - 1)}Started layer ${layer}.`)
	if (!lastLayer) ns.run("testLayers.js", 1, layer + 1);

	// Hack n00dles until it is successful, but only for the last layer.
	if (lastLayer) while (!await ns.hack("n00dles"));

	// Wait until this script has some profit. Then print this script's income and exit.
	let profit;
	while (!profit) await ns.asleep(1000).then(() => profit = ns.getRunningScript().onlineMoneyMade);

	// Print script profit, then exit after 1s.
	ns.tprintf(`${"  ".repeat(layer - 1)}Layer ${layer} detected profit of \$${profit}`);
	await ns.asleep(1000);
}
[03:57:32] [foodnstuff ~/]> run testLayers.js 
[03:57:32] Running script with 1 thread(s), pid 66 and args: [].
[03:57:32] Started layer 1.
[03:57:32]   Started layer 2.
[03:57:32]     Started layer 3.
[03:57:32]       Started layer 4.
[03:57:32]         Started layer 5.
[03:59:11]         Layer 5 detected profit of $287
[03:59:12]       Layer 4 detected profit of $287
[03:59:14]     Layer 3 detected profit of $287
[03:59:16]   Layer 2 detected profit of $287
[03:59:18] Layer 1 detected profit of $287

Note that if a layer 2 process is killed before the layer 3 process, then the layer 3 process will still not transfer its earnings to the level 1 process. Script income transfers up 1 layer and it happens when a script dies, so the only time you transfer income from layer 2 to 1 is when the layer 2 process dies.

Can launch multiple copies of a script with same arguments on same host using `exec()` from multiple servers

[macdjord]

  • Create the following scripts on home:
    • test_run.js:
    /** @param {NS} ns **/
    export async function main(ns) {
    	const deploy_from_servers = [
    		"n00dles",
    		"foodnstuff",
    		"sigma-cosmetics",
    		"joesguns",
    		"hong-fang-tea",
    		"harakiri-sushi",
    		"iron-gym",
    	];
    	const host_server = "home";
    	const test_script = "/test_sleep.js";
    
    	for (const deploy_from_server of deploy_from_servers) {
    		ns.connect(deploy_from_server);
    		ns.exec(test_script, host_server);
    		ns.connect("home");
    	}
    }
    • test_sleep.js:
    /** @param {NS} ns **/
    export async function main(ns) {
    	await ns.sleep(60 * 1000);
    }
  • Run test_run.js from the terminal (Singularity functions required)
  • Check active scripts; you will find 7 copies of test_sleep.js all running on home, all with the same arguments (i.e. none)
  • These script entries will behave very oddly; it is impossible to open the logs tab for one of them if the logs tab for another is already open, and if you expand one of them in the active scripts tab, then hit the 'kill' button, the killed script will vanish, but the next script's entry will spontaneously expand in its place

Version: a3c599e

Comments From Original Issue

[phyzical]

i think the fact you can run multiple scripts with the same args is valid.

But the log bug is probably a bug related to scripts getting confused or rather not being unique enough.

[macdjord]

@phyzical No, by design you cannot run multiple copies of the same script with the same arguments on the same server; if you try the game will refuse to run it and tell you that the script is already running.

[phyzical]

welll... this has either changed or its now a bug. last time i launched my batchers i remember seeing plenty of the same scripts.

ill have a look at my scripts and give it a try, maybe i was taking on multiple arguments.

[hydroflame]

Nah this is weird a.f.

Add missing git tags

[MartinFournier]

Add missing git tags

I recommend you add the missing tags for version updates in the repository. I stopped listing revisions around 2 years ago.

git tag v0.43.1 9137c2427415c4dc344876a3c30ee445d92ebe4f
git tag v0.44.0 f1e43a86db09fa2dbc1e334c5ab6a907fef50c18
git tag v0.44.1 f2b4ae86926bb1a7977a36bd4a002ef16da74ebc
git tag v0.45.1 29c5c9b99d397cab675166439417a41e48dbf17e
git tag v0.46.1 2e9b028174623b6ddde3a47ced94dc66fcfd16ea
git tag v0.46.2 7417fb6ef8f3b62b4c5f4263da771a5195425039
git tag v0.46.3 bcb198220d9a2745e71d2389ef2a1355b9c6c58b
git tag v0.47.0 15a324a9466d360cc6f7be844076c799fe33889b
git tag v0.47.1 433b399de9397b805181dc89c8e1a024e6490dbe
git tag v0.47.2 59cf1d5baf78ccca32dfefe80717cbb1d284c23a
git tag v0.47.3 e9dfe3c3896329a135f96302e372c46926ff5101
git tag v0.48.0 56441b8e34b595d31e0f90354f47ab84ec72fac8
git tag v0.49.0 123628ec0b81383516e727f5a88c7262c99c84cd
git tag v0.49.1 a00c253dcb2768dd7ecb90f555be5e94ac2e8429
git tag v0.49.3 31e9f65f0622a4dec8f8133420b3fe8c44b59ae3
git tag v0.50.2 69124e7146003aad1acfc245bce9e62073750865
git tag v0.51.0 e572c6dad8793ba5a9ca6c1e76041c6eedd324f9
git tag v0.51.1 db2bf79e3b9e2fae7835a95597d1513ab1849662
git tag v0.51.2 925e96345da94b9f994f0be97c953cbcbad3793c
git tag v0.51.3 4e5ebcfe6f6bf08f7b040ff68383e7ac57821b4d
git tag v0.51.4 135df8703c651e17e0a1eae5a534c6f08ad215c1
git tag v0.51.5 b2aafea656bf1cbe4c143b62c35eba607af2d7d0
git tag v0.51.6 52a80ad23612562be51a8b7f9dd2c82b6553e39a
git tag v0.51.7 c9b5aaa2f74daa7323ae4ceb84ab63bf3b2c31ef
git tag v0.51.8 d96ad9fa6e8f94beb992c558b72e4a45352979dc
git tag v0.51.9 b28f60705697041be4bdf8213a4a91d089f1a290
git tag v0.52.1 8c9f78394b70d94dbba0b4e610eea88cb9eab190
git tag v0.52.2 67e5e413e4d98fb45caeb55f1427ea1bae8cb00a
git tag v0.52.3 e4b2a6853d713551cc31ec057e617da2a976abdf
git tag v0.52.4 1a1a43c1cea63f892c7946223d31157b8030403c
git tag v0.52.5 df457a0c6e07d847d22232ea28fc1d771832419a
git tag v0.52.6 474befa0919542b46656c29d9264c0447db3b74a
git tag v0.52.7 a564957092320bfb6c4df1175afb48733c26a953
git tag v0.52.8 6d2b8b4f6fb41ed74525653eea654922155eca2f
git tag v0.52.9 42704d86957482386f2197b27429490909b4ff22
git tag v0.53.0 cb31954b082fea47f8fe74632100c9fbf3c4e8ed
git tag v0.54.0 74906cc9e6498d728f93193096885214b172d16f
git tag v0.55.0 50cf362b3bd93255325bfa741a2911dedd33cedd
git tag v0.56.0 87c63cde59299c15de252e00acb6e29e69c420a7
git tag v0.57.0 c96c7e3d2e8bace9b983cff7b308c3031bf3c636
git tag v1.0.0 c87e9bdf843a05322e081d3527185483ca26e824
git tag v1.0.1 f3fa2a7c791a9166aa6a3b457776a4c47b4b4b58
git tag v1.1.0 3c27893aa30158fdd04ef2dc93f8cba1f13d6ece
git tag v1.2.0 02605090df38914ee5a288aedcc711d611d3e2fa
git tag v1.3.0 faf8389befec1b74133c6da6f892a6a7f951acdc
git tag v1.4.0 05cbc25a8fed73b9982925526940d65e55a842a1
git push --tags

v0.43.1 9137c24
v0.44.0 f1e43a8
v0.44.1 f2b4ae8
v0.45.1 29c5c9b
v0.46.1 2e9b028
v0.46.2 7417fb6
v0.46.3 bcb1982
v0.47.0 15a324a
v0.47.1 433b399
v0.47.2 59cf1d5
v0.47.3 e9dfe3c
v0.48.0 56441b8
v0.49.0 123628e
v0.49.1 a00c253
v0.49.3 31e9f65
v0.50.2 69124e7
v0.51.0 e572c6d
v0.51.1 db2bf79
v0.51.2 925e963
v0.51.3 4e5ebcf
v0.51.4 135df87
v0.51.5 b2aafea
v0.51.6 52a80ad
v0.51.7 c9b5aaa
v0.51.8 d96ad9f
v0.51.9 b28f607
v0.52.1 8c9f783
v0.52.2 67e5e41
v0.52.3 e4b2a68
v0.52.4 1a1a43c
v0.52.5 df457a0
v0.52.6 474befa
v0.52.7 a564957
v0.52.8 6d2b8b4
v0.52.9 42704d8
v0.53.0 cb31954
v0.54.0 74906cc
v0.55.0 50cf362
v0.56.0 87c63cd
v0.57.0 c96c7e3
v1.0.0 c87e9bd
v1.0.1 f3fa2a7
v1.1.0 3c27893
v1.2.0 0260509
v1.3.0 faf8389
v1.4.0 05cbc25

Comments From Original Issue

[phyzical]

seems responsible for debugging what things looked like at certain tags (shortcuts)

Pagination Elements Pushed off screen in Active Scripts

[Boraz]
Display size 4k: 3840 x 2160

Looking at Active Scripts
Expand a server
Pagination elements are pushed off screen when scripts have long details

BitBurner_minor_issue

Comments From Original Issue

[Boraz]

Looked into this further and built off dev branch. Page width is being pushed out by the script name/details. They are not wrapping on the current size of their container. It pushed everything out and might be wrapping on the max window size. I can now scroll left and right with long names.

I may attempt a fix. 🤞

Keyboard mapping not working

[LuisAmorimDev]
My keyboard when im write have caracters wrong, the keys are not like the leanguage of my keyboard and i cant change that in the game.

Comments From Original Issue

[phyzical]

workaround would be to ask users to use some sort of keyboard software to being english?

actual solutions would be a kin to adding other multi language support i.e translations

[Master-Guy]

Weird thought, but could it be that the Keyboard layout in the Windows settings of @raskilo are set incorrectly?
Using US-international myself as that is the most commonly used layout in the Netherlands, so I cannot reproduce this.

Weird dynamic RAM calculation with re-exports

[MatthewTh0]
So, I found a weird interaction, this is almost undoubtedly a bug, but I did find a workaround so this is low-priority. If one tries to re-export a function (using export * from "fileWithFunctionExports";) then it won't calculate RAM costs properly if you import from that file (using import {functionFromFileWithFunctionExports} from "reExportFile";). Interestingly enough, if one imports directly from the file with function exports using a name (like import * as fooBar from "fileWithFunctionExports";), it then calculates correctly, even if you don't use this name or change anything else.

Example:
libFunction.js

export function testFunc(ns) {
let x =ns.getServer();
}

importTest.js

import {testFunc} from "reExport";
/** @param {NS} ns **/
export async function main(ns {
  testFunc(ns);
}

reExport.js (Bad version)

export * from "libFunction"; // won't calculate ram correctly when imported

reExport.js (Good version, somehow)

export * from "libFunction";
import * as FooBar from "libFunction"; // never used, but allows correct ram calculation

Exact Error:

RUNTIME ERROR
/scripts/hacking/foreverLoop.js@home

Dynamic RAM usage calculated to be greater than initial RAM usage on fn: getServer.
This is probably because you somehow circumvented the static RAM calculation.

Threads: 1
Dynamic RAM Usage: 3.60GB
Static RAM Usage: 1.60GB

One of these could be the reason:
* Using eval() to get a reference to a ns function
  const myScan = eval('ns.scan');

* Using map access to do the same
  const myScan = ns['scan'];

Sorry :(

Comments From Original Issue

[MatthewTh0]

So, I guess this doesn't fix it, but just gives the RAM cost of importing everything even if you don't use it.

[phyzical]

the way the ram usage works is it just parses your code for keywords that line up with functions that require ram nothing too special. there is probably code trying to stop you from trying to circumvent it, but

Interestingly enough, if one imports directly from the file with function exports using a name (like import * as fooBar from "fileWithFunctionExports";), it then calculates correctly,

this probably just isnt in whatever logic is trying to stop you if i was to guess

[MatthewTh0]

Now, from what I've tested, if you import from a file that has classes, it will give the RAM cost as if using ALL functions in the class even if you don't export the class or anything related to it (for example, importing a constant from a file with a class that isn't exported, and therefore has no way to be imported, will still cost you as if you used every function in the class).

[phyzical]

yes this is correct as if the current implementations.

the issue is (AFAIK) there are many ways to exploit the system ill leave those up to you to find ;) (part of the game in its current state) but tbh when i first started playing i wanted it to work like you have done,

just wanted more readable/reusable code 😆 one workaround would be to have a bunch of files instead of say one helper file. even though that would be painful. and in many cases result in duplicate code

[jacktose]

Maybe this is a separate issue, but you can cause the same problem/hack by using default export import.

// find.js
export default function find(ns, target, seen=[ns.getHostname()]) {
    const here = seen.slice(-1)[0];
    if (here == target) { return seen; }
    for (const neighbor of ns.scan(here).filter(n => !seen.includes(n))) {
        const path = find(ns, target, seen.concat(neighbor));
        if (path) { return path; }
    }
    return null;
}
// auto_connect.js
import { default as find } from '/find.js';  // <- causes error
//`import { find } from '/find.js';`  // <- works fine

function auto_connect(ns, server) {
    find(ns, server).forEach(ns.connect);
    const endpoint = ns.getCurrentServer();
    return endpoint;
}

export async function main(ns) {
    return auto_connect(ns, ns.args[0]);
}

By “the problem,” I mean that the in-game editor's RAM button doesn't show the RAM from the import, and I get the runtime error as quoted above.

Gangs feature needs documentation

[macdjord]
There is no out-of-game (and almost no in-game) documentation for how gangs are supposed to work. I managed to get through BN2 using this two-year-old guide on Reddit, plus occasionally reading the source code. Now I'm on another BN, and I can't even figure out how to start a gang - I've joined the Slum Snakes faction, but the 'Form gang' button isn't showing up. The guide suggests that you need different amounts of negative karma to form a gang on different bitnodes, but we have (supposedly) complete documentation for the bitnode multipliers and 'karma required for gang' is not among them.

Version: a3c599e

Comments From Original Issue

[zeddrak]

As far as I know, you need approximately -54k karma to start a gang, This has been the same for all BN's I've played in.
It's not documented anywhere that I could find either, nor explained well. I just used the API to constantly try to create a gang every few seconds.

[macdjord]

Note that the question of 'Why can't I start a gang?' is only one part of what needs to be documented. The whole process and mechanics of gangs needs to be explained.

[phyzical]

yeah part of the issue with this one is i thiiink its meant to be a motivation for the user to find out how/why in the source code, motivate them to learn about opensource

(encouraging users to understand why things don't work how they expect)

there is probably a consideration on spoilers also

Active scripts navigation UI bounces around when viewing last page

[Sleaker]
For control scripts that actively launch multiple other scripts in quick succession it becomes impossible to navigate the list once the last page has been reached as the footer UI which controls rows per page and back continually pops up and down as scripts are destroyed/started up.

This can make finding a specific script on servers with many active scripts difficult to find in the active scripts page.

UI elements that control navigation should be locked in place elements so they don't bounce around:
Fix 1) move the navigation elements to the header,
Fix 2) Fill in empty rows until 'rows per page' has been reached.

Side feature: make the search box filter out any scripts that don't have the name, not just the servers with them running.

Comments From Original Issue

[phyzical]

if this hasn't been addressed i think it would be a good idea. i know i've had a hard time clicking the right script sometimes.

Running `kill` on a script that uses asleep to do something in parallel causes the "UNCAUGHT PROMISE ERROR" dialogue box to appear.

[ballardrog]
Steps to reproduce:

  1. Save the following as repro.js:
/** @param {NS} ns **/
export async function main(ns) {
	delayedPrint(ns);
	await ns.asleep(10_000);
}

async function delayedPrint(ns) {
	await ns.asleep(5_000);
	ns.tprint("Foo");
}
  1. run repro.js
  2. kill repro.js (within 5 seconds)
  3. The UNCAUGHT PROMISE ERROR dialog box appears 5 seconds after you ran repro.js.

Would it be possible to mark the environment of a killed process, so that the error only shows up for scripts that exited normally instead of also showing up for scripts that were killed?

Note that there is a workaround:

/** @param {NS} ns **/
export async function main(ns) {
	delayedPrint(ns).then(() => { }, () => { });
	await ns.asleep(10_000);
}

async function delayedPrint(ns) {
	await ns.asleep(5_000);
	ns.tprint("Foo");
}

Comments From Original Issue

[heap-underflow]

IMO, the bug is in the fact that your delayedPrint (an async function) doesn't always throw the uncaught promise error when it's not awaited (or otherwise resolved) like you have, not that it only sometimes does (when killed).

You get the same error, with a slightly different delayedPrint function, even without killing the process.

/** @param {NS} ns **/
export async function main(ns) {
	delayedPrint(ns)
	ns.asleep(10_000)
}

async function delayedPrint(ns) {
	ns.tprint(0)
	await ns.asleep(1_000)
	ns.tprint(1)
	await ns.asleep(1_000)
	ns.tprint(2)	
}

So, I don't think the issue is in how it's behaving when scripts are killed, I think the real issue (in a loose sense) is that you don't always get the error when you're not resolving promises.

An alternative to your /then then might be

await Promise.all([delayedPrint(ns), ns.asleep(10_000)])

[ballardrog]

The modified version you gave is only throwing an error because the asleep in main isn't being awaited. The error happens when code in a promise tries to access ns after the script dies, which can happen either because main exits normally or the process is killed. There are valid usecases for not awaiting an asleep-based function; I don't think that should always be an error. (And I don't think there's a clean way to make it be, anyway.)

[phyzical]

not sure if this helps or is even possible but can you use the workerscripts's .env.stopFlag ?

Function to generate 0-reward coding contracts for testing

[macdjord]
I'm currently working on an automated contract-solving suite, but it's slow going, mostly because I cannot create my interfaces or test my solutions without an actual contract of a given type.

I propose two new functions be added, to allow players to practice contract and test solvers without needing to wait for real contracts of the appropriate type:

  • ns.codingcontract.listContractTypes(): Returns a list of all the types of coding contract in the game. 0GB RAM cost.
  • ns.codingcontract.generateSampleContract(contractType, host?, name?): Causes a contract of the given type to be immediately spawned. Such a contract will always have a reward of $0. If possible, such contracts will give the player unlimited attempts. Returns the name of the generated contract, or the empty string on failure.
    • host: Server on which to create the contract; default to the server the script is running on
    • name: Filename to give the contract; must end in '.cct'; defaults to a random filename of the form contract-######-test.cct

Comments From Original Issue

[phyzical]

cool idea 👍
i would argue that it should cost ram though, forces the user to be sparing with ram as with anything in the game.

[macdjord]

@phyzical Yes, of course. listContractTypes() should be 0-cost, like all static game info functions, but generateSampleContract() would cost some RAM. Not sure how much; that sort of balance question is up to the devs.

[MaWo2]

I really like this idea. It would help me, too.
It would also push this game even more into the educational direction.

However, I am not sure, whether RAM cost really is an issue here. In most use-cases, people would spawn the test contract only once, most likely from the terminal or a separate script. Accordingly, the RAM-cost is neglectible (as long as it is not extremely high).

Therefore, I was wondering, whether this function might be something you could buy from the darknet, for instance, or develop at a certain level.
A completely different approach: Make it a degree at the University.

rm -r should confirm that you want to delete a directory and then do it.

[hydroflame]
null

Comments From Original Issue

[Master-Guy]

Do you want this to be a yes/no prompt in the UI, or a textual yes/no question in the terminal?
The first is easy to implement, the latter might be very non-trivial

[Undeemiss]

bump. I can do this if given clear direction (I was planning to write a script to do this for my personal save, but can just write it as a feature instead if you want)

Working-for-companies mechanic has poor UI and documentation

[macdjord]
The gameplay mechanic whereby you can work for a company & get promoted is almost entirely undocumented and has a non-discoverable, unclear GUI:

  • The fact that you can get a promoted by applying for the job you already have is not obvious and not explained anywhere
  • The fact that there even is a career ladder to advance up is not immediately obvious
  • Hovering over one of the job application buttons tells you the minimum stat requirements for that job (or, of you already have a job on that career track, for the next promotion level). However, if the player already meets the stat requirements for a more senior position in that same career track, they will skip directly to the most-senior position they qualify for. Nothing in the UI tells you this is going to happen, or even notifies you that it has happened when it does.
  • The career tracks are not documented anywhere. ('So, I'm a Senior Software Engineer now? How many more steps does that mean I have to make CTO?')
  • Nothing explains what player stats the different career tracks depend on when calculating reputation gain and salary (so that the user can pick the one most in line with their current build)
  • There's a quit button, but no explanation of why you might need it. You can hold jobs at multiple companies at once, there's no obligation involved in holding a job (e.g. you aren't forced to work a shift every day), and if you do quit you can reapply and get your job back instantly at, AFAICT, no penalty. The only purpose I can maybe see for it is leaving the CIA or NSA so you can join one of the criminal factions?
    • I think it would be more interesting if you couldn't join a criminal faction after being employed by one of the agencies, and conversely could not join the agencies if you're part of those factions; if you wish to switch, you must wait until the next reset. Currently, the only mutually-exclusive choice is which city-based faction to join on each reset.

Comments From Original Issue

[Kebap]

Small improvements for point 1 and 2 maybe change button from "Apply for X" to "Promote in X" if you already hold that title and there is a promotion available (no matter if you fulfill the criteria yet) so players actually are shown a difference and can find more info with mouse-over.

[devnuhl]

Related to hovering and having information with a mouse-over, I just encountered the mouse-over information being irrelevant to my current position / next promotion. I know my current position because it's at the top.
Screenshot 2022-10-03 161952

The hover shows the basic position info, which it has not shown for the last several promotions, but the correct values. Attempting the promotion, though, says I'm ineligible because I lack the stats/rep I need. I'm guessing the tooltips may have been copy/pasted, and this one missed getting updated to the appropriate numbers?

Screenshot 2022-10-03 162008

Faction security work & field work stat effects do not match descriptions

[macdjord]

  • The description for 'Field work' says: "Your effectiveness [...] is based on all of your stats. You will gain exp for all stats."
  • The description for 'Security work' says: "Your effectiveness [...] is based on your combat stats. You will gain exp for all combat stats."
  • Currently, I have 3221 Hack, 450 Cha, and 133 to 171 for my combat stats

My expectations, based on this:

  • I will gain faction rep faster from field work than security work, since my combat stats are the lowest of my stats
  • From field work I will gain exp in all stats; from security work I will gain combat stats but not Hack or Cha
  • In all stats where security work gives me exp, it will give me more than field work does to compensate for not giving as many different types.

Instead, working for Volhaven I observed the following:

  • From field work:
    94.076 (8.111 / sec) reputation for this faction
    
    42.158 (3.634 / sec) hacking exp
    
    15.792 (1.361 / sec) strength exp
    15.792 (1.361 / sec) defense exp
    15.792 (1.361 / sec) dexterity exp
    15.792 (1.361 / sec) agility exp
    
    13.160 (1.135 / sec) charisma exp
    
  • From security work:
    97.625 (8.876 / sec) reputation for this faction
    
    19.989 (1.817 / sec) hacking exp
    
    22.463 (2.042 / sec) strength exp
    22.463 (2.042 / sec) defense exp
    22.463 (2.042 / sec) dexterity exp
    22.463 (2.042 / sec) agility exp
    

I.e. security work is giving me more faction rep than field, and also giving me Hack exp when it shouldn't be. Also, while its giving more combat exp, its giving less Hack exp than field.

Comments From Original Issue

[Undeemiss]

I don't understand what the problem is here, beyond that security work should be listed as giving a little bit of hacking exp. It never made any claims about the scaling of these actions; my understanding is that field work intentionally scales worse than security work because it's easier to gain stats in general than specifically to gain physical stats.

Unhandled player-written promise reject results in bug message

[quyteriyaki]
Description: Unhandled promise reject with return value other than string results in a "Script runtime error. This is a bug please contact game developer"

Steps to reproduce:

import { NS } from '@ns'

export async function main(ns: NS): Promise<void> {
  await new Promise<string>((resolve, reject) => {
    reject(400)
  })
}

Expected: The game notifies the location of the exception, something like ("You've written something that causes an exception, did you remember to handle it?") or the game outputs the message of the exception.
Actual: The game shows the the bug error with no meaningful response and the script hangs.

Suggested solution:

  1. Inform the user to handle the exception themselves given that the exception is raised within a player-written script.
  2. Inform the user of the value being passed through the exception. This would be in line with the behaviour presented upon passing a string to the exception.

Comments From Original Issue

[phyzical]

i couldn't run the provided script verbaitum, if i run the following it get told an unexpected error occurs. (presumably because resolve is never called), if i add a resolve instead of reject things work.
image

export async function main(ns) {
  await new Promise((resolve, reject) => {
    reject(400)
  })
}

so the question is,

  • is promises in user code supported?
  • if so why doesn't it work.

save files should be zipped

[hydroflame]
null

Comments From Original Issue

[phyzical]

i think this one is closable too (unless we dont zip given certain conditions?)

[phyzical]

(unless we are referring to export in settings?)

[Master-Guy]

Just a basic ZIP reduces used storage by about 50%. In my case from ~160 MB to ~80 MB.
In a game that is all about optimization, this seems to be a basic thing to do :)

Various issues relating to leading slashes in file names

[Xynrati]
Should be standard support and handled the same everywhere

Comments From Original Issue

[rabirabirara]

To be specific, in the documentation (https://bitburner.readthedocs.io/en/latest/basicgameplay/terminal.html?highlight=backdoor#netscript), it is noted that files not in the root directory need to be referred to by absolute path. This is a limitation that is documented as part of the game; it is not a bug per se.

However, the documentation does not mention that you cannot refer to files in the root directory by absolute path in arguments passed to functions like fileExists() or exec(). This is probably the main problem (besides the inherent inconsistency of NetScript's filepath behavior) and why a few people comment on the forward-slash in file paths.

So for future users with this problem, you can do the following to standardize file paths so that they are correctly treated. This is a NetScript 2 function.

function standardize(path) {
    // remove all slashes at the start of the string
    let s = path.replace(/^\/*/g, "");
    if (s.includes("/")) {
        // the file is not in the root directory; prepend a single slash
        return "/" + s;
    } else {
        // the file is in the root directory (no slashes in the filename that aren't in front); prepend no slashes
        return s;
    }
}

[Xynrati]

Not exactly. If you do this using wget for files in the root folder, you'll cause problems.

[rabirabirara]

I see. Since your original post is quite bare, I had thought you were referring to a different problem. Could you elaborate what your issue actually is? After all, your choice of the word "oddness" leaves a lot to the imagination.

EDIT: I see; you're a contributor, which means this issue is probably something you're referring to yourself. My bad! I was thinking that this was along the lines of #1634, which was closed without comment. I was thinking I could be helpful to people with that problem, but I suppose I missed the mark on your issue.

Toasts: use const objects (enums) instead of magic strings

[BrianLDev]
This came up in a broader discussion on the Discord dev channel about moving away from "magic strings" in general.

To start, hydroflame recommended converting Toasts, and then later we can look into enums for Gang names, crimes, universities, courses, etc.

image

Comments From Original Issue

[waffleattack]

Could I have an example for what the magic strings are in toasts?

[BrianLDev]

@waffleattack since hydroflame was the source of this request, they're the best one to ask for more details.

But if I had to guess, I'd say that the toast variants should be converted from magic strings into const objects/enums. Screenshot below:
image

[waffleattack]

ah so instead of inputting

ns.toast("Alert!", "warning", 10000)

you would instead be able to do

ns.toast("Alert!", TOASTS.WARNING, 10000)

if I understand it correctly?

[BrianLDev]

@waffleattack Yup, that's exactly how I'd do it. But you might want to check with hydroflame to see if they had anything else in mind.

[phyzical]

nah thats correct 👍

[hydroflame]

Yeah it's not that easy
How do you feed TOASTS to the scripts?

[waffleattack]

could we do it similar to ns.args? so instead of using TOASTS.WARNING you would use ns.TOASTS.WARNING?

[hydroflame]

https://github.com/danielyxie/bitburner/blob/dev/src/ScriptEditor/NetscriptDefinitions.d.ts#L6426

If someone can uncomment this line and make it compile ...

Product's sell price shown in UI is different from the actual sell price

[swofle]

Version of the game

Bitburner v1.4.0 (49de4a28)

Description

The actual sell price of product is different from the price displayed in UI when player uses the 'MP' variable.
The displayed sell price is computed based on the estimated market price, but the sell price of the transaction uses the actual market price. This means that the displayed sell price is much lower than the actual value, resulting in confusion.

Setting the sell price: MP*70600
use_mp
Setting the sell price: 650000000
use_price_input

You can see from the above example that although the 2nd sell price is ten times of the 1st one, the product is actually selling. While in the 1st instance, the product is not selling (net increase of 15.530/s).

Steps to reproduce

  1. Starts a corporation with Tobacco industry.
  2. Create a product, and enable Smart supply.
  3. Sell product at Max quantity and enable Market-TA.II. Note the optimal sell price(OSPrice) shown.
  4. Turn off Market-TA.II and sell the product at 'MP*N' where N = OSPrice / Est. Market Price.
  5. Observe that the displayed sell price is the same as in step 3 but the product is not selling.

Proposed solution

It is stated in the description that 'MP' variable corresponds to the Product's estimated market price. So use that instead of the actual market price. Specifically change this line:
https://github.com/danielyxie/bitburner/blob/07fe3c1906b569799652cd1f7a36de2abe306802/src/Corporation/Industry.ts#L1178
to

sCost = sCostString.replace(/MP/g, product.pCost + "");

Embed a font

[theit8514]
unknown

MacOS uses by default a Mac-specific font. These fonts are missing the Unicode characters for minimize and restore. Potential solution is to change the unicode symbols used, or embed a font with those symbols.

Corporation stock price grows exponentially when there are no private investors

[bmartin1234]
Steps to reproduce:

  • Buy a corporation
  • Get corporation to be profitable ($1m or so should be plenty) [edit: possibly you can skip this step]
  • Go public WITHOUT having any private investors
  • Buyback all shares
  • Wait for stock price to grow

It looks like shares owned by the player are not counted in the divisor for share price, so in this scenario target share price = valuation.

See /src/Corporation/Corporation.tsx line 189

bitrunner_corp_price

Comments From Original Issue

[phyzical]

good spot, now whether this should be adjusted not sure (i would say probably? as corps are too op)
leaving to higher powers

Ending Infliltration Repositions, Resizes, and Repopens Script Logs

[Xenosplitter]

Expected Behavior

When exiting an infiltration, open script (file.script and file.js) logs remain how they were set up before beginning the infiltration

Actual Behavior

Exiting an infiltration via running out of HP, completing the infiltration, canceling mid infiltration, and canceling before starting the infiltration cause all open script logs to reappear in the middle of the screen, how they appear when first opened. This resets log window sizes, positions, and minimized status.

Steps to Reproduce

  1. Run a script
  2. Open the script's log
  3. Resize, reposition, or minimize the log file, keeping it on screen
  4. Navigate to an infiltration (I use Joe's Guns, but others work too)
  5. Finish the infiltration in some fashion (success, failure, cancelation)
  6. Note how the log window repositions itself to the center

Comments From Original Issue

[akuma6099]

I just wanted to tack onto this because I was about to open an issue on it. You can reproduce this problem by simpling navigating to any company, selecting infiltration, then cancel. I've yet to reach a level of XP to bring down the difficulty so I kept checking then cancelling and I observed this same behavior. My organized log windows stacked in the lower right corner all resized and opened in the middle as if I just launched the scripts with --tail.

[Xenosplitter]

Without doing any investigative work, a blind guess on why this might happen is that opening the infiltration screen tries to hide open logs. This might be done by noting which logs were open, closing them, then reopening the logs once more. This would explain why all windows reset (because they are in this theory). Perhaps a better way to hide the log windows would be to set their element display styles to display: none; temporarily, resetting back to display: flex; once finished.

wget with / causes bad files

[hydroflame]
null

Comments From Original Issue

[phyzical]

to confirm i think this is the bug?

/** @param {NS} ns **/
export async function main(ns) {
	await ns.wget("https://gist.githubusercontent.com/ramzs/35fa68c0e4c83e4b66d2137d8364dbd6/raw/281998608078700ed213bad1cc019b31a5b2cccd/PaymentNotificator.gs", "/file.txt", "home")
}

image

it works if i use file.txt
if i use /file.txt it saves it as a directory called / that you cannot cd into and cannot ls

[phyzical]

on a side note should we even allow this anymore given the vscode integration?

[phyzical]

related danielyxie/bitburner#2991

disableLog() not returning fails

[Master-Guy]
Version: Steam - Bitburner v1.5.0 (3aabbb7)
Script:

export async function main(ns) {
ns.disableLog("ALL");
ns.purchaseServer("hostname", ns.getPurchasedServerMaxRam());
}

Reproduce: New save game (so you don't have enough money) and run the script.

Issue:
ns.purchaseServer() and ns.deleteServer() don't log errors after ns.disableLog("ALL") even though the documentation tells us that it should. It might be a wider issue.
https://github.com/danielyxie/bitburner/blob/dev/markdown/bitburner.ns.disablelog.md

Note that this does not completely remove all logging functionality. This only stops a function from logging when the function is successful. If the function fails, it will still log the reason for failure.

Comments From Original Issue

[Master-Guy]

Needs a comment from @hydroflame on how to solve:
Either remove this part of the documentation (see the quote), or go through all functions and check if this has been implemented correctly.

i.e.:
disableLog("ALL") currently works by adding all possible log options, so you can re-enable them one by one if you want to:

      if (fn === "ALL") {
        for (fn of Object.keys(possibleLogs)) {
          workerScript.disableLogs[fn] = true;
        }

However, the checks in PlayerObjectGeneralMethods.tsx are checking for "ALL" (an old way of doing it):
if (ws.disableLogs.ALL == null && ws.disableLogs.commitCrime == null) {

The WorkerScript log doesn't differentiate between success and failure:

    getPurchasedServerCost: function (ram: any): any {
      updateDynamicRam("getPurchasedServerCost", getRamCost(Player, "getPurchasedServerCost"));

      const cost = getPurchaseServerCost(ram);
      if (cost === Infinity) {
        workerScript.log("getPurchasedServerCost", () => `Invalid argument: ram='${ram}'`);
        return Infinity;
      }
  log(func: string, txt: () => string): void {
    if (this.shouldLog(func)) {
  shouldLog(fn: string): boolean {
    return this.disableLogs[fn] == null;
  }

Suggestion: Add constants (enums) to singularity API to avoid "magic strings"

[BrianLDev]
This was talked about in depth on the Bitburner discord today (Feb 24, 2022), but to summarize:

There are a lot of Singularity API functions that require "magic strings" like University name, course name, Crime name, Faction name, etc. "Magic strings" are generally considered to be no bueno when it comes to good programming habits, so it would be great if we could add some simple constant objects that contain the names of related items.

note: these are usually called enums, but vanilla JS doesn't have enums, so they're implemented in JS as constant objects

Here's an example of all the crimes in a constant object (aka an enum):

export const Crimes = {
	shoplift: "shoplift",
	rob: "rob store",
	mug: "mug someone",
	larceny: "larceny",
	dealDrugs: "deal drugs",
	bondForgery: "bond forgery",
	traffickIllegalArms: "traffick illegal arms",
	homicide: "homicide",
	grandTheftAuto: "grand theft auto",
	kidnap: "kidnap",
	assassination: "assassination",
	heist: "heist",
	none: "none"
};

Generally, enums allow for autocomplete which is one of the big benefits to avoid typos, misspellings, future changes to strings, etc. The autocomplete in Bitburner doesn't always seem to correctly look up object properties, so we would have to also make sure that functionality works as well.

Since autocomplete might create some spoilers, I highly recommend that these const objects (aka enums) get added to the Singularity API and marked as FREE (no RAM cost). When players have reached the Singularity API, they won't be spoiled by having a full list of University names, Crime names, etc. The other benefit of having these in the Singularity API is that players will probably run into problems with magic strings along the way, and experiencing that pain will show the value of using enums/const objects.

One nice thing about this change is that it would be "backwards compatible", meaning that the const enums will just provide a better way to input strings to function args, and all previously created functions and scripts will be unaffected.

Since this would be a moderate sized change, Hydroflame suggested that we start by converting the Toasts over to enums, so there's a separate issue created for that specific one (3032). Once the Toasts issue is resolved, we can move on to this one.

SUGGESTIONS FOR CONST OBJECTS/ENUMS:

No big spoiler concerns:

  • City names
  • City.location names (locations within a city)
  • University names
  • University course names
  • Gym names
  • Work type
  • Crimes
  • Program names
  • Hack type (weaken, grow, hack)

Possible spoiler concerns (will have to discuss before implementing)

  • Company names
  • Faction names
  • Augmentation names

Comments From Original Issue

[BrianLDev]

For the possible spoiler concern items: one way to minimize that is to keep the full enum hidden (e.g. Augmentation names), and create a separate object that contains only the items that the player has accessed so far.

That will prevent the player from seeing any spoilers, and new items can be added added every time a player accesses something new (e.g. joins a new faction with a list of augmentations not seen before)

Script Editor hijinx (Illegal invocations abound)

[storm6436]

TypeError: Illegal invocation (at "ScriptEditor")

How: Attempted to edit a script.

Minimal scripts to reproduce the issue: breakout.js (Included in save)
Steps to reproduce:
(Inconsistent reproduction, but frequent enough I'm finally filling this out)
run the following
'reset all'
'cm'
'run overseer.js'
'autopop'
'run breakout.js 5' <- # is largely irrelevant, any valid can trigger (valid: 0-5)

Then attempt to open the script editor, either by the navigation pane or via terminal with nano.

Notes: Have checked file integrity, etc. several times.

Environment

  • Error: TypeError: Illegal invocation
  • Page: ScriptEditor
  • Version: v1.4.0 (49de4a28)
  • Environment: Production
  • Platform: Steam
  • UserAgent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) bitburner/1.0.0 Chrome/93.0.4577.82 Electron/14.0.2 Safari/537.36
  • Features: lang=en-US cookiesEnabled=true doNotTrack=null indexedDb=true
  • Source: n/a

(Just whack the fake file extension. It's a bit odd to ask for a save file that's less than a MB and autoreject it based on extension.)

Save

RECOVERY_BITBURNER_1643078738.json.notreallya.zip

Comments From Original Issue

[phyzical]

@storm6436 is this still an issue?

[storm6436]

Not sure? I'll have to check what patch supposedly fixed it and do some
testing once I get in a place that won't poleaxe my BN13 progress. Just
started the node yesterday and... it's slow.

On Sun, Mar 13, 2022, 08:13 Jack @.***> wrote:

@storm6436 https://github.com/storm6436 is this still an issue?


Reply to this email directly, view it on GitHub
danielyxie/bitburner#2799 (comment),
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ASAWRUBSROQFUZFSXRSH5J3U7XSWXANCNFSM5MXBPKOA
.
Triage notifications on the go with GitHub Mobile for iOS
https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675
or Android
https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

You are receiving this because you were mentioned.Message ID:
@.***>

[storm6436]

Yeah, got another crash just now. Not sure if you guys need me to upload that recovery file or not.

[phyzical]

@storm6436 all good, just wanted to confirm before trying to replicate ill let you know where i get

[borisflagell]

Still a valid issue as of 1.7.0

You can't disable production limit for product.

[hydroflame]
null

Comments From Original Issue

[phyzical]

Is this one just a matter of providing "reset" buttons for all actions, we would add it to the sell action also.

also adding api actions for this "cancel"

Set up proper CD pipeline

[HeinousTugboat]
Per hydro, adding an issue for this: we should add a proper pipeline so we can have both a beta and prod release, allowing us to release features to a limited set of users before more broadly pushing them out to the full userbase. Additionally, we should use envvars to track the deployed sha so we can avoid the chicken-and-egg issue of not knowing the current sha of the deployed code.

Comments From Original Issue

[marcjmiller]

This is up my alley, what does the current process look like? I don't see any CI/CD at present, so am I to assume it's a 100% manual job right now? I'm not familiar with building electron apps, but walk me through the steps and I'll at least get it started. I normally work in gitlab, so transitioning to GitHub actions might take a bit, but I'll give it a go.

[phyzical]

we are working on this, if you checkout the .github/workflows there is some. the main issue we currently have is lack of full access to handle secrets ect. soon we will be moving to an org to gain this control.

TLDR; i wouldn't worry about it at this time

[hydroflame]

https://github.com/HeinousTugboat/bitburner/blob/htugboat/deploy-wip/.github/workflows/deploy-pages.yml i
^ relevant

hackAnalyzeThreads results always in infinite on various servers V1.3.0

[Unkn0wnNPC]
Just run the script below and it'll always result in Infinite on various servers

export async function main(ns) { let destinations = ns.read("/hackV2/servers-sorted.txt"); destinations = JSON.parse(destinations); let test = ns.hackAnalyzeThreads("foodnstuff", 1) ns.print(test) }

bitburner_Issue
bitburnerSave_1642201801_BN1x0.json.txt

Comments From Original Issue

[nickinitro]

can confirm!

[geiloschefos]

same...

[zeddrak]

Are you in a bitnode with a BitNodeMultipliers.ScriptHackMoney == 0?
If so, this would be the correct response (no amount of threads will allow you to steal any money)

#2454
One recent correction that I know was made was to include the BitNodeMultipliers.ScriptHackMoney, but that shouldn't create this behavior where it wasn't before, as the 0 case would be the same either way.

Similarly having a server security of 100+ should result in infinity, because of:
const difficultyMult = (100 - server.hackDifficulty) / 100;

As would a server.moneyAvailable == 0.

Basically, anything that makes this denominator 0 should return infinity:
return hackAmount / Math.floor(server.moneyAvailable * percentHacked);

    hackAnalyzeThreads: function (hostname: any, hackAmount: any): any {
      updateDynamicRam("hackAnalyzeThreads", getRamCost(Player, "hackAnalyzeThreads"));

      // Check argument validity
      const server = safeGetServer(hostname, "hackAnalyzeThreads");
      if (!(server instanceof Server)) {
        workerScript.log("hackAnalyzeThreads", () => "Cannot be executed on this server.");
        return -1;
      }
      if (isNaN(hackAmount)) {
        throw makeRuntimeErrorMsg(
          "hackAnalyzeThreads",
          `Invalid growth argument passed into hackAnalyzeThreads: ${hackAmount}. Must be numeric.`,
        );
      }

      if (hackAmount < 0 || hackAmount > server.moneyAvailable) {
        return -1;
      } else if (hackAmount === 0) {
        return 0;
      }

      const percentHacked = calculatePercentMoneyHacked(server, Player);

      return hackAmount / Math.floor(server.moneyAvailable * percentHacked);
    }

/**
 * Returns the percentage of money that will be stolen from a server if
 * it is successfully hacked (returns the decimal form, not the actual percent value)
 */
export function calculatePercentMoneyHacked(server: Server, player: IPlayer): number {
  // Adjust if needed for balancing. This is the divisor for the final calculation
  const balanceFactor = 240;

  const difficultyMult = (100 - server.hackDifficulty) / 100;
  const skillMult = (player.hacking - (server.requiredHackingSkill - 1)) / player.hacking;
  const percentMoneyHacked = (difficultyMult * skillMult * player.hacking_money_mult * BitNodeMultipliers.ScriptHackMoney) / balanceFactor;
  if (percentMoneyHacked < 0) {
    return 0;
  }
  if (percentMoneyHacked > 1) {
    return 1;
  }

  return percentMoneyHacked;
}

[zeddrak]

Hmm...
I guess that if BitNodeMultipliers.ScriptHackMoney could be < 0, then moving it before the check could result in a different behavior, but that'd still be really weird, as the previous version would've ended up in negative threads being needed.

[zeddrak]

Update, I am working on a fix for this in my scripts. Once I've completed and tested there, I will check with Hydroflame if he wants them imported into the source game. It is a complicated problem though (since the amount grown is now partially based on the threads used, making getting the threads needed a self-referential nightmare akin to determining how much rocket fuel you need to get into orbit...)

[zeddrak]

My Discord discussion in developement

Ok, concerning the growAnalyze, I have a couple of options to deal with the infinity issues:
danielyxie/bitburner#2635
danielyxie/bitburner#2628

Option 1) Just retun Math.min(growAnalyze normal value, server.moneyMax) --- this basically assumes a minimum of $1 server and ignores the extra power added to grow ($1/thread) and so will return larger values than actually needed (potentially MANY times larger in some case. Theoretical example: if it takes 100 threads to double - grow x2 - a certain server with moneyMax of $200, then 100 threads is all that would be needed to grow it to max from $0, but this naïve solution is returning 200)

Option 2) Is basically to use a first order differential equation - ie, how many threads it takes is dependent on how many threads you need... I'll look up one of the approximation techniques for that kind of first order differential equation and use that (most approach very quickly, and we only need to get to an error <1 since integer threads anyways). This has the added advantage of taking into consideration the extra grow power for non-full grows as well.

Opinions?
(Follow-up: If we go with option 1, should I also change the previously discussed functions to behave accordingly - eliminating the infinity thing entirely? Basically, this would change the mechanic for growing <$1 servers to assume $1, instead of $1/thread, consistently.)

[phyzical]

i'm personally not a fan of having an equation
Mostly because a complicated algorithm to stop this issue will break one day, not if just when 😆

The other way to look at this would be to fix the issue on the other side, anywhere the result could be Infinitymake it invalid.
though i dont like this one because Infinity will eventually be a valid result due to the cap on number in JS land
So we would have to consider to use a number system similar to other idle games where they use letters for additional categorizing of large numbers. but we just have no reason for numbers to get bigger than the js cap at this time

imho, just make the minimum 0.00000000001 (or 1).

But its a question for higher powers

Hacking gangs should do territory warfare with hacking.

[DJ-Laser]
Ngl im kinda salty about this. I made a HACKING gang so I wouldn't have to worry about clashing, so when I lost all my territory on accident and it cut my production massively (~50m/sec to ~1m/sec) I was kinda mad. Now I'm trying to train all my members of a HACKING gang in COMBAT, so I can get territory to be able to make enough money to actually get enough neuroflux to get 15k skill and beat the BN, but it is so slow -_-

This is my 2nd BN so I only have gangs to work with, so I am stuck and it is kinda demoralizing to me to have all my hard work lost and I might need to flume and reset. Pls fix this.

Steps:

  1. Make a HACKING gang
  2. lvl them up a lot
  3. Accidentally lose all your territory
  4. Observe massive money/rep production decrease

Version: Bitburner v1.6.1 (d949907)
Save:
bitburnerSave_1648836646_BN2x0.txt

Comments From Original Issue

[phyzical]

what do you mean by "accidentally lost territory"? i would just flume and do it again if you messed up

[hydroflame]

That won't fix this users issue but we'll make hacking gangs participate in territory warfare with their hacking skills.

Closing file in editor sometimes asks to save changes when nothing has changed

[macdjord]
Closing a script by clicking the 'X' button on its tab at the top of the screen will sometimes ask if you want to save changes, even though the tab was not showing the 'unsaved changes' asterisk.

Note: Every time this has happened, it has been a file I thought I had already saved, so I believe the problem is that the editor is asking to save changes when there are none, but it's possible the files had changed and I'd forgotten, in which case the actual bug is 'editor not displaying unsaved-changes asterisk'.

Version: a3c599e

Comments From Original Issue

[phyzical]

@macdjord mind giving exact repo steps please?

[macdjord]

@phyzical Don't have them; that's why I said 'sometimes'.

[phyzical]

im sorry but there is only so much time one can dedicate to a plethora of bug reports, without enough information bugs get closed to reduce the load of trying to fix more important bugs.

[OriginalRobotWizard]

This is super easy 100% reproducible:

  1. nano test.txt
  2. Close and save
  3. Start over at 1 (popup to be asked to save will be displayed every time for .txt files)

[phyzical]

thx is it only txt files by chance?

[OriginalRobotWizard]

Yes, it only happens with .txt files. Not with .js, .script, or .ns files.

some coding contracts have &nbsp;

[hydroflame]
null

Comments From Original Issue

[phyzical]

is this one

  • just a matter of replaces the &nbsp; with pre tags
  • just removing them and tweeking the text until they are all readable?
  • just removing the &nbsp; entirely?

[borisflagell]

Still a relevant issue as of 1.7.0

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.