Merge branch 'dev' into bugfix/3348

# Conflicts:
#	src/Faction/FactionInfo.tsx
#	src/NetscriptFunctions/Singularity.ts
This commit is contained in:
phyzical
2022-04-07 16:17:28 +08:00
188 changed files with 4016 additions and 3210 deletions
+1 -1
View File
@@ -31,7 +31,7 @@ export function ActiveScriptsRoot(props: IProps): React.ReactElement {
}
return (
<>
<Tabs variant="fullWidth" value={tab} onChange={handleChange} sx={{ minWidth: 'fit-content', maxWidth: '25%' }}>
<Tabs variant="fullWidth" value={tab} onChange={handleChange} sx={{ minWidth: "fit-content", maxWidth: "25%" }}>
<Tab label={"Active"} value={"active"} />
<Tab label={"Recently Killed"} value={"recent"} />
</Tabs>
@@ -67,7 +67,13 @@ export function WorkerScriptAccordion(props: IProps): React.ReactElement {
return (
<>
<ListItemButton onClick={() => setOpen((old) => !old)} component={Paper}>
<ListItemText primary={<Typography> {props.workerScript.name} {JSON.stringify(props.workerScript.args)}</Typography>} />
<ListItemText
primary={
<Typography>
{props.workerScript.name} {JSON.stringify(props.workerScript.args)}
</Typography>
}
/>
{open ? <ExpandLess color="primary" /> : <ExpandMore color="primary" />}
</ListItemButton>
<Collapse in={open} timeout={0} unmountOnExit>
+12
View File
@@ -1,4 +1,5 @@
import React, { useEffect, useState } from "react";
import { EventEmitter } from "../utils/EventEmitter";
import { Modal } from "./React/Modal";
const frames = [
@@ -37,6 +38,8 @@ function isApr1(): boolean {
return d.getMonth() === 3 && d.getDate() === 1;
}
export const Apr1Events = new EventEmitter();
export function Apr1(): React.ReactElement {
const [open, setOpen] = useState(isApr1());
const [n, setN] = useState(0);
@@ -45,6 +48,15 @@ export function Apr1(): React.ReactElement {
const id = setInterval(() => setN((n) => (n + 1) % frames.length), 100);
return () => clearInterval(id);
}, []);
useEffect(
() =>
Apr1Events.subscribe(() => {
setOpen(true);
}),
[],
);
if (!open) return <></>;
return (
+11 -5
View File
@@ -17,7 +17,7 @@ interface IState {
}
export class ErrorBoundary extends React.Component<IProps, IState> {
state: IState
state: IState;
constructor(props: IProps) {
super(props);
@@ -25,7 +25,7 @@ export class ErrorBoundary extends React.Component<IProps, IState> {
}
reset(): void {
this.setState( { hasError: false } as IState);
this.setState({ hasError: false } as IState);
}
componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
@@ -47,12 +47,18 @@ export class ErrorBoundary extends React.Component<IProps, IState> {
}
}
return <RecoveryRoot router={this.props.router} softReset={this.props.softReset}
errorData={errorData} resetError={() => this.reset()} />;
return (
<RecoveryRoot
router={this.props.router}
softReset={this.props.softReset}
errorData={errorData}
resetError={() => this.reset()}
/>
);
}
return this.props.children;
}
static getDerivedStateFromError(error: Error): IState {
return { hasError: true, error};
return { hasError: true, error };
}
}
+1 -1
View File
@@ -66,7 +66,7 @@ export function AlertManager(): React.ReactElement {
{alerts.length > 0 && (
<Modal open={true} onClose={close}>
<Box overflow="scroll" sx={{ overflowWrap: "break-word", whiteSpace: "pre-line" }}>
<Typography component={'span'}>{alerts[0].text}</Typography>
<Typography component={"span"}>{alerts[0].text}</Typography>
</Box>
</Modal>
)}
+5 -3
View File
@@ -33,9 +33,11 @@ export function CorruptableText(props: IProps): JSX.Element {
const index = Math.random() * content.length;
const letter = content.charAt(index);
setContent((content) => replace(content, index, randomize(letter)));
timers.push(window.setTimeout(() => {
setContent((content) => replace(content, index, letter));
}, 500));
timers.push(
window.setTimeout(() => {
setContent((content) => replace(content, index, letter));
}, 500),
);
}, 20);
return () => {
+27 -23
View File
@@ -1,11 +1,11 @@
import React, { useState } from 'react';
import React, { useState } from "react";
import { deleteGame } from "../../db";
import { ConfirmationModal } from "./ConfirmationModal";
import Button from "@mui/material/Button";
import { Tooltip } from '@mui/material';
import { Tooltip } from "@mui/material";
import DeleteIcon from '@mui/icons-material/Delete';
import { pushDisableRestore } from '../../Electron';
import DeleteIcon from "@mui/icons-material/Delete";
import { pushDisableRestore } from "../../Electron";
interface IProps {
color?: "primary" | "warning" | "error";
@@ -14,23 +14,27 @@ interface IProps {
export function DeleteGameButton({ color = "primary" }: IProps): React.ReactElement {
const [modalOpened, setModalOpened] = useState(false);
return (<>
<Tooltip title="This will permanently delete your local save game. Did you export it before?">
<Button startIcon={<DeleteIcon />} color={color} onClick={() => setModalOpened(true)}>Delete Save</Button>
</Tooltip>
<ConfirmationModal
onConfirm={() => {
setModalOpened(false);
deleteGame()
.then(() => {
pushDisableRestore();
setTimeout(() => location.reload(), 1000);
})
.catch((r) => console.error(`Could not delete game: ${r}`));
}}
open={modalOpened}
onClose={() => setModalOpened(false)}
confirmationText={"Really delete your game? (It's permanent!)"}
/>
</>)
return (
<>
<Tooltip title="This will permanently delete your local save game. Did you export it before?">
<Button startIcon={<DeleteIcon />} color={color} onClick={() => setModalOpened(true)}>
Delete Save
</Button>
</Tooltip>
<ConfirmationModal
onConfirm={() => {
setModalOpened(false);
deleteGame()
.then(() => {
pushDisableRestore();
setTimeout(() => location.reload(), 1000);
})
.catch((r) => console.error(`Could not delete game: ${r}`));
}}
open={modalOpened}
onClose={() => setModalOpened(false)}
confirmationText={"Really delete your game? (It's permanent!)"}
/>
</>
);
}
+2 -2
View File
@@ -22,7 +22,7 @@ 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 PaletteIcon from '@mui/icons-material/Palette';
import PaletteIcon from "@mui/icons-material/Palette";
import { FileDiagnosticModal } from "../../Diagnostic/FileDiagnosticModal";
import { ConfirmationModal } from "./ConfirmationModal";
@@ -157,7 +157,7 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
<Grid item xs={12} sm={6}>
<List>
<ListItem>
<Box display="grid" sx={{ width: 'fit-content', gridTemplateColumns: '1fr 3.5fr', gap: 1 }}>
<Box display="grid" sx={{ width: "fit-content", gridTemplateColumns: "1fr 3.5fr", gap: 1 }}>
<Tooltip
title={
<Typography>
+7 -5
View File
@@ -121,7 +121,7 @@ export function ImportSaveRoot(props: IProps): JSX.Element {
Settings.AutosaveInterval = initialAutosave;
pushImportResult(false);
props.router.allowRouting(true);
setHeadback(true)
setHeadback(true);
}
async function handleImport(): Promise<void> {
@@ -211,12 +211,14 @@ export function ImportSaveRoot(props: IProps): JSX.Element {
<TableRow>
<TableCell>Saved On</TableCell>
<TableCell>
{(currentData.playerData?.lastSave ?? 0) > 0 ?
new Date(currentData.playerData?.lastSave ?? 0).toLocaleString() : 'n/a'}
{(currentData.playerData?.lastSave ?? 0) > 0
? new Date(currentData.playerData?.lastSave ?? 0).toLocaleString()
: "n/a"}
</TableCell>
<TableCell>
{(importData.playerData?.lastSave ?? 0) > 0 ?
new Date(importData.playerData?.lastSave ?? 0).toLocaleString() : 'n/a'}
{(importData.playerData?.lastSave ?? 0) > 0
? new Date(importData.playerData?.lastSave ?? 0).toLocaleString()
: "n/a"}
</TableCell>
<TableCell>
{importData.playerData?.lastSave !== currentData.playerData?.lastSave && (
-1
View File
@@ -18,7 +18,6 @@ import { Theme } from "@mui/material";
import { findRunningScript } from "../../Script/ScriptHelpers";
import { Player } from "../../Player";
import { debounce } from "lodash";
import { WorkerScriptStartStopEventEmitter } from "../../Netscript/WorkerScriptStartStopEventEmitter";
let layerCounter = 0;
+28 -15
View File
@@ -9,7 +9,7 @@ import { IErrorData, newIssueUrl } from "../../utils/ErrorHelper";
import { DeleteGameButton } from "./DeleteGameButton";
import { SoftResetButton } from "./SoftResetButton";
import DirectionsRunIcon from '@mui/icons-material/DirectionsRun';
import DirectionsRunIcon from "@mui/icons-material/DirectionsRun";
import GitHubIcon from "@mui/icons-material/GitHub";
export let RecoveryMode = false;
@@ -42,21 +42,27 @@ export function RecoveryRoot({ router, softReset, errorData, resetError }: IProp
}, []);
return (
<Box sx={{ padding: "8px 16px", minHeight: "100vh", maxWidth: '1200px', boxSizing: "border-box",}}>
<Box sx={{ padding: "8px 16px", minHeight: "100vh", maxWidth: "1200px", boxSizing: "border-box" }}>
<Typography variant="h3">RECOVERY MODE ACTIVATED</Typography>
<Typography>
There was an error with your save file and the game went into recovery mode. In this mode saving is disabled
and the game will automatically export your save file (to prevent corruption).
There was an error with your save file and the game went into recovery mode. In this mode saving is disabled and
the game will automatically export your save file (to prevent corruption).
</Typography>
<Typography>At this point it is recommended to alert a developer.</Typography>
<Typography>
<Link href={errorData?.issueUrl ?? newIssueUrl} target="_blank">File an issue on github</Link>
<Link href={errorData?.issueUrl ?? newIssueUrl} target="_blank">
File an issue on github
</Link>
</Typography>
<Typography>
<Link href="https://www.reddit.com/r/Bitburner/" target="_blank">Make a reddit post</Link>
<Link href="https://www.reddit.com/r/Bitburner/" target="_blank">
Make a reddit post
</Link>
</Typography>
<Typography>
<Link href="https://discord.gg/TFc3hKD" target="_blank">Post in the #bug-report channel on Discord.</Link>
<Link href="https://discord.gg/TFc3hKD" target="_blank">
Post in the #bug-report channel on Discord.
</Link>
</Typography>
<Typography>Please include your save file.</Typography>
<br />
@@ -64,17 +70,17 @@ export function RecoveryRoot({ router, softReset, errorData, resetError }: IProp
<Typography>You can disable recovery mode now. But chances are the game will not work correctly.</Typography>
<ButtonGroup sx={{ my: 2 }}>
<Tooltip title="Disables the recovery mode & attempt to head back to the terminal page. This may or may not work. Ensure you have saved the recovery file.">
<Button onClick={recover} startIcon={<DirectionsRunIcon />}>Disable Recovery Mode</Button>
<Button onClick={recover} startIcon={<DirectionsRunIcon />}>
Disable Recovery Mode
</Button>
</Tooltip>
<SoftResetButton color="warning" onTriggered={softReset} />
<DeleteGameButton color="error" />
</ButtonGroup>
{errorData && (
<Paper sx={{ px: 2, pt: 1, pb: 2, mt: 2}}>
<Typography variant="h5">
{errorData.title}
</Typography>
<Paper sx={{ px: 2, pt: 1, pb: 2, mt: 2 }}>
<Typography variant="h5">{errorData.title}</Typography>
<Box sx={{ my: 2 }}>
<TextField
label="Bug Report Text"
@@ -84,11 +90,18 @@ export function RecoveryRoot({ router, softReset, errorData, resetError }: IProp
multiline
fullWidth
rows={12}
sx={{ "& .MuiOutlinedInput-root": { color: Settings.theme.secondary }}} />
sx={{ "& .MuiOutlinedInput-root": { color: Settings.theme.secondary } }}
/>
</Box>
<Tooltip title="Submitting an issue to GitHub really help us improve the game!">
<Button component={Link} startIcon={<GitHubIcon />} color="info" sx={{ px: 2 }}
href={errorData.issueUrl ?? newIssueUrl} target={"_blank"} >
<Button
component={Link}
startIcon={<GitHubIcon />}
color="info"
sx={{ px: 2 }}
href={errorData.issueUrl ?? newIssueUrl}
target={"_blank"}
>
Submit Issue to GitHub
</Button>
</Tooltip>
+13 -6
View File
@@ -16,22 +16,29 @@ const useStyles = makeStyles(() => ({
zIndex: `${logBoxBaseZIndex + 1000} !important` as any,
"& .MuiAlert-icon": {
alignSelf: 'center',
alignSelf: "center",
},
}
},
}));
export function SnackbarProvider(props: IProps): React.ReactElement {
const classes = useStyles();
return (
<SB dense maxSnack={9} anchorOrigin={{ horizontal: "right", vertical: "bottom" }} autoHideDuration={2000}
classes={{ containerRoot: classes.snackbar }}>
<SB
dense
maxSnack={9}
anchorOrigin={{ horizontal: "right", vertical: "bottom" }}
autoHideDuration={2000}
classes={{ containerRoot: classes.snackbar }}
>
{props.children}
</SB>
);
}
export const SnackbarEvents = new EventEmitter<[string | React.ReactNode, "success" | "warning" | "error" | "info", number]>();
export const SnackbarEvents = new EventEmitter<
[string | React.ReactNode, "success" | "warning" | "error" | "info", number]
>();
export function Snackbar(): React.ReactElement {
const { enqueueSnackbar, closeSnackbar } = useSnackbar();
@@ -43,7 +50,7 @@ export function Snackbar(): React.ReactElement {
variant: variant,
autoHideDuration: duration,
onClick: () => closeSnackbar(id),
})
});
}),
);
return <></>;
+23 -15
View File
@@ -1,9 +1,9 @@
import React, { useState } from 'react';
import React, { useState } from "react";
import { ConfirmationModal } from "./ConfirmationModal";
import Button from "@mui/material/Button";
import { Tooltip } from '@mui/material';
import RestartAltIcon from '@mui/icons-material/RestartAlt';
import { Tooltip } from "@mui/material";
import RestartAltIcon from "@mui/icons-material/RestartAlt";
interface IProps {
color?: "primary" | "warning" | "error";
@@ -11,7 +11,11 @@ interface IProps {
onTriggered: () => void;
}
export function SoftResetButton({ color = "primary", noConfirmation = false, onTriggered }: IProps): React.ReactElement {
export function SoftResetButton({
color = "primary",
noConfirmation = false,
onTriggered,
}: IProps): React.ReactElement {
const [modalOpened, setModalOpened] = useState(false);
function handleButtonClick(): void {
@@ -22,15 +26,19 @@ export function SoftResetButton({ color = "primary", noConfirmation = false, onT
}
}
return (<>
<Tooltip title="Perform a soft reset. Resets everything as if you had just purchased an Augmentation.">
<Button startIcon={<RestartAltIcon />} color={color} onClick={handleButtonClick}>Soft Reset</Button>
</Tooltip>
<ConfirmationModal
onConfirm={onTriggered}
open={modalOpened}
onClose={() => setModalOpened(false)}
confirmationText={"This will perform the same action as installing Augmentations, are you sure?"}
/>
</>)
return (
<>
<Tooltip title="Perform a soft reset. Resets everything as if you had just purchased an Augmentation.">
<Button startIcon={<RestartAltIcon />} color={color} onClick={handleButtonClick}>
Soft Reset
</Button>
</Tooltip>
<ConfirmationModal
onConfirm={onTriggered}
open={modalOpened}
onClose={() => setModalOpened(false)}
confirmationText={"This will perform the same action as installing Augmentations, are you sure?"}
/>
</>
);
}
+9 -2
View File
@@ -19,9 +19,16 @@ interface IStatsOverviewCellProps {
color?: React.CSSProperties["color"];
}
export function StatsProgressBar({ min, max, current, remaining, progress, color }: IProgressProps): React.ReactElement {
export function StatsProgressBar({
min,
max,
current,
remaining,
progress,
color,
}: IProgressProps): React.ReactElement {
const tooltip = (
<Typography sx={{ textAlign: 'right' }}>
<Typography sx={{ textAlign: "right" }}>
<strong>Progress:</strong>&nbsp;
{numeralWrapper.formatExp(current)} / {numeralWrapper.formatExp(max - min)}
<br />
+4 -10
View File
@@ -1,10 +1,6 @@
import React from "react";
import {
Typography,
TableCell,
TableRow,
} from "@mui/material";
import { Typography, TableCell, TableRow } from "@mui/material";
import { numeralWrapper } from "../numeralFormat";
import { formatNumber } from "../../utils/StringHelperFunctions";
@@ -40,10 +36,8 @@ export const StatsRow = ({ name, color, classes = useStyles(), data }: IProps):
<Typography style={{ color: color }}>{name}</Typography>
</TableCell>
<TableCell align="right" classes={{ root: classes.cellNone }}>
<Typography style={{ color: color }}>
{content}
</Typography>
<Typography style={{ color: color }}>{content}</Typography>
</TableCell>
</TableRow>
)
}
);
};
+8 -11
View File
@@ -14,13 +14,13 @@ interface ICityProps {
const useStyles = makeStyles((theme: Theme) =>
createStyles({
travel: {
color: theme.colors.white,
lineHeight: "1em",
whiteSpace: "pre",
cursor: "pointer"
},
})
travel: {
color: theme.colors.white,
lineHeight: "1em",
whiteSpace: "pre",
cursor: "pointer",
},
}),
);
function City(props: ICityProps): React.ReactElement {
@@ -28,10 +28,7 @@ function City(props: ICityProps): React.ReactElement {
if (props.city !== props.currentCity) {
return (
<Tooltip title={<Typography>{props.city}</Typography>}>
<span
onClick={() => props.onTravel(props.city)}
className={classes.travel}
>
<span onClick={() => props.onTravel(props.city)} className={classes.travel}>
{props.city[0]}
</span>
</Tooltip>