Skip to content

Commit

Permalink
Merge branch 'master' into public-release
Browse files Browse the repository at this point in the history
  • Loading branch information
TheApplePieGod committed Jan 11, 2025
2 parents a49ec40 + 32a36a1 commit ca8fb21
Show file tree
Hide file tree
Showing 21 changed files with 238 additions and 149 deletions.
10 changes: 10 additions & 0 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@
"pako": "^2.1.0",
"path": "^0.12.7",
"process": "^0.11.10",
"re-resizable": "^6.10.3",
"react": "^18.2.0",
"react-color": "^2.19.3",
"react-custom-scrollbars-2": "^4.5.0",
Expand Down
8 changes: 7 additions & 1 deletion client/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,10 @@ import '../style.css'

const elem = document.getElementById('root')
const root = ReactDom.createRoot(elem!)
root.render(<BrowserRouter><AppContextProvider><MainPage /></AppContextProvider></BrowserRouter>)
root.render(
<BrowserRouter>
<AppContextProvider>
<MainPage />
</AppContextProvider>
</BrowserRouter>
)
2 changes: 2 additions & 0 deletions client/src/components/sidebar/game/game.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ export const GamePage: React.FC<Props> = React.memo((props) => {
<ResourceGraph active={showStats} property="paintPercent" propertyDisplayName="Coverage %" />
<br />
<ResourceGraph active={showStats} property="moneyAmount" propertyDisplayName="Chips" />
<br />
<ResourceGraph active={showStats} property="totalPaint" propertyDisplayName="Paint" />
</div>
) : (
<div>Select a game to see stats</div>
Expand Down
14 changes: 10 additions & 4 deletions client/src/components/sidebar/game/quick-line-chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,14 @@ export const QuickLineChart: React.FC<LineChartProps> = ({

setCanvasResolution(canvas, width, height, resolution)

const max = Math.max(...data.map((d) => Math.max(d.team0, d.team1)))
const { xScale, yScale, innerWidth, innerHeight } = getAxes(width, height, margin, { x: data.length, y: max })
let maxX = -9999999
let maxY = -9999999
for (const d of data) {
maxX = Math.max(maxX, d.round)
maxY = Math.max(maxY, Math.max(d.team0, d.team1))
}

const { xScale, yScale, innerWidth, innerHeight } = getAxes(width, height, margin, { x: maxX, y: maxY })

context.clearRect(0, 0, width, height)

Expand All @@ -65,11 +71,11 @@ export const QuickLineChart: React.FC<LineChartProps> = ({
height,
margin,
{
range: { min: 0, max: data.length },
range: { min: 0, max: maxX },
options: { textColor: 'white', lineColor: 'white' }
},
{
range: { min: 0, max: max },
range: { min: 0, max: maxY },
options: { textColor: 'white', lineColor: 'white' }
}
)
Expand Down
43 changes: 23 additions & 20 deletions client/src/components/sidebar/game/resource-graph.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,37 @@
import React from 'react'
import assert from 'assert'
import { useRound } from '../../../playback/GameRunner'
import Round from '../../../playback/Round'
import { LineChartDataPoint, QuickLineChart } from './quick-line-chart'
import { TeamRoundStat } from '../../../playback/RoundStat'

interface Props {
active: boolean
property: string
property: keyof TeamRoundStat
propertyDisplayName: string
}
function hasKey<O extends Object>(obj: O, key: PropertyKey): key is keyof O {
return key in obj
}

function getChartData(round: Round, property: string): LineChartDataPoint[] {
const values = [0, 1].map((index) =>
round.match.stats.map((roundStat) => {
const teamStat = roundStat.getTeamStat(round.match.game.teams[index])
assert(hasKey(teamStat, property), `TeamStat missing property '${property}' when rendering chart`)
return teamStat[property]
function getChartData(round: Round, property: keyof TeamRoundStat): LineChartDataPoint[] {
const teams = round.match.game.teams

const result: LineChartDataPoint[] = []

// Sparser graph as datapoints increase
const interval = Math.ceil(round.roundNumber / 500)

for (let i = 0; i < round.roundNumber; i += interval) {
const roundStat = round.match.stats[i]

const team0Stat = roundStat.getTeamStat(teams[0])
const team1Stat = roundStat.getTeamStat(teams[1])

result.push({
round: i + 1,
team0: team0Stat[property] as number,
team1: team1Stat[property] as number
})
)
}

return values[0].slice(0, round.roundNumber).map((value, index) => {
return {
round: index + 1,
team0: value as number,
team1: values[1][index] as number
}
})
return result
}

export const ResourceGraph: React.FC<Props> = (props: Props) => {
Expand All @@ -38,7 +41,7 @@ export const ResourceGraph: React.FC<Props> = (props: Props) => {
return (
<div className="mt-2 w-full">
<h2 className="mx-auto text-center mb-2">{props.propertyDisplayName}</h2>
<QuickLineChart data={data} width={350} height={170} margin={{ top: 2, right: 20, bottom: 17, left: 30 }} />
<QuickLineChart data={data} width={350} height={170} margin={{ top: 2, right: 20, bottom: 17, left: 40 }} />
</div>
)
}
11 changes: 10 additions & 1 deletion client/src/components/sidebar/game/team-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,23 @@ export const UnitsTable: React.FC<UnitsTableProps> = ({ teamStat, teamIdx }) =>
['Mopper', <UnitsIcon teamIdx={teamIdx} robotType="mopper" key="5" />]
]

let data: [string, number[]][] = [['Count', [0, 0, 0, 0, 0, 0]]]
let data: [string, number[]][] = [
['Count', [0, 0, 0, 0, 0, 0]],
['Paint', [0, 0, 0, 0, 0, 0]]
]
if (teamStat) {
data = [
[
'Count',
Object.values(schema.RobotType)
.filter((k) => typeof k === 'number' && k !== schema.RobotType.NONE)
.map((k) => teamStat.robotCounts[k as schema.RobotType])
],
[
'Paint',
Object.values(schema.RobotType)
.filter((k) => typeof k === 'number' && k !== schema.RobotType.NONE)
.map((k) => teamStat.robotPaints[k as schema.RobotType])
]
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export const MapEditorBrushRowField: React.FC<Props> = (props: Props) => {
case MapEditorBrushFieldType.TEAM:
field = (
<Toggle
initialValue={props.field.value}
options={{
[TEAM_COLOR_NAMES[0]]: { value: 0, selectedClass: 'bg-team0 text-black' },
[TEAM_COLOR_NAMES[1]]: { value: 1, selectedClass: 'bg-team1 text-black' }
Expand Down
73 changes: 49 additions & 24 deletions client/src/components/sidebar/runner/runner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { RingBuffer } from '../../../util/ring-buffer'
import { ProfilerDialog } from './profiler'
import { GameRenderer } from '../../../playback/GameRenderer'
import GameRunner from '../../../playback/GameRunner'
import { Resizable } from 're-resizable'

type RunnerPageProps = {
open: boolean
Expand Down Expand Up @@ -91,14 +92,20 @@ export const RunnerPage: React.FC<RunnerPageProps> = ({ open, scaffold }) => {

const MemoConsole = React.useMemo(() => <Console lines={consoleLines} />, [consoleLines.effectiveLength()])

if (!open) return null
if (open && !nativeAPI) return <>Run the client locally to use the runner</>

if (!nativeAPI) return <>Run the client locally to use the runner</>
/* Keep the component mounted but hidden when !open so we retain any locally resized/edited elements */

const lastLogLine = consoleLines.get(consoleLines.length() - 1)
const runDisabled = !teamA || !teamB || maps.size === 0 || !langVersion
return (
<div className={'flex flex-col grow ' + (scaffoldLoading ? 'opacity-50 pointer-events-none' : '')}>
<div
className={
'flex flex-col grow' +
(scaffoldLoading ? ' opacity-50 pointer-events-none' : '') +
(open ? '' : ' hidden')
}
>
{!setup ? (
<>
{error && <div className="text-red">{`Setup Error: ${error}`}</div>}
Expand Down Expand Up @@ -286,7 +293,7 @@ const TeamSelector: React.FC<TeamSelectorProps> = ({ teamA, teamB, options, onCh
<label>Team A</label>
<Select className="w-full" value={teamA ?? 'NONE'} onChange={(e) => onChangeA(e)}>
{teamA === undefined && <option value={'NONE'}>Select a team</option>}
{[...options].map((t) => (
{[...options].sort().map((t) => (
<option key={t} value={t}>
{t}
</option>
Expand All @@ -309,7 +316,7 @@ const TeamSelector: React.FC<TeamSelectorProps> = ({ teamA, teamB, options, onCh
<label className="ml-auto">Team B</label>
<Select className="w-full" value={teamB ?? 'NONE'} onChange={(e) => onChangeB(e)}>
{teamB === undefined && <option value={'NONE'}>Select a team</option>}
{[...options].map((t) => (
{[...options].sort().map((t) => (
<option key={t} value={t}>
{t}
</option>
Expand All @@ -331,21 +338,36 @@ const MapSelector: React.FC<MapSelectorProps> = ({ maps, availableMaps, onSelect
return (
<div className="flex flex-col mt-3">
<label>Maps</label>
<div className="flex flex-col border border-white py-1 px-1 rounded-md max-h-[190px] overflow-y-auto">
{[...availableMaps].map((m) => {
const selected = maps.has(m)
return (
<div
key={m}
className={'cursor-pointer hover:bg-lightHighlight flex items-center justify-between'}
onClick={() => (maps.has(m) ? onDeselect(m) : onSelect(m))}
>
{m}
<input type={'checkbox'} readOnly checked={selected} className="pointer-events-none mr-2" />
</div>
)
})}
</div>
<Resizable
minWidth="100%"
maxWidth="100%"
minHeight={50}
defaultSize={{
width: '100%',
height: 120
}}
>
<div className="flex flex-col border border-white py-1 px-1 h-full rounded-md overflow-y-auto">
{[...availableMaps].sort().map((m) => {
const selected = maps.has(m)
return (
<div
key={m}
className={'cursor-pointer hover:bg-lightHighlight flex items-center justify-between'}
onClick={() => (maps.has(m) ? onDeselect(m) : onSelect(m))}
>
{m}
<input
type={'checkbox'}
readOnly
checked={selected}
className="pointer-events-none mr-2"
/>
</div>
)
})}
</div>
</Resizable>
</div>
)
}
Expand Down Expand Up @@ -377,6 +399,11 @@ export const Console: React.FC<Props> = ({ lines }) => {
setPopout(false)
GameRunner.jumpToRound(round)
GameRenderer.setSelectedRobot(id)

// If turn playback is enabled, focus the robot's exact turn as well
if (GameRunner.match?.playbackPerTurn) {
GameRunner.jumpToRobotTurn(id)
}
}

const ConsoleRow = (props: { index: number; style: any }) => {
Expand All @@ -390,7 +417,7 @@ export const Console: React.FC<Props> = ({ lines }) => {
const team = found[1]
const id = Number(found[2])
const round = Number(found[3])
const ogText = found[4]
const ogText = found[4].replace(/\n/g, ' ')

return (
<div className="flex items-center gap-1 sele" style={props.style}>
Expand All @@ -400,9 +427,7 @@ export const Console: React.FC<Props> = ({ lines }) => {
>
{`[Team ${team}, ID #${id}, Round ${round}]`}
</span>
<span className={getLineClass(lines.get(props.index)!) + ' text-xs whitespace-nowrap'}>
{ogText}
</span>
<span className={getLineClass(lines.get(props.index)!) + ' text-xs whitespace-pre'}>{ogText}</span>
</div>
)
}
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/sidebar/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ export const Sidebar: React.FC = () => {
</div>
</>
)}
<div className="h-full overflow-y-scroll overflow-x-hidden">
<div className="h-full overflow-y-auto overflow-x-hidden">
<GamePage open={open && page == PageType.GAME} />
<QueuePage open={open && page == PageType.QUEUE} />
<RunnerPage open={open && page == PageType.RUNNER} scaffold={scaffold} />
Expand Down
3 changes: 2 additions & 1 deletion client/src/components/toggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ interface OptionProp {
}

interface Props {
initialValue?: string
options: Record<string, OptionProp>
onChange: (value: any) => void
flipOnRightClickCanvas?: boolean
}

export const Toggle: React.FC<Props> = (props: Props) => {
const [value, setValue] = React.useState(Object.values(props.options)[0].value)
const [value, setValue] = React.useState(props.initialValue ?? Object.values(props.options)[0].value)
const { canvasRightClick } = GameRenderer.useCanvasClickEvents()

const onClick = (val: any) => {
Expand Down
2 changes: 1 addition & 1 deletion client/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const CLIENT_VERSION = '1.4.0'
export const CLIENT_VERSION = '1.4.1'
export const SPEC_VERSION = '1'
export const BATTLECODE_YEAR: number = 2025
export const MAP_SIZE_RANGE = {
Expand Down
8 changes: 7 additions & 1 deletion client/src/playback/Actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,13 @@ export default class Actions {
for (let i = 0; i < this.actions.length; i++) {
this.actions[i].duration--
if (this.actions[i].duration == 0) {
this.actions.splice(i, 1)
// If action render order matters, use this (slower)
//this.actions.splice(i, 1)

// Otherwise, this is faster
this.actions[i] = this.actions[this.actions.length - 1]
this.actions.pop()

i--
}
}
Expand Down
Loading

0 comments on commit ca8fb21

Please sign in to comment.