Skip to content

Commit

Permalink
v0.12.5: Added 'secret' utils tab with tools to repair game state
Browse files Browse the repository at this point in the history
  • Loading branch information
JessicaMulein committed Nov 13, 2024
1 parent 1109d27 commit 99984e3
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 3 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,11 @@ Join our community of developers.

## Changelog

### Tue Nov 12 23:15:00 2024

- Version 0.12.5
- Added "secret" utils tab with tools to repair game state

### Tue Nov 12 22:09:00 2024

- Version 0.12.4
Expand Down
30 changes: 28 additions & 2 deletions src/app/app.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React, { useRef, ReactElement, ReactNode } from 'react';
import React, { useRef, ReactElement, ReactNode, useEffect, useState } from 'react';
import { ThemeProvider } from '@mui/material/styles';
import { BrowserRouter as Router, useRoutes } from 'react-router-dom';
import { BrowserRouter as Router, useLocation, useNavigate, useRoutes } from 'react-router-dom';
import AboutScreen from '@/components/screens/AboutScreen';
import HomeIcon from '@mui/icons-material/Home';
import BookIcon from '@mui/icons-material/Book';
import SaveIcon from '@mui/icons-material/Save';
import SettingsIcon from '@mui/icons-material/Settings';
import BarChartIcon from '@mui/icons-material/BarChart';
import DominionVictoryIcon from '@/assets/images/Dominion-Victory.png';
import TabBarIcon from '@/components/TabBarIcon';
Expand All @@ -17,6 +18,7 @@ import { GameProvider } from '@/components/GameContext';
import { AlertProvider } from '@/components/AlertContext';
import AlertDialog from '@/components/AlertDialog';
import StatisticsScreen from '@/components/screens/StatisticsScreen';
import { UtilsScreen } from '@/components/screens/UtilsScreen';

interface ITab {
label: string;
Expand All @@ -28,6 +30,21 @@ interface ITab {

function AppRoutes() {
const tabViewRef = useRef<TabViewHandle>(null);
const location = useLocation();
const [utilsEnabled, setUtilsEnabled] = useState(() => {
return localStorage.getItem('utilsEnabled') === 'true';
});

useEffect(() => {
const searchParams = new URLSearchParams(location.search);
if (searchParams.get('utils') === 'true') {
localStorage.setItem('utilsEnabled', 'true');
setUtilsEnabled(true);
} else if (searchParams.get('utils') === 'false') {
localStorage.setItem('utilsEnabled', 'false');
setUtilsEnabled(false);
}
}, [location.search]);

const tabs: ITab[] = [
{
Expand Down Expand Up @@ -63,6 +80,15 @@ function AppRoutes() {
},
];

if (utilsEnabled) {
tabs.push({
label: 'Utils',
icon: <TabBarIcon name="utils" icon={SettingsIcon} focused={false} />,
content: <UtilsScreen />,
path: '/utils',
});
}

const routes = useRoutes([
{
path: '/',
Expand Down
71 changes: 71 additions & 0 deletions src/components/screens/UtilsScreen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { Box, Link, List, ListItem, styled } from '@mui/material';
import React, { FC } from 'react';
import TabTitle from '@/components/TabTitle';
import { useGameContext } from '@/components/GameContext';
import { rebuildGameTimeHistory, rebuildTurnStatisticsCache } from '@/game/dominion-lib-log';
import { deepClone } from '@/game/utils';
import { IGame } from '@/game/interfaces/game';
import { CurrentStep } from '@/game/enumerations/current-step';

const StyledContainer = styled(Box)(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: theme.spacing(2),
height: 'calc(100vh - 56px)',
}));

export const UtilsScreen: FC = () => {
const { gameState, setGameState } = useGameContext();

const handleRebuildGameTime = () => {
setGameState((prevState) => {
if (
prevState.currentStep !== CurrentStep.Game &&
prevState.currentStep !== CurrentStep.EndGame
) {
return prevState;
}
const newGame = rebuildGameTimeHistory(prevState);
return newGame;
});
};

const handleRebuildTurnStatistics = () => {
setGameState((prevState) => {
if (
prevState.currentStep !== CurrentStep.Game &&
prevState.currentStep !== CurrentStep.EndGame
) {
return prevState;
}
const newGame = deepClone<IGame>(prevState);
newGame.turnStatisticsCache = rebuildTurnStatisticsCache(prevState);
return newGame;
});
};

return (
<StyledContainer>
<TabTitle>Utilities</TabTitle>
{(gameState.currentStep === CurrentStep.Game ||
gameState.currentStep === CurrentStep.EndGame) && (
<List>
<ListItem>
<Link onClick={handleRebuildGameTime}>Rebuild Game Time</Link>
</ListItem>
<ListItem>
<Link onClick={handleRebuildTurnStatistics}>Rebuild Turn Statistics</Link>
</ListItem>
</List>
)}
{gameState.currentStep !== CurrentStep.Game &&
gameState.currentStep !== CurrentStep.EndGame && (
<Box>
The utilities tab is only available when a game is in progress or is in the end game
state.
</Box>
)}
</StyledContainer>
);
};
2 changes: 1 addition & 1 deletion src/game/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { IRisingSunFeatures } from '@/game/interfaces/set-features/rising-sun';
import { IExpansionsEnabled } from '@/game/interfaces/expansions-enabled';
import { calculateInitialSunTokens } from '@/game/interfaces/set-mats/prophecy';

export const VERSION_NUMBER = '0.12.4';
export const VERSION_NUMBER = '0.12.5';
export const LAST_COMPATIBLE_SAVE_VERSION = '0.12.0';

export const MIN_PLAYERS = 2;
Expand Down
27 changes: 27 additions & 0 deletions src/game/dominion-lib-log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1250,3 +1250,30 @@ export function rebuildTurnStatisticsCache(game: IGame): Array<ITurnStatistics>

return newTurnStatisticsCache;
}

/**
* Rebuild the game time history for a given game.
* @param game - The game object containing log entries and time cache.
* @returns The game object with updated game time history.
*/
export function rebuildGameTimeHistory(game: IGame): IGame {
const newGame = deepClone<IGame>(game);
newGame.log = [game.log[0]];
const lastGameTime = 0;
for (let i = 1; i < game.log.length; i++) {
// if the entry is a load or unpause, we dont increase the game time from the associated save/pause
if (
game.log[i].action === GameLogAction.LOAD_GAME ||
game.log[i].action === GameLogAction.UNPAUSE
) {
newGame.log.push({ ...game.log[i], gameTime: lastGameTime });
} else {
const gameTime = calculateDurationUpToEvent(newGame.log, game.log[i].timestamp);
newGame.log.push({
...game.log[i],
gameTime,
});
}
}
return newGame;
}

0 comments on commit 99984e3

Please sign in to comment.