Skip to content

Commit 2622c0e

Browse files
Merge branch 'client'
2 parents 97cc43d + 5c17def commit 2622c0e

28 files changed

+187
-54
lines changed

client/src/app-context.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export interface AppState {
99
activeGame: Game | undefined
1010
activeMatch: Match | undefined
1111
tournament: Tournament | undefined
12+
tournamentMinRound: number // Minimum round to display
1213
loadingRemoteContent: string
1314
updatesPerSecond: number
1415
paused: boolean
@@ -21,6 +22,7 @@ const DEFAULT_APP_STATE: AppState = {
2122
activeGame: undefined,
2223
activeMatch: undefined,
2324
tournament: undefined,
25+
tournamentMinRound: 1,
2426
loadingRemoteContent: '',
2527
updatesPerSecond: 1,
2628
paused: true,

client/src/client-config.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ const DEFAULT_CONFIG = {
1414
showHealthBars: false,
1515
showMapXY: true,
1616
showFlagCarryIndicator: true,
17-
streamRunnerGames: false
17+
streamRunnerGames: false,
18+
validateMaps: false
1819
}
1920

2021
const configDescription: { [key: string]: string } = {
@@ -23,7 +24,8 @@ const configDescription: { [key: string]: string } = {
2324
showHealthBars: 'Show health bars below all robots',
2425
showMapXY: 'Show X,Y when hovering a tile',
2526
showFlagCarryIndicator: 'Show an obvious indicator over flag carriers',
26-
streamRunnerGames: 'Stream each round from the runner live as the game is being played'
27+
streamRunnerGames: 'Stream each round from the runner live as the game is being played',
28+
validateMaps: 'Validate maps before running a game'
2729
}
2830

2931
export function getDefaultConfig(): ClientConfig {

client/src/components/forms.tsx

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React, { PropsWithChildren } from 'react'
2+
import { useAppContext } from '../app-context'
23

34
interface SelectProps {
45
value?: string | number
@@ -40,11 +41,14 @@ interface NumInputProps {
4041
changeValue: (newValue: number) => void
4142
}
4243
export const NumInput: React.FC<NumInputProps> = (props) => {
44+
const context = useAppContext()
45+
46+
const [focused, setFocused] = React.useState(false)
4347
const [tempValue, setTempValue] = React.useState<string | undefined>()
4448

45-
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
49+
const handleInputChange = (val: string) => {
4650
// Direct change from arrows
47-
const value = parseInt(e.target.value)
51+
const value = parseInt(val)
4852
if (!isNaN(value) && value >= props.min && value <= props.max) {
4953
props.changeValue(value)
5054
}
@@ -53,16 +57,28 @@ export const NumInput: React.FC<NumInputProps> = (props) => {
5357
const handleInputBlur = () => {
5458
// Reset temp value after user loses focus
5559
setTempValue(undefined)
60+
setFocused(false)
5661
}
5762

63+
const handleClick = () => {
64+
setTempValue(undefined)
65+
handleInputChange(tempValue || '')
66+
}
67+
68+
React.useEffect(() => {
69+
context.setState((prevState) => ({ ...prevState, disableHotkeys: focused }))
70+
}, [focused])
71+
5872
return (
5973
<input
6074
className={'border border-black py-0.5 px-1 rounded-md w-12 ' + (props.className ?? '')}
6175
type="number"
6276
value={tempValue ?? props.value}
6377
onBlur={handleInputBlur}
64-
onInput={handleInputChange}
78+
onFocus={() => setFocused(true)}
79+
onInput={(e) => handleInputChange(e.currentTarget.value)}
6580
onChange={(e) => setTempValue(e.target.value)}
81+
onClick={handleClick}
6682
/>
6783
)
6884
}

client/src/components/game/game-renderer.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ export const GameRenderer: React.FC = () => {
7373
updateCanvasDimensions(dynamicCanvas.current, { x: width, y: height })
7474
updateCanvasDimensions(overlayCanvas.current, { x: width, y: height })
7575
setSelectedSquare(undefined)
76+
setSelectedBodyID(undefined)
77+
setHoveredTile(undefined)
78+
setHoveredBodyID(undefined)
7679
publishEvent(EventType.INITIAL_RENDER, {})
7780
}, [appContext.state.activeMatch, backgroundCanvas.current, dynamicCanvas.current, overlayCanvas.current])
7881

client/src/components/game/tournament-renderer/tournament-renderer.tsx

Lines changed: 73 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,21 @@ import { useAppContext } from '../../../app-context'
33
import { TournamentGameElement } from './tournament-game'
44
import Tournament, { TournamentGame } from '../../../playback/Tournament'
55
import { Space } from 'react-zoomable-ui'
6-
import { useForceUpdate } from '../../../util/react-util'
76

87
export const TournamentRenderer: React.FC = () => {
98
const appContext = useAppContext()
109

10+
const spaceRef = useRef<Space | null>(null)
11+
1112
return (
1213
<div className="w-full h-screen relative">
13-
<Space treatTwoFingerTrackPadGesturesLikeTouch={false}>
14-
{appContext.state.tournament ? (
15-
<TournamentTree tournament={appContext.state.tournament} />
14+
<Space ref={spaceRef} treatTwoFingerTrackPadGesturesLikeTouch={false}>
15+
{appContext.state.tournament && spaceRef.current ? (
16+
<TournamentTree
17+
tournament={appContext.state.tournament}
18+
minRound={appContext.state.tournamentMinRound}
19+
spaceRef={spaceRef.current}
20+
/>
1621
) : (
1722
<>Missing Tournament</>
1823
)}
@@ -23,9 +28,11 @@ export const TournamentRenderer: React.FC = () => {
2328

2429
interface TournamentTreeProps {
2530
tournament: Tournament
31+
minRound: number
32+
spaceRef: Space
2633
}
2734

28-
const TournamentTree: React.FC<TournamentTreeProps> = ({ tournament }) => {
35+
const TournamentTree: React.FC<TournamentTreeProps> = (props) => {
2936
// const [leafWidth, setLeafWidth] = useState<number | undefined>(undefined)
3037
// const leafRef = useRef<HTMLDivElement>(null)
3138

@@ -38,18 +45,18 @@ const TournamentTree: React.FC<TournamentTreeProps> = ({ tournament }) => {
3845
// resizeObserver.observe(leafRef.current)
3946
// }, [])
4047

41-
const brackets: [TournamentGame, string][] = tournament.losersBracketRoot
48+
const brackets: [TournamentGame, string][] = props.tournament.losersBracketRoot
4249
? [
43-
[tournament.winnersBracketRoot, 'Winners Bracket'],
44-
[tournament.losersBracketRoot, 'Losers Bracket']
50+
[props.tournament.winnersBracketRoot, 'Winners Bracket'],
51+
[props.tournament.losersBracketRoot, 'Losers Bracket']
4552
]
46-
: [[tournament.winnersBracketRoot, '']]
53+
: [[props.tournament.winnersBracketRoot, '']]
4754

4855
return (
4956
<div className="flex flex-row items-center justify-center w-full h-screen">
5057
{brackets.map(([rootGame, bracketTitle]) => (
5158
<div className="flex flex-col justify-center w-max mx-2" key={bracketTitle}>
52-
<TournamentGameWrapper game={rootGame} />
59+
<TournamentGameWrapper game={rootGame} minRound={props.minRound} spaceRef={props.spaceRef} />
5360
{bracketTitle && (
5461
<div className="text-white pt-2 text-center border-t border-white">{bracketTitle}</div>
5562
)}
@@ -59,7 +66,13 @@ const TournamentTree: React.FC<TournamentTreeProps> = ({ tournament }) => {
5966
)
6067
}
6168

62-
const TournamentGameWrapper: React.FC<{ game: TournamentGame }> = ({ game }) => {
69+
interface TournamentGameWrapperProps {
70+
game: TournamentGame
71+
minRound: number
72+
spaceRef: Space
73+
}
74+
75+
const TournamentGameWrapper: React.FC<TournamentGameWrapperProps> = (props) => {
6376
const wrapperRef = useRef<HTMLDivElement>(null)
6477
const childWrapper1Ref = useRef<HTMLDivElement>(null)
6578
const childWrapper2Ref = useRef<HTMLDivElement>(null)
@@ -71,56 +84,73 @@ const TournamentGameWrapper: React.FC<{ game: TournamentGame }> = ({ game }) =>
7184
})
7285

7386
useEffect(() => {
74-
if (!wrapperRef.current) return
87+
setTimeout(() => {
88+
if (!wrapperRef.current) return
89+
90+
const wrapperRect = wrapperRef.current.getBoundingClientRect()
91+
const scale = props.spaceRef.viewPort?.zoomFactor ?? 1
92+
const startX = wrapperRect.x + wrapperRect.width / 2
93+
const startY = wrapperRect.y + wrapperRect.height - 17.45
7594

76-
const wrapperRect = wrapperRef.current.getBoundingClientRect()
77-
const startX = wrapperRect.x + wrapperRect.width / 2
78-
const startY = wrapperRect.y + wrapperRect.height - 17.45
95+
let left = undefined
96+
let right = undefined
97+
let down = 0
7998

80-
let left = undefined
81-
let right = undefined
82-
let down = 0
99+
if (childWrapper1Ref.current) {
100+
const childWrapper1Rect = childWrapper1Ref.current.getBoundingClientRect()
101+
const child1X = childWrapper1Rect.x + childWrapper1Rect.width / 2
102+
const child1Y = childWrapper1Rect.y + 17.45
83103

84-
if (childWrapper1Ref.current) {
85-
const childWrapper1Rect = childWrapper1Ref.current.getBoundingClientRect()
86-
const child1X = childWrapper1Rect.x + childWrapper1Rect.width / 2
87-
const child1Y = childWrapper1Rect.y + 17.45
104+
left = Math.abs(child1X - startX) / scale
105+
down = Math.abs(child1Y - startY)
106+
}
88107

89-
left = Math.abs(child1X - startX)
90-
down = Math.abs(child1Y - startY)
91-
}
108+
if (childWrapper2Ref.current) {
109+
const childWrapper2Rect = childWrapper2Ref.current.getBoundingClientRect()
110+
const child2X = childWrapper2Rect.x + childWrapper2Rect.width / 2
111+
const child2Y = childWrapper2Rect.y + 17.45
92112

93-
if (childWrapper2Ref.current) {
94-
const childWrapper2Rect = childWrapper2Ref.current.getBoundingClientRect()
95-
const child2X = childWrapper2Rect.x + childWrapper2Rect.width / 2
96-
const child2Y = childWrapper2Rect.y + 17.45
113+
right = Math.abs(child2X - startX) / scale
114+
down = Math.abs(Math.max(down, child2Y - startY))
115+
}
97116

98-
right = Math.abs(child2X - startX)
99-
down = Math.abs(Math.max(down, child2Y - startY))
100-
}
117+
setLines({ left, right, down })
118+
}, 2)
119+
}, [wrapperRef.current, childWrapper1Ref.current, childWrapper2Ref.current, props.minRound])
101120

102-
setLines({ left, right, down })
103-
}, [wrapperRef.current, childWrapper1Ref.current, childWrapper2Ref.current])
121+
if (props.game.round < props.minRound) {
122+
props.game.viewed = true
123+
}
104124

105125
return (
106-
<div className="flex flex-col" key={game.id}>
126+
<div className="flex flex-col" key={props.game.id}>
107127
<div
108128
className="flex flex-col flex-grow basis-0 " /*ref={round === 1 && index === 0 ? leafRef : undefined}*/
109129
>
110-
<div className="mx-auto relative" ref={wrapperRef}>
111-
<TournamentGameElement game={game} />
112-
<GameChildrenLines lines={lines} />
113-
</div>
130+
{props.game.round >= props.minRound && (
131+
<div className="mx-auto relative" ref={wrapperRef}>
132+
<TournamentGameElement game={props.game} />
133+
{props.game.round > props.minRound && <GameChildrenLines lines={lines} />}
134+
</div>
135+
)}
114136
</div>
115137
<div className="flex flex-row">
116-
{game.dependsOn[0] && (
138+
{props.game.dependsOn[0] && (
117139
<div className="mx-auto" ref={childWrapper1Ref}>
118-
<TournamentGameWrapper game={game.dependsOn[0]} />
140+
<TournamentGameWrapper
141+
game={props.game.dependsOn[0]}
142+
minRound={props.minRound}
143+
spaceRef={props.spaceRef}
144+
/>
119145
</div>
120146
)}
121-
{game.dependsOn[1] && (
147+
{props.game.dependsOn[1] && (
122148
<div className="mx-auto" ref={childWrapper2Ref}>
123-
<TournamentGameWrapper game={game.dependsOn[1]} />
149+
<TournamentGameWrapper
150+
game={props.game.dependsOn[1]}
151+
minRound={props.minRound}
152+
spaceRef={props.spaceRef}
153+
/>
124154
</div>
125155
)}
126156
</div>

client/src/components/sidebar/game/game.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ export const GamePage: React.FC<Props> = React.memo((props) => {
6262

6363
return (
6464
<div className="flex flex-col overflow-x-hidden">
65+
<div className="w-full pb-3 px-4 text-center">
66+
{activeGame && activeGame.currentMatch && (
67+
<div className="border-black border rounded-md font-bold">{activeGame.currentMatch.map.name}</div>
68+
)}
69+
</div>
6570
{teamBox(0)}
6671
<TeamTable teamIdx={0} />
6772

client/src/components/sidebar/runner/scaffold.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,18 @@ export function useScaffold(): Scaffold {
5151

5252
async function runMatch(javaPath: string, teamA: string, teamB: string, selectedMaps: Set<string>): Promise<void> {
5353
if (matchPID.current || !scaffoldPath) return
54+
const shouldProfile = false
5455
try {
55-
const newPID = await dispatchMatch(javaPath, teamA, teamB, selectedMaps, nativeAPI!, scaffoldPath!)
56+
const newPID = await dispatchMatch(
57+
javaPath,
58+
teamA,
59+
teamB,
60+
selectedMaps,
61+
nativeAPI!,
62+
scaffoldPath!,
63+
appContext.state.config.validateMaps,
64+
shouldProfile
65+
)
5666
setConsoleLines([])
5767
matchPID.current = newPID
5868
} catch (e: any) {
@@ -272,7 +282,9 @@ async function dispatchMatch(
272282
teamB: string,
273283
selectedMaps: Set<string>,
274284
nativeAPI: NativeAPI,
275-
scaffoldPath: string
285+
scaffoldPath: string,
286+
validate: boolean,
287+
profile: boolean
276288
): Promise<string> {
277289
const options = [
278290
`run`,
@@ -282,8 +294,8 @@ async function dispatchMatch(
282294
`-PteamA=${teamA}`,
283295
`-PteamB=${teamB}`,
284296
`-Pmaps=${[...selectedMaps].join(',')}`,
285-
`-PvalidateMaps=false`,
286-
`-PenableProfiler=${false}`
297+
`-PvalidateMaps=${validate}`,
298+
`-PenableProfiler=${profile}`
287299
]
288300

289301
return nativeAPI.child_process.spawn(scaffoldPath, javaPath, options)

0 commit comments

Comments
 (0)