import React, { useState, useRef } from "react"; import { IPlayer } from "../../PersonObjects/IPlayer"; import { Theme } from "@mui/material/styles"; import makeStyles from "@mui/styles/makeStyles"; import createStyles from "@mui/styles/createStyles"; import Typography from "@mui/material/Typography"; import Slider from "@mui/material/Slider"; import Grid from "@mui/material/Grid"; import Select, { SelectChangeEvent } from "@mui/material/Select"; import MenuItem from "@mui/material/MenuItem"; import Button from "@mui/material/Button"; import Box from "@mui/material/Box"; import List from "@mui/material/List"; import ListItem from "@mui/material/ListItem"; import Link from "@mui/material/Link"; import Tooltip from "@mui/material/Tooltip"; import TextField from "@mui/material/TextField"; import DownloadIcon from "@mui/icons-material/Download"; import UploadIcon from "@mui/icons-material/Upload"; import SaveIcon from "@mui/icons-material/Save"; import { FileDiagnosticModal } from "../../Diagnostic/FileDiagnosticModal"; import { dialogBoxCreate } from "./DialogBox"; import { ConfirmationModal } from "./ConfirmationModal"; import { ThemeEditorModal } from "./ThemeEditorModal"; import { StyleEditorModal } from "./StyleEditorModal"; import { SnackbarEvents } from "./Snackbar"; import { Settings } from "../../Settings/Settings"; import { save } from "../../db"; import { formatTime } from "../../utils/helpers/formatTime"; import { OptionSwitch } from "./OptionSwitch"; import { DeleteGameButton } from "./DeleteGameButton"; import { SoftResetButton } from "./SoftResetButton"; const useStyles = makeStyles((theme: Theme) => createStyles({ root: { width: 50, padding: theme.spacing(2), userSelect: "none", }, }), ); interface IProps { player: IPlayer; save: () => void; export: () => void; forceKill: () => void; softReset: () => void; } interface ImportData { base64: string; parsed: any; exportDate?: Date; } export function GameOptionsRoot(props: IProps): React.ReactElement { const classes = useStyles(); const importInput = useRef(null); const [execTime, setExecTime] = useState(Settings.CodeInstructionRunTime); const [logSize, setLogSize] = useState(Settings.MaxLogCapacity); const [portSize, setPortSize] = useState(Settings.MaxPortCapacity); const [terminalSize, setTerminalSize] = useState(Settings.MaxTerminalCapacity); const [autosaveInterval, setAutosaveInterval] = useState(Settings.AutosaveInterval); const [timestampFormat, setTimestampFormat] = useState(Settings.TimestampsFormat); const [locale, setLocale] = useState(Settings.Locale); const [diagnosticOpen, setDiagnosticOpen] = useState(false); const [themeEditorOpen, setThemeEditorOpen] = useState(false); const [styleEditorOpen, setStyleEditorOpen] = useState(false); const [importSaveOpen, setImportSaveOpen] = useState(false); const [importData, setImportData] = useState(null); function handleExecTimeChange(event: any, newValue: number | number[]): void { setExecTime(newValue as number); Settings.CodeInstructionRunTime = newValue as number; } function handleLogSizeChange(event: any, newValue: number | number[]): void { setLogSize(newValue as number); Settings.MaxLogCapacity = newValue as number; } function handlePortSizeChange(event: any, newValue: number | number[]): void { setPortSize(newValue as number); Settings.MaxPortCapacity = newValue as number; } function handleTerminalSizeChange(event: any, newValue: number | number[]): void { setTerminalSize(newValue as number); Settings.MaxTerminalCapacity = newValue as number; } function handleAutosaveIntervalChange(event: any, newValue: number | number[]): void { setAutosaveInterval(newValue as number); Settings.AutosaveInterval = newValue as number; } function handleLocaleChange(event: SelectChangeEvent): void { setLocale(event.target.value as string); Settings.Locale = event.target.value as string; } function handleTimestampFormatChange(event: React.ChangeEvent): void { setTimestampFormat(event.target.value); Settings.TimestampsFormat = event.target.value; } function startImport(): void { if (!window.File || !window.FileReader || !window.FileList || !window.Blob) return; const ii = importInput.current; if (ii === null) throw new Error("import input should not be null"); ii.click(); } function onImport(event: React.ChangeEvent): void { const files = event.target.files; if (files === null) return; const file = files[0]; if (!file) { dialogBoxCreate("Invalid file selected"); return; } const reader = new FileReader(); reader.onload = function (this: FileReader, e: ProgressEvent) { const target = e.target; if (target === null) { console.error("error importing file"); return; } const result = target.result; if (typeof result !== "string" || result === null) { console.error("FileReader event was not type string"); return; } const contents = result; let newSave; try { newSave = window.atob(contents); newSave = newSave.trim(); } catch (error) { console.log(error); // We'll handle below } if (!newSave || newSave === "") { SnackbarEvents.emit("Save game had not content or was not base64 encoded", "error", 5000); return; } let parsedSave; try { parsedSave = JSON.parse(newSave); } catch (error) { console.log(error); // We'll handle below } if (!parsedSave || parsedSave.ctor !== "BitburnerSaveObject" || !parsedSave.data) { SnackbarEvents.emit("Save game did not seem valid", "error", 5000); return; } const data: ImportData = { base64: contents, parsed: parsedSave, }; const timestamp = parsedSave.data.SaveTimestamp; if (timestamp && timestamp !== "0") { data.exportDate = new Date(parseInt(timestamp, 10)); } setImportData(data); setImportSaveOpen(true); }; reader.readAsText(file); } function confirmedImportGame(): void { if (!importData) return; setImportSaveOpen(false); save(importData.base64).then(() => { setImportData(null); setTimeout(() => location.reload(), 1000); }); } return (
Options The minimum number of milliseconds it takes to execute an operation in Netscript. Setting this too low can result in poor performance if you have many scripts running. } > .script exec time (ms) The maximum number of lines a script's logs can hold. Setting this too high can cause the game to use a lot of memory if you have many scripts running. } > Netscript log size The maximum number of entries that can be written to a port using Netscript's write() function. Setting this too high can cause the game to use a lot of memory. } > Netscript port size The maximum number of entries that can be written to the terminal. Setting this too high can cause the game to use a lot of memory. } > Terminal capacity The time (in seconds) between each autosave. Set to 0 to disable autosave. } > Autosave interval (s) (Settings.SuppressMessages = newValue)} text="Suppress story messages" tooltip={ <> If this is set, then any messages you receive will not appear as popups on the screen. They will still get sent to your home computer as '.msg' files and can be viewed with the 'cat' Terminal command. } /> (Settings.SuppressFactionInvites = newValue)} text="Suppress faction invites" tooltip={ <> If this is set, then any faction invites you receive will not appear as popups on the screen. Your outstanding faction invites can be viewed in the 'Factions' page. } /> (Settings.SuppressTravelConfirmation = newValue)} text="Suppress travel confirmations" tooltip={ <> If this is set, the confirmation message before traveling will not show up. You will automatically be deducted the travel cost as soon as you click. } /> (Settings.SuppressBuyAugmentationConfirmation = newValue)} text="Suppress augmentations confirmation" tooltip={<>If this is set, the confirmation message before buying augmentation will not show up.} /> (Settings.SuppressTIXPopup = newValue)} text="Suppress TIX messages" tooltip={<>If this is set, the stock market will never create any popup.} /> {!!props.player.bladeburner && ( (Settings.SuppressBladeburnerPopup = newValue)} text="Suppress bladeburner popup" tooltip={ <> If this is set, then having your Bladeburner actions interrupted by being busy with something else will not display a popup message. } /> )} (Settings.SuppressSavedGameToast = newValue)} text="Suppress Auto-Save Game Toast" tooltip={<>If this is set, there will be no "Game Saved!" toast appearing after an auto-save.} /> (Settings.DisableHotkeys = newValue)} text="Disable hotkeys" tooltip={ <> If this is set, then most hotkeys (keyboard shortcuts) in the game are disabled. This includes Terminal commands, hotkeys to navigate between different parts of the game, and the "Save and Close (Ctrl + b)" hotkey in the Text Editor. } /> (Settings.DisableASCIIArt = newValue)} text="Disable ascii art" tooltip={<>If this is set all ASCII art will be disabled.} /> (Settings.DisableTextEffects = newValue)} text="Disable text effects" tooltip={ <> If this is set, text effects will not be displayed. This can help if text is difficult to read in certain areas. } /> (Settings.DisableOverviewProgressBars = newValue)} text="Disable Overview Progress Bars" tooltip={<>If this is set, the progress bars in the character overview will be hidden.} /> (Settings.EnableBashHotkeys = newValue)} text="Enable bash hotkeys" tooltip={ <> Improved Bash emulation mode. Setting this to 1 enables several new Terminal shortcuts and features that more closely resemble a real Bash-style shell. Note that when this mode is enabled, the default browser shortcuts are overriden by the new Bash shortcuts. } /> (Settings.UseIEC60027_2 = newValue)} text="Use GiB instead of GB" tooltip={ <> If this is set all references to memory will use GiB instead of GB, in accordance with IEC 60027-2. } /> (Settings.ExcludeRunningScriptsFromSave = newValue)} text="Exclude Running Scripts from Save" tooltip={ <> If this is set, the save file will exclude all running scripts. This is only useful if your save is lagging a lot. You'll have to restart your script every time you launch the game. } /> Terminal commands and log entries will be timestamped. See https://date-fns.org/docs/Getting-Started/ } > Timestamp format:  ), }} value={timestampFormat} onChange={handleTimestampFormatChange} placeholder="yyyy-MM-dd hh:mm:ss" /> (Settings.SaveGameOnFileSave = newValue)} text="Save game on file save" tooltip={<>Save your game any time a file is saved in the script editor.} /> Sets the locale for displaying numbers.}> Locale  {!location.href.startsWith("file://") && ( <> danielyxie / BigD (Original developer):
hydroflame (Current maintainer):{" "} Donate blood! {" "} )}
Export your game to a text file.}> Import your game from a text file.
This will overwrite your current game. Back it up first! } >
setImportSaveOpen(false)} onConfirm={() => confirmedImportGame()} confirmationText={ <> Importing a new game will completely wipe the current data!

Make sure to have a backup of your current save file before importing.
The file you are attempting to import seems valid.

{importData?.exportDate && ( <> The export date of the save file is {importData?.exportDate.toString()}

)} } />
Forcefully kill all active running scripts, in case there is a bug or some unexpected issue with the game. After using this, save the game and then reload the page. This is different then normal kill in that normal kill will tell the script to shut down while force kill just removes the references to it (and it should crash on it's own). This will not remove the files on your computer. Just forcefully kill all running instance of all scripts. } > If your save file is extremely big you can use this button to view a map of all the files on every server. Be careful there might be spoilers. } > Report bug Changelog Documentation Discord Reddit Incremental game plaza
setDiagnosticOpen(false)} /> setThemeEditorOpen(false)} /> setStyleEditorOpen(false)} />
); }