Added network sync to drawing

This commit is contained in:
Mitchell McCaffrey 2020-04-19 15:15:48 +10:00
parent 9f97cf3bb4
commit ad236d6e6a
2 changed files with 85 additions and 30 deletions

View File

@ -22,6 +22,11 @@ function Map({
onMapTokenChange,
onMapTokenRemove,
onMapChange,
onMapDraw,
onMapDrawUndo,
onMapDrawRedo,
drawActions,
drawActionIndex,
}) {
function handleProxyDragEnd(isOnMap, token) {
if (isOnMap && onMapTokenChange) {
@ -40,30 +45,15 @@ function Map({
const [selectedTool, setSelectedTool] = useState("pan");
const [drawnShapes, setDrawnShapes] = useState([]);
const [drawActions, setDrawActions] = useState([]);
const [drawActionIndex, setDrawActionIndex] = useState(-1);
function handleShapeAdd(shape) {
setDrawActions((prevActions) => {
const newActions = [
...prevActions.slice(0, drawActionIndex + 1),
{ type: "add", shape },
];
setDrawActionIndex(newActions.length - 1);
return newActions;
});
onMapDraw({ type: "add", shape });
}
function handleShapeRemove(shapeId) {
setDrawActions((prevActions) => {
const newActions = [
...prevActions.slice(0, drawActionIndex + 1),
{ type: "remove", shapeId },
];
setDrawActionIndex(newActions.length - 1);
return newActions;
});
onMapDraw({ type: "remove", shapeId });
}
// Replay the draw actions and convert them to shapes for the map drawing
useEffect(() => {
let shapesById = {};
for (let i = 0; i <= drawActionIndex; i++) {
@ -78,16 +68,6 @@ function Map({
setDrawnShapes(Object.values(shapesById));
}, [drawActions, drawActionIndex]);
function handleDrawActionUndo() {
setDrawActionIndex((prevIndex) => Math.max(prevIndex - 1, -1));
}
function handleDrawActionRedo() {
setDrawActionIndex((prevIndex) =>
Math.min(prevIndex + 1, drawActions.length - 1)
);
}
const disabledTools = [];
if (!mapData) {
disabledTools.push("pan");
@ -290,8 +270,8 @@ function Map({
onToolChange={setSelectedTool}
selectedTool={selectedTool}
disabledTools={disabledTools}
onUndo={handleDrawActionUndo}
onRedo={handleDrawActionRedo}
onUndo={onMapDrawUndo}
onRedo={onMapDrawRedo}
undoDisabled={drawActionIndex < 0}
redoDisabled={drawActionIndex === drawActions.length - 1}
/>

View File

@ -36,6 +36,10 @@ function Game() {
handlePeerError
);
/**
* Map state
*/
const [mapSource, setMapSource] = useState(null);
const mapDataRef = useRef(null);
@ -74,6 +78,52 @@ function Game() {
}
}
const [mapDrawActions, setMapDrawActions] = useState([]);
// An index into the draw actions array to which only actions before the
// index will be performed (used in undo and redo)
const [mapDrawActionIndex, setMapDrawActionIndex] = useState(-1);
function addNewMapDrawActions(actions) {
setMapDrawActions((prevActions) => {
const newActions = [
...prevActions.slice(0, mapDrawActionIndex + 1),
...actions,
];
const newIndex = newActions.length - 1;
setMapDrawActionIndex(newIndex);
return newActions;
});
}
function handleMapDraw(action) {
addNewMapDrawActions([action]);
for (let peer of Object.values(peers)) {
peer.connection.send({ id: "mapDraw", data: [action] });
}
}
function handleMapDrawUndo() {
const newIndex = Math.max(mapDrawActionIndex - 1, -1);
setMapDrawActionIndex(newIndex);
for (let peer of Object.values(peers)) {
peer.connection.send({ id: "mapDrawIndex", data: newIndex });
}
}
function handleMapDrawRedo() {
const newIndex = Math.min(
mapDrawActionIndex + 1,
mapDrawActions.length - 1
);
setMapDrawActionIndex(newIndex);
for (let peer of Object.values(peers)) {
peer.connection.send({ id: "mapDrawIndex", data: newIndex });
}
}
/**
* Party state
*/
const { nickname, setNickname } = useNickname();
const [partyNicknames, setPartyNicknames] = useState({});
@ -94,6 +144,10 @@ function Game() {
}
}
/**
* Peer handlers
*/
function handlePeerData({ data, peer }) {
if (data.id === "sync") {
if (mapSource) {
@ -102,6 +156,12 @@ function Game() {
if (mapTokens) {
peer.connection.send({ id: "tokenEdit", data: mapTokens });
}
if (mapDrawActions) {
peer.connection.send({ id: "mapDraw", data: mapDrawActions });
}
if (mapDrawActionIndex != mapDrawActions.length - 1) {
peer.connection.send({ id: "mapDrawIndex", data: mapDrawActionIndex });
}
}
if (data.id === "map") {
const blob = new Blob([data.data.file]);
@ -125,6 +185,12 @@ function Game() {
...data.data,
}));
}
if (data.id === "mapDraw") {
addNewMapDrawActions(data.data);
}
if (data.id === "mapDrawIndex") {
setMapDrawActionIndex(data.data);
}
}
function handlePeerDisconnected(peer) {
@ -169,6 +235,10 @@ function Game() {
}
}
/**
* Stream handler
*/
function handleStreamStart(localStream) {
setStream(localStream);
const tracks = localStream.getTracks();
@ -238,6 +308,11 @@ function Game() {
onMapTokenChange={handleMapTokenChange}
onMapTokenRemove={handleMapTokenRemove}
onMapChange={handleMapChange}
onMapDraw={handleMapDraw}
onMapDrawUndo={handleMapDrawUndo}
onMapDrawRedo={handleMapDrawRedo}
drawActions={mapDrawActions}
drawActionIndex={mapDrawActionIndex}
/>
<Tokens onCreateMapToken={handleMapTokenChange} />
</Flex>