script
This commit is contained in:
parent
41e3b3fbcd
commit
dd9664d4ee
329
.eslintrc.js
329
.eslintrc.js
@ -16,322 +16,23 @@ module.exports = {
|
||||
plugins: ["@typescript-eslint"],
|
||||
ignorePatterns: ['NetscriptDefinitions.d.ts', '*.js'],
|
||||
rules: {
|
||||
"accessor-pairs": [
|
||||
"@typescript-eslint/array-type": ["error", { "default": "array-simple" }],
|
||||
"@typescript-eslint/ban-ts-comment": ["off"],
|
||||
"@typescript-eslint/explicit-member-accessibility": ["off"],
|
||||
"@typescript-eslint/explicit-module-boundary-types": ["off"],
|
||||
"@typescript-eslint/no-non-null-assertion": ["off"],
|
||||
"@typescript-eslint/no-use-before-define": ["off"],
|
||||
"@typescript-eslint/no-parameter-properties": ["off"],
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
setWithoutGet: true,
|
||||
getWithoutSet: false,
|
||||
},
|
||||
{ "argsIgnorePattern": "^_", "varsIgnorePattern": "^_" }
|
||||
],
|
||||
"array-bracket-newline": ["off"],
|
||||
"array-bracket-spacing": ["off"],
|
||||
"array-callback-return": ["off"],
|
||||
"array-element-newline": ["off"],
|
||||
"arrow-body-style": ["off"],
|
||||
"arrow-parens": ["off"],
|
||||
"arrow-spacing": ["off"],
|
||||
"block-scoped-var": ["off"],
|
||||
"block-spacing": ["off"],
|
||||
"brace-style": ["off"],
|
||||
"callback-return": ["error"],
|
||||
camelcase: ["off"],
|
||||
"capitalized-comments": ["off"],
|
||||
"class-methods-use-this": ["off"],
|
||||
complexity: ["off"],
|
||||
"consistent-return": ["off"],
|
||||
"consistent-this": ["off"],
|
||||
"constructor-super": ["error"],
|
||||
curly: ["off"],
|
||||
"default-case": ["off"],
|
||||
"dot-notation": ["off"],
|
||||
"eol-last": ["off"],
|
||||
eqeqeq: ["off"],
|
||||
"for-direction": ["error"],
|
||||
"func-call-spacing": ["off"],
|
||||
"func-name-matching": ["error"],
|
||||
"func-names": ["off", "never"],
|
||||
"func-style": ["off"],
|
||||
"function-paren-newline": ["off"],
|
||||
"getter-return": [
|
||||
"error",
|
||||
{
|
||||
allowImplicit: false,
|
||||
},
|
||||
],
|
||||
"global-require": ["off"],
|
||||
"guard-for-in": ["off"],
|
||||
"handle-callback-err": ["error"],
|
||||
"id-blacklist": ["error"],
|
||||
"id-length": ["off"],
|
||||
"id-match": ["error"],
|
||||
indent: ["off"],
|
||||
"indent-legacy": ["off"],
|
||||
"init-declarations": ["off"],
|
||||
"key-spacing": ["off"],
|
||||
"keyword-spacing": ["off"],
|
||||
"line-comment-position": ["off"],
|
||||
"linebreak-style": [
|
||||
"off", // Line endings automatically converted to LF on git commit so probably shouldn't care about it here
|
||||
],
|
||||
"lines-around-comment": ["off"],
|
||||
"lines-around-directive": ["error"],
|
||||
"lines-between-class-members": ["error"],
|
||||
"max-depth": ["off"],
|
||||
"max-len": ["off"],
|
||||
"max-lines": ["off"],
|
||||
"max-nested-callbacks": ["error"],
|
||||
"max-params": ["off"],
|
||||
"max-statements": ["off"],
|
||||
"max-statements-per-line": ["off"],
|
||||
"multiline-comment-style": ["off", "starred-block"],
|
||||
"multiline-ternary": ["off", "never"],
|
||||
"new-cap": ["off"],
|
||||
"new-parens": ["off"],
|
||||
"newline-after-var": ["off"],
|
||||
"newline-before-return": ["off"],
|
||||
"newline-per-chained-call": ["off"],
|
||||
"no-alert": ["error"],
|
||||
"no-array-constructor": ["error"],
|
||||
"no-await-in-loop": ["off"],
|
||||
"no-bitwise": ["off"],
|
||||
"no-buffer-constructor": ["error"],
|
||||
"no-caller": ["error"],
|
||||
"no-case-declarations": ["error"],
|
||||
"no-catch-shadow": ["error"],
|
||||
"no-class-assign": ["error"],
|
||||
"no-compare-neg-zero": ["error"],
|
||||
"no-confusing-arrow": ["error"],
|
||||
"no-console": ["off"],
|
||||
"no-const-assign": ["error"],
|
||||
"no-constant-condition": [
|
||||
"error",
|
||||
{
|
||||
checkLoops: false,
|
||||
},
|
||||
],
|
||||
"no-continue": ["off"],
|
||||
"no-control-regex": ["error"],
|
||||
"no-debugger": ["error"],
|
||||
"no-delete-var": ["error"],
|
||||
"no-div-regex": ["error"],
|
||||
"no-dupe-args": ["error"],
|
||||
"no-dupe-class-members": ["error"],
|
||||
"no-dupe-keys": ["error"],
|
||||
"no-duplicate-case": ["error"],
|
||||
"no-duplicate-imports": [
|
||||
"error",
|
||||
{
|
||||
includeExports: true,
|
||||
},
|
||||
],
|
||||
"no-else-return": ["off"],
|
||||
"no-empty": [
|
||||
"off",
|
||||
{
|
||||
allowEmptyCatch: false,
|
||||
},
|
||||
],
|
||||
"no-empty-character-class": ["error"],
|
||||
"no-empty-function": ["off"],
|
||||
"no-empty-pattern": ["error"],
|
||||
"no-eq-null": ["off"],
|
||||
"no-ex-assign": ["off"],
|
||||
"no-extra-boolean-cast": ["error"],
|
||||
"no-extra-parens": ["off"],
|
||||
"no-extra-semi": ["off"],
|
||||
"no-eval": ["off"],
|
||||
"no-extend-native": ["off"],
|
||||
"no-extra-bind": ["error"],
|
||||
"no-extra-label": ["error"],
|
||||
"no-fallthrough": ["off"],
|
||||
"no-floating-decimal": ["off"],
|
||||
"no-func-assign": ["error"],
|
||||
"no-global-assign": ["error"],
|
||||
"no-implicit-coercion": ["off"],
|
||||
"no-implicit-globals": ["error"],
|
||||
"no-implied-eval": ["error"],
|
||||
"no-inline-comments": ["off"],
|
||||
"no-inner-declarations": ["off", "both"],
|
||||
"no-invalid-regexp": ["error"],
|
||||
"no-invalid-this": ["off"],
|
||||
"no-irregular-whitespace": [
|
||||
"error",
|
||||
{
|
||||
skipStrings: false,
|
||||
skipComments: false,
|
||||
skipRegExps: false,
|
||||
skipTemplates: false,
|
||||
},
|
||||
],
|
||||
"no-iterator": ["error"],
|
||||
"no-label-var": ["error"],
|
||||
"no-labels": ["off"],
|
||||
"no-lone-blocks": ["error"],
|
||||
"no-lonely-if": ["off"],
|
||||
"no-loop-func": ["off"],
|
||||
"no-magic-numbers": ["off"],
|
||||
"no-mixed-operators": ["off"],
|
||||
"no-mixed-requires": ["error"],
|
||||
"no-mixed-spaces-and-tabs": ["off"],
|
||||
"no-multi-assign": ["off"],
|
||||
"no-multi-spaces": ["off"],
|
||||
"no-multi-str": ["error"],
|
||||
"no-multiple-empty-lines": [
|
||||
"off",
|
||||
{
|
||||
max: 1,
|
||||
},
|
||||
],
|
||||
"no-native-reassign": ["error"],
|
||||
"no-negated-condition": ["off"],
|
||||
"no-negated-in-lhs": ["error"],
|
||||
"no-nested-ternary": ["off"],
|
||||
"no-new": ["error"],
|
||||
"no-new-func": ["error"],
|
||||
"no-new-object": ["error"],
|
||||
"no-new-require": ["error"],
|
||||
"no-new-symbol": ["error"],
|
||||
"no-new-wrappers": ["error"],
|
||||
"no-octal": ["error"],
|
||||
"no-octal-escape": ["error"],
|
||||
"no-obj-calls": ["error"],
|
||||
"no-param-reassign": ["off"],
|
||||
"no-path-concat": ["error"],
|
||||
"no-plusplus": ["off"],
|
||||
"no-process-env": ["off"],
|
||||
"no-process-exit": ["error"],
|
||||
"no-proto": ["error"],
|
||||
"no-prototype-builtins": ["off"],
|
||||
"no-redeclare": ["off"],
|
||||
"no-regex-spaces": ["error"],
|
||||
"no-restricted-globals": ["error"],
|
||||
"no-restricted-imports": ["error"],
|
||||
"no-restricted-modules": ["error"],
|
||||
"no-restricted-properties": [
|
||||
"off",
|
||||
{
|
||||
object: "console",
|
||||
property: "log",
|
||||
message: "'log' is too general, use an appropriate level when logging.",
|
||||
},
|
||||
],
|
||||
"no-restricted-syntax": ["error"],
|
||||
"no-return-assign": ["off"],
|
||||
"no-return-await": ["error"],
|
||||
"no-script-url": ["error"],
|
||||
"no-self-assign": [
|
||||
"error",
|
||||
{
|
||||
props: false,
|
||||
},
|
||||
],
|
||||
"no-self-compare": ["error"],
|
||||
"no-sequences": ["error"],
|
||||
"no-shadow": ["off"],
|
||||
"no-shadow-restricted-names": ["error"],
|
||||
"no-spaced-func": ["off"],
|
||||
"no-sparse-arrays": ["error"],
|
||||
"no-sync": ["error"],
|
||||
"no-tabs": ["error"],
|
||||
"no-template-curly-in-string": ["error"],
|
||||
"no-ternary": ["off"],
|
||||
"no-this-before-super": ["off"],
|
||||
"no-throw-literal": ["error"],
|
||||
"no-trailing-spaces": ["off"],
|
||||
"no-undef": ["off"],
|
||||
"no-undef-init": ["error"],
|
||||
"no-undefined": ["off"],
|
||||
"no-underscore-dangle": ["off"],
|
||||
"no-unexpected-multiline": ["error"],
|
||||
"no-unmodified-loop-condition": ["error"],
|
||||
"no-unneeded-ternary": ["off"],
|
||||
"no-unreachable": ["off"],
|
||||
"no-unsafe-finally": ["error"],
|
||||
"no-unsafe-negation": ["error"],
|
||||
"no-unused-expressions": ["off"],
|
||||
"no-unused-labels": ["error"],
|
||||
"no-unused-vars": ["off"],
|
||||
"no-use-before-define": ["off"],
|
||||
"no-useless-call": ["off"],
|
||||
"no-useless-computed-key": ["error"],
|
||||
"no-useless-concat": ["off"],
|
||||
"no-useless-constructor": ["error"],
|
||||
"no-useless-escape": ["off"],
|
||||
"no-useless-rename": [
|
||||
"error",
|
||||
{
|
||||
ignoreDestructuring: false,
|
||||
ignoreExport: false,
|
||||
ignoreImport: false,
|
||||
},
|
||||
],
|
||||
"no-useless-return": ["off"],
|
||||
"no-var": ["off"],
|
||||
"no-void": ["off"],
|
||||
"no-warning-comments": ["off"],
|
||||
"no-whitespace-before-property": ["error"],
|
||||
"no-with": ["error"],
|
||||
"nonblock-statement-body-position": ["off", "below"],
|
||||
"object-curly-newline": ["off"],
|
||||
"object-curly-spacing": ["off"],
|
||||
"object-property-newline": ["off"],
|
||||
"object-shorthand": ["off"],
|
||||
"one-var": ["off"],
|
||||
"one-var-declaration-per-line": ["off"],
|
||||
"operator-assignment": ["off"],
|
||||
"operator-linebreak": ["off", "none"],
|
||||
"padded-blocks": ["off"],
|
||||
"padding-line-between-statements": ["error"],
|
||||
"prefer-arrow-callback": ["off"],
|
||||
"prefer-const": ["off"],
|
||||
"prefer-destructuring": ["off"],
|
||||
"prefer-numeric-literals": ["error"],
|
||||
"prefer-promise-reject-errors": ["off"],
|
||||
"prefer-reflect": ["off"],
|
||||
"prefer-rest-params": ["off"],
|
||||
"prefer-spread": ["off"],
|
||||
"prefer-template": ["off"],
|
||||
"quote-props": ["off"],
|
||||
quotes: ["off"],
|
||||
radix: ["off", "as-needed"],
|
||||
"require-await": ["off"],
|
||||
"require-jsdoc": ["off"],
|
||||
"require-yield": ["error"],
|
||||
"rest-spread-spacing": ["error", "never"],
|
||||
semi: ["warn", "never"],
|
||||
"semi-spacing": ["off"],
|
||||
"semi-style": ["error", "last"],
|
||||
"sort-imports": ["off"],
|
||||
"sort-keys": ["off"],
|
||||
"sort-vars": ["off"],
|
||||
"space-before-blocks": ["off"],
|
||||
"space-before-function-paren": ["off"],
|
||||
"space-in-parens": ["off"],
|
||||
"space-infix-ops": ["off"],
|
||||
"space-unary-ops": ["off"],
|
||||
"spaced-comment": ["off"],
|
||||
strict: ["off"],
|
||||
"switch-colon-spacing": [
|
||||
"error",
|
||||
{
|
||||
after: true,
|
||||
before: false,
|
||||
},
|
||||
],
|
||||
"symbol-description": ["error"],
|
||||
"template-curly-spacing": ["error"],
|
||||
"template-tag-spacing": ["error"],
|
||||
"unicode-bom": ["error", "never"],
|
||||
"use-isnan": ["error"],
|
||||
"valid-jsdoc": ["off"],
|
||||
"valid-typeof": ["error"],
|
||||
"vars-on-top": ["off"],
|
||||
"wrap-iife": ["error", "any"],
|
||||
"wrap-regex": ["off"],
|
||||
"yield-star-spacing": ["error", "before"],
|
||||
yoda: ["error", "never"],
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/ban-ts-ignore": ["off"],
|
||||
"@typescript-eslint/no-empty-function": ["off"],
|
||||
"no-return-await": "error",
|
||||
"require-await": "error",
|
||||
"no-async-promise-executor": "error",
|
||||
"no-constant-condition": ["off"]
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -6,9 +6,12 @@
|
||||
"eslint.workingDirectories": ["./src"],
|
||||
"editor.codeActionsOnSave": {"source.fixAll.eslint": true},
|
||||
|
||||
"bitburner.authToken": "MOG9GEp4MGcw4aupPiqC6C9kd8jtFR2JgWcuS9JMyJjYfRCv0sqWdoB1H0G7HMQY",
|
||||
"bitburner.fileWatcher.enable": true,
|
||||
// Bitburner Extension Settings
|
||||
"bitburner.scriptRoot": "./dist/",
|
||||
|
||||
|
||||
// Autosave Settings
|
||||
"files.autoSave": "off",
|
||||
|
||||
|
37
build.js
Normal file
37
build.js
Normal file
@ -0,0 +1,37 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const esbuild = require("esbuild");
|
||||
const yargs = require("yargs");
|
||||
yargs.scriptName("builder")
|
||||
.usage("$0 <cmd> [args]")
|
||||
.command("watch","watch and build",(yargs)=>{
|
||||
|
||||
},(argv)=>{
|
||||
build({
|
||||
watch:true,
|
||||
});
|
||||
})
|
||||
.command("build","build",(yargs)=>{},
|
||||
(argv)=>{
|
||||
build();
|
||||
})
|
||||
.help()
|
||||
.argv;
|
||||
|
||||
async function build(options){
|
||||
options = options || {};
|
||||
options.watch = options.watch || false;
|
||||
let dir = fs.readdirSync("src");
|
||||
dir = dir.filter(x=>x.endsWith(".ts"));
|
||||
|
||||
await esbuild.build({
|
||||
entryPoints:dir,
|
||||
bundle:true,
|
||||
write: true,
|
||||
treeShaking: true,
|
||||
watch: options.watch,
|
||||
platform: "neutral",
|
||||
target:"es2020",
|
||||
outdir:"./dist",
|
||||
});
|
||||
}
|
14
package.json
14
package.json
@ -4,8 +4,7 @@
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"watch": "npx tsc -w",
|
||||
"lint": "eslint . --ext .ts",
|
||||
"build": "node build.js",
|
||||
"defs": "node ./updateDefs.js"
|
||||
},
|
||||
"repository": {
|
||||
@ -18,12 +17,13 @@
|
||||
},
|
||||
"homepage": "https://github.com/SlyCedix/bitburner-typescript-template#readme",
|
||||
"devDependencies": {
|
||||
"@types/lodash": "^4.14.178",
|
||||
"@types/node": "^16.4.3",
|
||||
"@types/yargs": "^17.0.11",
|
||||
"@typescript-eslint/eslint-plugin": "^4.28.4",
|
||||
"@typescript-eslint/parser": "^4.28.4",
|
||||
"eslint": "^7.31.0",
|
||||
"ts-node": "^9.1.1",
|
||||
"typescript": "^4.3.5"
|
||||
"esbuild": "^0.15.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"yargs": "^17.5.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
15
src/auto-hacking.ts
Normal file
15
src/auto-hacking.ts
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
import { selectHackableServerList, hackServer } from "./lib/hack"
|
||||
import {isRootedServer} from "./lib/servers"
|
||||
import {NS} from "@ns"
|
||||
|
||||
/** @param {NS} ns */
|
||||
// eslint-disable-next-line require-await
|
||||
export async function main(ns: NS): Promise<void> {
|
||||
//ns.disableLog("ALL")
|
||||
const servers = selectHackableServerList(ns).filter(x => !isRootedServer(x))
|
||||
servers.forEach(x => {
|
||||
ns.tprint(`hack ${x.hostname}`)
|
||||
hackServer(ns, x)
|
||||
})
|
||||
}
|
6
src/get-share-power.ts
Normal file
6
src/get-share-power.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import {NS} from "@ns"
|
||||
|
||||
// eslint-disable-next-line require-await
|
||||
export async function main(ns:NS):Promise<void>{
|
||||
ns.tprint(ns.getSharePower());
|
||||
}
|
178
src/hacknet-daemon.ts
Normal file
178
src/hacknet-daemon.ts
Normal file
@ -0,0 +1,178 @@
|
||||
import {NS} from "@ns"
|
||||
import { parse } from "./lib/flag";
|
||||
import {range} from "./util/range";
|
||||
|
||||
class Account{
|
||||
value: number;
|
||||
timer?: NodeJS.Timer;
|
||||
constructor(value: number){
|
||||
this.value = value;
|
||||
this.timer = undefined;
|
||||
}
|
||||
startIncrement(ns:NS, rate: number): void{
|
||||
this.timer = setInterval(()=>{
|
||||
this.value += ns.hacknet.getNodeStats().production * rate;
|
||||
},1000);
|
||||
}
|
||||
stopIncrement(): void{
|
||||
clearInterval(this.timer)
|
||||
}
|
||||
}
|
||||
|
||||
export function getNodeProduction(level: number, ram: number, cores: number, mult: number, bitMult:number): number{
|
||||
const moneyGainPerLevel = 1.5;
|
||||
const levelMult = level * moneyGainPerLevel;
|
||||
const ramMult = Math.pow(1.035, ram - 1);
|
||||
const coreMult = ((cores + 5) / 6);
|
||||
return levelMult * ramMult * coreMult * mult * bitMult;
|
||||
}
|
||||
|
||||
interface HacknetNodeComponent<T> {
|
||||
level: T;
|
||||
core: T;
|
||||
ram: T;
|
||||
}
|
||||
|
||||
type ComponentKind = "level" | "core" | "ram";
|
||||
|
||||
export interface CEInfo {
|
||||
upgradeCost : HacknetNodeComponent<number>;
|
||||
production : HacknetNodeComponent<number>;
|
||||
costEffective : HacknetNodeComponent<number>;
|
||||
}
|
||||
|
||||
function getCostEffective(ns:NS, nodeIndex: number, n:number): CEInfo{
|
||||
const coreUpgradeCost = ns.hacknet.getCoreUpgradeCost(nodeIndex,n);
|
||||
const ramUpgradeCost = ns.hacknet.getRamUpgradeCost(nodeIndex,n);
|
||||
const levelUpgradeCost = ns.hacknet.getLevelUpgradeCost(nodeIndex,n);
|
||||
const mult = ns.getHacknetMultipliers().production;
|
||||
const bitMult = 1//ns.getBitNodeMultipliers().HacknetNodeMoney;
|
||||
const stat = ns.hacknet.getNodeStats(nodeIndex);
|
||||
|
||||
const coreProduction = getNodeProduction(stat.level, stat.ram, stat.cores + n, mult, bitMult) - stat.production;
|
||||
const levelProduction = getNodeProduction(stat.level + n, stat.ram, stat.cores, mult, bitMult) - stat.production;
|
||||
const ramProduction = getNodeProduction(stat.level, stat.ram * Math.pow(2,n), stat.cores, mult, bitMult) - stat.production;
|
||||
|
||||
return {
|
||||
upgradeCost:{
|
||||
core: coreUpgradeCost,
|
||||
ram: ramUpgradeCost,
|
||||
level: levelUpgradeCost,
|
||||
},
|
||||
production:{
|
||||
core: coreProduction,
|
||||
ram: ramProduction,
|
||||
level: levelProduction,
|
||||
},
|
||||
costEffective:{
|
||||
core: coreProduction/coreUpgradeCost,
|
||||
ram: ramProduction/ramUpgradeCost,
|
||||
level: levelProduction/levelUpgradeCost
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createUpgradeAction(ns:NS, index: number, n: number, kind:ComponentKind):(account: Account)=>void{
|
||||
return (account: Account)=>{
|
||||
switch (kind) {
|
||||
case "core":
|
||||
account.value -= ns.hacknet.getCoreUpgradeCost(index,n);
|
||||
ns.hacknet.upgradeCore(index,n)
|
||||
break;
|
||||
case "level":
|
||||
account.value -= ns.hacknet.getLevelUpgradeCost(index,n);
|
||||
ns.hacknet.upgradeLevel(index,n)
|
||||
break;
|
||||
case "ram":
|
||||
account.value -= ns.hacknet.getRamUpgradeCost(index,n);
|
||||
ns.hacknet.upgradeRam(index,n)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getMinCENode(ns:NS, index: number, n: number):[number,ComponentKind]{
|
||||
const {costEffective: ce} = getCostEffective(ns,index,n);
|
||||
if(ce.core < ce.level){
|
||||
if(ce.core < ce.ram){
|
||||
return [ce.core, "core"];
|
||||
}
|
||||
else{
|
||||
return [ce.ram, "ram"];
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(ce.level < ce.ram){
|
||||
return [ce.level,"level"];
|
||||
}
|
||||
else {
|
||||
return [ce.ram,"ram"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function* getIndexOfHackNode(ns:NS): Generator<number>{
|
||||
for (const it of range(ns.hacknet.numNodes())) {
|
||||
yield it;
|
||||
}
|
||||
}
|
||||
|
||||
function getMinCEIndex(ns:NS, n: number):[number,number,ComponentKind]{
|
||||
let optimalC = Infinity;
|
||||
let kind = "";
|
||||
let minIndex = 0;
|
||||
for(const it of getIndexOfHackNode(ns)){
|
||||
const [c, k] = getMinCENode(ns,it,n);
|
||||
if(c < optimalC){
|
||||
optimalC = c;
|
||||
kind = k;
|
||||
minIndex = it;
|
||||
}
|
||||
}
|
||||
return [minIndex,optimalC,kind];
|
||||
}
|
||||
|
||||
function getBuyNodeCE(ns:NS):{cost:number;production:number;costEffective: number}{
|
||||
const mult = ns.getHacknetMultipliers().production;
|
||||
const bitMult = 1//ns.getBitNodeMultipliers().HacknetNodeMoney;
|
||||
const cost = ns.hacknet.maxNumNodes() > ns.hacknet.numNodes() ? ns.hacknet.getPurchaseNodeCost() : Infinity;
|
||||
const production = getNodeProduction(1,1,1,mult,bitMult);
|
||||
return {
|
||||
cost,
|
||||
production,
|
||||
costEffective: cost/production,
|
||||
};
|
||||
}
|
||||
|
||||
function cycle(ns:NS, account:Account): void{
|
||||
const chunkN = 1;
|
||||
|
||||
const [upgradeNodeIndex,upgradeNodeCE,kind] = getMinCEIndex(ns,chunkN);
|
||||
const {costEffective: buyNew} = getBuyNodeCE(ns);
|
||||
if(upgradeNodeCE < buyNew){
|
||||
const action = createUpgradeAction(ns,upgradeNodeIndex,chunkN,kind);
|
||||
action(account);
|
||||
}
|
||||
else {
|
||||
ns.hacknet.purchaseNode()
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line require-await
|
||||
export async function main(ns:NS):Promise<void>{
|
||||
ns.disableLog("ALL")
|
||||
const flag = parse(ns.args);
|
||||
const iter = parseInt(flag.i ?? flag.iter ?? "10");
|
||||
const rate = parseFloat(flag.r ?? flag.rate ?? "0.5");
|
||||
const budget = parseInt(flag.b ?? flag.budget ?? "0");
|
||||
|
||||
const account = new Account(budget);
|
||||
account.startIncrement(ns,rate);
|
||||
ns.tail();
|
||||
for (let i = 0; i < iter; i++) {
|
||||
ns.clearLog()
|
||||
ns.print(`budget ${account.value}`);
|
||||
cycle(ns,account);
|
||||
await ns.sleep(1000);
|
||||
}
|
||||
}
|
455
src/lib/flag.ts
Normal file
455
src/lib/flag.ts
Normal file
@ -0,0 +1,455 @@
|
||||
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||
/**
|
||||
* CLI flag parser.
|
||||
*
|
||||
* This module is browser compatible.
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
import { assert } from "../util/assert";
|
||||
|
||||
/** The value returned from `parse`. */
|
||||
export interface Args {
|
||||
/** Contains all the arguments that didn't have an option associated with
|
||||
* them. */
|
||||
_: Array<string | number>;
|
||||
// deno-lint-ignore no-explicit-any
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/** The options for the `parse` call. */
|
||||
export interface ParseOptions {
|
||||
/** When `true`, populate the result `_` with everything before the `--` and
|
||||
* the result `['--']` with everything after the `--`. Here's an example:
|
||||
*
|
||||
* ```ts
|
||||
* // $ deno run example.ts -- a arg1
|
||||
* import { parse } from "./mod.ts";
|
||||
* console.dir(parse(Deno.args, { "--": false }));
|
||||
* // output: { _: [ "a", "arg1" ] }
|
||||
* console.dir(parse(Deno.args, { "--": true }));
|
||||
* // output: { _: [], --: [ "a", "arg1" ] }
|
||||
* ```
|
||||
*
|
||||
* Defaults to `false`.
|
||||
*/
|
||||
"--"?: boolean;
|
||||
|
||||
/** An object mapping string names to strings or arrays of string argument
|
||||
* names to use as aliases. */
|
||||
alias?: Record<string, string | string[]>;
|
||||
|
||||
/** A boolean, string or array of strings to always treat as booleans. If
|
||||
* `true` will treat all double hyphenated arguments without equal signs as
|
||||
* `boolean` (e.g. affects `--foo`, not `-f` or `--foo=bar`) */
|
||||
boolean?: boolean | string | string[];
|
||||
|
||||
/** An object mapping string argument names to default values. */
|
||||
default?: Record<string, unknown>;
|
||||
|
||||
/** When `true`, populate the result `_` with everything after the first
|
||||
* non-option. */
|
||||
stopEarly?: boolean;
|
||||
|
||||
/** A string or array of strings argument names to always treat as strings. */
|
||||
string?: string | string[];
|
||||
|
||||
/** A string or array of strings argument names to always treat as arrays.
|
||||
* Collectable options can be used multiple times. All values will be
|
||||
* colelcted into one array. If a non-collectable option is used multiple
|
||||
* times, the last value is used. */
|
||||
collect?: string | string[];
|
||||
|
||||
/** A string or array of strings argument names which can be negated
|
||||
* by prefixing them with `--no-`, like `--no-config`. */
|
||||
negatable?: string | string[];
|
||||
|
||||
/** A function which is invoked with a command line parameter not defined in
|
||||
* the `options` configuration object. If the function returns `false`, the
|
||||
* unknown option is not added to `parsedArgs`. */
|
||||
unknown?: (arg: string, key?: string, value?: unknown) => unknown;
|
||||
}
|
||||
|
||||
interface Flags {
|
||||
bools: Record<string, boolean>;
|
||||
strings: Record<string, boolean>;
|
||||
collect: Record<string, boolean>;
|
||||
negatable: Record<string, boolean>;
|
||||
unknownFn: (arg: string, key?: string, value?: unknown) => unknown;
|
||||
allBools: boolean;
|
||||
}
|
||||
|
||||
interface NestedMapping {
|
||||
[key: string]: NestedMapping | unknown;
|
||||
}
|
||||
|
||||
const { hasOwn } = Object;
|
||||
|
||||
function get<T>(obj: Record<string, T>, key: string): T | undefined {
|
||||
if (hasOwn(obj, key)) {
|
||||
return obj[key];
|
||||
}
|
||||
}
|
||||
|
||||
function getForce<T>(obj: Record<string, T>, key: string): T {
|
||||
const v = get(obj, key);
|
||||
assert(v != null);
|
||||
return v;
|
||||
}
|
||||
|
||||
function isNumber(x: unknown): boolean {
|
||||
if (typeof x === "number") return true;
|
||||
if (/^0x[0-9a-f]+$/i.test(String(x))) return true;
|
||||
return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(String(x));
|
||||
}
|
||||
|
||||
function hasKey(obj: NestedMapping, keys: string[]): boolean {
|
||||
let o = obj;
|
||||
keys.slice(0, -1).forEach((key) => {
|
||||
o = (get(o, key) ?? {}) as NestedMapping;
|
||||
});
|
||||
|
||||
const key = keys[keys.length - 1];
|
||||
return key in o;
|
||||
}
|
||||
|
||||
/** Take a set of command line arguments, optionally with a set of options, and
|
||||
* return an object representing the flags found in the passed arguments.
|
||||
*
|
||||
* By default any arguments starting with `-` or `--` are considered boolean
|
||||
* flags. If the argument name is followed by an equal sign (`=`) it is
|
||||
* considered a key-value pair. Any arguments which could not be parsed are
|
||||
* available in the `_` property of the returned object.
|
||||
*
|
||||
* ```ts
|
||||
* import { parse } from "./mod.ts";
|
||||
* const parsedArgs = parse(Deno.args);
|
||||
* ```
|
||||
*
|
||||
* ```ts
|
||||
* import { parse } from "./mod.ts";
|
||||
* const parsedArgs = parse(["--foo", "--bar=baz", "--no-qux", "./quux.txt"]);
|
||||
* // parsedArgs: { foo: true, bar: "baz", qux: false, _: ["./quux.txt"] }
|
||||
* ```
|
||||
*/
|
||||
export function parse(
|
||||
args: string[],
|
||||
{
|
||||
"--": doubleDash = false,
|
||||
alias = {},
|
||||
boolean = false,
|
||||
default: defaults = {},
|
||||
stopEarly = false,
|
||||
string = [],
|
||||
collect = [],
|
||||
negatable = [],
|
||||
unknown = (i: string): unknown => i,
|
||||
}: ParseOptions = {},
|
||||
): Args {
|
||||
const flags: Flags = {
|
||||
bools: {},
|
||||
strings: {},
|
||||
unknownFn: unknown,
|
||||
allBools: false,
|
||||
collect: {},
|
||||
negatable: {},
|
||||
};
|
||||
|
||||
if (boolean !== undefined) {
|
||||
if (typeof boolean === "boolean") {
|
||||
flags.allBools = !!boolean;
|
||||
} else {
|
||||
const booleanArgs = typeof boolean === "string" ? [boolean] : boolean;
|
||||
|
||||
for (const key of booleanArgs.filter(Boolean)) {
|
||||
flags.bools[key] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const aliases: Record<string, string[]> = {};
|
||||
if (alias !== undefined) {
|
||||
for (const key in alias) {
|
||||
const val = getForce(alias, key);
|
||||
if (typeof val === "string") {
|
||||
aliases[key] = [val];
|
||||
} else {
|
||||
aliases[key] = val;
|
||||
}
|
||||
for (const alias of getForce(aliases, key)) {
|
||||
aliases[alias] = [key].concat(aliases[key].filter((y) => alias !== y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (string !== undefined) {
|
||||
const stringArgs = typeof string === "string" ? [string] : string;
|
||||
|
||||
for (const key of stringArgs.filter(Boolean)) {
|
||||
flags.strings[key] = true;
|
||||
const alias = get(aliases, key);
|
||||
if (alias) {
|
||||
for (const al of alias) {
|
||||
flags.strings[al] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (collect !== undefined) {
|
||||
const collectArgs = typeof collect === "string" ? [collect] : collect;
|
||||
|
||||
for (const key of collectArgs.filter(Boolean)) {
|
||||
flags.collect[key] = true;
|
||||
const alias = get(aliases, key);
|
||||
if (alias) {
|
||||
for (const al of alias) {
|
||||
flags.collect[al] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (negatable !== undefined) {
|
||||
const negatableArgs = typeof negatable === "string"
|
||||
? [negatable]
|
||||
: negatable;
|
||||
|
||||
for (const key of negatableArgs.filter(Boolean)) {
|
||||
flags.negatable[key] = true;
|
||||
const alias = get(aliases, key);
|
||||
if (alias) {
|
||||
for (const al of alias) {
|
||||
flags.negatable[al] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const argv: Args = { _: [] };
|
||||
|
||||
function argDefined(key: string, arg: string): boolean {
|
||||
return (
|
||||
(flags.allBools && /^--[^=]+$/.test(arg)) ||
|
||||
get(flags.bools, key) ||
|
||||
!!get(flags.strings, key) ||
|
||||
!!get(aliases, key)
|
||||
);
|
||||
}
|
||||
|
||||
function setKey(
|
||||
obj: NestedMapping,
|
||||
name: string,
|
||||
value: unknown,
|
||||
collect = true,
|
||||
): void {
|
||||
let o = obj;
|
||||
const keys = name.split(".");
|
||||
keys.slice(0, -1).forEach(function (key): void {
|
||||
if (get(o, key) === undefined) {
|
||||
o[key] = {};
|
||||
}
|
||||
o = get(o, key) as NestedMapping;
|
||||
});
|
||||
|
||||
const key = keys[keys.length - 1];
|
||||
const collectable = collect && !!get(flags.collect, name);
|
||||
|
||||
if (!collectable) {
|
||||
o[key] = value;
|
||||
} else if (get(o, key) === undefined) {
|
||||
o[key] = [value];
|
||||
} else if (Array.isArray(get(o, key))) {
|
||||
(o[key] as unknown[]).push(value);
|
||||
} else {
|
||||
o[key] = [get(o, key), value];
|
||||
}
|
||||
}
|
||||
|
||||
function setArg(
|
||||
key: string,
|
||||
val: unknown,
|
||||
arg: string | undefined = undefined,
|
||||
collect?: boolean,
|
||||
): void {
|
||||
if (arg && flags.unknownFn && !argDefined(key, arg)) {
|
||||
if (flags.unknownFn(arg, key, val) === false) return;
|
||||
}
|
||||
|
||||
const value = !get(flags.strings, key) && isNumber(val) ? Number(val) : val;
|
||||
setKey(argv, key, value, collect);
|
||||
|
||||
const alias = get(aliases, key);
|
||||
if (alias) {
|
||||
for (const x of alias) {
|
||||
setKey(argv, x, value, collect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function aliasIsBoolean(key: string): boolean {
|
||||
return getForce(aliases, key).some(
|
||||
(x) => typeof get(flags.bools, x) === "boolean",
|
||||
);
|
||||
}
|
||||
|
||||
let notFlags: string[] = [];
|
||||
|
||||
// all args after "--" are not parsed
|
||||
if (args.includes("--")) {
|
||||
notFlags = args.slice(args.indexOf("--") + 1);
|
||||
args = args.slice(0, args.indexOf("--"));
|
||||
}
|
||||
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
const arg = args[i];
|
||||
|
||||
if (/^--.+=/.test(arg)) {
|
||||
const m = arg.match(/^--([^=]+)=(.*)$/s);
|
||||
assert(m != null);
|
||||
const [, key, value] = m;
|
||||
|
||||
if (flags.bools[key]) {
|
||||
const booleanValue = value !== "false";
|
||||
setArg(key, booleanValue, arg);
|
||||
} else {
|
||||
setArg(key, value, arg);
|
||||
}
|
||||
} else if (
|
||||
/^--no-.+/.test(arg) && get(flags.negatable, arg.replace(/^--no-/, ""))
|
||||
) {
|
||||
const m = arg.match(/^--no-(.+)/);
|
||||
assert(m != null);
|
||||
setArg(m[1], false, arg, false);
|
||||
} else if (/^--.+/.test(arg)) {
|
||||
const m = arg.match(/^--(.+)/);
|
||||
assert(m != null);
|
||||
const [, key] = m;
|
||||
const next = args[i + 1];
|
||||
if (
|
||||
next !== undefined &&
|
||||
!/^-/.test(next) &&
|
||||
!get(flags.bools, key) &&
|
||||
!flags.allBools &&
|
||||
(get(aliases, key) ? !aliasIsBoolean(key) : true)
|
||||
) {
|
||||
setArg(key, next, arg);
|
||||
i++;
|
||||
} else if (/^(true|false)$/.test(next)) {
|
||||
setArg(key, next === "true", arg);
|
||||
i++;
|
||||
} else {
|
||||
setArg(key, get(flags.strings, key) ? "" : true, arg);
|
||||
}
|
||||
} else if (/^-[^-]+/.test(arg)) {
|
||||
const letters = arg.slice(1, -1).split("");
|
||||
|
||||
let broken = false;
|
||||
for (let j = 0; j < letters.length; j++) {
|
||||
const next = arg.slice(j + 2);
|
||||
|
||||
if (next === "-") {
|
||||
setArg(letters[j], next, arg);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (/[A-Za-z]/.test(letters[j]) && /=/.test(next)) {
|
||||
setArg(letters[j], next.split(/=(.+)/)[1], arg);
|
||||
broken = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (
|
||||
/[A-Za-z]/.test(letters[j]) &&
|
||||
/-?\d+(\.\d*)?(e-?\d+)?$/.test(next)
|
||||
) {
|
||||
setArg(letters[j], next, arg);
|
||||
broken = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (letters[j + 1] && letters[j + 1].match(/\W/)) {
|
||||
setArg(letters[j], arg.slice(j + 2), arg);
|
||||
broken = true;
|
||||
break;
|
||||
} else {
|
||||
setArg(letters[j], get(flags.strings, letters[j]) ? "" : true, arg);
|
||||
}
|
||||
}
|
||||
|
||||
const [key] = arg.slice(-1);
|
||||
if (!broken && key !== "-") {
|
||||
if (
|
||||
args[i + 1] &&
|
||||
!/^(-|--)[^-]/.test(args[i + 1]) &&
|
||||
!get(flags.bools, key) &&
|
||||
(get(aliases, key) ? !aliasIsBoolean(key) : true)
|
||||
) {
|
||||
setArg(key, args[i + 1], arg);
|
||||
i++;
|
||||
} else if (args[i + 1] && /^(true|false)$/.test(args[i + 1])) {
|
||||
setArg(key, args[i + 1] === "true", arg);
|
||||
i++;
|
||||
} else {
|
||||
setArg(key, get(flags.strings, key) ? "" : true, arg);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!flags.unknownFn || flags.unknownFn(arg) !== false) {
|
||||
argv._.push(flags.strings["_"] ?? !isNumber(arg) ? arg : Number(arg));
|
||||
}
|
||||
if (stopEarly) {
|
||||
argv._.push(...args.slice(i + 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const [key, value] of Object.entries(defaults)) {
|
||||
if (!hasKey(argv, key.split("."))) {
|
||||
setKey(argv, key, value);
|
||||
|
||||
if (aliases[key]) {
|
||||
for (const x of aliases[key]) {
|
||||
setKey(argv, x, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const key of Object.keys(flags.bools)) {
|
||||
if (!hasKey(argv, key.split("."))) {
|
||||
const value = get(flags.collect, key) ? [] : false;
|
||||
setKey(
|
||||
argv,
|
||||
key,
|
||||
value,
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (const key of Object.keys(flags.strings)) {
|
||||
if (!hasKey(argv, key.split(".")) && get(flags.collect, key)) {
|
||||
setKey(
|
||||
argv,
|
||||
key,
|
||||
[],
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (doubleDash) {
|
||||
argv["--"] = [];
|
||||
for (const key of notFlags) {
|
||||
argv["--"].push(key);
|
||||
}
|
||||
} else {
|
||||
for (const key of notFlags) {
|
||||
argv._.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
return argv;
|
||||
}
|
95
src/lib/hack.ts
Normal file
95
src/lib/hack.ts
Normal file
@ -0,0 +1,95 @@
|
||||
import { NS, Server } from '@ns'
|
||||
import {selectAllServerList, ServerInfo} from "./servers"
|
||||
|
||||
export type Hackability = "hackable" | "rooted" | "impossible"
|
||||
|
||||
export function getHackability(ns: NS,hostname:string): Hackability{
|
||||
if (ns.hasRootAccess(hostname)) {
|
||||
return "rooted";
|
||||
}
|
||||
if (ns.getServerRequiredHackingLevel(hostname) > ns.getHackingLevel() ||
|
||||
ns.getServerNumPortsRequired(hostname) > hackablePorts(ns)) {
|
||||
return "impossible";
|
||||
}
|
||||
return "hackable";
|
||||
}
|
||||
export function getHackabilityServer(ns: NS,server:Server): Hackability{
|
||||
if (server.hasAdminRights) {
|
||||
return "rooted";
|
||||
}
|
||||
if (server.requiredHackingSkill > ns.getHackingLevel() ||
|
||||
server.numOpenPortsRequired > hackablePorts(ns)) {
|
||||
return "impossible";
|
||||
}
|
||||
return "hackable";
|
||||
}
|
||||
|
||||
export function getLockSymbol(k:Hackability):string{
|
||||
switch (k) {
|
||||
case "rooted":
|
||||
return "🔓"
|
||||
case "hackable":
|
||||
return "🔐"
|
||||
case "impossible":
|
||||
return "🔒"
|
||||
}
|
||||
}
|
||||
|
||||
type Hack = {
|
||||
file: string;
|
||||
exec: (ns: NS, target:string)=> void;
|
||||
};
|
||||
|
||||
export const hacks: Hack[] = [
|
||||
{ file: 'BruteSSH.exe', exec: (ns: NS, target: string) => ns.brutessh(target) },
|
||||
{ file: 'FTPCrack.exe', exec: (ns: NS, target: string) => ns.ftpcrack(target) },
|
||||
{ file: 'relaySMTP.exe', exec: (ns: NS, target: string) => ns.relaysmtp(target) },
|
||||
{ file: 'HTTPWorm.exe', exec: (ns: NS, target: string) => ns.httpworm(target) },
|
||||
{ file: 'SQLInject.exe', exec: (ns: NS, target: string) => ns.sqlinject(target) },
|
||||
]
|
||||
|
||||
/**
|
||||
* @param {NS} ns
|
||||
*/
|
||||
export function hackablePorts(ns: NS): number {
|
||||
return hacks.map(x=>(ns.fileExists(x.file) ? 1 : 0)).reduce((x,y)=>x+y)
|
||||
}
|
||||
|
||||
export function isHackableServer(ns: NS, target: Server): boolean{
|
||||
return target.numOpenPortsRequired <= hackablePorts(ns) &&
|
||||
target.hackDifficulty <= ns.getHackingLevel()
|
||||
}
|
||||
export function selectHackableServerList(ns: NS): ServerInfo[]{
|
||||
return selectAllServerList(ns).filter(x=>{
|
||||
return isHackableServer(ns,x)
|
||||
})
|
||||
}
|
||||
|
||||
export function hackServer(ns:NS,target:Server);
|
||||
export function hackServer(ns:NS,target:string);
|
||||
export function hackServer(ns:NS,target:string|Server):void{
|
||||
const hostname = typeof target === "string" ? target : target.hostname
|
||||
hacks.forEach(x=>{
|
||||
if(ns.fileExists(x.file,"home")){
|
||||
x.exec(ns, hostname)
|
||||
}
|
||||
})
|
||||
ns.nuke(hostname)
|
||||
}
|
||||
|
||||
/** @param {NS} ns */
|
||||
// eslint-disable-next-line require-await
|
||||
export async function main(ns: NS):Promise<void> {
|
||||
if(ns.args.length == 0){
|
||||
ns.tprint("argument required")
|
||||
ns.tprint("run cmd [target]")
|
||||
return
|
||||
}
|
||||
const target = ns.args[0]
|
||||
hackServer(target)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export function autocomplete(data : ServerData, args : string[]) : string[] {
|
||||
return [...data.servers]
|
||||
}
|
71
src/lib/servers.ts
Normal file
71
src/lib/servers.ts
Normal file
@ -0,0 +1,71 @@
|
||||
import { NS, Server } from '@ns'
|
||||
|
||||
/** @param {NS} ns */
|
||||
export async function main(ns: NS): Promise<void> {
|
||||
if (ns.args.length == 0) {
|
||||
ns.tprint("argument required")
|
||||
ns.tprint("search all server and print to json")
|
||||
ns.tprint("run cmd [filePath]")
|
||||
ns.exit()
|
||||
}
|
||||
const filePath = ns.args[0]
|
||||
const collectedData = selectAllServerList()
|
||||
const buf = JSON.stringify(collectedData, undefined, 2)
|
||||
await ns.write(filePath, buf, "w")
|
||||
}
|
||||
|
||||
export interface ServerInfo extends Server{
|
||||
relHost:string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {NS} ns
|
||||
* @param func
|
||||
*/
|
||||
export function visitAllServerList(ns: NS, func:(data: ServerInfo)=>void):void {
|
||||
/** @type {string[]} */
|
||||
const queue = ["home"]
|
||||
/** @type {Set<string>} */
|
||||
const visited = new Set()
|
||||
|
||||
//breadth first search
|
||||
while (queue.length > 0) {
|
||||
const vHost = queue.pop()
|
||||
const data = getServersInfo(ns, vHost)
|
||||
|
||||
func(data)
|
||||
|
||||
visited.add(vHost)
|
||||
for (const h of data.relHost) {
|
||||
if (!visited.has(h)) {
|
||||
queue.push(h)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**@param {NS} ns */
|
||||
export function selectAllServerList(ns: NS): ServerInfo[] {
|
||||
const collectedData: ServerInfo[] = []
|
||||
visitAllServerList(ns, (data) => {
|
||||
collectedData.push(data)
|
||||
})
|
||||
return collectedData
|
||||
}
|
||||
|
||||
export function isRootedServer(server:Server):boolean{
|
||||
return server.hasAdminRights
|
||||
}
|
||||
|
||||
export function selectRootedServerList(ns:NS): ServerInfo[]{
|
||||
return selectAllServerList(ns).filter(isRootedServer)
|
||||
}
|
||||
|
||||
/** @param {NS} ns
|
||||
* @param {string} host
|
||||
* @return {Server & {relHost: string[]}}
|
||||
*/
|
||||
export function getServersInfo(ns: NS, host: string): ServerInfo {
|
||||
const neighbor = ns.scan(host)
|
||||
const info = ns.getServer(host)
|
||||
return { ...info, relHost: neighbor }
|
||||
}
|
27
src/list-all-server.ts
Normal file
27
src/list-all-server.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import {NS} from "@ns"
|
||||
import {getHackability,getLockSymbol} from "./lib/hack";
|
||||
|
||||
/** @param {NS} ns */
|
||||
// eslint-disable-next-line require-await
|
||||
export async function main(ns: NS): Promise<void> {
|
||||
findServer(ns, 'home', 'home', 1);
|
||||
}
|
||||
|
||||
/** @param {NS} ns
|
||||
* @param {string} startServer
|
||||
* @param {string} targetServer
|
||||
* @param {number} depth
|
||||
*/
|
||||
function findServer(ns: NS, startServer: string, targetServer: string, depth: number): void {
|
||||
const servers = ns.scan(targetServer)
|
||||
.filter((server) => server !== startServer);
|
||||
servers.forEach((server) => {
|
||||
const lock = getHackability(ns, server);
|
||||
const lock_symbol = getLockSymbol(lock);
|
||||
const info = ns.getServer(server);
|
||||
ns.tprint(`😹${'>'.repeat(depth)} ${lock_symbol} ${server} ${info.backdoorInstalled ? '✅': '❌'}`);
|
||||
if (lock !== "impossible") {
|
||||
findServer(ns, targetServer, server, depth + 1);
|
||||
}
|
||||
});
|
||||
}
|
13
src/list-purchase-server.ts
Normal file
13
src/list-purchase-server.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import {NS} from "@ns"
|
||||
import {parse} from "lib/flag"
|
||||
|
||||
/** @param {NS} ns */
|
||||
// eslint-disable-next-line require-await
|
||||
export async function main(ns: NS):Promise<void> {
|
||||
const flag = parse(ns.args);
|
||||
if(flag.help || flag.h){
|
||||
ns.tprint(`* list all purchased server`);
|
||||
ns.exit();
|
||||
}
|
||||
ns.tprint(ns.getPurchasedServers().join("\n"));
|
||||
}
|
72
src/purchase-server.ts
Normal file
72
src/purchase-server.ts
Normal file
@ -0,0 +1,72 @@
|
||||
import { NS } from "@ns"
|
||||
import {parse} from "./lib/flag"
|
||||
import {range} from "./util/range";
|
||||
|
||||
|
||||
/** @param {NS} ns */
|
||||
export async function main(ns: NS): Promise<void> {
|
||||
const flag = parse(ns.args);
|
||||
if(flag.h || flag.help){
|
||||
ns.tprint("script : purchase server")
|
||||
ns.tprint("");
|
||||
ns.exit()
|
||||
}
|
||||
if(Boolean(flag.i) || Boolean(flag.interactive)){
|
||||
const ramLimit = ns.getPurchasedServerMaxRam()
|
||||
const choices = [...range(3,20)].map(x=>Math.pow(2,x)).filter(x=>x <= ramLimit).map((x)=>{
|
||||
const cost = ns.getPurchasedServerCost(x);
|
||||
return `${x}GB (${ns.nFormat(cost,"$0.000a")})`
|
||||
});
|
||||
const choice = await ns.prompt("which server do you purchase?",{
|
||||
type:"select",
|
||||
choices
|
||||
});
|
||||
if(choice === ""){
|
||||
ns.tprint("canceled");
|
||||
ns.exit();
|
||||
return;
|
||||
}
|
||||
const gb = parseInt(/^(\d+)GB/.exec(choice)[1]);
|
||||
ns.tprint("you select ",gb,"GB");
|
||||
const hostname = await ns.prompt("name your server",{type:"text"});
|
||||
if(hostname === ""){
|
||||
ns.tprint("canceled");
|
||||
ns.exit();
|
||||
return;
|
||||
}
|
||||
const p = await ns.prompt(
|
||||
`do you want to purchase server ${gb}GB(${
|
||||
ns.nFormat(ns.getPurchasedServerCost(gb),"$0.000a")})?`,
|
||||
{ type: "boolean" });
|
||||
if (p) {
|
||||
const l = ns.purchaseServer(hostname, ram)
|
||||
ns.tprint(l, " purchased");
|
||||
}
|
||||
ns.exit()
|
||||
return;
|
||||
}
|
||||
|
||||
if ((flag.n || flag.name) && (flag.s || flag.size)) {
|
||||
ns.tprint("argument needed")
|
||||
ns.tprint("run cmd -n [hostname] -s [ram(GB)]")
|
||||
ns.tprint("run cmd --name [hostname] --size [ram(GB)]")
|
||||
ns.exit()
|
||||
return;
|
||||
}
|
||||
|
||||
const hostname = flag.n ?? flag.name
|
||||
const ram = parseInt(flag.s ?? flag.size)
|
||||
if(isNaN(ram)){
|
||||
ns.tprint("size must be integer!");
|
||||
ns.exit();
|
||||
return;
|
||||
}
|
||||
const f = ns.getPurchasedServerCost(ram)
|
||||
const ff = ns.nFormat(f, "($ 0.00 a)")
|
||||
const p = await ns.prompt("required : " + ff + "\ndo you want to purchase server " + ram + "GB?",
|
||||
{ type: "boolean" })
|
||||
if (p) {
|
||||
const l = ns.purchaseServer(hostname, ram)
|
||||
ns.tprint(l, " purchased")
|
||||
}
|
||||
}
|
79
src/server-status.ts
Normal file
79
src/server-status.ts
Normal file
@ -0,0 +1,79 @@
|
||||
import {NS} from "@ns";
|
||||
import {hackablePorts, getHackability, getLockSymbol} from "./lib/hack";
|
||||
import {parse} from "./lib/flag";
|
||||
|
||||
|
||||
type ReportOption = {
|
||||
detail?: boolean;
|
||||
}
|
||||
/*
|
||||
* Utility functions that report serverStatus
|
||||
* and Hackability
|
||||
* @param {NS} ns
|
||||
*/
|
||||
// eslint-disable-next-line require-await
|
||||
export async function main(ns: NS): Promise<void> {
|
||||
const flag = parse(ns.args);
|
||||
if (flag._.length == 0) {
|
||||
ns.tprint("argumented required");
|
||||
return;
|
||||
}
|
||||
const hostname = flag._[0];
|
||||
const detail = Boolean(flag.d) || Boolean(flag.detail);
|
||||
serverReport(ns, hostname,{
|
||||
detail: detail,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @param {NS} ns
|
||||
* @param {string} hostname
|
||||
*/
|
||||
export function serverReport(ns: NS, hostname: string, options?:ReportOption):void {
|
||||
options ??= {};
|
||||
const serverLock = getHackability(ns, hostname);
|
||||
ns.tprint(`${getLockSymbol(serverLock)} ${hostname}`);
|
||||
if(options.detail){
|
||||
const server = ns.getServer(hostname);
|
||||
const msg = ['',
|
||||
`hostname : ${server.hostname}(${server.ip})`,
|
||||
`🛡️${ns.nFormat(server.hackDifficulty,"0[.]000")}/${server.minDifficulty}(${server.baseDifficulty})`,
|
||||
`💸${ns.nFormat(server.moneyAvailable,"$0.000a")}/${ns.nFormat(server.moneyMax,"$0.000a")}`,
|
||||
`💾${server.ramUsed}GB/${server.maxRam}GB`,
|
||||
`backdoorInstalled \t: ${server.backdoorInstalled ? `🚪` : `❌`}`,
|
||||
`cpu \t\t\t: ${server.cpuCores}`,
|
||||
`growth \t\t\t: ${server.serverGrowth}`,
|
||||
`organization name\t: ${server.organizationName}`,
|
||||
`purchased \t\t: ${server.purchasedByPlayer}`,
|
||||
`required hacking skill\t: ${server.requiredHackingSkill}`,
|
||||
`ports \t\t\t: ${server.openPortCount}/${server.numOpenPortsRequired}`
|
||||
].join("\n");
|
||||
ns.tprint(msg);
|
||||
}
|
||||
else{
|
||||
if (serverLock == "rooted") {
|
||||
ns.tprint(`🛡️${Math.round(ns.getServerSecurityLevel(hostname))}/${ns.getServerMinSecurityLevel(hostname)}`);
|
||||
ns.tprint(`💸${ns.nFormat(ns.getServerMoneyAvailable(hostname), "$0.000a")}/${ns.nFormat(ns.getServerMaxMoney(hostname), "$0.000a")}`);
|
||||
} else {
|
||||
ns.tprint(`Hack Level: ${ns.getServerRequiredHackingLevel(hostname)}`);
|
||||
ns.tprint(`Ports: ${ns.getServerNumPortsRequired(hostname)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {NS} ns
|
||||
*/
|
||||
export function serverHackStatus(ns: NS, server: string): string {
|
||||
if (ns.hasRootAccess(server)) {
|
||||
return "🔓";
|
||||
}
|
||||
if (ns.getServerRequiredHackingLevel(server) > ns.getHackingLevel() ||
|
||||
ns.getServerNumPortsRequired(server) > hackablePorts(ns)) {
|
||||
return "🔒";
|
||||
}
|
||||
return "🔐";
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export function autocomplete(data : ServerData, args : string[]) : string[] {
|
||||
return [...data.servers]
|
||||
}
|
8
src/share-server.ts
Normal file
8
src/share-server.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import {NS} from "@ns"
|
||||
|
||||
// eslint-disable-next-line require-await
|
||||
export async function main(ns:NS):Promise<void>{
|
||||
while(true){
|
||||
await ns.share()
|
||||
}
|
||||
}
|
14
src/util/assert.ts
Normal file
14
src/util/assert.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import assert from "assert";
|
||||
|
||||
export class AssertionError extends Error{
|
||||
constructor(msg:string){
|
||||
super(msg);
|
||||
this.name = "AssertionError";
|
||||
}
|
||||
}
|
||||
|
||||
export function assert(expr: unknown, msg=""): asserts expr{
|
||||
if(!expr){
|
||||
throw new AssertionError(msg)
|
||||
}
|
||||
}
|
9
src/util/range.ts
Normal file
9
src/util/range.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export function* range(end: number): Generator<number>;
|
||||
export function* range(begin:number,end:number): Generator<number>;
|
||||
export function* range(arg1: number, arg2?: number): Generator<number>{
|
||||
const begin = arg2 ? arg1 : 0;
|
||||
const end = arg2 ?? arg1;
|
||||
for(let i = begin; i<end; i++){
|
||||
yield i;
|
||||
}
|
||||
}
|
@ -6,15 +6,15 @@ export async function main(ns: NS): Promise<void> {
|
||||
const files = ns.ls('home', '.js')
|
||||
for (const file of files) {
|
||||
const contents = ns.read(file)
|
||||
hashes[file] = getHash(contents)
|
||||
hashes[file] = getHash(contents as string)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
const files = ns.ls('home', '.js')
|
||||
|
||||
for (const file of files) {
|
||||
const contents = ns.read(file)
|
||||
const hash = getHash(contents)
|
||||
const hash = getHash(contents as string)
|
||||
|
||||
if (hash != hashes[file]) {
|
||||
ns.tprintf(`INFO: Detected change in ${file}`)
|
||||
|
@ -11,7 +11,6 @@
|
||||
"noImplicitThis": true,
|
||||
"esModuleInterop": true,
|
||||
"inlineSourceMap": true,
|
||||
"sourceRoot": "http://localhost:8000/sources/",
|
||||
"strict": true,
|
||||
"rootDir": "src/",
|
||||
"outDir": "dist/",
|
||||
|
Loading…
Reference in New Issue
Block a user