GANG: Show error popup when there are errors (#1763)

* GANG: Show error popup when there are errors

* Only show error once when it's in a hot code path
This commit is contained in:
catloversg 2024-11-11 22:41:38 +07:00 committed by GitHub
parent 72a63b15cb
commit 5d26f4fa56
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 36 additions and 12 deletions

@ -97,9 +97,6 @@ export class Gang {
/** Main process function called by the engine loop every game cycle */ /** Main process function called by the engine loop every game cycle */
process(numCycles = 1): void { process(numCycles = 1): void {
if (isNaN(numCycles)) {
console.error(`NaN passed into Gang.process(): ${numCycles}`);
}
this.storedCycles += numCycles; this.storedCycles += numCycles;
if (this.storedCycles < GangConstants.minCyclesToProcess) return; if (this.storedCycles < GangConstants.minCyclesToProcess) return;
@ -112,7 +109,7 @@ export class Gang {
this.processTerritoryAndPowerGains(cycles); this.processTerritoryAndPowerGains(cycles);
this.storedCycles -= cycles; this.storedCycles -= cycles;
} catch (e: unknown) { } catch (e: unknown) {
console.error("Exception caught when processing Gang", e); exceptionAlert(e, true);
} }
// Handle "nextUpdate" resolver after this update // Handle "nextUpdate" resolver after this update

@ -170,7 +170,10 @@ const Engine: {
decrementAllCounters: function (numCycles = 1) { decrementAllCounters: function (numCycles = 1) {
for (const [counterName, counter] of Object.entries(Engine.Counters)) { for (const [counterName, counter] of Object.entries(Engine.Counters)) {
if (counter === undefined) throw new Error("counter should not be undefined"); if (counter === undefined) {
exceptionAlert(new Error(`counter value is undefined. counterName: ${counterName}.`), true);
continue;
}
Engine.Counters[counterName] = counter - numCycles; Engine.Counters[counterName] = counter - numCycles;
} }
}, },
@ -207,7 +210,7 @@ const Engine: {
try { try {
Player.bladeburner.process(); Player.bladeburner.process();
} catch (e) { } catch (e) {
exceptionAlert(e); exceptionAlert(e, true);
} }
} }
Engine.Counters.mechanicProcess = 5; Engine.Counters.mechanicProcess = 5;

@ -2,19 +2,43 @@ import React from "react";
import { dialogBoxCreate } from "../../ui/React/DialogBox"; import { dialogBoxCreate } from "../../ui/React/DialogBox";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import { getErrorMetadata } from "../ErrorHelper"; import { getErrorMetadata } from "../ErrorHelper";
import { cyrb53 } from "../StringHelperFunctions";
export function exceptionAlert(e: unknown): void { const errorSet = new Set<string>();
console.error(e);
const errorMetadata = getErrorMetadata(e); /**
* Show the error in a popup:
* - Indicate that this is a bug and should be reported to developers.
* - Automatically include debug information (e.g., stack trace, commit id, user agent).
*
* @param error Error
* @param showOnlyOnce Set to true if you want to show the error only once, even when it happens many times. Default: false.
* @returns
*/
export function exceptionAlert(error: unknown, showOnlyOnce = false): void {
console.error(error);
const errorAsString = String(error);
const errorStackTrace = error instanceof Error ? error.stack : undefined;
if (showOnlyOnce) {
// Calculate the "id" of the error.
const errorId = cyrb53(errorAsString + errorStackTrace);
// Check if we showed it
if (errorSet.has(errorId)) {
return;
} else {
errorSet.add(errorId);
}
}
const errorMetadata = getErrorMetadata(error);
dialogBoxCreate( dialogBoxCreate(
<> <>
Caught an exception: {String(e)} Caught an exception: {errorAsString}
<br /> <br />
<br /> <br />
{e instanceof Error && ( {errorStackTrace && (
<Typography component="div" style={{ whiteSpace: "pre-wrap" }}> <Typography component="div" style={{ whiteSpace: "pre-wrap" }}>
Stack: {e.stack?.toString()} Stack: {errorStackTrace}
</Typography> </Typography>
)} )}
Commit: {errorMetadata.version.commitHash} Commit: {errorMetadata.version.commitHash}