From 659d3dd9e1be6856d35948eeb7cd2e2a26f981d9 Mon Sep 17 00:00:00 2001 From: Mitchell McCaffrey Date: Sun, 29 Aug 2021 19:45:31 +1000 Subject: [PATCH 01/15] Update alternating diagonals distance to be more accurate --- src/helpers/grid.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/grid.ts b/src/helpers/grid.ts index 626164a..2c5db2d 100644 --- a/src/helpers/grid.ts +++ b/src/helpers/grid.ts @@ -325,7 +325,7 @@ export function gridDistance( const delta = Vector2.abs(Vector2.subtract(aCoord, bCoord)); const max = Vector2.componentMax(delta); const min = Vector2.componentMin(delta); - return max - min + Math.floor(1.5 * min); + return max + Math.floor(0.5 * min); } else if (grid.measurement.type === "euclidean") { return Vector2.magnitude( Vector2.divide(Vector2.subtract(a, b), cellSize) From 5e407ba72dd065dbfef2af981016f8da3b058135 Mon Sep 17 00:00:00 2001 From: Mitchell McCaffrey Date: Thu, 2 Sep 2021 09:28:45 +1000 Subject: [PATCH 02/15] Move interaction to left click and added middle click move right click pointer --- package.json | 1 + src/components/konva/Note.tsx | 9 ++++ src/components/konva/Token.tsx | 11 +++- src/components/map/MapInteraction.tsx | 28 +++++++--- src/components/tools/DrawingTool.tsx | 17 ++++-- src/components/tools/FogTool.tsx | 26 +++++++-- src/components/tools/MeasureTool.tsx | 26 ++++++--- src/components/tools/NoteTool.tsx | 21 ++++++-- src/components/tools/PointerTool.tsx | 33 +++++++----- src/components/tools/SelectTool.tsx | 17 ++++-- src/contexts/MapInteractionContext.tsx | 75 ++++++++++++++++++-------- src/hooks/usePreventContextMenu.ts | 25 +++++++++ src/hooks/useStageInteraction.ts | 6 ++- yarn.lock | 5 ++ 14 files changed, 236 insertions(+), 64 deletions(-) create mode 100644 src/hooks/usePreventContextMenu.ts diff --git a/package.json b/package.json index 6131a98..7b6f04e 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "socket.io-msgpack-parser": "^3.0.1", "source-map-explorer": "^2.5.2", "theme-ui": "^0.10.0", + "tiny-typed-emitter": "^2.1.0", "use-image": "^1.0.8", "uuid": "^8.3.2", "webrtc-adapter": "^8.1.0" diff --git a/src/components/konva/Note.tsx b/src/components/konva/Note.tsx index e961854..96718a5 100644 --- a/src/components/konva/Note.tsx +++ b/src/components/konva/Note.tsx @@ -102,6 +102,9 @@ function Note({ } function handleClick(event: Konva.KonvaEventObject) { + if (event.evt.button !== 0) { + return; + } if (draggable) { const noteNode = event.target; onNoteMenuOpen && onNoteMenuOpen(note.id, noteNode, true); @@ -111,6 +114,9 @@ function Note({ // Store note pointer down time to check for a click when note is locked const notePointerDownTimeRef = useRef(0); function handlePointerDown(event: Konva.KonvaEventObject) { + if (event.evt.button !== 0) { + return; + } if (draggable) { setPreventMapInteraction(true); } @@ -120,6 +126,9 @@ function Note({ } function handlePointerUp(event: Konva.KonvaEventObject) { + if (event.evt.button !== 0) { + return; + } if (draggable) { setPreventMapInteraction(false); } diff --git a/src/components/konva/Token.tsx b/src/components/konva/Token.tsx index 5695a03..0de3667 100644 --- a/src/components/konva/Token.tsx +++ b/src/components/konva/Token.tsx @@ -197,7 +197,10 @@ function Token({ setAttachmentOverCharacter(false); } - function handleClick() { + function handleClick(event: Konva.KonvaEventObject) { + if (event.evt.button !== 0) { + return; + } if (selectable && draggable && transformRootRef.current) { onTokenMenuOpen(tokenState.id, transformRootRef.current, true); } @@ -207,6 +210,9 @@ function Token({ // Store token pointer down time to check for a click when token is locked const tokenPointerDownTimeRef = useRef(0); function handlePointerDown(event: Konva.KonvaEventObject) { + if (event.evt.button !== 0) { + return; + } if (draggable) { setPreventMapInteraction(true); } @@ -216,6 +222,9 @@ function Token({ } function handlePointerUp(event: Konva.KonvaEventObject) { + if (event.evt.button !== 0) { + return; + } if (draggable) { setPreventMapInteraction(false); } diff --git a/src/components/map/MapInteraction.tsx b/src/components/map/MapInteraction.tsx index 031a761..001b1f4 100644 --- a/src/components/map/MapInteraction.tsx +++ b/src/components/map/MapInteraction.tsx @@ -3,17 +3,20 @@ import { Box } from "theme-ui"; import ReactResizeDetector from "react-resize-detector"; import { Stage, Layer, Image, Group } from "react-konva"; import Konva from "konva"; -import { EventEmitter } from "events"; import useMapImage from "../../hooks/useMapImage"; import usePreventOverscroll from "../../hooks/usePreventOverscroll"; import useStageInteraction from "../../hooks/useStageInteraction"; import useImageCenter from "../../hooks/useImageCenter"; +import usePreventContextMenu from "../../hooks/usePreventContextMenu"; import { getGridMaxZoom } from "../../helpers/grid"; import KonvaBridge from "../../helpers/KonvaBridge"; -import { MapInteractionProvider } from "../../contexts/MapInteractionContext"; +import { + MapInteractionEmitter, + MapInteractionProvider, +} from "../../contexts/MapInteractionContext"; import { useMapStage } from "../../contexts/MapStageContext"; import { GridProvider } from "../../contexts/GridContext"; import { useKeyboard } from "../../contexts/KeyboardContext"; @@ -72,6 +75,7 @@ function MapInteraction({ const containerRef = useRef(null); usePreventOverscroll(containerRef); + usePreventContextMenu(containerRef); const [mapWidth, mapHeight] = useImageCenter( map, @@ -85,8 +89,9 @@ function MapInteraction({ ); const previousSelectedToolRef = useRef(selectedToolId); + const [currentMouseButtons, setCurentMouseButtons] = useState(0); - const [interactionEmitter] = useState(new EventEmitter()); + const [interactionEmitter] = useState(new MapInteractionEmitter()); useStageInteraction( mapStageRef, @@ -106,13 +111,17 @@ function MapInteraction({ onPinchEnd: () => { onSelectedToolChange(previousSelectedToolRef.current); }, - onDrag: ({ first, last }) => { + onDrag: (props) => { + const { first, last, buttons } = props; + if (buttons !== currentMouseButtons) { + setCurentMouseButtons(buttons); + } if (first) { - interactionEmitter.emit("dragStart"); + interactionEmitter.emit("dragStart", props); } else if (last) { - interactionEmitter.emit("dragEnd"); + interactionEmitter.emit("dragEnd", props); } else { - interactionEmitter.emit("drag"); + interactionEmitter.emit("drag", props); } }, } @@ -143,6 +152,11 @@ function MapInteraction({ useKeyboard(handleKeyDown, handleKeyUp); function getCursorForTool(tool: MapToolId) { + if (currentMouseButtons === 2) { + return "crosshair"; + } else if (currentMouseButtons > 2) { + return "move"; + } switch (tool) { case "move": return "move"; diff --git a/src/components/tools/DrawingTool.tsx b/src/components/tools/DrawingTool.tsx index f155da4..fa529cd 100644 --- a/src/components/tools/DrawingTool.tsx +++ b/src/components/tools/DrawingTool.tsx @@ -7,6 +7,8 @@ import { useMapWidth, useMapHeight, useInteractionEmitter, + leftMouseButton, + MapDragEvent, } from "../../contexts/MapInteractionContext"; import { useMapStage } from "../../contexts/MapStageContext"; import { @@ -103,7 +105,10 @@ function DrawingTool({ }); } - function handleBrushDown() { + function handleBrushDown(props: MapDragEvent) { + if (!leftMouseButton(props)) { + return; + } const brushPosition = getBrushPosition(); if (!brushPosition) { return; @@ -135,7 +140,10 @@ function DrawingTool({ setIsBrushDown(true); } - function handleBrushMove() { + function handleBrushMove(props: MapDragEvent) { + if (!leftMouseButton(props)) { + return; + } const brushPosition = getBrushPosition(); if (!brushPosition) { return; @@ -186,7 +194,10 @@ function DrawingTool({ } } - function handleBrushUp() { + function handleBrushUp(props: MapDragEvent) { + if (!leftMouseButton(props)) { + return; + } if (isBrush && drawing && drawing.type === "path") { if (drawing.data.points.length > 1) { onShapeAdd(drawing); diff --git a/src/components/tools/FogTool.tsx b/src/components/tools/FogTool.tsx index 16a760a..b0b48bc 100644 --- a/src/components/tools/FogTool.tsx +++ b/src/components/tools/FogTool.tsx @@ -3,6 +3,7 @@ import shortid from "shortid"; import { Group, Line } from "react-konva"; import useImage from "use-image"; import Color from "color"; +import Konva from "konva"; import diagonalPattern from "../../images/DiagonalPattern.png"; @@ -11,6 +12,8 @@ import { useMapWidth, useMapHeight, useInteractionEmitter, + MapDragEvent, + leftMouseButton, } from "../../contexts/MapInteractionContext"; import { useMapStage } from "../../contexts/MapStageContext"; import { @@ -160,7 +163,10 @@ function FogTool({ }); } - function handleBrushDown() { + function handleBrushDown(props: MapDragEvent) { + if (!leftMouseButton(props)) { + return; + } if (toolSettings.type === "brush") { const brushPosition = getBrushPosition(); if (!brushPosition) { @@ -203,7 +209,10 @@ function FogTool({ setIsBrushDown(true); } - function handleBrushMove() { + function handleBrushMove(props: MapDragEvent) { + if (!leftMouseButton(props)) { + return; + } if (toolSettings.type === "brush" && isBrushDown && drawingShape) { const brushPosition = getBrushPosition(); if (!brushPosition) { @@ -258,7 +267,10 @@ function FogTool({ } } - function handleBrushUp() { + function handleBrushUp(props: MapDragEvent) { + if (!leftMouseButton(props)) { + return; + } if ( (toolSettings.type === "brush" || toolSettings.type === "rectangle") && drawingShape @@ -318,7 +330,13 @@ function FogTool({ setIsBrushDown(false); } - function handlePointerClick() { + function handlePointerClick( + event: Konva.KonvaEventObject + ) { + // Left click only + if (event.evt instanceof MouseEvent && event.evt.button !== 0) { + return; + } if (toolSettings.type === "polygon") { const brushPosition = getBrushPosition(); if (brushPosition) { diff --git a/src/components/tools/MeasureTool.tsx b/src/components/tools/MeasureTool.tsx index 7e352b3..d57f851 100644 --- a/src/components/tools/MeasureTool.tsx +++ b/src/components/tools/MeasureTool.tsx @@ -1,7 +1,11 @@ import { useState, useEffect } from "react"; import { Group } from "react-konva"; -import { useInteractionEmitter } from "../../contexts/MapInteractionContext"; +import { + useInteractionEmitter, + MapDragEvent, + leftMouseButton, +} from "../../contexts/MapInteractionContext"; import { useMapStage } from "../../contexts/MapStageContext"; import { useGrid, @@ -40,8 +44,9 @@ function MeasureTool({ map, active }: MapMeasureProps) { const gridOffset = useGridOffset(); const mapStageRef = useMapStage(); - const [drawingShapeData, setDrawingShapeData] = - useState(null); + const [drawingShapeData, setDrawingShapeData] = useState( + null + ); const [isBrushDown, setIsBrushDown] = useState(false); const gridScale = parseGridScale(active ? grid.measurement.scale : null); @@ -75,7 +80,10 @@ function MeasureTool({ map, active }: MapMeasureProps) { }); } - function handleBrushDown() { + function handleBrushDown(props: MapDragEvent) { + if (!leftMouseButton(props)) { + return; + } const brushPosition = getBrushPosition(); if (!brushPosition) { return; @@ -89,7 +97,10 @@ function MeasureTool({ map, active }: MapMeasureProps) { setIsBrushDown(true); } - function handleBrushMove() { + function handleBrushMove(props: MapDragEvent) { + if (!leftMouseButton(props)) { + return; + } const brushPosition = getBrushPosition(); if (isBrushDown && drawingShapeData && brushPosition && mapImage) { const { points } = getUpdatedShapeData( @@ -123,7 +134,10 @@ function MeasureTool({ map, active }: MapMeasureProps) { } } - function handleBrushUp() { + function handleBrushUp(props: MapDragEvent) { + if (!leftMouseButton(props)) { + return; + } setDrawingShapeData(null); setIsBrushDown(false); } diff --git a/src/components/tools/NoteTool.tsx b/src/components/tools/NoteTool.tsx index 98195d8..e7ea19d 100644 --- a/src/components/tools/NoteTool.tsx +++ b/src/components/tools/NoteTool.tsx @@ -3,7 +3,11 @@ import shortid from "shortid"; import { Group } from "react-konva"; import Konva from "konva"; -import { useInteractionEmitter } from "../../contexts/MapInteractionContext"; +import { + useInteractionEmitter, + MapDragEvent, + leftMouseButton, +} from "../../contexts/MapInteractionContext"; import { useMapStage } from "../../contexts/MapStageContext"; import { useUserId } from "../../contexts/UserIdContext"; @@ -72,7 +76,10 @@ function NoteTool({ }); } - function handleBrushDown() { + function handleBrushDown(props: MapDragEvent) { + if (!leftMouseButton(props)) { + return; + } const brushPosition = getBrushPosition(); if (!brushPosition || !userId) { return; @@ -94,7 +101,10 @@ function NoteTool({ setIsBrushDown(true); } - function handleBrushMove() { + function handleBrushMove(props: MapDragEvent) { + if (!leftMouseButton(props)) { + return; + } if (noteData) { const brushPosition = getBrushPosition(); if (!brushPosition) { @@ -114,7 +124,10 @@ function NoteTool({ } } - function handleBrushUp() { + function handleBrushUp(props: MapDragEvent) { + if (!leftMouseButton(props)) { + return; + } if (noteData && creatingNoteRef.current) { onNoteCreate([noteData]); onNoteMenuOpen(noteData.id, creatingNoteRef.current, true); diff --git a/src/components/tools/PointerTool.tsx b/src/components/tools/PointerTool.tsx index de30bf0..63a3cb2 100644 --- a/src/components/tools/PointerTool.tsx +++ b/src/components/tools/PointerTool.tsx @@ -1,10 +1,13 @@ -import { useEffect } from "react"; +import { useEffect, useRef } from "react"; import { Group } from "react-konva"; import { useMapWidth, useMapHeight, useInteractionEmitter, + MapDragEvent, + leftMouseButton, + rightMouseButton, } from "../../contexts/MapInteractionContext"; import { useMapStage } from "../../contexts/MapStageContext"; import { useGridStrokeWidth } from "../../contexts/GridContext"; @@ -41,11 +44,9 @@ function PointerTool({ const gridStrokeWidth = useGridStrokeWidth(); const mapStageRef = useMapStage(); - useEffect(() => { - if (!active) { - return; - } + const brushDownRef = useRef(false); + useEffect(() => { const mapStage = mapStageRef.current; function getBrushPosition() { @@ -56,19 +57,27 @@ function PointerTool({ return getRelativePointerPositionNormalized(mapImage); } - function handleBrushDown() { - const brushPosition = getBrushPosition(); - brushPosition && onPointerDown?.(brushPosition); + function handleBrushDown(props: MapDragEvent) { + if ((leftMouseButton(props) && active) || rightMouseButton(props)) { + const brushPosition = getBrushPosition(); + brushPosition && onPointerDown?.(brushPosition); + brushDownRef.current = true; + } } function handleBrushMove() { - const brushPosition = getBrushPosition(); - brushPosition && visible && onPointerMove?.(brushPosition); + if (brushDownRef.current) { + const brushPosition = getBrushPosition(); + brushPosition && visible && onPointerMove?.(brushPosition); + } } function handleBrushUp() { - const brushPosition = getBrushPosition(); - brushPosition && onPointerUp?.(brushPosition); + if (brushDownRef.current) { + const brushPosition = getBrushPosition(); + brushPosition && onPointerUp?.(brushPosition); + brushDownRef.current = false; + } } interactionEmitter?.on("dragStart", handleBrushDown); diff --git a/src/components/tools/SelectTool.tsx b/src/components/tools/SelectTool.tsx index 2a29ca8..2c9be79 100644 --- a/src/components/tools/SelectTool.tsx +++ b/src/components/tools/SelectTool.tsx @@ -7,6 +7,8 @@ import { useMapWidth, useMapHeight, useInteractionEmitter, + MapDragEvent, + leftMouseButton, } from "../../contexts/MapInteractionContext"; import { useMapStage } from "../../contexts/MapStageContext"; @@ -96,7 +98,10 @@ function SelectTool({ }); } - function handleBrushDown() { + function handleBrushDown(props: MapDragEvent) { + if (!leftMouseButton(props)) { + return; + } const brushPosition = getBrushPosition(); if (!brushPosition || preventSelectionRef.current) { return; @@ -121,7 +126,10 @@ function SelectTool({ setIsBrushDown(true); } - function handleBrushMove() { + function handleBrushMove(props: MapDragEvent) { + if (!leftMouseButton(props)) { + return; + } const brushPosition = getBrushPosition(); if (!brushPosition || preventSelectionRef.current) { return; @@ -172,7 +180,10 @@ function SelectTool({ } } - function handleBrushUp() { + function handleBrushUp(props: MapDragEvent) { + if (!leftMouseButton(props)) { + return; + } if (preventSelectionRef.current) { return; } diff --git a/src/contexts/MapInteractionContext.tsx b/src/contexts/MapInteractionContext.tsx index 7362c86..21dd1d6 100644 --- a/src/contexts/MapInteractionContext.tsx +++ b/src/contexts/MapInteractionContext.tsx @@ -1,6 +1,21 @@ import React, { useContext } from "react"; -import { EventEmitter } from "stream"; +import { FullGestureState } from "react-use-gesture/dist/types"; import useDebounce from "../hooks/useDebounce"; +import { TypedEmitter } from "tiny-typed-emitter"; + +export type MapDragEvent = Omit, "event"> & { + event: React.PointerEvent | PointerEvent; +}; + +export type MapDragEventHandler = (props: MapDragEvent) => void; + +export interface MapInteractionEvents { + dragStart: MapDragEventHandler; + drag: MapDragEventHandler; + dragEnd: MapDragEventHandler; +} + +export class MapInteractionEmitter extends TypedEmitter {} type MapInteraction = { stageScale: number; @@ -9,29 +24,33 @@ type MapInteraction = { setPreventMapInteraction: React.Dispatch>; mapWidth: number; mapHeight: number; - interactionEmitter: EventEmitter | null; + interactionEmitter: MapInteractionEmitter | null; }; -export const StageScaleContext = - React.createContext(undefined); -export const DebouncedStageScaleContext = - React.createContext(undefined); -export const StageWidthContext = - React.createContext(undefined); -export const StageHeightContext = - React.createContext(undefined); -export const SetPreventMapInteractionContext = - React.createContext( - undefined - ); -export const MapWidthContext = - React.createContext(undefined); -export const MapHeightContext = - React.createContext(undefined); -export const InteractionEmitterContext = - React.createContext( - undefined - ); +export const StageScaleContext = React.createContext< + MapInteraction["stageScale"] | undefined +>(undefined); +export const DebouncedStageScaleContext = React.createContext< + MapInteraction["stageScale"] | undefined +>(undefined); +export const StageWidthContext = React.createContext< + MapInteraction["stageWidth"] | undefined +>(undefined); +export const StageHeightContext = React.createContext< + MapInteraction["stageHeight"] | undefined +>(undefined); +export const SetPreventMapInteractionContext = React.createContext< + MapInteraction["setPreventMapInteraction"] | undefined +>(undefined); +export const MapWidthContext = React.createContext< + MapInteraction["mapWidth"] | undefined +>(undefined); +export const MapHeightContext = React.createContext< + MapInteraction["mapHeight"] | undefined +>(undefined); +export const InteractionEmitterContext = React.createContext< + MapInteraction["interactionEmitter"] | undefined +>(undefined); export function MapInteractionProvider({ value, @@ -152,3 +171,15 @@ export function useDebouncedStageScale() { } return context; } + +export function leftMouseButton(event: MapDragEvent) { + return event.buttons <= 1; +} + +export function middleMouseButton(event: MapDragEvent) { + return event.buttons === 4; +} + +export function rightMouseButton(event: MapDragEvent) { + return event.buttons === 2; +} diff --git a/src/hooks/usePreventContextMenu.ts b/src/hooks/usePreventContextMenu.ts new file mode 100644 index 0000000..7073836 --- /dev/null +++ b/src/hooks/usePreventContextMenu.ts @@ -0,0 +1,25 @@ +import React, { useEffect } from "react"; + +function usePreventContextMenu(elementRef: React.RefObject) { + useEffect(() => { + // Stop conext menu i.e. right click dialog + function preventContextMenu(event: MouseEvent) { + event.preventDefault(); + return false; + } + const element = elementRef.current; + if (element) { + element.addEventListener("contextmenu", preventContextMenu, { + passive: false, + }); + } + + return () => { + if (element) { + element.removeEventListener("contextmenu", preventContextMenu); + } + }; + }, [elementRef]); +} + +export default usePreventContextMenu; diff --git a/src/hooks/useStageInteraction.ts b/src/hooks/useStageInteraction.ts index 88ad511..b005bfe 100644 --- a/src/hooks/useStageInteraction.ts +++ b/src/hooks/useStageInteraction.ts @@ -67,6 +67,7 @@ function useStageInteraction( return; } const { event, last } = props; + // Prevent double zoom on wheel end if (!last) { const { pixelY } = normalizeWheel(event); @@ -178,7 +179,7 @@ function useStageInteraction( gesture.onDragStart && gesture.onDragStart(props); }, onDrag: (props) => { - const { delta, pinching } = props; + const { delta, pinching, buttons } = props; const stage = stageRef.current; if ( preventInteraction || @@ -191,7 +192,8 @@ function useStageInteraction( const [dx, dy] = delta; const stageTranslate = stageTranslateRef.current; - if (tool === "move") { + // Move with move tool and left click or any mouse button but right click + if ((tool === "move" && buttons < 2) || buttons > 2) { const newTranslate = { x: stageTranslate.x + dx, y: stageTranslate.y + dy, diff --git a/yarn.lock b/yarn.lock index 411290c..d178a1a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13181,6 +13181,11 @@ tiny-invariant@^1.0.2: resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== +tiny-typed-emitter@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz#b3b027fdd389ff81a152c8e847ee2f5be9fad7b5" + integrity sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA== + tiny-warning@^1.0.0, tiny-warning@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" From ddb89c39bfde38d5e59fd9c33cc6ed7beec8438c Mon Sep 17 00:00:00 2001 From: Mitchell McCaffrey Date: Thu, 2 Sep 2021 11:03:27 +1000 Subject: [PATCH 03/15] Update session to remove rogue socket connection --- src/network/Session.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/network/Session.ts b/src/network/Session.ts index de04cc1..a85b8ad 100644 --- a/src/network/Session.ts +++ b/src/network/Session.ts @@ -35,7 +35,7 @@ class Session extends EventEmitter { * * @type {io.Socket} */ - socket: Socket = io(); + socket?: Socket; /** * A mapping of socket ids to session peers @@ -45,7 +45,7 @@ class Session extends EventEmitter { peers: Record; get id() { - return this.socket && this.socket.id; + return this.socket?.id || ""; } _iceServers: RTCIceServer[] = []; @@ -191,7 +191,7 @@ class Session extends EventEmitter { this._gameId = gameId; this._password = password; - this.socket.emit( + this.socket?.emit( "join_game", gameId, password, @@ -224,7 +224,7 @@ class Session extends EventEmitter { }; const handleSignal = (signal: SignalData) => { - this.socket.emit("signal", JSON.stringify({ to: peer.id, signal })); + this.socket?.emit("signal", JSON.stringify({ to: peer.id, signal })); }; const handleConnect = () => { @@ -373,7 +373,7 @@ class Session extends EventEmitter { } _handleForceUpdate() { - this.socket.disconnect(); + this.socket?.disconnect(); this.emit("status", "needs_update"); } } From d952d2c63ba20231cbfdc7b74653de34c13a2fcf Mon Sep 17 00:00:00 2001 From: Mitchell McCaffrey Date: Sat, 4 Sep 2021 10:04:25 +1000 Subject: [PATCH 04/15] Remove optionality from session socket Co-Authored-By: Nicola Thouliss <53867736+nthouliss@users.noreply.github.com> --- src/contexts/PartyContext.tsx | 4 ++-- src/contexts/PlayerContext.tsx | 18 ++++++++++-------- src/hooks/useNetworkedState.ts | 10 +++++----- src/network/NetworkedMapAndTokens.tsx | 8 ++++---- src/network/NetworkedMapPointer.tsx | 4 ++-- src/network/Session.ts | 27 ++++++++++----------------- 6 files changed, 33 insertions(+), 38 deletions(-) diff --git a/src/contexts/PartyContext.tsx b/src/contexts/PartyContext.tsx index e8ffc9d..370610e 100644 --- a/src/contexts/PartyContext.tsx +++ b/src/contexts/PartyContext.tsx @@ -23,10 +23,10 @@ export function PartyProvider({ session, children }: PartyProviderProps) { } } - session.socket?.on("party_state", handleSocketPartyState); + session.socket.on("party_state", handleSocketPartyState); return () => { - session.socket?.off("party_state", handleSocketPartyState); + session.socket.off("party_state", handleSocketPartyState); }; }); diff --git a/src/contexts/PlayerContext.tsx b/src/contexts/PlayerContext.tsx index ef19607..ea4a867 100644 --- a/src/contexts/PlayerContext.tsx +++ b/src/contexts/PlayerContext.tsx @@ -9,10 +9,12 @@ import useNetworkedState, { import Session, { SessionStatus } from "../network/Session"; import { PlayerState } from "../types/PlayerState"; -export const PlayerStateContext = - React.createContext(undefined); -export const PlayerUpdaterContext = - React.createContext | undefined>(undefined); +export const PlayerStateContext = React.createContext( + undefined +); +export const PlayerUpdaterContext = React.createContext< + SetNetworkedState | undefined +>(undefined); type PlayerProviderProps = { session: Session; @@ -104,13 +106,13 @@ export function PlayerProvider({ session, children }: PlayerProviderProps) { } session.on("status", handleSocketStatus); - session.socket?.on("connect", handleSocketConnect); - session.socket?.io.on("reconnect", handleSocketConnect); + session.socket.on("connect", handleSocketConnect); + session.socket.io.on("reconnect", handleSocketConnect); return () => { session.off("status", handleSocketStatus); - session.socket?.off("connect", handleSocketConnect); - session.socket?.io.off("reconnect", handleSocketConnect); + session.socket.off("connect", handleSocketConnect); + session.socket.io.off("reconnect", handleSocketConnect); }; }); diff --git a/src/hooks/useNetworkedState.ts b/src/hooks/useNetworkedState.ts index 8f201f6..7417767 100644 --- a/src/hooks/useNetworkedState.ts +++ b/src/hooks/useNetworkedState.ts @@ -60,7 +60,7 @@ function useNetworkedState( const debouncedState = useDebounce(state, debounceRate); const lastSyncedStateRef = useRef(); useEffect(() => { - if (session.socket && dirtyRef.current) { + if (dirtyRef.current) { // If partial updates enabled, send just the changes to the socket if ( lastSyncedStateRef.current && @@ -112,11 +112,11 @@ function useNetworkedState( }); } - session.socket?.on(eventName, handleSocketEvent); - session.socket?.on(`${eventName}_update`, handleSocketUpdateEvent); + session.socket.on(eventName, handleSocketEvent); + session.socket.on(`${eventName}_update`, handleSocketUpdateEvent); return () => { - session.socket?.off(eventName, handleSocketEvent); - session.socket?.off(`${eventName}_update`, handleSocketUpdateEvent); + session.socket.off(eventName, handleSocketEvent); + session.socket.off(`${eventName}_update`, handleSocketUpdateEvent); }; }, [session.socket, eventName, partialUpdatesKey]); diff --git a/src/network/NetworkedMapAndTokens.tsx b/src/network/NetworkedMapAndTokens.tsx index 997c53e..e6e09f9 100644 --- a/src/network/NetworkedMapAndTokens.tsx +++ b/src/network/NetworkedMapAndTokens.tsx @@ -202,12 +202,12 @@ function NetworkedMapAndTokens({ session }: { session: Session }) { ) { // Clear map before sending new one setCurrentMap(null); - session.socket?.emit("map", null); + session.socket.emit("map", null); setCurrentMapState(newMapState, true, true); setCurrentMap(newMap); - session.socket?.emit("map", newMap); + session.socket.emit("map", newMap); if (!newMap || !newMapState) { setAssetManifest(null, true, true); @@ -395,12 +395,12 @@ function NetworkedMapAndTokens({ session }: { session: Session }) { session.on("peerData", handlePeerData); session.on("peerDataProgress", handlePeerDataProgress); - session.socket?.on("map", handleSocketMap); + session.socket.on("map", handleSocketMap); return () => { session.off("peerData", handlePeerData); session.off("peerDataProgress", handlePeerDataProgress); - session.socket?.off("map", handleSocketMap); + session.socket.off("map", handleSocketMap); }; }); diff --git a/src/network/NetworkedMapPointer.tsx b/src/network/NetworkedMapPointer.tsx index cd44086..e0a5758 100644 --- a/src/network/NetworkedMapPointer.tsx +++ b/src/network/NetworkedMapPointer.tsx @@ -152,10 +152,10 @@ function NetworkedMapPointer({ session, active }: NetworkedMapPointerProps) { } } - session.socket?.on("player_pointer", handleSocketPlayerPointer); + session.socket.on("player_pointer", handleSocketPlayerPointer); return () => { - session.socket?.off("player_pointer", handleSocketPlayerPointer); + session.socket.off("player_pointer", handleSocketPlayerPointer); }; }, [session]); diff --git a/src/network/Session.ts b/src/network/Session.ts index a85b8ad..daac356 100644 --- a/src/network/Session.ts +++ b/src/network/Session.ts @@ -1,4 +1,4 @@ -import io, { Socket } from "socket.io-client"; +import io from "socket.io-client"; import msgParser from "socket.io-msgpack-parser"; import { EventEmitter } from "events"; @@ -32,10 +32,11 @@ export type PeerReply = (id: string, data: PeerData, chunkId?: string) => void; class Session extends EventEmitter { /** * The socket io connection - * - * @type {io.Socket} */ - socket?: Socket; + socket = io(process.env.REACT_APP_BROKER_URL!, { + withCredentials: true, + parser: msgParser, + }); /** * A mapping of socket ids to session peers @@ -45,7 +46,7 @@ class Session extends EventEmitter { peers: Record; get id() { - return this.socket?.id || ""; + return this.socket.id; } _iceServers: RTCIceServer[] = []; @@ -76,14 +77,6 @@ class Session extends EventEmitter { const data = await response.json(); this._iceServers = data.iceServers; - if (!process.env.REACT_APP_BROKER_URL) { - return; - } - this.socket = io(process.env.REACT_APP_BROKER_URL, { - withCredentials: true, - parser: msgParser, - }); - this.socket.on("player_joined", this._handlePlayerJoined.bind(this)); this.socket.on("player_left", this._handlePlayerLeft.bind(this)); this.socket.on("joined_game", this._handleJoinedGame.bind(this)); @@ -102,7 +95,7 @@ class Session extends EventEmitter { } disconnect() { - this.socket?.disconnect(); + this.socket.disconnect(); } /** @@ -191,7 +184,7 @@ class Session extends EventEmitter { this._gameId = gameId; this._password = password; - this.socket?.emit( + this.socket.emit( "join_game", gameId, password, @@ -224,7 +217,7 @@ class Session extends EventEmitter { }; const handleSignal = (signal: SignalData) => { - this.socket?.emit("signal", JSON.stringify({ to: peer.id, signal })); + this.socket.emit("signal", JSON.stringify({ to: peer.id, signal })); }; const handleConnect = () => { @@ -373,7 +366,7 @@ class Session extends EventEmitter { } _handleForceUpdate() { - this.socket?.disconnect(); + this.socket.disconnect(); this.emit("status", "needs_update"); } } From 863f20be950c52606ad48046f14ede0dced75378 Mon Sep 17 00:00:00 2001 From: Mitchell McCaffrey Date: Thu, 21 Oct 2021 13:37:46 +1100 Subject: [PATCH 05/15] Remove optionality from session socket This reverts commit 99a27365aead00e7e2d4098e770f0f917ad45858. --- src/network/Session.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/network/Session.ts b/src/network/Session.ts index b046c51..daac356 100644 --- a/src/network/Session.ts +++ b/src/network/Session.ts @@ -33,7 +33,10 @@ class Session extends EventEmitter { /** * The socket io connection */ - socket?: Socket; + socket = io(process.env.REACT_APP_BROKER_URL!, { + withCredentials: true, + parser: msgParser, + }); /** * A mapping of socket ids to session peers @@ -43,7 +46,7 @@ class Session extends EventEmitter { peers: Record; get id() { - return this.socket?.id || ""; + return this.socket.id; } _iceServers: RTCIceServer[] = []; @@ -181,7 +184,7 @@ class Session extends EventEmitter { this._gameId = gameId; this._password = password; - this.socket?.emit( + this.socket.emit( "join_game", gameId, password, @@ -214,7 +217,7 @@ class Session extends EventEmitter { }; const handleSignal = (signal: SignalData) => { - this.socket?.emit("signal", JSON.stringify({ to: peer.id, signal })); + this.socket.emit("signal", JSON.stringify({ to: peer.id, signal })); }; const handleConnect = () => { @@ -363,7 +366,7 @@ class Session extends EventEmitter { } _handleForceUpdate() { - this.socket?.disconnect(); + this.socket.disconnect(); this.emit("status", "needs_update"); } } From 38d8ca95b3892a3f93d0e533c11c70ddc80d0322 Mon Sep 17 00:00:00 2001 From: Mitchell McCaffrey Date: Thu, 21 Oct 2021 16:12:41 +1100 Subject: [PATCH 06/15] Optimise note creation for FireFox --- src/components/konva/BlankNote.tsx | 47 ++++++++++++++++++++++++++++++ src/components/tools/NoteTool.tsx | 31 +++++++------------- src/hooks/useMapNotes.tsx | 16 +++++----- 3 files changed, 66 insertions(+), 28 deletions(-) create mode 100644 src/components/konva/BlankNote.tsx diff --git a/src/components/konva/BlankNote.tsx b/src/components/konva/BlankNote.tsx new file mode 100644 index 0000000..f4a78e1 --- /dev/null +++ b/src/components/konva/BlankNote.tsx @@ -0,0 +1,47 @@ +import { Rect } from "react-konva"; + +import { + useMapWidth, + useMapHeight, +} from "../../contexts/MapInteractionContext"; +import { useGridCellPixelSize } from "../../contexts/GridContext"; + +import colors from "../../helpers/colors"; + +import { Note as NoteType } from "../../types/Note"; + +type NoteProps = { + note: NoteType; +}; + +function BlankNote({ note }: NoteProps) { + const mapWidth = useMapWidth(); + const mapHeight = useMapHeight(); + + const gridCellPixelSize = useGridCellPixelSize(); + + const minCellSize = Math.min( + gridCellPixelSize.width, + gridCellPixelSize.height + ); + const noteWidth = minCellSize * note.size; + const noteHeight = noteWidth; + + return ( + + ); +} + +export default BlankNote; diff --git a/src/components/tools/NoteTool.tsx b/src/components/tools/NoteTool.tsx index e7ea19d..b9455a0 100644 --- a/src/components/tools/NoteTool.tsx +++ b/src/components/tools/NoteTool.tsx @@ -16,7 +16,7 @@ import { getRelativePointerPosition } from "../../helpers/konva"; import useGridSnapping from "../../hooks/useGridSnapping"; -import Note from "../konva/Note"; +import BlankNote from "../konva/BlankNote"; import { Map } from "../../types/Map"; import { Note as NoteType } from "../../types/Note"; @@ -32,20 +32,12 @@ type MapNoteProps = { active: boolean; onNoteCreate: NoteCreateEventHander; onNoteMenuOpen: NoteMenuOpenEventHandler; - children: React.ReactNode; }; -function NoteTool({ - map, - active, - onNoteCreate, - onNoteMenuOpen, - children, -}: MapNoteProps) { +function NoteTool({ map, active, onNoteCreate, onNoteMenuOpen }: MapNoteProps) { const interactionEmitter = useInteractionEmitter(); const userId = useUserId(); const mapStageRef = useMapStage(); - const [isBrushDown, setIsBrushDown] = useState(false); const [noteData, setNoteData] = useState(null); const creatingNoteRef = useRef(null); @@ -98,7 +90,9 @@ function NoteTool({ textOnly: false, rotation: 0, }); - setIsBrushDown(true); + if (creatingNoteRef.current) { + creatingNoteRef.current.visible(true); + } } function handleBrushMove(props: MapDragEvent) { @@ -120,7 +114,6 @@ function NoteTool({ y: brushPosition.y, }; }); - setIsBrushDown(true); } } @@ -131,9 +124,10 @@ function NoteTool({ if (noteData && creatingNoteRef.current) { onNoteCreate([noteData]); onNoteMenuOpen(noteData.id, creatingNoteRef.current, true); + // Hide creating note tool here as settings noteData to null + // was causing performance issues in FireFox + creatingNoteRef.current.visible(false); } - setNoteData(null); - setIsBrushDown(false); } interactionEmitter?.on("dragStart", handleBrushDown); @@ -148,13 +142,8 @@ function NoteTool({ }); return ( - - {children} - - {isBrushDown && noteData && ( - - )} - + + {noteData && } ); } diff --git a/src/hooks/useMapNotes.tsx b/src/hooks/useMapNotes.tsx index 43647da..1392d2b 100644 --- a/src/hooks/useMapNotes.tsx +++ b/src/hooks/useMapNotes.tsx @@ -1,4 +1,5 @@ import Konva from "konva"; +import { Group } from "react-konva"; import { KonvaEventObject } from "konva/lib/Node"; import { useState } from "react"; import { v4 as uuid } from "uuid"; @@ -95,12 +96,7 @@ function useMapNotes( useBlur(handleBlur); const notes = ( - + {(mapState ? Object.values(mapState.notes).sort((a, b) => sortNotes(a, b, noteDraggingOptions) @@ -129,7 +125,13 @@ function useMapNotes( } /> ))} - + + ); const noteMenu = ( From 08e21b55b8c9cf77b39b0a1d390f51cf03c24e87 Mon Sep 17 00:00:00 2001 From: Mitchell McCaffrey Date: Thu, 21 Oct 2021 18:09:14 +1100 Subject: [PATCH 07/15] Fix touch interaction for token and notes --- src/components/konva/Note.tsx | 7 ++++--- src/components/konva/Token.tsx | 7 ++++--- src/contexts/MapInteractionContext.tsx | 20 ++++++++++++++++++-- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/components/konva/Note.tsx b/src/components/konva/Note.tsx index 96718a5..c73a6cc 100644 --- a/src/components/konva/Note.tsx +++ b/src/components/konva/Note.tsx @@ -8,6 +8,7 @@ import { useSetPreventMapInteraction, useMapWidth, useMapHeight, + leftMouseButton, } from "../../contexts/MapInteractionContext"; import { useGridCellPixelSize } from "../../contexts/GridContext"; @@ -102,7 +103,7 @@ function Note({ } function handleClick(event: Konva.KonvaEventObject) { - if (event.evt.button !== 0) { + if (!leftMouseButton(event)) { return; } if (draggable) { @@ -114,7 +115,7 @@ function Note({ // Store note pointer down time to check for a click when note is locked const notePointerDownTimeRef = useRef(0); function handlePointerDown(event: Konva.KonvaEventObject) { - if (event.evt.button !== 0) { + if (!leftMouseButton(event)) { return; } if (draggable) { @@ -126,7 +127,7 @@ function Note({ } function handlePointerUp(event: Konva.KonvaEventObject) { - if (event.evt.button !== 0) { + if (!leftMouseButton(event)) { return; } if (draggable) { diff --git a/src/components/konva/Token.tsx b/src/components/konva/Token.tsx index 0de3667..5f44556 100644 --- a/src/components/konva/Token.tsx +++ b/src/components/konva/Token.tsx @@ -12,6 +12,7 @@ import { useSetPreventMapInteraction, useMapWidth, useMapHeight, + leftMouseButton, } from "../../contexts/MapInteractionContext"; import { useGridCellPixelSize } from "../../contexts/GridContext"; import { useDataURL } from "../../contexts/AssetsContext"; @@ -198,7 +199,7 @@ function Token({ } function handleClick(event: Konva.KonvaEventObject) { - if (event.evt.button !== 0) { + if (!leftMouseButton(event)) { return; } if (selectable && draggable && transformRootRef.current) { @@ -210,7 +211,7 @@ function Token({ // Store token pointer down time to check for a click when token is locked const tokenPointerDownTimeRef = useRef(0); function handlePointerDown(event: Konva.KonvaEventObject) { - if (event.evt.button !== 0) { + if (!leftMouseButton(event)) { return; } if (draggable) { @@ -222,7 +223,7 @@ function Token({ } function handlePointerUp(event: Konva.KonvaEventObject) { - if (event.evt.button !== 0) { + if (!leftMouseButton(event)) { return; } if (draggable) { diff --git a/src/contexts/MapInteractionContext.tsx b/src/contexts/MapInteractionContext.tsx index 21dd1d6..6009e20 100644 --- a/src/contexts/MapInteractionContext.tsx +++ b/src/contexts/MapInteractionContext.tsx @@ -2,6 +2,7 @@ import React, { useContext } from "react"; import { FullGestureState } from "react-use-gesture/dist/types"; import useDebounce from "../hooks/useDebounce"; import { TypedEmitter } from "tiny-typed-emitter"; +import Konva from "konva"; export type MapDragEvent = Omit, "event"> & { event: React.PointerEvent | PointerEvent; @@ -172,8 +173,23 @@ export function useDebouncedStageScale() { return context; } -export function leftMouseButton(event: MapDragEvent) { - return event.buttons <= 1; +export function leftMouseButton(event: MapDragEvent): boolean; +export function leftMouseButton( + event: Konva.KonvaEventObject +): boolean; +export function leftMouseButton( + event: Konva.KonvaEventObject +): boolean; + +export function leftMouseButton(event: any) { + if (event.evt) { + // Konva events + // Check for undefined (touch) and mouse left click (0) + return event.evt.button === undefined || event.evt.button === 0; + } else { + // Drag event + return event.buttons <= 1; + } } export function middleMouseButton(event: MapDragEvent) { From f84febd3903b9c622c4428a0398f0568818fa748 Mon Sep 17 00:00:00 2001 From: Mitchell McCaffrey Date: Thu, 21 Oct 2021 18:11:01 +1100 Subject: [PATCH 08/15] Fix bug with polygon fog creation on touch devices --- src/components/tools/FogTool.tsx | 48 ++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/src/components/tools/FogTool.tsx b/src/components/tools/FogTool.tsx index b0b48bc..94494e8 100644 --- a/src/components/tools/FogTool.tsx +++ b/src/components/tools/FogTool.tsx @@ -107,7 +107,7 @@ function FogTool({ const [drawingShape, setDrawingShape] = useState(null); const [isBrushDown, setIsBrushDown] = useState(false); - const [editingShapes, setEditingShapes] = useState([]); + const [hoveredShapes, setHoveredShapes] = useState([]); // Shapes that have been merged for fog const [fogShapes, setFogShapes] = useState(shapes); @@ -330,11 +330,8 @@ function FogTool({ setIsBrushDown(false); } - function handlePointerClick( - event: Konva.KonvaEventObject - ) { - // Left click only - if (event.evt instanceof MouseEvent && event.evt.button !== 0) { + function handlePointerClick(event: Konva.KonvaEventObject) { + if (!leftMouseButton(event)) { return; } if (toolSettings.type === "polygon") { @@ -571,25 +568,25 @@ function FogTool({ function eraseHoveredShapes() { // Erase - if (editingShapes.length > 0) { + if (hoveredShapes.length > 0) { if (toolSettings.type === "remove") { - onShapesRemove(editingShapes.map((shape) => shape.id)); + onShapesRemove(hoveredShapes.map((shape) => shape.id)); } else if (toolSettings.type === "toggle") { onShapesEdit( - editingShapes.map((shape) => ({ + hoveredShapes.map((shape) => ({ id: shape.id, visible: !shape.visible, })) ); } - setEditingShapes([]); + setHoveredShapes([]); } } function handleShapeOver(shape: Fog, isDown: boolean) { if (shouldHover && isDown) { - if (editingShapes.findIndex((s) => s.id === shape.id) === -1) { - setEditingShapes((prevShapes) => [...prevShapes, shape]); + if (hoveredShapes.findIndex((s) => s.id === shape.id) === -1) { + setHoveredShapes((prevShapes) => [...prevShapes, shape]); } } } @@ -627,7 +624,7 @@ function FogTool({ ); } - function renderEditingShape(shape: Fog) { + function renderHoveredShape(shape: Fog) { const editingShape: Fog = { ...shape, color: "primary", @@ -635,6 +632,27 @@ function FogTool({ return renderShape(editingShape); } + function renderDrawingShape(shape: Fog) { + const opacity = editable ? editOpacity : 1; + const stroke = + editable && active + ? colors.lightGray + : colors[shape.color] || shape.color; + const fill = new Color(colors[shape.color] || shape.color) + .alpha(opacity) + .string(); + return ( + {}} + /> + ); + } + function renderPolygonAcceptTick(shape: Fog) { if (shape.data.points.length === 0) { return null; @@ -699,12 +717,12 @@ function FogTool({ {fogShapes.map(renderShape)} {shouldRenderGuides && renderGuides()} - {drawingShape && renderShape(drawingShape)} + {drawingShape && renderDrawingShape(drawingShape)} {drawingShape && toolSettings && toolSettings.type === "polygon" && renderPolygonAcceptTick(drawingShape)} - {editingShapes.length > 0 && editingShapes.map(renderEditingShape)} + {hoveredShapes.length > 0 && hoveredShapes.map(renderHoveredShape)} ); } From c359d3f3196e04c464e3959cbb52fe288262fcdb Mon Sep 17 00:00:00 2001 From: Nicola Thouliss <53867736+nthouliss@users.noreply.github.com> Date: Thu, 21 Oct 2021 18:34:57 +1100 Subject: [PATCH 09/15] Add volatile option to pointer event --- src/network/NetworkedMapPointer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/NetworkedMapPointer.tsx b/src/network/NetworkedMapPointer.tsx index e0a5758..5ba07e2 100644 --- a/src/network/NetworkedMapPointer.tsx +++ b/src/network/NetworkedMapPointer.tsx @@ -74,7 +74,7 @@ function NetworkedMapPointer({ session, active }: NetworkedMapPointerProps) { sessionRef.current && sessionRef.current.socket ) { - sessionRef.current.socket.emit( + sessionRef.current.socket.volatile.emit( "player_pointer", ownPointerUpdateRef.current ); From e92854137082dd3f988b719776ec90d8d1e6d344 Mon Sep 17 00:00:00 2001 From: Nicola Thouliss <53867736+nthouliss@users.noreply.github.com> Date: Thu, 21 Oct 2021 18:35:16 +1100 Subject: [PATCH 10/15] Clear socket buffer on reconnect --- src/network/Session.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/network/Session.ts b/src/network/Session.ts index daac356..5912c3d 100644 --- a/src/network/Session.ts +++ b/src/network/Session.ts @@ -88,7 +88,7 @@ class Session extends EventEmitter { this.socket.on("force_update", this._handleForceUpdate.bind(this)); this.emit("status", "ready"); - } catch (error) { + } catch (error: any) { logError(error); this.emit("status", "offline"); } @@ -302,7 +302,7 @@ class Session extends EventEmitter { this.peers[id] = peer; return true; - } catch (error) { + } catch (error: any) { logError(error); this.emit("peerError", { error }); for (let peer of Object.values(this.peers)) { @@ -360,6 +360,7 @@ class Session extends EventEmitter { } _handleSocketReconnect() { + this.socket.sendBuffer = []; if (this._gameId) { this.joinGame(this._gameId, this._password); } From 5d2e913925f02ef1d1f2eacc546a9dd1c458d379 Mon Sep 17 00:00:00 2001 From: Nicola Thouliss <53867736+nthouliss@users.noreply.github.com> Date: Thu, 21 Oct 2021 18:35:25 +1100 Subject: [PATCH 11/15] Edit backend servers --- .env.production | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.production b/.env.production index 6709c31..af31a79 100644 --- a/.env.production +++ b/.env.production @@ -1,5 +1,5 @@ -REACT_APP_BROKER_URL=https://prod.owlbear.rodeo -REACT_APP_ICE_SERVERS_URL=https://prod.owlbear.rodeo/iceservers +REACT_APP_BROKER_URL=https://stage.owlbear.rodeo +REACT_APP_ICE_SERVERS_URL=https://stage.owlbear.rodeo/iceservers REACT_APP_STRIPE_API_KEY=pk_live_MJjzi5djj524Y7h3fL5PNh4e00a852XD51 REACT_APP_STRIPE_URL=https://payment.owlbear.rodeo REACT_APP_VERSION=$npm_package_version From f359ce17325c0843a96a0bb0bc312a871c8c882f Mon Sep 17 00:00:00 2001 From: Mitchell McCaffrey Date: Thu, 21 Oct 2021 19:41:30 +1100 Subject: [PATCH 12/15] Update shortcuts doc --- src/docs/howTo/shortcuts.md | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/docs/howTo/shortcuts.md b/src/docs/howTo/shortcuts.md index b7c0a48..f963c50 100644 --- a/src/docs/howTo/shortcuts.md +++ b/src/docs/howTo/shortcuts.md @@ -1,21 +1,23 @@ ## General -| Shortcut | Description | -| ---------------- | ----------------------- | -| W | Move Tool | -| Space Bar (Hold) | Move Tool | -| F | Fog Tool | -| D | Drawing Tool | -| M | Measure Tool | -| Q | Pointer Tool | -| N | Note Tool | -| + | Zoom In | -| - | Zoom Out | -| Shift + Zoom | Precision Zoom | -| Ctrl + Z | Undo | -| Ctrl + Shift + Z | Redo | -| Ctrl (Hold) | Disabled Grid Snapping | -| Alt + Drag | Duplicate Token or Note | +| Shortcut | Description | +| ------------------- | ----------------------- | +| W | Move Tool | +| Space Bar (Hold) | Move Tool | +| Middle Mouse Button | Move Tool | +| F | Fog Tool | +| D | Drawing Tool | +| M | Measure Tool | +| Q | Pointer Tool | +| Right Mouse Button | Pointer Tool | +| N | Note Tool | +| + | Zoom In | +| - | Zoom Out | +| Shift + Zoom | Precision Zoom | +| Ctrl + Z | Undo | +| Ctrl + Shift + Z | Redo | +| Ctrl (Hold) | Disabled Grid Snapping | +| Alt + Drag | Duplicate Token or Note | ## Select Tool From ae72ae55d313b26de238de3ad6217795200acbd0 Mon Sep 17 00:00:00 2001 From: Mitchell McCaffrey Date: Thu, 21 Oct 2021 19:42:27 +1100 Subject: [PATCH 13/15] Add v1.10.1 release notes --- src/docs/releaseNotes/v1.10.1.md | 20 ++++++++++++++++++++ src/routes/ReleaseNotes.tsx | 6 ++++++ 2 files changed, 26 insertions(+) create mode 100644 src/docs/releaseNotes/v1.10.1.md diff --git a/src/docs/releaseNotes/v1.10.1.md b/src/docs/releaseNotes/v1.10.1.md new file mode 100644 index 0000000..dced762 --- /dev/null +++ b/src/docs/releaseNotes/v1.10.1.md @@ -0,0 +1,20 @@ +## Minor Changes + +This is a small release fixing a few bugs and adding some QoL improvements. + +- Updated alternating diagonals measurement to fix inaccuracy with diagonal distances. +- Added support for middle mouse button move shortcut. +- Added support for right mouse button pointer shortcut. +- Optimised note creation to reduce lag when creating a note on FireFox. +- Fixed a bug with using the polygon fog tool on touch devices. +- Fixed a bug that would cause phantom players to be shown in the party view on a server error. + +We are currently working on some big changes that will take some time so expect smaller releases like this one until that is ready. If you'd like to keep up with the development of these changes check out our [Patreon](https://patreon.com/owlbearrodeo) where we are sharing previews of what's to come. + +[Reddit]() +[Twitter]() +[Patreon]() + +--- + +October 21 2021 diff --git a/src/routes/ReleaseNotes.tsx b/src/routes/ReleaseNotes.tsx index 1d240a0..9dabf12 100644 --- a/src/routes/ReleaseNotes.tsx +++ b/src/routes/ReleaseNotes.tsx @@ -27,6 +27,7 @@ const v180 = raw("../docs/releaseNotes/v1.8.0.md"); const v181 = raw("../docs/releaseNotes/v1.8.1.md"); const v190 = raw("../docs/releaseNotes/v1.9.0.md"); const v1100 = raw("../docs/releaseNotes/v1.10.0.md"); +const v1101 = raw("../docs/releaseNotes/v1.10.1.md"); function ReleaseNotes() { const location = useLocation(); @@ -51,6 +52,11 @@ function ReleaseNotes() { Release Notes +
+ + + +
From 1ada85795e93664a0867ffe54e0286e482935207 Mon Sep 17 00:00:00 2001 From: Mitchell McCaffrey Date: Thu, 21 Oct 2021 19:43:08 +1100 Subject: [PATCH 14/15] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 078ec70..21e4591 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "owlbear-rodeo", - "version": "1.10.0.2", + "version": "1.10.1", "private": true, "dependencies": { "@babylonjs/core": "^4.2.0", From 67a4076cd2246477c683fb66828984915b2dcdae Mon Sep 17 00:00:00 2001 From: Mitchell McCaffrey Date: Thu, 21 Oct 2021 19:59:06 +1100 Subject: [PATCH 15/15] Update YouTube embeds --- src/docs/howTo/usingDice.md | 2 -- src/docs/howTo/usingDrawing.md | 2 -- src/docs/howTo/usingTokens.md | 2 ++ 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/docs/howTo/usingDice.md b/src/docs/howTo/usingDice.md index 5079516..5d9c918 100644 --- a/src/docs/howTo/usingDice.md +++ b/src/docs/howTo/usingDice.md @@ -1,5 +1,3 @@ -![embed:](https://www.youtube.com/embed/Er_grVmqpk0) - Owlbear Rodeo supports a physically simulated 3D dice tray and dice. To access these features click the Show Dice Tray icon in the top left of the map view. ![Open Dice Tray](openDiceTray) diff --git a/src/docs/howTo/usingDrawing.md b/src/docs/howTo/usingDrawing.md index ffb6456..29b9d90 100644 --- a/src/docs/howTo/usingDrawing.md +++ b/src/docs/howTo/usingDrawing.md @@ -1,5 +1,3 @@ -![embed:](https://www.youtube.com/embed/2e07DtB-Xrc) - The Drawing Tool allows you to draw on top of a map. To access the Drawing Tool click the Drawing Tool button in the top right of the map view. ![Using Drawing](usingDrawing) diff --git a/src/docs/howTo/usingTokens.md b/src/docs/howTo/usingTokens.md index 003a07b..f9fa37e 100644 --- a/src/docs/howTo/usingTokens.md +++ b/src/docs/howTo/usingTokens.md @@ -1,3 +1,5 @@ +![embed:](https://www.youtube.com/embed/MCOzpQ4auqs) + Once you have a map shared between a party all players can drag tokens from the Token List on the right hand side of the screen. Tokens can then be used to represent players, monsters or any other object that needs to be moved around the map. ## Default Tokens