From 00e517045ba39584c536677e246460ff76024cb0 Mon Sep 17 00:00:00 2001 From: Akita Noek Date: Fri, 10 May 2024 12:38:58 -0600 Subject: [PATCH] Add support for switching between the new SVG based goban renderer and the old canvas renderer --- .../AnnulQueueModal/AnnulQueueModal.tsx | 6 +-- .../ChallengeModal/ChallengeModal.tsx | 4 +- src/components/ChallengeModal/ForkModal.tsx | 8 ++-- src/components/GameList/GameList.tsx | 14 +++---- .../GobanContainer/GobanContainer.tsx | 9 ++--- .../GobanLineSummary/GobanLineSummary.tsx | 8 ++-- src/components/MiniGoban/MiniGoban.tsx | 8 ++-- src/components/TimeControl/util.ts | 4 +- src/lib/configure-goban.ts | 13 +++++-- src/lib/sockets.ts | 4 +- src/views/Game/AIDemoReview.tsx | 8 ++-- src/views/Game/Game.tsx | 16 ++++---- src/views/Game/GameChat.tsx | 4 +- src/views/Game/GameDock.test.tsx | 4 +- src/views/Game/GameLinkModal.tsx | 8 ++-- src/views/Game/PlayButtons.test.tsx | 38 +++++++++---------- src/views/Game/PlayControls.test.tsx | 22 +++++------ src/views/Game/PlayControls.tsx | 10 ++--- src/views/Game/PlayerCards.test.tsx | 6 +-- src/views/Game/PlayerCards.tsx | 4 +- src/views/Game/goban_context.ts | 6 +-- src/views/Joseki/Joseki.tsx | 8 ++-- src/views/LearningHub/InstructionalGoban.tsx | 6 +-- src/views/Puzzle/Puzzle.tsx | 10 ++--- src/views/Puzzle/PuzzleEditing.ts | 6 +-- src/views/Puzzle/PuzzleNavigation.ts | 6 +-- src/views/ReportsCenter/ReportedGame.tsx | 8 ++-- .../ReportsCenter/ScoringEventThumbnail.tsx | 8 ++-- 28 files changed, 131 insertions(+), 125 deletions(-) diff --git a/src/components/AnnulQueueModal/AnnulQueueModal.tsx b/src/components/AnnulQueueModal/AnnulQueueModal.tsx index 8df2d39c19..5802bb06e8 100644 --- a/src/components/AnnulQueueModal/AnnulQueueModal.tsx +++ b/src/components/AnnulQueueModal/AnnulQueueModal.tsx @@ -18,7 +18,7 @@ import * as React from "react"; import { _ } from "translate"; import { MiniGoban } from "MiniGoban"; -import { Goban } from "goban"; +import { GobanRenderer } from "goban"; import { AIReview, GameTimings, ChatMode, GameChat, GobanContext } from "Game"; import { Player } from "Player"; import { Resizable } from "Resizable"; @@ -45,9 +45,9 @@ export function AnnulQueueModal({ }: AnnulQueueModalProps) { // Declare state variables const [selectedGameIndex, setSelectedGameIndex] = React.useState(0); - const [goban, setGoban] = React.useState(null); + const [goban, setGoban] = React.useState(null); const [selectedChatLog, setSelectedChatLog] = React.useState("main"); - const onGobanCreated = React.useCallback((goban: Goban) => { + const onGobanCreated = React.useCallback((goban: GobanRenderer) => { setGoban(goban); }, []); const [, setAiReviewUuid] = React.useState(null); diff --git a/src/components/ChallengeModal/ChallengeModal.tsx b/src/components/ChallengeModal/ChallengeModal.tsx index 446e57a5bd..07542f1d72 100644 --- a/src/components/ChallengeModal/ChallengeModal.tsx +++ b/src/components/ChallengeModal/ChallengeModal.tsx @@ -41,7 +41,7 @@ import { notification_manager, NotificationManagerEvents } from "Notifications/N import { one_bot, bot_count, bots_list } from "bots"; import { goban_view_mode } from "Game/util"; import { - Goban, + GobanRenderer, GoEngineConfig, GoEngineInitialState, GoEnginePlayerEntry, @@ -1889,7 +1889,7 @@ export function challengeComputer() { return challenge(undefined, null, true); } export function challengeRematch( - goban: Goban, + goban: GobanRenderer, opponent: GoEnginePlayerEntry, original_game_meta: GoEngineConfig & { pause_on_weekends?: boolean }, ) { diff --git a/src/components/ChallengeModal/ForkModal.tsx b/src/components/ChallengeModal/ForkModal.tsx index fe0be0f5b9..b2ba370bf1 100644 --- a/src/components/ChallengeModal/ForkModal.tsx +++ b/src/components/ChallengeModal/ForkModal.tsx @@ -19,7 +19,7 @@ import * as React from "react"; import * as data from "data"; import { _ } from "translate"; import { Modal, openModal } from "Modal"; -import { Goban } from "goban"; +import { GobanRenderer } from "goban"; import { PlayerAutocomplete } from "PlayerAutocomplete"; import { MiniGoban } from "MiniGoban"; import { challenge } from "ChallengeModal"; @@ -28,7 +28,7 @@ import { PlayerCacheEntry } from "src/lib/player_cache"; interface Events {} interface ForkModalProperties { - goban: Goban; + goban: GobanRenderer; } export class ForkModal extends Modal { @@ -99,10 +99,10 @@ export class ForkModal extends Modal { } } -export function openForkModal(goban: Goban) { +export function openForkModal(goban: GobanRenderer) { return openModal(); } -export function challengeFromBoardPosition(goban: Goban) { +export function challengeFromBoardPosition(goban: GobanRenderer) { if (!goban) { return; } diff --git a/src/components/GameList/GameList.tsx b/src/components/GameList/GameList.tsx index 352eeaca68..4f795b3e75 100644 --- a/src/components/GameList/GameList.tsx +++ b/src/components/GameList/GameList.tsx @@ -30,7 +30,7 @@ import { AdHocPlayerClock, AdHocPauseControl, AdHocPackedMove, - Goban, + GobanRenderer, } from "goban"; interface UserType { @@ -43,7 +43,7 @@ interface GameType { name: string; black: UserType; white: UserType; - goban?: Goban; + goban?: GobanRenderer; json?: { clock: AdHocClock; moves: AdHocPackedMove[]; @@ -373,7 +373,7 @@ export class GameList extends React.PureComponent currentSort={this.state.sort_order} player={this.props.player} lineSummaryMode={this.props.lineSummaryMode} - onGobanCreated={(game: GameType, goban: Goban) => + onGobanCreated={(game: GameType, goban: GobanRenderer) => this.onGobanCreated(game, goban) } > @@ -382,14 +382,14 @@ export class GameList extends React.PureComponent return MiniGobanList( games, !!this.props.namesByGobans, - (game: GameType, goban: Goban) => this.onGobanCreated(game, goban), + (game: GameType, goban: GobanRenderer) => this.onGobanCreated(game, goban), this.props?.player, this.props.miniGobanProps, ); } } - onGobanCreated(game: GameType, goban: Goban) { + onGobanCreated(game: GameType, goban: GobanRenderer) { // Save a pointer into the goban to use when sorting. game.goban = goban; @@ -419,7 +419,7 @@ interface LineSummaryTableProps extends GameListProps { disableSort: boolean; currentSort: SortOrder | DescendingSortOrder; onSort: (sortBy: SortOrder) => void; - onGobanCreated: (game: GameType, goban: Goban) => void; + onGobanCreated: (game: GameType, goban: GobanRenderer) => void; } function LineSummaryTable({ @@ -523,7 +523,7 @@ function LineSummaryTable({ function MiniGobanList( games: GameType[], withNames: boolean, - onGobanCreated: (game: GameType, goban: Goban) => void, + onGobanCreated: (game: GameType, goban: GobanRenderer) => void, player?: { id: number }, miniGobanProps?: MiniGobanProps, ): JSX.Element { diff --git a/src/components/GobanContainer/GobanContainer.tsx b/src/components/GobanContainer/GobanContainer.tsx index 51123cdd54..f519a62a0e 100644 --- a/src/components/GobanContainer/GobanContainer.tsx +++ b/src/components/GobanContainer/GobanContainer.tsx @@ -18,7 +18,7 @@ import * as React from "react"; import { PersistentElement } from "PersistentElement"; import { OgsResizeDetector } from "OgsResizeDetector"; -import { GobanCanvas, GobanCanvasConfig } from "goban"; +import { GobanRenderer, GobanRendererConfig } from "goban"; // Pull this out its own util import { goban_view_mode } from "Game/util"; //import { generateGobanHook } from "Game/GameHooks"; @@ -26,7 +26,7 @@ import { goban_view_mode } from "Game/util"; import { usePreference } from "preferences"; interface GobanContainerProps { - goban?: GobanCanvas; + goban?: GobanRenderer; /** callback that is called when the goban detects a resize. */ onResize?: () => void; /** Additional props to pass to the PersistentElement that wraps the goban_div */ @@ -45,8 +45,7 @@ export function GobanContainer({ const resize_debounce = React.useRef(null); const [last_move_opacity] = usePreference("last-move-opacity"); - // Since goban is a GobanCanvas, we know goban.config is a GobanCanvasConfig - const goban_div = (goban?.config as GobanCanvasConfig | undefined)?.board_div; + const goban_div = (goban?.config as GobanRendererConfig | undefined)?.board_div; const recenterGoban = () => { if (!ref_goban_container.current || !goban || !goban_div) { @@ -112,7 +111,7 @@ export function GobanContainer({ [goban, goban_div, onResizeCb], ); - // Trigger resize on new Goban and subsequent "load" events + // Trigger resize on createGoban and subsequent "load" events //generateGobanHook(() => onResize(/* no_debounce */ true, /* do_cb */ false))(goban || null); if (!goban || !goban_div) { diff --git a/src/components/GobanLineSummary/GobanLineSummary.tsx b/src/components/GobanLineSummary/GobanLineSummary.tsx index 833bd5ae1d..5e5f46d96f 100644 --- a/src/components/GobanLineSummary/GobanLineSummary.tsx +++ b/src/components/GobanLineSummary/GobanLineSummary.tsx @@ -18,7 +18,7 @@ import * as React from "react"; import { Link } from "react-router-dom"; import { interpolate } from "translate"; -import { Goban } from "goban"; +import { createGoban, GobanRenderer } from "goban"; import * as data from "data"; import { rankString } from "rank_utils"; import { Player } from "Player"; @@ -41,7 +41,7 @@ interface GobanLineSummaryProps { black: UserType; white: UserType; player?: { id: number }; - gobanRef?: (goban: Goban) => void; + gobanRef?: (goban: GobanRenderer) => void; width?: number; height?: number; rengo_teams?: { @@ -62,7 +62,7 @@ export class GobanLineSummary extends React.Component< GobanLineSummaryProps, GobanLineSummaryState > { - goban!: Goban; + goban!: GobanRenderer; constructor(props: GobanLineSummaryProps) { super(props); @@ -100,7 +100,7 @@ export class GobanLineSummary extends React.Component< */ requestAnimationFrame(() => { - this.goban = new Goban({ + this.goban = createGoban({ board_div: undefined, draw_top_labels: false, draw_bottom_labels: false, diff --git a/src/components/MiniGoban/MiniGoban.tsx b/src/components/MiniGoban/MiniGoban.tsx index de2ed82b18..b205f976c7 100644 --- a/src/components/MiniGoban/MiniGoban.tsx +++ b/src/components/MiniGoban/MiniGoban.tsx @@ -20,7 +20,7 @@ import { Link } from "react-router-dom"; import { npgettext, interpolate } from "translate"; import * as moment from "moment"; import * as preferences from "preferences"; -import { Goban } from "goban"; +import { GobanRenderer, createGoban } from "goban"; import * as data from "data"; import { PersistentElement } from "PersistentElement"; import { getUserRating, PROVISIONAL_RATING_CUTOFF } from "rank_utils"; @@ -51,7 +51,7 @@ export interface MiniGobanProps { openLinksInNewTab?: boolean; noText?: boolean; title?: boolean; - onGobanCreated?: (goban: Goban) => void; + onGobanCreated?: (goban: GobanRenderer) => void; chat?: boolean; } @@ -63,7 +63,7 @@ export function MiniGoban(props: MiniGobanProps): JSX.Element { return ret; })(), ); - const goban = React.useRef(); + const goban = React.useRef(); const [white_points, setWhitePoints] = React.useState(""); const [black_points, setBlackPoints] = React.useState(""); @@ -83,7 +83,7 @@ export function MiniGoban(props: MiniGobanProps): JSX.Element { const [last_move_opacity] = usePreference("last-move-opacity"); React.useEffect(() => { - goban.current = new Goban( + goban.current = createGoban( { board_div: goban_div.current, draw_top_labels: false, diff --git a/src/components/TimeControl/util.ts b/src/components/TimeControl/util.ts index f26fbf4b71..799f2f7682 100644 --- a/src/components/TimeControl/util.ts +++ b/src/components/TimeControl/util.ts @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -import { computeAverageMoveTime, Goban, JGOFTimeControl } from "goban"; +import { computeAverageMoveTime, GobanRenderer, JGOFTimeControl } from "goban"; import { _, pgettext, ngettext, interpolate } from "translate"; import { TimeControl, TimeControlTypes } from "./TimeControl"; @@ -454,7 +454,7 @@ export function usedForCheating(_time_control: ValidTimeControlFormats) { export function lookingAtOurLiveGame(): boolean { // Is the current page looking at a game we are live playing in... - const goban = (window as any)["global_goban"] as Goban; + const goban = (window as any)["global_goban"] as GobanRenderer; if (!goban) { return false; } diff --git a/src/lib/configure-goban.ts b/src/lib/configure-goban.ts index 45ac65e98b..2163dbb8d4 100644 --- a/src/lib/configure-goban.ts +++ b/src/lib/configure-goban.ts @@ -20,10 +20,10 @@ import * as data from "data"; import * as Sentry from "@sentry/browser"; import { get_clock_drift, get_network_latency, socket } from "sockets"; import { current_language } from "translate"; -import { Goban, GobanCore, GoEngine, GoThemes } from "goban"; +import { GobanCore, GoEngine, GoThemes, setGobanRenderer } from "goban"; import { sfx } from "sfx"; -(window as any)["Goban"] = Goban; +//(window as any)["Goban"] = Goban; (window as any)["GoThemes"] = GoThemes; (window as any)["GoEngine"] = GoEngine; @@ -34,7 +34,14 @@ data.setDefault("custom.line", "#000000"); data.setDefault("custom.url", ""); export function configure_goban() { - Goban.setHooks({ + data.watch("experiments.v6", () => { + const v = data.get("experiments.v6"); + if (v === "enabled") { + setGobanRenderer("svg"); + } + }); + + GobanCore.setHooks({ defaultConfig: () => { return { server_socket: socket, diff --git a/src/lib/sockets.ts b/src/lib/sockets.ts index a72f4e4d59..e3e4eda3b3 100644 --- a/src/lib/sockets.ts +++ b/src/lib/sockets.ts @@ -16,7 +16,7 @@ */ import Debug from "debug"; -import { GobanSocket, protocol, Goban, JGOFTimeControl } from "goban"; +import { GobanSocket, protocol, GobanRenderer, JGOFTimeControl } from "goban"; import { lookingAtOurLiveGame } from "TimeControl/util"; const debug = new Debug("sockets"); @@ -95,7 +95,7 @@ socket.on("latency", (latency, drift) => { // If they are playing a live game at the moment, work out what timing they would like // us to make sure that they have... if (lookingAtOurLiveGame()) { - const goban = (window as any)["global_goban"] as Goban; + const goban = (window as any)["global_goban"] as GobanRenderer; const time_control = goban.engine.time_control as JGOFTimeControl; switch (time_control.system) { case "fischer": diff --git a/src/views/Game/AIDemoReview.tsx b/src/views/Game/AIDemoReview.tsx index 25b222589c..f3d0d1f23f 100644 --- a/src/views/Game/AIDemoReview.tsx +++ b/src/views/Game/AIDemoReview.tsx @@ -22,7 +22,7 @@ import { Toggle } from "Toggle"; import { uuid } from "misc"; import * as preferences from "preferences"; import { usePreference } from "preferences"; -import { JGOFNumericPlayerColor, ColoredCircle, MoveTree, Goban } from "goban"; +import { JGOFNumericPlayerColor, ColoredCircle, MoveTree, GobanRenderer } from "goban"; import { useUser } from "hooks"; const cached_data: { [review_id: number]: { [board_string: string]: any } } = {}; @@ -36,7 +36,7 @@ export function AIDemoReview({ goban, controller, }: { - goban: Goban; + goban: GobanRenderer; controller: number; }): JSX.Element | null { const user = useUser(); @@ -324,7 +324,7 @@ function stringifyBoardState(move: MoveTree): string { return move.state.board.reduce((a, b) => a + b.reduce((a, b) => a + b, ""), ""); } -function clearAnalysis(goban: Goban) { +function clearAnalysis(goban: GobanRenderer) { goban.setMarks({}, true); /* draw the remaining AI sequence as ghost marks, if any */ goban.setHeatmap(undefined, true); goban.setColoredCircles([], false); @@ -334,7 +334,7 @@ function computePrediction(data: any): any { return { score: data.analysis.score, win_rate: data.analysis.win_rate }; } -function renderAnalysis(goban: Goban, data: any) { +function renderAnalysis(goban: GobanRenderer, data: any) { if (!preferences.get("ai-review-enabled")) { return; } diff --git a/src/views/Game/Game.tsx b/src/views/Game/Game.tsx index 6019afeef6..901e63eeb8 100644 --- a/src/views/Game/Game.tsx +++ b/src/views/Game/Game.tsx @@ -28,9 +28,9 @@ import { KBShortcut } from "KBShortcut"; import { UIPush } from "UIPush"; import { errorAlerter, ignore, rulesText } from "misc"; import { - Goban, - GobanCanvas, - GobanCanvasConfig, + createGoban, + GobanRenderer, + GobanRendererConfig, GoMath, MoveTree, AudioClockEvent, @@ -99,7 +99,7 @@ export function Game(): JSX.Element | null { const copied_node = React.useRef(); const white_username = React.useRef("White"); const black_username = React.useRef("Black"); - const goban = React.useRef(null); + const goban = React.useRef(null); const return_url_debounce = React.useRef(false); const last_phase = React.useRef(""); const page_loaded_time = React.useRef(Date.now()); // when we first created this view @@ -1041,7 +1041,7 @@ export function Game(): JSX.Element | null { const setMoveTreeContainer = (resizable: Resizable): void => { ref_move_tree_container.current = resizable ? resizable.div ?? undefined : undefined; if (goban.current && ref_move_tree_container.current) { - (goban.current as GobanCanvas).setMoveTreeContainer(ref_move_tree_container.current); + (goban.current as GobanRenderer).setMoveTreeContainer(ref_move_tree_container.current); } }; @@ -1073,7 +1073,7 @@ export function Game(): JSX.Element | null { document.addEventListener("keypress", setLabelHandler); const label_position = preferences.get("label-positioning"); - const opts: GobanCanvasConfig = { + const opts: GobanRendererConfig = { board_div: goban_div.current, move_tree_container: ref_move_tree_container.current, interactive: true, @@ -1107,7 +1107,7 @@ export function Game(): JSX.Element | null { goban.current?.review_controller_id === data.get("user").id; } - goban.current = new Goban(opts); + goban.current = createGoban(opts); onResize(true); (window as any)["global_goban"] = goban.current; @@ -1772,7 +1772,7 @@ export function Game(): JSX.Element | null { ); } -function bindAudioEvents(goban: Goban): void { +function bindAudioEvents(goban: GobanRenderer): void { // called by init const user = data.get("user"); diff --git a/src/views/Game/GameChat.tsx b/src/views/Game/GameChat.tsx index 7eba8873ad..2ed36c3597 100644 --- a/src/views/Game/GameChat.tsx +++ b/src/views/Game/GameChat.tsx @@ -24,7 +24,7 @@ import { Link } from "react-router-dom"; import { _, pgettext, interpolate, current_language } from "translate"; import { Player } from "Player"; import { profanity_filter } from "profanity_filter"; -import { Goban, GobanCore, protocol } from "goban"; +import { GobanRenderer, GobanCore, protocol } from "goban"; import { ChatUserList, ChatUserCount } from "ChatUserList"; import { TabCompleteInput } from "TabCompleteInput"; import { chat_markup } from "components/Chat"; @@ -329,7 +329,7 @@ export function GameChat(props: GameChatProperties): JSX.Element { interface QuickChatProperties { selected_chat_log: ChatMode; - goban: Goban; + goban: GobanRenderer; onSend: () => void; } diff --git a/src/views/Game/GameDock.test.tsx b/src/views/Game/GameDock.test.tsx index d841c825a2..6fa04ffb6d 100644 --- a/src/views/Game/GameDock.test.tsx +++ b/src/views/Game/GameDock.test.tsx @@ -1,7 +1,7 @@ import { render, screen } from "@testing-library/react"; import * as React from "react"; import { GameDock } from "./GameDock"; -import { Goban } from "goban"; +import { createGoban } from "goban"; import { GobanContext } from "./goban_context"; import { BrowserRouter as Router } from "react-router-dom"; import * as data from "data"; @@ -59,7 +59,7 @@ const BASE_PROPS = { test("providing both Game ID and Review ID cause SGF buttons to link to review SGFs", () => { data.set("user", TEST_USER); - const goban = new Goban({ game_id: 123456, review_id: 123 }); + const goban = createGoban({ game_id: 123456, review_id: 123 }); render( diff --git a/src/views/Game/GameLinkModal.tsx b/src/views/Game/GameLinkModal.tsx index 2f8bf30557..50c7d716d8 100644 --- a/src/views/Game/GameLinkModal.tsx +++ b/src/views/Game/GameLinkModal.tsx @@ -18,13 +18,13 @@ import * as React from "react"; import { pgettext, _ } from "translate"; import { openModal, Modal } from "Modal"; -import { Goban } from "goban"; +import { GobanRenderer } from "goban"; import { Player } from "Player"; interface Events {} interface GameLinkModalProperties { - goban: Goban; + goban: GobanRenderer; } export class GameLinkModal extends Modal { @@ -97,7 +97,7 @@ export class GameLinkModal extends Modal { } } -function AnimatedPngCreator({ goban }: { goban: Goban }): JSX.Element { +function AnimatedPngCreator({ goban }: { goban: GobanRenderer }): JSX.Element { const engine = goban.engine; const MAX_MOVES = 30; const NUM_MOVES = engine?.last_official_move.move_number || 1; @@ -198,7 +198,7 @@ function AnimatedPngCreator({ goban }: { goban: Goban }): JSX.Element { ); } -export function openGameLinkModal(goban: Goban): void { +export function openGameLinkModal(goban: GobanRenderer): void { openModal(); } diff --git a/src/views/Game/PlayButtons.test.tsx b/src/views/Game/PlayButtons.test.tsx index 2c9c6d8cbf..5e05a49c80 100644 --- a/src/views/Game/PlayButtons.test.tsx +++ b/src/views/Game/PlayButtons.test.tsx @@ -1,4 +1,4 @@ -import { AdHocPackedMove, Goban } from "goban"; +import { AdHocPackedMove, createGoban, GobanRenderer } from "goban"; import { CancelButton, PlayButtons } from "./PlayButtons"; import { act, cleanup, fireEvent, render, screen /* waitFor */ } from "@testing-library/react"; import * as React from "react"; @@ -66,7 +66,7 @@ afterEach(() => { describe("CancelButton", () => { test('says "Cancel game" in the first 6 moves.', () => { - const goban = new Goban(LESS_THAN_SIX_MOVES); + const goban = createGoban(LESS_THAN_SIX_MOVES); render( @@ -79,7 +79,7 @@ describe("CancelButton", () => { }); test('says "Resign" after 6 moves', () => { - const goban = new Goban(MORE_THAN_SIX_MOVES); + const goban = createGoban(MORE_THAN_SIX_MOVES); render( @@ -92,7 +92,7 @@ describe("CancelButton", () => { }); test('changes to "Resign" on the 6th move.', () => { - const goban = new Goban({ + const goban = createGoban({ // 5 moves moves: [ [16, 3, 9136.12], @@ -129,7 +129,7 @@ describe("CancelButton", () => { uncomment this test after upgrading... test("allows user to cancel before 6 moves.", async () => { - const goban = new Goban(LESS_THAN_SIX_MOVES); + const goban = createGoban(LESS_THAN_SIX_MOVES); const cancel_spy = spyOn(goban, "cancelGame"); render( @@ -148,7 +148,7 @@ describe("CancelButton", () => { }); test("allows user to resign after 6 moves.", async () => { - const goban = new Goban(MORE_THAN_SIX_MOVES); + const goban = createGoban(MORE_THAN_SIX_MOVES); const resign_spy = spyOn(goban, "resign"); render( @@ -167,7 +167,7 @@ describe("CancelButton", () => { }); test("allows user to abandon in casual rengo.", async () => { - const goban = new Goban({ + const goban = createGoban({ ...MORE_THAN_SIX_MOVES, rengo: true, rengo_teams: { @@ -197,7 +197,7 @@ describe("CancelButton", () => { }); test("allows user to change their mind", async () => { - const goban = new Goban(MORE_THAN_SIX_MOVES); + const goban = createGoban(MORE_THAN_SIX_MOVES); const resign_spy = spyOn(goban, "resign"); render( @@ -218,7 +218,7 @@ describe("CancelButton", () => { */ }); -function WrapTest(props: { goban: Goban; children: any }): JSX.Element { +function WrapTest(props: { goban: GobanRenderer; children: any }): JSX.Element { return ( {props.children} @@ -228,7 +228,7 @@ function WrapTest(props: { goban: Goban; children: any }): JSX.Element { describe("PlayButtons", () => { test("normal game when it's my opponent's turn.", () => { - const goban = new Goban({ + const goban = createGoban({ moves: [ [16, 3, 9136.12], // B [3, 2, 1897.853], // W @@ -257,7 +257,7 @@ describe("PlayButtons", () => { }); test("normal game when it's my turn.", () => { - const goban = new Goban({ + const goban = createGoban({ moves: [ [16, 3, 9136.12], // B [3, 2, 1897.853], // W @@ -287,7 +287,7 @@ describe("PlayButtons", () => { }); test('shows "Accept Undo" when opponent requested an undo.', () => { - const goban = new Goban({ + const goban = createGoban({ moves: [ [16, 3, 9136.12], // B [3, 2, 1897.853], // W @@ -317,7 +317,7 @@ describe("PlayButtons", () => { }); test('shows "Accept undo" if undo was requested after initial render', () => { - const goban = new Goban({ + const goban = createGoban({ moves: [ [16, 3, 9136.12], // B [3, 2, 1897.853], // W @@ -350,7 +350,7 @@ describe("PlayButtons", () => { }); test('shows "Submit Move" when user staged a move.', () => { - const goban = new Goban({ + const goban = createGoban({ moves: [ [16, 3, 9136.12], // B [3, 2, 1897.853], // W @@ -387,7 +387,7 @@ describe("PlayButtons", () => { }); test("Don't show undo for rengo", () => { - const goban = new Goban({ + const goban = createGoban({ moves: [ [16, 3, 9136.12], // B [3, 2, 1897.853], // W @@ -417,7 +417,7 @@ describe("PlayButtons", () => { }); test("Don't show undo on the first move", () => { - const goban = new Goban({ + const goban = createGoban({ players: { black: { id: LOGGED_IN_USER.id, username: LOGGED_IN_USER.username }, white: { id: 456, username: "test_user2" }, @@ -441,7 +441,7 @@ describe("PlayButtons", () => { }); test("Don't show undo if analyzing the game", () => { - const goban = new Goban({ + const goban = createGoban({ moves: [ [16, 3, 9136.12], // B [3, 2, 1897.853], // W @@ -470,7 +470,7 @@ describe("PlayButtons", () => { test("Don't show accept undo if analyzing the game", () => { console.log("test started"); - const goban = new Goban({ + const goban = createGoban({ moves: [ [16, 3, 9136.12], // B [3, 2, 1897.853], // W @@ -502,7 +502,7 @@ describe("PlayButtons", () => { }); test("forked game where it's the first move, white to play, my move.", () => { - const goban = new Goban({ + const goban = createGoban({ initial_player: "white", players: { black: { id: 456, username: "test_user2" }, diff --git a/src/views/Game/PlayControls.test.tsx b/src/views/Game/PlayControls.test.tsx index a40b1b5bac..fe1eefc910 100644 --- a/src/views/Game/PlayControls.test.tsx +++ b/src/views/Game/PlayControls.test.tsx @@ -1,4 +1,4 @@ -import { Goban, GoConditionalMove } from "goban"; +import { createGoban, GobanRenderer, GoConditionalMove } from "goban"; import { PlayControls } from "./PlayControls"; import { render, screen } from "@testing-library/react"; import * as React from "react"; @@ -77,7 +77,7 @@ const PLAY_CONTROLS_DEFAULTS = { }, } as const; -function WrapTest(props: { goban: Goban; children: any }): JSX.Element { +function WrapTest(props: { goban: GobanRenderer; children: any }): JSX.Element { return ( @@ -88,7 +88,7 @@ function WrapTest(props: { goban: Goban; children: any }): JSX.Element { } test("No moves have been played", () => { - const goban = new Goban({ + const goban = createGoban({ game_id: 1234, // TEST_USER must be a member of the game in order for cancel to show up. players: { @@ -112,7 +112,7 @@ test("No moves have been played", () => { }); test("Don't render play buttons if user is not a player", () => { - const goban = new Goban({ game_id: 1234 }); + const goban = createGoban({ game_id: 1234 }); data.set("user", TEST_USER); render( @@ -129,7 +129,7 @@ test("Don't render play buttons if user is not a player", () => { }); test("Renders undo if it is not the players turn", () => { - const goban = new Goban({ + const goban = createGoban({ game_id: 1234, // Need to play at least one move before Undo button shows up moves: [ @@ -157,7 +157,7 @@ test("Renders undo if it is not the players turn", () => { }); test("Renders accept undo if undo requested", () => { - const goban = new Goban({ + const goban = createGoban({ game_id: 1234, // Need to play at least one move before Undo button shows up moves: [ @@ -187,7 +187,7 @@ test("Renders accept undo if undo requested", () => { }); test("Renders Pass if it is the user's turn", () => { - const goban = new Goban({ + const goban = createGoban({ game_id: 1234, moves: [ [15, 15, 5241], @@ -233,7 +233,7 @@ function makeConditionalMoveTree() { } test("Renders conditional moves", () => { - const goban = new Goban({ + const goban = createGoban({ game_id: 1234, moves: [], players: { @@ -256,10 +256,10 @@ test("Renders conditional moves", () => { }); test("Unsubscribe from all events on unmount", () => { - const goban = new Goban({ game_id: 1234 }); + const goban = createGoban({ game_id: 1234 }); data.set("user", TEST_USER); - const getListenerCounts = (emitter: Goban) => + const getListenerCounts = (emitter: GobanRenderer) => Object.fromEntries(emitter.eventNames().map((key) => [key, emitter.listenerCount(key)])); // Goban may set up listeners on itself @@ -276,7 +276,7 @@ test("Unsubscribe from all events on unmount", () => { }); test("Pause buttons show up", () => { - const goban = new Goban({ + const goban = createGoban({ game_id: 1234, // TEST_USER must be a member of the game in order for cancel to show up. players: { diff --git a/src/views/Game/PlayControls.tsx b/src/views/Game/PlayControls.tsx index 67f581a4b2..5d296f6e02 100644 --- a/src/views/Game/PlayControls.tsx +++ b/src/views/Game/PlayControls.tsx @@ -21,7 +21,7 @@ import * as DynamicHelp from "react-dynamic-help"; import * as data from "data"; import { ConditionalMoveTree, - Goban, + GobanRenderer, GobanCore, GoConditionalMove, GobanModes, @@ -826,7 +826,7 @@ export function AnalyzeButtonBar({ } export function copyBranch( - goban: Goban, + goban: GobanRenderer, copied_node: React.MutableRefObject, mode: GobanModes, ) { @@ -847,7 +847,7 @@ export function copyBranch( toast(
{_("Branch copied")}
, 1000); } export function pasteBranch( - goban: Goban, + goban: GobanRenderer, copied_node: React.MutableRefObject, mode: GobanModes, ) { @@ -893,7 +893,7 @@ export function pasteBranch( } } -export function deleteBranch(goban: Goban, mode: GobanModes) { +export function deleteBranch(goban: GobanRenderer, mode: GobanModes) { if (mode !== "analyze") { return; } @@ -1247,7 +1247,7 @@ function diffToConditionalMove(moves: string): GoConditionalMove { // Copies branch to conditional move planner (only copies up to the selected // move). Should only be called in analyze mode. -function automateBranch(goban: Goban): void { +function automateBranch(goban: GobanRenderer): void { if (goban.engine.phase === "finished") { return; } diff --git a/src/views/Game/PlayerCards.test.tsx b/src/views/Game/PlayerCards.test.tsx index 6cf2da0b14..3088d37e44 100644 --- a/src/views/Game/PlayerCards.test.tsx +++ b/src/views/Game/PlayerCards.test.tsx @@ -2,7 +2,7 @@ import { render } from "@testing-library/react"; import "@testing-library/jest-dom"; import * as React from "react"; import { PlayerCard } from "./PlayerCards"; -import { Goban } from "goban"; +import { createGoban } from "goban"; import { GobanContext } from "./goban_context"; import { BrowserRouter as Router } from "react-router-dom"; import * as data from "data"; @@ -53,7 +53,7 @@ test("make sure komi is displayed for white", () => { data.set("preferences.moderator.hide-flags", false); data.set("preferences.moderator.hide-player-card-mod-controls", false); - const goban = new Goban({ game_id: 123456, komi: 5 }); + const goban = createGoban({ game_id: 123456, komi: 5 }); const props = { goban: goban, ...BASE_PROPS }; @@ -74,7 +74,7 @@ test("make sure komi is not displayed for black", () => { data.set("preferences.moderator.hide-flags", false); data.set("preferences.moderator.hide-player-card-mod-controls", false); - const goban = new Goban({ game_id: 123456, komi: 5 }); + const goban = createGoban({ game_id: 123456, komi: 5 }); const props = { goban: goban, ...BASE_PROPS, color: "black" as const }; diff --git a/src/views/Game/PlayerCards.tsx b/src/views/Game/PlayerCards.tsx index 8d669d23d1..31eee83042 100644 --- a/src/views/Game/PlayerCards.tsx +++ b/src/views/Game/PlayerCards.tsx @@ -18,7 +18,7 @@ import * as React from "react"; import { get } from "requests"; -import { Goban, GobanCore, PlayerScore, JGOFPlayerSummary } from "goban"; +import { GobanRenderer, GobanCore, PlayerScore, JGOFPlayerSummary } from "goban"; import { icon_size_url } from "PlayerIcon"; import { CountDown } from "./CountDown"; import { Flag } from "Flag"; @@ -181,7 +181,7 @@ const useScore = generateGobanHook( ); interface PlayerCardProps { color: "black" | "white"; - goban: Goban; + goban: GobanRenderer; historical: PlayerType | null; estimating_score: boolean; show_score_breakdown: boolean; diff --git a/src/views/Game/goban_context.ts b/src/views/Game/goban_context.ts index ae58835f78..4e406266b4 100644 --- a/src/views/Game/goban_context.ts +++ b/src/views/Game/goban_context.ts @@ -16,16 +16,16 @@ */ import * as React from "react"; -import { Goban } from "goban"; +import { GobanRenderer } from "goban"; -export const GobanContext = React.createContext(null); +export const GobanContext = React.createContext(null); /** * A React hook that provides the goban. * * Throws if a goban is not set. */ -export function useGoban(): Goban { +export function useGoban(): GobanRenderer { const goban = React.useContext(GobanContext); if (goban === null) { diff --git a/src/views/Joseki/Joseki.tsx b/src/views/Joseki/Joseki.tsx index c4876f9c00..f590cb7db1 100644 --- a/src/views/Joseki/Joseki.tsx +++ b/src/views/Joseki/Joseki.tsx @@ -29,7 +29,7 @@ import * as data from "data"; import { _, interpolate, pgettext, npgettext } from "translate"; import { get, put, post } from "requests"; import { KBShortcut } from "KBShortcut"; -import { Goban, GoMath, GobanConfig, JGOFMove } from "goban"; +import { GobanRenderer, GoMath, GobanRendererConfig, JGOFMove, createGoban } from "goban"; import { AutoTranslate } from "AutoTranslate"; import { Markdown } from "Markdown"; import { chat_manager } from "chat_manager"; @@ -194,7 +194,7 @@ interface JosekiState { } class _Joseki extends React.Component { - goban!: Goban; + goban!: GobanRenderer; goban_div: HTMLDivElement; goban_opts: any = {}; goban_container!: HTMLDivElement; @@ -322,7 +322,7 @@ class _Joseki extends React.Component { this.goban.destroy(); } - const opts: GobanConfig = { + const opts: GobanRendererConfig = { board_div: this.goban_div, interactive: true, mode: "puzzle", @@ -335,7 +335,7 @@ class _Joseki extends React.Component { opts["moves"] = initial_position as any; } this.goban_opts = opts; - this.goban = new Goban(opts); + this.goban = createGoban(opts); this.goban.setMode("puzzle"); this.goban.on("update", () => this.onBoardUpdate()); (window as any)["global_goban"] = this.goban; diff --git a/src/views/LearningHub/InstructionalGoban.tsx b/src/views/LearningHub/InstructionalGoban.tsx index 030a829959..1251f9b1e5 100644 --- a/src/views/LearningHub/InstructionalGoban.tsx +++ b/src/views/LearningHub/InstructionalGoban.tsx @@ -16,7 +16,7 @@ */ import * as React from "react"; -import { Goban } from "goban"; +import { createGoban, GobanRenderer } from "goban"; import { sfx } from "sfx"; import { PersistentElement } from "PersistentElement"; @@ -31,7 +31,7 @@ interface InstructionalGobanProps { export class InstructionalGoban extends React.Component { goban_div: HTMLDivElement; - goban?: Goban; + goban?: GobanRenderer; constructor(props: InstructionalGobanProps) { super(props); @@ -61,7 +61,7 @@ export class InstructionalGoban extends React.Component } initialize() { - this.goban = new Goban( + this.goban = createGoban( { board_div: this.goban_div, initial_player: "black", diff --git a/src/views/Puzzle/Puzzle.tsx b/src/views/Puzzle/Puzzle.tsx index 8906359395..c8c9e259f7 100644 --- a/src/views/Puzzle/Puzzle.tsx +++ b/src/views/Puzzle/Puzzle.tsx @@ -25,7 +25,7 @@ import { KBShortcut } from "KBShortcut"; import { goban_view_mode, goban_view_squashed } from "Game"; import { errorAlerter, errorLogger, ignore } from "misc"; import { longRankString, rankList } from "rank_utils"; -import { Goban, GobanCanvas, GobanCanvasConfig, PuzzlePlacementSetting } from "goban"; +import { createGoban, GobanRenderer, GobanRendererConfig, PuzzlePlacementSetting } from "goban"; import { Markdown } from "Markdown"; import { Player } from "Player"; import { StarRating } from "StarRating"; @@ -100,7 +100,7 @@ export class _Puzzle extends React.Component { ref_hint_button: React.RefObject; ref_toggle_coordinates_button?: React.RefObject; - goban!: Goban; + goban!: GobanRenderer; goban_div: HTMLDivElement; goban_opts: any = {}; solve_time_start: number = Date.now(); @@ -276,7 +276,7 @@ export class _Puzzle extends React.Component { } reset(editing?: boolean) { - const opts: GobanCanvasConfig = this.editor.reset( + const opts: GobanRendererConfig = this.editor.reset( this.goban_div, !!editing, this.replacementSettingFunction.bind(this), @@ -285,7 +285,7 @@ export class _Puzzle extends React.Component { opts.move_tree_container = this.ref_move_tree_container; this.goban_opts = opts; - this.goban = new Goban(opts); + this.goban = createGoban(opts); this.goban.setMode("puzzle"); (window as any)["global_goban"] = this.goban; this.goban.on("update", () => this.onUpdate()); @@ -647,7 +647,7 @@ export class _Puzzle extends React.Component { setMoveTreeContainer = (resizable: Resizable): void => { this.ref_move_tree_container = resizable?.div ? resizable.div : undefined; if (this.goban && this.ref_move_tree_container) { - (this.goban as GobanCanvas).setMoveTreeContainer(this.ref_move_tree_container); + (this.goban as GobanRenderer).setMoveTreeContainer(this.ref_move_tree_container); } }; toggleCoordinates = () => { diff --git a/src/views/Puzzle/PuzzleEditing.ts b/src/views/Puzzle/PuzzleEditing.ts index de12d76bf8..026adf2b43 100644 --- a/src/views/Puzzle/PuzzleEditing.ts +++ b/src/views/Puzzle/PuzzleEditing.ts @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -import { GobanCanvasConfig, GoMath, PuzzleConfig, PuzzlePlacementSetting } from "goban"; +import { GobanRendererConfig, GoMath, PuzzleConfig, PuzzlePlacementSetting } from "goban"; import { errorAlerter, dup } from "misc"; import { PuzzleTransform } from "./PuzzleTransform"; import { _Puzzle } from "./Puzzle"; @@ -214,7 +214,7 @@ export class PuzzleEditor { goban_div: HTMLDivElement, editing: boolean, replacementSettingsFunction: () => PuzzlePlacementSetting, - ): GobanCanvasConfig { + ): GobanRendererConfig { const puzzle = (this.puzzle_config = dup(this.orig_puzzle_config)); if (!puzzle) { @@ -237,7 +237,7 @@ export class PuzzleEditor { goban_div.removeChild(goban_div.firstChild); } - const opts: GobanCanvasConfig = Object.assign( + const opts: GobanRendererConfig = Object.assign( { board_div: goban_div, interactive: true, diff --git a/src/views/Puzzle/PuzzleNavigation.ts b/src/views/Puzzle/PuzzleNavigation.ts index 7af9b21884..c7c7a25b0b 100644 --- a/src/views/Puzzle/PuzzleNavigation.ts +++ b/src/views/Puzzle/PuzzleNavigation.ts @@ -15,12 +15,12 @@ * along with this program. If not, see . */ -import { Goban } from "goban"; +import { GobanRenderer } from "goban"; export class PuzzleNavigation { - _goban!: Goban; + _goban!: GobanRenderer; - set goban(newValue: Goban) { + set goban(newValue: GobanRenderer) { this._goban = newValue; } diff --git a/src/views/ReportsCenter/ReportedGame.tsx b/src/views/ReportsCenter/ReportedGame.tsx index 3a6c786346..0322588e3b 100644 --- a/src/views/ReportsCenter/ReportedGame.tsx +++ b/src/views/ReportsCenter/ReportedGame.tsx @@ -37,7 +37,7 @@ import { LogEntry, LogData, } from "Game"; -import { Goban } from "goban"; +import { GobanRenderer } from "goban"; import { Resizable } from "Resizable"; import { socket } from "sockets"; import { Player } from "Player"; @@ -53,10 +53,10 @@ export function ReportedGame({ game_id: number; reported_at: number | undefined; }): JSX.Element | null { - const [goban, setGoban] = React.useState(null); + const [goban, setGoban] = React.useState(null); const [selectedChatLog, setSelectedChatLog] = React.useState("main"); const refresh = useRefresh(); - const onGobanCreated = React.useCallback((goban: Goban) => { + const onGobanCreated = React.useCallback((goban: GobanRenderer) => { setGoban(goban); }, []); const cur_move = useCurrentMove(goban); @@ -279,7 +279,7 @@ export function ReportedGame({ ); } -function GameLog({ goban }: { goban: Goban }): JSX.Element { +function GameLog({ goban }: { goban: GobanRenderer }): JSX.Element { const [log, setLog] = React.useState([]); const game_id = goban.engine.game_id; diff --git a/src/views/ReportsCenter/ScoringEventThumbnail.tsx b/src/views/ReportsCenter/ScoringEventThumbnail.tsx index 96276dc388..08e73e63d2 100644 --- a/src/views/ReportsCenter/ScoringEventThumbnail.tsx +++ b/src/views/ReportsCenter/ScoringEventThumbnail.tsx @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -import { GoMath, Goban, GobanConfig } from "goban"; +import { GoMath, GobanRenderer, GobanRendererConfig, createGoban } from "goban"; import React from "react"; import { PersistentElement } from "../../components/PersistentElement"; @@ -25,7 +25,7 @@ export function ScoringEventThumbnail({ move_number, removal_string, }: { - config: GobanConfig; + config: GobanRendererConfig; move_number: number | undefined; removal_string: string | undefined; }) { @@ -36,10 +36,10 @@ export function ScoringEventThumbnail({ return ret; })(), ); - const goban = React.useRef(); + const goban = React.useRef(); React.useEffect(() => { - goban.current = new Goban({ + goban.current = createGoban({ ...config, board_div: goban_div.current, server_socket: undefined,