mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-17 13:13:49 +01:00
CODEBASE: Fix lint errors 1 (#1732)
This commit is contained in:
parent
f7ee3a340f
commit
f6502dd490
@ -34,6 +34,7 @@ module.exports = {
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"react/no-unescaped-entities": "off",
|
||||
"@typescript-eslint/restrict-template-expressions": "off",
|
||||
},
|
||||
settings: {
|
||||
react: {
|
||||
|
17
src/@types/global.d.ts
vendored
17
src/@types/global.d.ts
vendored
@ -31,4 +31,21 @@ declare global {
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* "loader" is not exposed in the public API.
|
||||
*/
|
||||
module "monaco-editor" {
|
||||
namespace languages {
|
||||
interface ILanguageExtensionPoint {
|
||||
loader: () => Promise<{
|
||||
language: {
|
||||
tokenizer: {
|
||||
root: any[];
|
||||
};
|
||||
};
|
||||
}>;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ function sanitizeRewardType(rewardType: CodingContractRewardType): CodingContrac
|
||||
try {
|
||||
return Factions[fac].getInfo().offerHackingWork;
|
||||
} catch (e) {
|
||||
console.error(`Error when trying to filter Hacking Factions for Coding Contract Generation: ${e}`);
|
||||
console.error("Error when trying to filter Hacking Factions for Coding Contract Generation", e);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
@ -207,8 +207,8 @@ export function sellMaterial(material: Material, amount: string, price: string):
|
||||
try {
|
||||
if (temp.includes("MP")) throw "Only one reference to MP is allowed in sell price.";
|
||||
temp = eval?.(temp);
|
||||
} catch (e) {
|
||||
throw new Error("Invalid value or expression for sell price field: " + e);
|
||||
} catch (error) {
|
||||
throw new Error("Invalid value or expression for sell price field", { cause: error });
|
||||
}
|
||||
|
||||
if (temp == null || isNaN(parseFloat(temp))) {
|
||||
@ -231,8 +231,8 @@ export function sellMaterial(material: Material, amount: string, price: string):
|
||||
tempQty = tempQty.replace(/INV/g, material.productionAmount.toString());
|
||||
try {
|
||||
tempQty = eval?.(tempQty);
|
||||
} catch (e) {
|
||||
throw new Error("Invalid value or expression for sell quantity field: " + e);
|
||||
} catch (error) {
|
||||
throw new Error("Invalid value or expression for sell quantity field", { cause: error });
|
||||
}
|
||||
|
||||
if (tempQty == null || isNaN(parseFloat(tempQty))) {
|
||||
@ -263,8 +263,8 @@ export function sellProduct(product: Product, city: CityName, amt: string, price
|
||||
try {
|
||||
if (temp.includes("MP")) throw "Only one reference to MP is allowed in sell price.";
|
||||
temp = eval?.(temp);
|
||||
} catch (e) {
|
||||
throw new Error("Invalid value or expression for sell price field: " + e);
|
||||
} catch (error) {
|
||||
throw new Error("Invalid value or expression for sell price field.", { cause: error });
|
||||
}
|
||||
if (temp == null || isNaN(parseFloat(temp))) {
|
||||
throw new Error("Invalid value or expression for sell price field.");
|
||||
@ -291,8 +291,8 @@ export function sellProduct(product: Product, city: CityName, amt: string, price
|
||||
temp = temp.replace(/INV/g, product.cityData[city].stored.toString());
|
||||
try {
|
||||
temp = eval?.(temp);
|
||||
} catch (e) {
|
||||
throw new Error("Invalid value or expression for sell quantity field: " + e);
|
||||
} catch (error) {
|
||||
throw new Error("Invalid value or expression for sell quantity field", { cause: error });
|
||||
}
|
||||
|
||||
if (temp == null || isNaN(parseFloat(temp))) {
|
||||
@ -585,13 +585,16 @@ Attempted export amount: ${amount}`);
|
||||
}
|
||||
if (!error && isNaN(evaluated)) error = "evaluated value is NaN";
|
||||
if (error) {
|
||||
throw new Error(`Error while trying to set the exported amount of ${material.name}.
|
||||
throw new Error(
|
||||
`Error while trying to set the exported amount of ${material.name}.
|
||||
Error occurred while testing keyword replacement with ${testReplacement}.
|
||||
Your input: ${amount}
|
||||
Sanitized input: ${sanitizedAmt}
|
||||
Input after replacement: ${replaced}
|
||||
Evaluated value: ${evaluated}
|
||||
Error encountered: ${error}`);
|
||||
Evaluated value: ${evaluated}` +
|
||||
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
||||
`Error encountered: ${error}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,8 +29,8 @@ export function ExpandNewCity(props: IProps): React.ReactElement {
|
||||
function expand(): void {
|
||||
try {
|
||||
purchaseOffice(corp, division, city);
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
} catch (error) {
|
||||
dialogBoxCreate(String(error));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -39,8 +39,8 @@ export function NewDivisionTab(props: IProps): React.ReactElement {
|
||||
if (disabledText) return;
|
||||
try {
|
||||
createDivision(corp, industry, name);
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
} catch (error) {
|
||||
dialogBoxCreate(String(error));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -43,8 +43,8 @@ export function BuybackSharesModal(props: IProps): React.ReactElement {
|
||||
props.onClose();
|
||||
props.rerender();
|
||||
setShares(NaN);
|
||||
} catch (err) {
|
||||
dialogBoxCreate(`${err}`);
|
||||
} catch (error) {
|
||||
dialogBoxCreate(String(error));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,8 +59,8 @@ export function ExportModal(props: ExportModalProps): React.ReactElement {
|
||||
try {
|
||||
if (!targetDivision || !targetCity) return;
|
||||
actions.exportMaterial(targetDivision, targetCity, props.mat, exportAmount);
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
} catch (error) {
|
||||
dialogBoxCreate(String(error));
|
||||
}
|
||||
props.onClose();
|
||||
}
|
||||
|
@ -37,8 +37,8 @@ export function FindInvestorsModal(props: IProps): React.ReactElement {
|
||||
);
|
||||
props.onClose();
|
||||
props.rerender();
|
||||
} catch (err) {
|
||||
dialogBoxCreate(`${err}`);
|
||||
} catch (error) {
|
||||
dialogBoxCreate(String(error));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,8 +45,8 @@ export function GoPublicModal(props: IProps): React.ReactElement {
|
||||
props.onClose();
|
||||
props.rerender();
|
||||
setShares(NaN);
|
||||
} catch (err) {
|
||||
dialogBoxCreate(`${err}`);
|
||||
} catch (error) {
|
||||
dialogBoxCreate(String(error));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,8 +27,8 @@ export function IssueDividendsModal(props: IProps): React.ReactElement {
|
||||
if (percent === null) return;
|
||||
try {
|
||||
actions.issueDividends(corp, percent / 100);
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
} catch (error) {
|
||||
dialogBoxCreate(String(error));
|
||||
}
|
||||
|
||||
props.onClose();
|
||||
|
@ -55,8 +55,8 @@ export function IssueNewSharesModal(props: IProps): React.ReactElement {
|
||||
);
|
||||
props.onClose();
|
||||
props.rerender();
|
||||
} catch (err) {
|
||||
dialogBoxCreate(`${err}`);
|
||||
} catch (error) {
|
||||
dialogBoxCreate(String(error));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,8 +47,8 @@ export function MakeProductModal(props: IProps): React.ReactElement {
|
||||
if (isNaN(design) || isNaN(marketing)) return;
|
||||
try {
|
||||
actions.makeProduct(corp, division, city, name, design, marketing);
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
} catch (error) {
|
||||
dialogBoxCreate(String(error));
|
||||
}
|
||||
props.onClose();
|
||||
}
|
||||
|
@ -67,8 +67,8 @@ function BulkPurchaseSection(props: IBPProps): React.ReactElement {
|
||||
function bulkPurchase(): void {
|
||||
try {
|
||||
actions.bulkPurchase(corp, division, props.warehouse, props.mat, parseFloat(buyAmt));
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
} catch (error) {
|
||||
dialogBoxCreate(String(error));
|
||||
}
|
||||
props.onClose();
|
||||
}
|
||||
@ -119,8 +119,8 @@ export function PurchaseMaterialModal(props: IProps): React.ReactElement {
|
||||
if (buyAmt === null) return;
|
||||
try {
|
||||
actions.buyMaterial(division, props.mat, buyAmt);
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
} catch (error) {
|
||||
dialogBoxCreate(String(error));
|
||||
}
|
||||
|
||||
props.onClose();
|
||||
|
@ -39,8 +39,8 @@ function Upgrade({ n, division }: INodeProps): React.ReactElement {
|
||||
if (n === null || disabled) return;
|
||||
try {
|
||||
actions.research(division, n.researchName);
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
} catch (error) {
|
||||
dialogBoxCreate(String(error));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -24,8 +24,8 @@ export function SellMaterialModal(props: IProps): React.ReactElement {
|
||||
function sellMaterial(): void {
|
||||
try {
|
||||
actions.sellMaterial(props.mat, amt, price);
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
} catch (error) {
|
||||
dialogBoxCreate(String(error));
|
||||
}
|
||||
props.onClose();
|
||||
}
|
||||
|
@ -31,8 +31,8 @@ export function SellProductModal(props: IProps): React.ReactElement {
|
||||
function sellProduct(): void {
|
||||
try {
|
||||
actions.sellProduct(props.product, props.city, iQty, px, checked);
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
} catch (error) {
|
||||
dialogBoxCreate(String(error));
|
||||
}
|
||||
|
||||
props.onClose();
|
||||
|
@ -27,8 +27,9 @@ function SSoption(props: ISSoptionProps): React.ReactElement {
|
||||
const matName = props.matName;
|
||||
const material = props.warehouse.materials[matName];
|
||||
setSmartSupplyOption(props.warehouse, material, newValue);
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
} catch (error) {
|
||||
dialogBoxCreate(String(error));
|
||||
return;
|
||||
}
|
||||
setChecked(newValue);
|
||||
}
|
||||
@ -40,8 +41,9 @@ function SSoption(props: ISSoptionProps): React.ReactElement {
|
||||
const matName = props.matName;
|
||||
const material = props.warehouse.materials[matName];
|
||||
setSmartSupplyOption(props.warehouse, material, newValue);
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
} catch (error) {
|
||||
dialogBoxCreate(String(error));
|
||||
return;
|
||||
}
|
||||
setChecked(newValue);
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import { CONSTANTS } from "./Constants";
|
||||
import { commitHash } from "./utils/helpers/commitHash";
|
||||
import { resolveFilePath } from "./Paths/FilePath";
|
||||
import { hasScriptExtension } from "./Paths/ScriptFilePath";
|
||||
import { handleGetSaveDataError } from "./Netscript/ErrorMessages";
|
||||
import { handleGetSaveDataInfoError } from "./Netscript/ErrorMessages";
|
||||
|
||||
interface IReturnWebStatus extends IReturnStatus {
|
||||
data?: Record<string, unknown>;
|
||||
@ -103,14 +103,14 @@ function initAppNotifier(): void {
|
||||
const funcs = {
|
||||
terminal: (message: string, type?: string) => {
|
||||
const typesFn: Record<string, (s: string) => void> = {
|
||||
info: Terminal.info,
|
||||
warn: Terminal.warn,
|
||||
error: Terminal.error,
|
||||
success: Terminal.success,
|
||||
info: (s) => Terminal.info(s),
|
||||
warn: (s) => Terminal.warn(s),
|
||||
error: (s) => Terminal.error(s),
|
||||
success: (s) => Terminal.success(s),
|
||||
};
|
||||
let fn;
|
||||
if (type) fn = typesFn[type];
|
||||
if (!fn) fn = Terminal.print;
|
||||
if (!fn) fn = (s: string) => Terminal.print(s);
|
||||
fn.bind(Terminal)(message);
|
||||
},
|
||||
toast: (message: string, type: ToastVariant, duration = 2000) => SnackbarEvents.emit(message, type, duration),
|
||||
@ -124,12 +124,10 @@ function initSaveFunctions(): void {
|
||||
const funcs = {
|
||||
triggerSave: (): Promise<void> => saveObject.saveGame(true),
|
||||
triggerGameExport: (): void => {
|
||||
try {
|
||||
saveObject.exportGame();
|
||||
} catch (error) {
|
||||
saveObject.exportGame().catch((error) => {
|
||||
console.error(error);
|
||||
SnackbarEvents.emit("Could not export game.", ToastVariant.ERROR, 2000);
|
||||
}
|
||||
});
|
||||
},
|
||||
triggerScriptsExport: (): void => exportScripts("*", Player.getHomeComputer()),
|
||||
getSaveData: async (): Promise<{ save: SaveData; fileName: string }> => {
|
||||
@ -159,22 +157,28 @@ function initElectronBridge(): void {
|
||||
const bridge = window.electronBridge;
|
||||
if (!bridge) return;
|
||||
|
||||
bridge.receive("get-save-data-request", async () => {
|
||||
let saveData;
|
||||
try {
|
||||
saveData = await window.appSaveFns.getSaveData();
|
||||
} catch (error) {
|
||||
handleGetSaveDataError(error);
|
||||
return;
|
||||
}
|
||||
bridge.send("get-save-data-response", saveData);
|
||||
bridge.receive("get-save-data-request", () => {
|
||||
window.appSaveFns
|
||||
.getSaveData()
|
||||
.then((saveData) => {
|
||||
bridge.send("get-save-data-response", saveData);
|
||||
})
|
||||
.catch((error) => {
|
||||
handleGetSaveDataInfoError(error);
|
||||
});
|
||||
});
|
||||
bridge.receive("get-save-info-request", async (saveData: unknown) => {
|
||||
bridge.receive("get-save-info-request", (saveData: unknown) => {
|
||||
if (typeof saveData !== "string" && !(saveData instanceof Uint8Array)) {
|
||||
throw new Error("Error while trying to get save info");
|
||||
}
|
||||
const saveInfo = await window.appSaveFns.getSaveInfo(saveData);
|
||||
bridge.send("get-save-info-response", saveInfo);
|
||||
window.appSaveFns
|
||||
.getSaveInfo(saveData)
|
||||
.then((saveInfo) => {
|
||||
bridge.send("get-save-info-response", saveInfo);
|
||||
})
|
||||
.catch((error) => {
|
||||
handleGetSaveDataInfoError(error, true);
|
||||
});
|
||||
});
|
||||
bridge.receive("push-save-request", (params: unknown) => {
|
||||
if (typeof params !== "object") throw new Error("Error trying to push save request");
|
||||
@ -182,7 +186,7 @@ function initElectronBridge(): void {
|
||||
window.appSaveFns.pushSaveData(save, automatic);
|
||||
});
|
||||
bridge.receive("trigger-save", () => {
|
||||
return window.appSaveFns
|
||||
window.appSaveFns
|
||||
.triggerSave()
|
||||
.then(() => {
|
||||
bridge.send("save-completed");
|
||||
|
@ -97,7 +97,7 @@ function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.Rea
|
||||
startWork();
|
||||
}
|
||||
|
||||
// We have a special flag for whether the player this faction is the player's
|
||||
// We have a special flag for whether this faction is the player's
|
||||
// gang faction because if the player has a gang, they cannot do any other action
|
||||
const isPlayersGang = Player.gang && Player.getGangName() === faction.name;
|
||||
|
||||
|
@ -90,6 +90,7 @@ export const GameOptionsSidebar = (props: IProps): React.ReactElement => {
|
||||
try {
|
||||
await saveObject.importGame(importData.saveData);
|
||||
} catch (e: unknown) {
|
||||
console.error(e);
|
||||
SnackbarEvents.emit(String(e), ToastVariant.ERROR, 5000);
|
||||
}
|
||||
|
||||
|
@ -112,7 +112,7 @@ export class Gang {
|
||||
this.processTerritoryAndPowerGains(cycles);
|
||||
this.storedCycles -= cycles;
|
||||
} catch (e: unknown) {
|
||||
console.error(`Exception caught when processing Gang: ${e}`);
|
||||
console.error("Exception caught when processing Gang", e);
|
||||
}
|
||||
|
||||
// Handle "nextUpdate" resolver after this update
|
||||
|
@ -1,96 +0,0 @@
|
||||
/** @param {NS} ns */
|
||||
export async function main(ns) {
|
||||
let result;
|
||||
|
||||
do {
|
||||
const board = ns.go.getBoardState();
|
||||
const validMoves = ns.go.analysis.getValidMoves();
|
||||
|
||||
const [growX, growY] = getGrowMove(board, validMoves);
|
||||
const [randX, randY] = getRandomMove(board, validMoves);
|
||||
// Try to pick a grow move, otherwise choose a random move
|
||||
const x = growX ?? randX;
|
||||
const y = growY ?? randY;
|
||||
|
||||
if (x === undefined) {
|
||||
// Pass turn if no moves are found
|
||||
result = await ns.go.passTurn();
|
||||
} else {
|
||||
// Play the selected move
|
||||
result = await ns.go.makeMove(x, y);
|
||||
}
|
||||
|
||||
await ns.sleep(100);
|
||||
} while (result?.type !== "gameOver" && result?.type !== "pass");
|
||||
|
||||
// After the opponent passes, end the game by passing as well
|
||||
await ns.go.passTurn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Choose one of the empty points on the board at random to play
|
||||
*/
|
||||
const getRandomMove = (board, validMoves) => {
|
||||
const moveOptions = [];
|
||||
const size = board[0].length;
|
||||
|
||||
// Look through all the points on the board
|
||||
for (let x = 0; x < size; x++) {
|
||||
for (let y = 0; y < size; y++) {
|
||||
// Make sure the point is a valid move
|
||||
const isValidMove = validMoves[x][y];
|
||||
// Leave some spaces to make it harder to capture our pieces
|
||||
const isNotReservedSpace = x % 2 || y % 2;
|
||||
|
||||
if (isValidMove && isNotReservedSpace) {
|
||||
moveOptions.push([x, y]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Choose one of the found moves at random
|
||||
const randomIndex = Math.floor(Math.random() * moveOptions.length);
|
||||
return moveOptions[randomIndex] ?? [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Choose a point connected to a friendly stone to play
|
||||
*/
|
||||
const getGrowMove = (board, validMoves) => {
|
||||
const moveOptions = [];
|
||||
const size = board[0].length;
|
||||
|
||||
// Look through all the points on the board
|
||||
for (let x = 0; x < size; x++) {
|
||||
for (let y = 0; y < size; y++) {
|
||||
// make sure the move is valid
|
||||
const isValidMove = validMoves[x][y];
|
||||
// Leave some open spaces to make it harder to capture our pieces
|
||||
const isNotReservedSpace = x % 2 || y % 2;
|
||||
|
||||
// Make sure we are connected to a friendly piece
|
||||
const neighbors = getNeighbors(board, x, y);
|
||||
const hasFriendlyNeighbor = neighbors.includes("X");
|
||||
|
||||
if (isValidMove && isNotReservedSpace && hasFriendlyNeighbor) {
|
||||
moveOptions.push([x, y]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Choose one of the found moves at random
|
||||
const randomIndex = Math.floor(Math.random() * moveOptions.length);
|
||||
return moveOptions[randomIndex] ?? [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Find all adjacent points in the four connected directions
|
||||
*/
|
||||
const getNeighbors = (board, x, y) => {
|
||||
const north = board[x + 1]?.[y];
|
||||
const east = board[x][y + 1];
|
||||
const south = board[x - 1]?.[y];
|
||||
const west = board[x]?.[y - 1];
|
||||
|
||||
return [north, east, south, west];
|
||||
};
|
@ -20,6 +20,7 @@ import { GoSubnetSearch } from "./GoSubnetSearch";
|
||||
import { CorruptableText } from "../../ui/React/CorruptableText";
|
||||
import { makeAIMove, resetAI, resolveCurrentTurn } from "../boardAnalysis/goAI";
|
||||
import { GoScoreExplanation } from "./GoScoreExplanation";
|
||||
import { exceptionAlert } from "../../utils/helpers/exceptionAlert";
|
||||
|
||||
interface GoGameboardWrapperProps {
|
||||
showInstructions: () => void;
|
||||
@ -63,7 +64,7 @@ export function GoGameboardWrapper({ showInstructions }: GoGameboardWrapperProps
|
||||
|
||||
// Do not implement useCallback for this function without ensuring GoGameboard still rerenders for every move
|
||||
// Currently this function changing is what triggers a GoGameboard rerender, which is needed
|
||||
async function clickHandler(x: number, y: number) {
|
||||
function clickHandler(x: number, y: number) {
|
||||
if (showPriorMove) {
|
||||
SnackbarEvents.emit(
|
||||
`Currently showing a past board state. Please disable "Show previous move" to continue.`,
|
||||
@ -94,7 +95,7 @@ export function GoGameboardWrapper({ showInstructions }: GoGameboardWrapperProps
|
||||
const didUpdateBoard = makeMove(boardState, x, y, currentPlayer);
|
||||
if (didUpdateBoard) {
|
||||
rerender();
|
||||
takeAiTurn(boardState);
|
||||
takeAiTurn(boardState).catch((error) => exceptionAlert(error));
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,7 +114,7 @@ export function GoGameboardWrapper({ showInstructions }: GoGameboardWrapperProps
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
takeAiTurn(boardState);
|
||||
takeAiTurn(boardState).catch((error) => exceptionAlert(error));
|
||||
}, 100);
|
||||
}
|
||||
|
||||
|
@ -99,13 +99,13 @@ export function handleUnknownError(e: unknown, ws: WorkerScript | null = null, i
|
||||
Error has been logged to the console.\n\nType of error: ${typeof e}\nValue of error: ${e}`;
|
||||
e = ws ? basicErrorMessage(ws, msg, "UNKNOWN") : msg;
|
||||
}
|
||||
dialogBoxCreate(initialText + e);
|
||||
dialogBoxCreate(initialText + String(e));
|
||||
}
|
||||
|
||||
/** Use this handler to handle the error when we call getSaveData function */
|
||||
export function handleGetSaveDataError(error: unknown) {
|
||||
/** Use this handler to handle the error when we call getSaveData function or getSaveInfo function */
|
||||
export function handleGetSaveDataInfoError(error: unknown, fromGetSaveInfo = false) {
|
||||
console.error(error);
|
||||
let errorMessage = `Cannot get save data. Error: ${error}.`;
|
||||
let errorMessage = `Cannot get save ${fromGetSaveInfo ? "info" : "data"}. Error: ${error}.`;
|
||||
if (error instanceof RangeError) {
|
||||
errorMessage += " This may be because the save data is too large.";
|
||||
}
|
||||
|
@ -232,7 +232,7 @@ function spawnOptions(ctx: NetscriptContext, threadOrOption: unknown): CompleteS
|
||||
function mapToString(map: Map<unknown, unknown>): string {
|
||||
const formattedMap = [...map]
|
||||
.map((m) => {
|
||||
return `${m[0]} => ${m[1]}`;
|
||||
return `${String(m[0])} => ${String(m[1])}`;
|
||||
})
|
||||
.join("; ");
|
||||
return `< Map: ${formattedMap} >`;
|
||||
@ -245,7 +245,7 @@ function setToString(set: Set<unknown>): string {
|
||||
/** Convert multiple arguments for tprint or print into a single string. */
|
||||
function argsToString(args: unknown[]): string {
|
||||
// Reduce array of args into a single output string
|
||||
return args.reduce((out, arg) => {
|
||||
return args.reduce((out: string, arg) => {
|
||||
if (arg === null) {
|
||||
return (out += "null");
|
||||
}
|
||||
@ -264,12 +264,13 @@ function argsToString(args: unknown[]): string {
|
||||
return (out += setToString(nativeArg));
|
||||
}
|
||||
if (typeof nativeArg === "object") {
|
||||
return (out += JSON.stringify(nativeArg, (_, value) => {
|
||||
return (out += JSON.stringify(nativeArg, (_, value: unknown) => {
|
||||
/**
|
||||
* If the property is a promise, we will return a string that clearly states that it's a promise object, not a
|
||||
* normal object. If we don't do that, all promises will be serialized into "{}".
|
||||
*/
|
||||
if (value instanceof Promise) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-base-to-string -- "[object Promise]" is exactly the string that we want.
|
||||
return value.toString();
|
||||
}
|
||||
if (value instanceof Map) {
|
||||
@ -282,8 +283,8 @@ function argsToString(args: unknown[]): string {
|
||||
}));
|
||||
}
|
||||
|
||||
return (out += `${nativeArg}`);
|
||||
}, "") as string;
|
||||
return (out += String(nativeArg));
|
||||
}, "");
|
||||
}
|
||||
|
||||
function validateHGWOptions(ctx: NetscriptContext, opts: unknown): CompleteHGWOptions {
|
||||
@ -296,6 +297,7 @@ function validateHGWOptions(ctx: NetscriptContext, opts: unknown): CompleteHGWOp
|
||||
return result;
|
||||
}
|
||||
if (typeof opts !== "object") {
|
||||
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
||||
throw errorMessage(ctx, `BasicHGWOptions must be an object if specified, was ${opts}`);
|
||||
}
|
||||
// Safe assertion since threadOrOption type has been narrowed to a non-null object
|
||||
@ -723,7 +725,7 @@ function createPublicRunningScript(runningScript: RunningScript, workerScript?:
|
||||
args: runningScript.args.slice(),
|
||||
dynamicRamUsage: workerScript && roundToTwo(workerScript.dynamicRamUsage),
|
||||
filename: runningScript.filename,
|
||||
logs: runningScript.logs.map((x) => "" + x),
|
||||
logs: runningScript.logs.map((x) => String(x)),
|
||||
offlineExpGained: runningScript.offlineExpGained,
|
||||
offlineMoneyMade: runningScript.offlineMoneyMade,
|
||||
offlineRunningTime: runningScript.offlineRunningTime,
|
||||
@ -782,13 +784,21 @@ function validateBitNodeOptions(ctx: NetscriptContext, bitNodeOptions: unknown):
|
||||
return result;
|
||||
}
|
||||
if (typeof bitNodeOptions !== "object") {
|
||||
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
||||
throw errorMessage(ctx, `bitNodeOptions must be an object if it's specified. It was ${bitNodeOptions}.`);
|
||||
}
|
||||
const options = bitNodeOptions as Unknownify<BitNodeOptions>;
|
||||
if (!(options.sourceFileOverrides instanceof Map)) {
|
||||
throw errorMessage(ctx, `sourceFileOverrides must be a Map.`);
|
||||
}
|
||||
const validationResultForSourceFileOverrides = validateSourceFileOverrides(options.sourceFileOverrides, true);
|
||||
const validationResultForSourceFileOverrides = validateSourceFileOverrides(
|
||||
/**
|
||||
* Cast the type from Map<any, any> to Map<number, number> to satisfy the lint rule. The validation logic in
|
||||
* validateSourceFileOverrides will check the data.
|
||||
*/
|
||||
options.sourceFileOverrides as Map<number, number>,
|
||||
true,
|
||||
);
|
||||
if (!validationResultForSourceFileOverrides.valid) {
|
||||
throw errorMessage(
|
||||
ctx,
|
||||
|
@ -542,7 +542,7 @@ export const ns: InternalAPI<NSFull> = {
|
||||
return [] as string[];
|
||||
}
|
||||
|
||||
return runningScriptObj.logs.map((x) => "" + x);
|
||||
return runningScriptObj.logs.map((x) => String(x));
|
||||
},
|
||||
tail:
|
||||
(ctx) =>
|
||||
@ -1870,7 +1870,7 @@ function getFunctionNames(obj: object, prefix: string): string[] {
|
||||
} else if (typeof value === "function") {
|
||||
functionNames.push(prefix + key);
|
||||
} else if (typeof value === "object") {
|
||||
functionNames.push(...getFunctionNames(value, `${prefix}${key}.`));
|
||||
functionNames.push(...getFunctionNames(value as object, `${prefix}${key}.`));
|
||||
}
|
||||
}
|
||||
return functionNames;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type { Singularity as ISingularity, Task as ITask } from "@nsdefs";
|
||||
import type { Singularity as ISingularity } from "@nsdefs";
|
||||
|
||||
import { Player } from "@player";
|
||||
import { AugmentationName, CityName, FactionWorkType, GymType, LocationName, UniversityClassType } from "@enums";
|
||||
@ -1142,7 +1142,7 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
|
||||
? resolveScriptFilePath(helpers.string(ctx, "cbScript", _cbScript), ctx.workerScript.name)
|
||||
: false;
|
||||
if (cbScript === null) {
|
||||
throw helpers.errorMessage(ctx, `Could not resolve file path: ${_cbScript}`);
|
||||
throw helpers.errorMessage(ctx, `Could not resolve file path. callbackScript is null.`);
|
||||
}
|
||||
enterBitNode(true, Player.bitNodeN, nextBN, helpers.validateBitNodeOptions(ctx, _bitNodeOptions));
|
||||
if (cbScript) {
|
||||
@ -1159,7 +1159,7 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
|
||||
? resolveScriptFilePath(helpers.string(ctx, "cbScript", _cbScript), ctx.workerScript.name)
|
||||
: false;
|
||||
if (cbScript === null) {
|
||||
throw helpers.errorMessage(ctx, `Could not resolve file path: ${_cbScript}`);
|
||||
throw helpers.errorMessage(ctx, `Could not resolve file path. callbackScript is null.`);
|
||||
}
|
||||
|
||||
const wd = GetServer(SpecialServers.WorldDaemon);
|
||||
@ -1194,7 +1194,7 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
|
||||
getCurrentWork: (ctx) => () => {
|
||||
helpers.checkSingularityAccess(ctx);
|
||||
if (!Player.currentWork) return null;
|
||||
return Player.currentWork.APICopy() as ITask;
|
||||
return Player.currentWork.APICopy();
|
||||
},
|
||||
exportGame: (ctx) => () => {
|
||||
helpers.checkSingularityAccess(ctx);
|
||||
|
@ -30,7 +30,7 @@ function makeScriptBlob(code: string): Blob {
|
||||
// config object to provide a hook point.
|
||||
export const config = {
|
||||
doImport(url: ScriptURL): Promise<ScriptModule> {
|
||||
return import(/*webpackIgnore:true*/ url);
|
||||
return import(/*webpackIgnore:true*/ url) as Promise<ScriptModule>;
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -36,9 +36,9 @@ export function getGangFaction(this: PlayerObject): Faction {
|
||||
return fac;
|
||||
}
|
||||
|
||||
export function getGangName(this: PlayerObject): string {
|
||||
export function getGangName(this: PlayerObject): FactionName | null {
|
||||
const gang = this.gang;
|
||||
return gang ? gang.facName : "";
|
||||
return gang ? gang.facName : null;
|
||||
}
|
||||
|
||||
export function hasGangWith(this: PlayerObject, facName: FactionName): boolean {
|
||||
|
@ -302,7 +302,7 @@ export function applyForJob(
|
||||
}
|
||||
|
||||
if (!company.hasPosition(pos)) {
|
||||
console.error(`Company ${company.name} does not have position ${pos}. Player.applyToCompany() failed.`);
|
||||
console.error(`Company ${company.name} does not have position ${pos.name}. Player.applyToCompany() failed.`);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ export function setPlayer(playerObj: PlayerObject): void {
|
||||
}
|
||||
|
||||
export function loadPlayer(saveString: string): PlayerObject {
|
||||
const player = JSON.parse(saveString, Reviver);
|
||||
const player = JSON.parse(saveString, Reviver) as PlayerObject;
|
||||
player.money = parseFloat(player.money + "");
|
||||
player.exploits = sanitizeExploits(player.exploits);
|
||||
return player;
|
||||
|
@ -18,7 +18,7 @@ function error(errorMsg: string, { id }: RFAMessage): RFAMessage {
|
||||
return new RFAMessage({ error: errorMsg, id: id });
|
||||
}
|
||||
|
||||
export const RFARequestHandler: Record<string, (message: RFAMessage) => void | RFAMessage> = {
|
||||
export const RFARequestHandler: Record<string, (message: RFAMessage) => RFAMessage> = {
|
||||
pushFile: function (msg: RFAMessage): RFAMessage {
|
||||
if (!isFileData(msg.params)) return error("Misses parameters", msg);
|
||||
|
||||
|
@ -40,7 +40,7 @@ export class Remote {
|
||||
}
|
||||
|
||||
function handleMessageEvent(this: WebSocket, e: MessageEvent): void {
|
||||
const msg: RFAMessage = JSON.parse(e.data);
|
||||
const msg = JSON.parse(e.data as string) as RFAMessage;
|
||||
|
||||
if (!msg.method || !RFARequestHandler[msg.method]) {
|
||||
const response = new RFAMessage({ error: "Unknown message received", id: msg.id });
|
||||
|
@ -44,7 +44,7 @@ import { isBinaryFormat } from "../electron/saveDataBinaryFormat";
|
||||
import { downloadContentAsFile } from "./utils/FileUtils";
|
||||
import { showAPIBreaks } from "./utils/APIBreaks/APIBreak";
|
||||
import { breakInfos261 } from "./utils/APIBreaks/2.6.1";
|
||||
import { handleGetSaveDataError } from "./Netscript/ErrorMessages";
|
||||
import { handleGetSaveDataInfoError } from "./Netscript/ErrorMessages";
|
||||
|
||||
/* SaveObject.js
|
||||
* Defines the object used to save/load games
|
||||
@ -130,7 +130,7 @@ class BitburnerSaveObject {
|
||||
try {
|
||||
saveData = await this.getSaveData();
|
||||
} catch (error) {
|
||||
handleGetSaveDataError(error);
|
||||
handleGetSaveDataInfoError(error);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
@ -170,7 +170,7 @@ class BitburnerSaveObject {
|
||||
try {
|
||||
saveData = await this.getSaveData();
|
||||
} catch (error) {
|
||||
handleGetSaveDataError(error);
|
||||
handleGetSaveDataInfoError(error);
|
||||
return;
|
||||
}
|
||||
const filename = this.getSaveFileName();
|
||||
@ -698,9 +698,12 @@ function evaluateVersionCompatibility(ver: string | number): void {
|
||||
} catch (e) {
|
||||
anyExportsFailed = true;
|
||||
// We just need the text error, not a full stack trace
|
||||
console.error(`Failed to load export of material ${material.name} (${division.name} ${warehouse.city})
|
||||
console.error(
|
||||
`Failed to load export of material ${material.name} (${division.name} ${warehouse.city})
|
||||
Original export details: ${JSON.stringify(originalExport)}
|
||||
Error: ${e}`);
|
||||
Error: ${e}`,
|
||||
e,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -805,16 +808,16 @@ async function loadGame(saveData: SaveData): Promise<boolean> {
|
||||
if (Object.hasOwn(saveObj, "LastExportBonus")) {
|
||||
try {
|
||||
ExportBonus.setLastExportBonus(JSON.parse(saveObj.LastExportBonus));
|
||||
} catch (err) {
|
||||
} catch (error) {
|
||||
ExportBonus.setLastExportBonus(new Date().getTime());
|
||||
console.error("ERROR: Failed to parse last export bonus Settings " + err);
|
||||
console.error(`ERROR: Failed to parse last export bonus setting. Error: ${error}.`, error);
|
||||
}
|
||||
}
|
||||
if (Player.gang && Object.hasOwn(saveObj, "AllGangsSave")) {
|
||||
try {
|
||||
loadAllGangs(saveObj.AllGangsSave);
|
||||
} catch (e) {
|
||||
console.error("ERROR: Failed to parse AllGangsSave: " + e);
|
||||
} catch (error) {
|
||||
console.error(`ERROR: Failed to parse AllGangsSave. Error: ${error}.`, error);
|
||||
}
|
||||
}
|
||||
if (Object.hasOwn(saveObj, "VersionSave")) {
|
||||
|
@ -106,7 +106,7 @@ export class RunningScript {
|
||||
|
||||
let logEntry = txt;
|
||||
if (Settings.TimestampsFormat && typeof txt === "string") {
|
||||
logEntry = "[" + formatTime(Settings.TimestampsFormat) + "] " + logEntry;
|
||||
logEntry = `[${formatTime(Settings.TimestampsFormat)}] ${txt}`;
|
||||
}
|
||||
|
||||
this.logs.push(logEntry);
|
||||
|
@ -14,6 +14,7 @@ import { NetscriptExtra } from "../NetscriptFunctions/Extra";
|
||||
import * as enums from "../Enums";
|
||||
import { ns } from "../NetscriptFunctions";
|
||||
import { isLegacyScript } from "../Paths/ScriptFilePath";
|
||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||
|
||||
/** Event emitter used for tracking when changes have been made to a content file. */
|
||||
export const fileEditEvents = new EventEmitter<[hostname: string, filename: ContentFilePath]>();
|
||||
@ -36,7 +37,9 @@ export class ScriptEditor {
|
||||
for (const [apiKey, apiValue] of Object.entries(apiLayer)) {
|
||||
if (apiLayer === api && apiKey in hiddenAPI) continue;
|
||||
apiKeys.push(apiKey);
|
||||
if (typeof apiValue === "object") populate(apiValue);
|
||||
if (typeof apiValue === "object") {
|
||||
populate(apiValue as object);
|
||||
}
|
||||
}
|
||||
}
|
||||
populate();
|
||||
@ -44,23 +47,25 @@ export class ScriptEditor {
|
||||
(async function () {
|
||||
// We have to improve the default js language otherwise theme sucks
|
||||
const jsLanguage = monaco.languages.getLanguages().find((l) => l.id === "javascript");
|
||||
// Unsupported function is not exposed in monaco public API.
|
||||
const l = await (jsLanguage as any).loader();
|
||||
if (!jsLanguage) {
|
||||
return;
|
||||
}
|
||||
const loader = await jsLanguage.loader();
|
||||
// replaced the bare tokens with regexes surrounded by \b, e.g. \b{token}\b which matches a word-break on either side
|
||||
// this prevents the highlighter from highlighting pieces of variables that start with a reserved token name
|
||||
l.language.tokenizer.root.unshift([new RegExp("\\bns\\b"), { token: "ns" }]);
|
||||
loader.language.tokenizer.root.unshift([new RegExp("\\bns\\b"), { token: "ns" }]);
|
||||
for (const symbol of apiKeys)
|
||||
l.language.tokenizer.root.unshift([new RegExp(`\\b${symbol}\\b`), { token: "netscriptfunction" }]);
|
||||
loader.language.tokenizer.root.unshift([new RegExp(`\\b${symbol}\\b`), { token: "netscriptfunction" }]);
|
||||
const otherKeywords = ["let", "const", "var", "function", "arguments"];
|
||||
const otherKeyvars = ["true", "false", "null", "undefined"];
|
||||
otherKeywords.forEach((k) =>
|
||||
l.language.tokenizer.root.unshift([new RegExp(`\\b${k}\\b`), { token: "otherkeywords" }]),
|
||||
loader.language.tokenizer.root.unshift([new RegExp(`\\b${k}\\b`), { token: "otherkeywords" }]),
|
||||
);
|
||||
otherKeyvars.forEach((k) =>
|
||||
l.language.tokenizer.root.unshift([new RegExp(`\\b${k}\\b`), { token: "otherkeyvars" }]),
|
||||
loader.language.tokenizer.root.unshift([new RegExp(`\\b${k}\\b`), { token: "otherkeyvars" }]),
|
||||
);
|
||||
l.language.tokenizer.root.unshift([new RegExp("\\bthis\\b"), { token: "this" }]);
|
||||
})();
|
||||
loader.language.tokenizer.root.unshift([new RegExp("\\bthis\\b"), { token: "this" }]);
|
||||
})().catch((e) => exceptionAlert(e));
|
||||
|
||||
// Add ts definitions for API
|
||||
const source = netscriptDefinitions.replace(/export /g, "");
|
||||
@ -112,16 +117,20 @@ export class ScriptEditor {
|
||||
// returns a reject promise if the language worker is not loaded yet, so we wait to
|
||||
// call it until the language gets loaded.
|
||||
const languageWorker = new Promise<(...uris: monaco.Uri[]) => unknown>((resolve) =>
|
||||
monaco.languages.onLanguage(language, () => getLanguageWorker().then(resolve)),
|
||||
monaco.languages.onLanguage(language, () => {
|
||||
getLanguageWorker()
|
||||
.then(resolve)
|
||||
.catch((error) => exceptionAlert(error));
|
||||
}),
|
||||
);
|
||||
// Whenever a model is created, arange for it synced to the language server.
|
||||
// Whenever a model is created, arrange for it to be synced to the language server.
|
||||
monaco.editor.onDidCreateModel((model) => {
|
||||
if (language === "typescript" && isLegacyScript(model.uri.path)) {
|
||||
// Don't sync legacy scripts to typescript worker.
|
||||
return;
|
||||
}
|
||||
if (["javascript", "typescript"].includes(model.getLanguageId())) {
|
||||
languageWorker.then((cb) => cb(model.uri));
|
||||
languageWorker.then((resolve) => resolve(model.uri)).catch((error) => exceptionAlert(error));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ import { useCallback } from "react";
|
||||
import { type AST, getFileType, parseAST } from "../../utils/ScriptTransformer";
|
||||
import { RamCalculationErrorCode } from "../../Script/RamCalculationErrorCodes";
|
||||
import { hasScriptExtension, isLegacyScript } from "../../Paths/ScriptFilePath";
|
||||
import { exceptionAlert } from "../../utils/helpers/exceptionAlert";
|
||||
|
||||
interface IProps {
|
||||
// Map of filename -> code
|
||||
@ -105,7 +106,9 @@ function Root(props: IProps): React.ReactElement {
|
||||
const server = GetServer(currentScript.hostname);
|
||||
if (server === null) throw new Error("Server should not be null but it is.");
|
||||
server.writeToContentFile(currentScript.path, currentScript.code);
|
||||
if (Settings.SaveGameOnFileSave) saveObject.saveGame();
|
||||
if (Settings.SaveGameOnFileSave) {
|
||||
saveObject.saveGame().catch((error) => exceptionAlert(error));
|
||||
}
|
||||
rerender();
|
||||
}, [rerender]);
|
||||
|
||||
@ -285,7 +288,9 @@ function Root(props: IProps): React.ReactElement {
|
||||
if (!server) throw new Error("Server should not be null but it is.");
|
||||
// This server helper already handles overwriting, etc.
|
||||
server.writeToContentFile(scriptToSave.path, scriptToSave.code);
|
||||
if (Settings.SaveGameOnFileSave) saveObject.saveGame();
|
||||
if (Settings.SaveGameOnFileSave) {
|
||||
saveObject.saveGame().catch((error) => exceptionAlert(error));
|
||||
}
|
||||
}
|
||||
|
||||
function currentTabIndex(): number | undefined {
|
||||
|
@ -35,7 +35,10 @@ export function Toolbar({ editor, onSave }: IProps) {
|
||||
const [optionsOpen, { on: openOptions, off: closeOptions }] = useBoolean(false);
|
||||
|
||||
function beautify(): void {
|
||||
editor?.getAction("editor.action.formatDocument")?.run();
|
||||
editor
|
||||
?.getAction("editor.action.formatDocument")
|
||||
?.run()
|
||||
.catch((error) => console.error(error));
|
||||
}
|
||||
|
||||
const { ram, ramEntries, isUpdatingRAM, options, saveOptions } = useScriptEditorContext();
|
||||
|
@ -218,7 +218,7 @@ export function makeTheme(theme: IScriptEditorTheme): editor.IStandaloneThemeDat
|
||||
return { base: theme.base, inherit: theme.inherit, rules: themeRules, colors: themeColors };
|
||||
}
|
||||
|
||||
export async function loadThemes(defineTheme: DefineThemeFn): Promise<void> {
|
||||
export function loadThemes(defineTheme: DefineThemeFn): void {
|
||||
defineTheme("monokai", {
|
||||
base: "vs-dark",
|
||||
inherit: true,
|
||||
|
@ -157,7 +157,12 @@ export const Settings = {
|
||||
disableSuffixes: false,
|
||||
|
||||
load(saveString: string) {
|
||||
const save = JSON.parse(saveString);
|
||||
const save = JSON.parse(saveString) as {
|
||||
theme?: typeof Settings.theme;
|
||||
styles?: typeof Settings.styles;
|
||||
overview?: typeof Settings.overview;
|
||||
EditorTheme?: typeof Settings.EditorTheme;
|
||||
};
|
||||
save.theme && Object.assign(Settings.theme, save.theme);
|
||||
save.styles && Object.assign(Settings.styles, save.styles);
|
||||
save.overview && Object.assign(Settings.overview, save.overview);
|
||||
|
@ -50,7 +50,7 @@ export function buyStock(
|
||||
}
|
||||
if (stock == null || isNaN(shares)) {
|
||||
if (ctx) {
|
||||
helpers.log(ctx, () => `Invalid arguments: stock='${stock}' shares='${shares}'`);
|
||||
helpers.log(ctx, () => `Invalid arguments: stock='${stock?.name}' shares='${shares}'`);
|
||||
} else if (opts.suppressDialog !== true) {
|
||||
dialogBoxCreate("Failed to buy stock. This may be a bug, contact developer");
|
||||
}
|
||||
@ -145,7 +145,7 @@ export function sellStock(
|
||||
// Sanitize/Validate arguments
|
||||
if (stock == null || shares < 0 || isNaN(shares)) {
|
||||
if (ctx) {
|
||||
helpers.log(ctx, () => `Invalid arguments: stock='${stock}' shares='${shares}'`);
|
||||
helpers.log(ctx, () => `Invalid arguments: stock='${stock?.name}' shares='${shares}'`);
|
||||
} else if (opts.suppressDialog !== true) {
|
||||
dialogBoxCreate(
|
||||
"Failed to sell stock. This is probably due to an invalid quantity. Otherwise, this may be a bug, contact developer",
|
||||
@ -225,7 +225,7 @@ export function shortStock(
|
||||
}
|
||||
if (stock == null || isNaN(shares)) {
|
||||
if (ctx) {
|
||||
helpers.log(ctx, () => `Invalid arguments: stock='${stock}' shares='${shares}'`);
|
||||
helpers.log(ctx, () => `Invalid arguments: stock='${stock?.name}' shares='${shares}'`);
|
||||
} else if (opts.suppressDialog !== true) {
|
||||
dialogBoxCreate(
|
||||
"Failed to initiate a short position in a stock. This is probably " +
|
||||
@ -321,7 +321,7 @@ export function sellShort(
|
||||
): boolean {
|
||||
if (stock == null || isNaN(shares) || shares < 0) {
|
||||
if (ctx) {
|
||||
helpers.log(ctx, () => `Invalid arguments: stock='${stock}' shares='${shares}'`);
|
||||
helpers.log(ctx, () => `Invalid arguments: stock='${stock?.name}' shares='${shares}'`);
|
||||
} else if (!opts.suppressDialog) {
|
||||
dialogBoxCreate(
|
||||
"Failed to sell a short position in a stock. This is probably " +
|
||||
|
@ -20,7 +20,13 @@ export function exportScripts(pattern: string, server: BaseServer, currDir = roo
|
||||
const filename = `bitburner${
|
||||
hasScriptExtension(pattern) ? "Scripts" : pattern.endsWith(".txt") ? "Texts" : "Files"
|
||||
}.zip`;
|
||||
zip.generateAsync({ type: "blob" }).then((content: Blob) => downloadContentAsFile(content, filename));
|
||||
zip
|
||||
.generateAsync({ type: "blob" })
|
||||
.then((content: Blob) => downloadContentAsFile(content, filename))
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
Terminal.error(`Cannot compress scripts with pattern ${pattern} on ${server.hostname}. Error: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
export function download(args: (string | number | boolean)[], server: BaseServer): void {
|
||||
@ -33,9 +39,10 @@ export function download(args: (string | number | boolean)[], server: BaseServer
|
||||
try {
|
||||
exportScripts(pattern, server, Terminal.currDir);
|
||||
return;
|
||||
} catch (e: any) {
|
||||
const msg = String(e?.message ?? e);
|
||||
return Terminal.error(msg);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Terminal.error(`Cannot export scripts with pattern ${pattern} on ${server.hostname}. Error: ${error}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
const path = Terminal.getFilepath(pattern);
|
||||
|
@ -383,13 +383,19 @@ function writeToTerminal(
|
||||
if (options.isVerbose) Terminal.print(verboseInfo);
|
||||
}
|
||||
|
||||
function checkOutFile(outFileStr: string, options: Options, server: BaseServer): ContentFilePath | void {
|
||||
if (!outFileStr) return;
|
||||
function checkOutFile(outFileStr: string, options: Options, server: BaseServer): ContentFilePath | null {
|
||||
if (!outFileStr) {
|
||||
return null;
|
||||
}
|
||||
const outFilePath = Terminal.getFilepath(outFileStr);
|
||||
if (!outFilePath || !hasTextExtension(outFilePath)) {
|
||||
return Terminal.error(ERR.badOutFile(outFileStr));
|
||||
Terminal.error(ERR.badOutFile(outFileStr));
|
||||
return null;
|
||||
}
|
||||
if (!options.isOverWrite && server.textFiles.has(outFilePath)) {
|
||||
Terminal.error(ERR.outFileExists(outFileStr));
|
||||
return null;
|
||||
}
|
||||
if (!options.isOverWrite && server.textFiles.has(outFilePath)) return Terminal.error(ERR.outFileExists(outFileStr));
|
||||
return outFilePath;
|
||||
}
|
||||
|
||||
@ -433,7 +439,8 @@ export function grep(args: (string | number | boolean)[], server: BaseServer): v
|
||||
if (options.isPipeIn) files.length = 0;
|
||||
if (!options.isQuiet) writeToTerminal(prettyResult, options, results, files, pattern);
|
||||
if (params.outfile && outFilePath) server.writeToContentFile(outFilePath, rawResult.join("\n"));
|
||||
} catch (e) {
|
||||
Terminal.error("grep processing error: " + e);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Terminal.error(`grep processing error: ${error}`);
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,8 @@ export function kill(args: (string | number | boolean)[], server: BaseServer): v
|
||||
if (killed >= 5) {
|
||||
Terminal.print(`... killed ${killed} instances total`);
|
||||
}
|
||||
} catch (e) {
|
||||
Terminal.error(e + "");
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Terminal.error(String(error));
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,8 @@ export function mem(args: (string | number | boolean)[], server: BaseServer): vo
|
||||
// Let's warn the user that he might need to save his script again to generate the detailed entries
|
||||
Terminal.warn("You might have to open & save this script to see the detailed RAM usage information.");
|
||||
}
|
||||
} catch (e) {
|
||||
Terminal.error(e + "");
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Terminal.error(String(error));
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,10 @@ export function run(args: (string | number | boolean)[], server: BaseServer): vo
|
||||
if (hasScriptExtension(path)) {
|
||||
return runScript(path, args, server);
|
||||
} else if (hasContractExtension(path)) {
|
||||
Terminal.runContract(path);
|
||||
Terminal.runContract(path).catch((error) => {
|
||||
console.error(error);
|
||||
Terminal.error(`Cannot run contract ${path} on ${server.hostname}. Error: ${error}.`);
|
||||
});
|
||||
return;
|
||||
} else if (hasProgramExtension(path)) {
|
||||
return runProgram(path, args, server);
|
||||
|
@ -25,7 +25,7 @@ export function runScript(path: ScriptFilePath, commandArgs: (string | number |
|
||||
argv: commandArgs,
|
||||
});
|
||||
} catch (error) {
|
||||
Terminal.error(`Invalid arguments. ${String(error)}.`);
|
||||
Terminal.error(`Invalid arguments. ${error}.`);
|
||||
return;
|
||||
}
|
||||
const tailFlag = flags["--tail"] === true;
|
||||
|
@ -32,7 +32,8 @@ export function tail(commandArray: (string | number | boolean)[], server: BaseSe
|
||||
}
|
||||
LogBoxEvents.emit(runningScript);
|
||||
}
|
||||
} catch (e) {
|
||||
Terminal.error(e + "");
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
Terminal.error(String(error));
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ function getDB(): Promise<IDBObjectStore> {
|
||||
export function load(): Promise<SaveData> {
|
||||
return getDB().then((db) => {
|
||||
return new Promise<SaveData>((resolve, reject) => {
|
||||
const request: IDBRequest<SaveData> = db.get("save");
|
||||
const request = db.get("save") as IDBRequest<SaveData>;
|
||||
request.onerror = function (this: IDBRequest<SaveData>) {
|
||||
reject(new Error("Error in Database request to get save data", { cause: this.error }));
|
||||
};
|
||||
|
@ -237,7 +237,7 @@ const Engine: {
|
||||
Engine.Counters.autoSaveCounter = 60 * 5; // Let's check back in a bit
|
||||
} else {
|
||||
Engine.Counters.autoSaveCounter = Settings.AutosaveInterval * 5;
|
||||
saveObject.saveGame(!Settings.SuppressSavedGameToast);
|
||||
saveObject.saveGame(!Settings.SuppressSavedGameToast).catch((error) => console.error(error));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -75,6 +75,7 @@ import { HistoryProvider } from "./React/Documentation";
|
||||
import { GoRoot } from "../Go/ui/GoRoot";
|
||||
import { Settings } from "../Settings/Settings";
|
||||
import { isBitNodeFinished } from "../BitNode/BitNodeUtils";
|
||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||
|
||||
const htmlLocation = location;
|
||||
|
||||
@ -154,8 +155,14 @@ export function GameRoot(): React.ReactElement {
|
||||
for (const server of GetAllServers()) {
|
||||
server.runningScriptMap.clear();
|
||||
}
|
||||
saveObject.saveGame();
|
||||
setTimeout(() => htmlLocation.reload(), 2000);
|
||||
saveObject
|
||||
.saveGame()
|
||||
.then(() => {
|
||||
setTimeout(() => htmlLocation.reload(), 2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
exceptionAlert(error);
|
||||
});
|
||||
}
|
||||
|
||||
function attemptedForbiddenRouting(name: string) {
|
||||
@ -333,11 +340,13 @@ export function GameRoot(): React.ReactElement {
|
||||
case Page.Options: {
|
||||
mainPage = (
|
||||
<GameOptionsRoot
|
||||
save={() => saveObject.saveGame()}
|
||||
save={() => {
|
||||
saveObject.saveGame().catch((error) => exceptionAlert(error));
|
||||
}}
|
||||
export={() => {
|
||||
// Apply the export bonus before saving the game
|
||||
onExport();
|
||||
saveObject.exportGame();
|
||||
saveObject.exportGame().catch((error) => exceptionAlert(error));
|
||||
}}
|
||||
forceKill={killAllScripts}
|
||||
softReset={softReset}
|
||||
@ -356,7 +365,7 @@ export function GameRoot(): React.ReactElement {
|
||||
exportGameFn={() => {
|
||||
// Apply the export bonus before saving the game
|
||||
onExport();
|
||||
saveObject.exportGame();
|
||||
saveObject.exportGame().catch((error) => exceptionAlert(error));
|
||||
}}
|
||||
installAugmentationsFn={() => {
|
||||
installAugmentations();
|
||||
@ -395,7 +404,9 @@ export function GameRoot(): React.ReactElement {
|
||||
!ITutorial.isRunning ? (
|
||||
<CharacterOverview
|
||||
parentOpen={parentOpen}
|
||||
save={() => saveObject.saveGame()}
|
||||
save={() => {
|
||||
saveObject.saveGame().catch((error) => exceptionAlert(error));
|
||||
}}
|
||||
killScripts={killAllScripts}
|
||||
/>
|
||||
) : (
|
||||
|
@ -38,7 +38,7 @@ import { useBoolean } from "../hooks";
|
||||
|
||||
import { ComparisonIcon } from "./ComparisonIcon";
|
||||
import { SaveData } from "../../../types";
|
||||
import { handleGetSaveDataError } from "../../../Netscript/ErrorMessages";
|
||||
import { handleGetSaveDataInfoError } from "../../../Netscript/ErrorMessages";
|
||||
|
||||
const useStyles = makeStyles()((theme: Theme) => ({
|
||||
root: {
|
||||
@ -140,7 +140,7 @@ export const ImportSave = (props: { saveData: SaveData; automatic: boolean }): J
|
||||
// We cannot show dialog box in this screen (due to "withPopups = false"), so we will try showing it with a
|
||||
// delay. 1 second is usually enough to go back to other normal screens that allow showing popups.
|
||||
setTimeout(() => {
|
||||
handleGetSaveDataError(error);
|
||||
handleGetSaveDataInfoError(error);
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
/** Generic Event Emitter class following a subscribe/publish paradigm. */
|
||||
export class EventEmitter<T extends any[]> {
|
||||
private subscribers: Set<(...args: [...T]) => void | undefined> = new Set();
|
||||
|
||||
constructor() {}
|
||||
private subscribers: Set<(...args: [...T]) => void> = new Set();
|
||||
|
||||
subscribe(s: (...args: [...T]) => void): () => void {
|
||||
this.subscribers.add(s);
|
||||
|
@ -239,7 +239,7 @@ export const v2APIBreak = () => {
|
||||
for (const server of GetAllServers()) {
|
||||
server.runningScriptMap = new Map();
|
||||
}
|
||||
saveObject.exportGame();
|
||||
saveObject.exportGame().catch((e) => console.error(e));
|
||||
};
|
||||
|
||||
const formatOffenders = (offenders: IFileLine[]): string => {
|
||||
|
Loading…
Reference in New Issue
Block a user