2021-02-06 13:32:38 +11:00
|
|
|
import React, { useState, useEffect, useRef } from "react";
|
2020-07-16 17:27:39 +10:00
|
|
|
|
2021-02-06 13:32:38 +11:00
|
|
|
import { useTokenData } from "../contexts/TokenDataContext";
|
|
|
|
|
import { useMapData } from "../contexts/MapDataContext";
|
|
|
|
|
import { useMapLoading } from "../contexts/MapLoadingContext";
|
|
|
|
|
import { useAuth } from "../contexts/AuthContext";
|
|
|
|
|
import { useDatabase } from "../contexts/DatabaseContext";
|
|
|
|
|
import { useParty } from "../contexts/PartyContext";
|
2020-07-16 17:27:39 +10:00
|
|
|
|
|
|
|
|
import { omit } from "../helpers/shared";
|
2021-02-04 15:06:34 +11:00
|
|
|
|
|
|
|
|
import useDebounce from "../hooks/useDebounce";
|
|
|
|
|
import useNetworkedState from "../hooks/useNetworkedState";
|
|
|
|
|
|
2020-07-16 17:27:39 +10:00
|
|
|
// Load session for auto complete
|
|
|
|
|
// eslint-disable-next-line no-unused-vars
|
2020-10-23 10:27:22 +11:00
|
|
|
import Session from "./Session";
|
2020-07-16 17:27:39 +10:00
|
|
|
|
|
|
|
|
import Map from "../components/map/Map";
|
|
|
|
|
import Tokens from "../components/token/Tokens";
|
|
|
|
|
|
2021-02-04 09:11:27 +11:00
|
|
|
const defaultMapActions = {
|
|
|
|
|
mapDrawActions: [],
|
|
|
|
|
mapDrawActionIndex: -1,
|
|
|
|
|
fogDrawActions: [],
|
|
|
|
|
fogDrawActionIndex: -1,
|
|
|
|
|
};
|
|
|
|
|
|
2020-07-16 17:27:39 +10:00
|
|
|
/**
|
|
|
|
|
* @typedef {object} NetworkedMapProps
|
|
|
|
|
* @property {Session} session
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param {NetworkedMapProps} props
|
|
|
|
|
*/
|
|
|
|
|
function NetworkedMapAndTokens({ session }) {
|
2021-02-06 13:32:38 +11:00
|
|
|
const { userId } = useAuth();
|
|
|
|
|
const partyState = useParty();
|
2020-07-17 15:57:52 +10:00
|
|
|
const {
|
|
|
|
|
assetLoadStart,
|
|
|
|
|
assetLoadFinish,
|
|
|
|
|
assetProgressUpdate,
|
|
|
|
|
isLoading,
|
2021-02-06 13:32:38 +11:00
|
|
|
} = useMapLoading();
|
2020-07-16 17:27:39 +10:00
|
|
|
|
2021-03-22 21:23:43 +11:00
|
|
|
const { putToken, getTokenFromDB } = useTokenData();
|
2021-02-06 13:32:38 +11:00
|
|
|
const { putMap, updateMap, getMapFromDB, updateMapState } = useMapData();
|
2020-07-16 17:27:39 +10:00
|
|
|
|
|
|
|
|
const [currentMap, setCurrentMap] = useState(null);
|
2020-12-05 17:16:06 +11:00
|
|
|
const [currentMapState, setCurrentMapState] = useNetworkedState(
|
|
|
|
|
null,
|
|
|
|
|
session,
|
2021-01-04 09:34:25 +11:00
|
|
|
"map_state",
|
2021-01-22 06:59:49 +11:00
|
|
|
500,
|
2021-01-04 09:34:25 +11:00
|
|
|
true,
|
|
|
|
|
"mapId"
|
2020-12-05 17:16:06 +11:00
|
|
|
);
|
2020-12-11 13:24:39 +11:00
|
|
|
const [assetManifest, setAssetManifest] = useNetworkedState(
|
2021-01-21 13:51:23 +11:00
|
|
|
null,
|
2020-12-11 13:24:39 +11:00
|
|
|
session,
|
2021-01-03 12:12:13 +11:00
|
|
|
"manifest",
|
2021-01-22 06:59:49 +11:00
|
|
|
500,
|
2021-03-22 21:23:43 +11:00
|
|
|
true,
|
|
|
|
|
"mapId"
|
2020-12-11 13:24:39 +11:00
|
|
|
);
|
|
|
|
|
|
2021-01-25 08:38:50 +11:00
|
|
|
async function loadAssetManifestFromMap(map, mapState) {
|
2021-03-23 10:24:01 +11:00
|
|
|
const assets = {};
|
2020-12-11 13:24:39 +11:00
|
|
|
if (map.type === "file") {
|
|
|
|
|
const { id, lastModified, owner } = map;
|
2021-03-22 21:23:43 +11:00
|
|
|
assets[`map-${id}`] = { type: "map", id, lastModified, owner };
|
2020-12-11 13:24:39 +11:00
|
|
|
}
|
|
|
|
|
let processedTokens = new Set();
|
|
|
|
|
for (let tokenState of Object.values(mapState.tokens)) {
|
2021-01-25 08:38:50 +11:00
|
|
|
const token = await getTokenFromDB(tokenState.tokenId);
|
2020-12-11 13:24:39 +11:00
|
|
|
if (
|
|
|
|
|
token &&
|
|
|
|
|
token.type === "file" &&
|
|
|
|
|
!processedTokens.has(tokenState.tokenId)
|
|
|
|
|
) {
|
|
|
|
|
processedTokens.add(tokenState.tokenId);
|
|
|
|
|
// Omit file from token peer will request file if needed
|
|
|
|
|
const { id, lastModified, owner } = token;
|
2021-03-22 21:23:43 +11:00
|
|
|
assets[`token-${id}`] = { type: "token", id, lastModified, owner };
|
2020-12-11 13:24:39 +11:00
|
|
|
}
|
|
|
|
|
}
|
2021-03-23 10:24:01 +11:00
|
|
|
setAssetManifest({ mapId: map.id, assets }, true, true);
|
2020-12-11 13:24:39 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function compareAssets(a, b) {
|
|
|
|
|
return a.type === b.type && a.id === b.id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Return true if an asset is out of date
|
|
|
|
|
function assetNeedsUpdate(oldAsset, newAsset) {
|
|
|
|
|
return (
|
|
|
|
|
compareAssets(oldAsset, newAsset) &&
|
2021-03-22 21:23:43 +11:00
|
|
|
oldAsset.lastModified < newAsset.lastModified
|
2020-12-11 13:24:39 +11:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function addAssetIfNeeded(asset) {
|
2021-03-23 10:24:01 +11:00
|
|
|
setAssetManifest((prevManifest) => {
|
|
|
|
|
if (prevManifest?.assets) {
|
|
|
|
|
const id =
|
|
|
|
|
asset.type === "map" ? `map-${asset.id}` : `token-${asset.id}`;
|
|
|
|
|
const exists = id in prevManifest.assets;
|
|
|
|
|
const needsUpdate =
|
|
|
|
|
exists && assetNeedsUpdate(prevManifest.assets[id], asset);
|
|
|
|
|
if (!exists || needsUpdate) {
|
|
|
|
|
return {
|
|
|
|
|
...prevManifest,
|
|
|
|
|
assets: {
|
|
|
|
|
...prevManifest.assets,
|
|
|
|
|
[id]: asset,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
2021-03-22 21:23:43 +11:00
|
|
|
}
|
2021-03-23 10:24:01 +11:00
|
|
|
return prevManifest;
|
2021-03-22 21:23:43 +11:00
|
|
|
});
|
2020-12-11 13:24:39 +11:00
|
|
|
}
|
|
|
|
|
|
2021-01-25 08:38:50 +11:00
|
|
|
// Keep track of assets we are already requesting to prevent from loading them multiple times
|
|
|
|
|
const requestingAssetsRef = useRef(new Set());
|
|
|
|
|
|
2020-12-11 13:24:39 +11:00
|
|
|
useEffect(() => {
|
|
|
|
|
if (!assetManifest) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function requestAssetsIfNeeded() {
|
2021-03-23 10:24:01 +11:00
|
|
|
for (let asset of Object.values(assetManifest.assets)) {
|
2021-01-25 08:38:50 +11:00
|
|
|
if (
|
|
|
|
|
asset.owner === userId ||
|
|
|
|
|
requestingAssetsRef.current.has(asset.id)
|
|
|
|
|
) {
|
2020-12-11 13:24:39 +11:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const owner = Object.values(partyState).find(
|
|
|
|
|
(player) => player.userId === asset.owner
|
|
|
|
|
);
|
|
|
|
|
if (!owner) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-07 14:47:34 +11:00
|
|
|
requestingAssetsRef.current.add(asset.id);
|
|
|
|
|
|
2020-12-11 13:24:39 +11:00
|
|
|
if (asset.type === "map") {
|
2021-01-25 08:38:50 +11:00
|
|
|
const cachedMap = await getMapFromDB(asset.id);
|
2021-01-22 14:59:05 +11:00
|
|
|
if (cachedMap && cachedMap.lastModified === asset.lastModified) {
|
2021-02-07 14:47:34 +11:00
|
|
|
requestingAssetsRef.current.delete(asset.id);
|
2020-12-11 13:24:39 +11:00
|
|
|
} else {
|
2021-01-04 13:34:09 +11:00
|
|
|
session.sendTo(owner.sessionId, "mapRequest", asset.id);
|
2020-12-11 13:24:39 +11:00
|
|
|
}
|
2020-12-12 15:03:24 +11:00
|
|
|
} else if (asset.type === "token") {
|
2021-01-25 08:38:50 +11:00
|
|
|
const cachedToken = await getTokenFromDB(asset.id);
|
2021-01-22 14:59:05 +11:00
|
|
|
if (cachedToken && cachedToken.lastModified === asset.lastModified) {
|
2021-02-07 14:47:34 +11:00
|
|
|
requestingAssetsRef.current.delete(asset.id);
|
2020-12-12 15:03:24 +11:00
|
|
|
} else {
|
2021-01-04 13:34:09 +11:00
|
|
|
session.sendTo(owner.sessionId, "tokenRequest", asset.id);
|
2020-12-12 15:03:24 +11:00
|
|
|
}
|
2020-12-11 13:24:39 +11:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
requestAssetsIfNeeded();
|
2021-01-22 14:59:05 +11:00
|
|
|
}, [
|
|
|
|
|
assetManifest,
|
|
|
|
|
partyState,
|
|
|
|
|
session,
|
2021-01-25 08:38:50 +11:00
|
|
|
getMapFromDB,
|
|
|
|
|
getTokenFromDB,
|
2021-01-22 14:59:05 +11:00
|
|
|
updateMap,
|
|
|
|
|
userId,
|
|
|
|
|
]);
|
2020-07-16 17:27:39 +10:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Map state
|
|
|
|
|
*/
|
|
|
|
|
|
2021-02-06 13:32:38 +11:00
|
|
|
const { database } = useDatabase();
|
2020-07-16 17:27:39 +10:00
|
|
|
// Sync the map state to the database after 500ms of inactivity
|
|
|
|
|
const debouncedMapState = useDebounce(currentMapState, 500);
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (
|
|
|
|
|
debouncedMapState &&
|
|
|
|
|
debouncedMapState.mapId &&
|
|
|
|
|
currentMap &&
|
|
|
|
|
currentMap.owner === userId &&
|
|
|
|
|
database
|
|
|
|
|
) {
|
2020-10-22 20:57:29 +11:00
|
|
|
updateMapState(debouncedMapState.mapId, debouncedMapState);
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
2021-01-22 14:59:05 +11:00
|
|
|
}, [currentMap, debouncedMapState, userId, database, updateMapState]);
|
2020-07-16 17:27:39 +10:00
|
|
|
|
2021-02-08 16:53:56 +11:00
|
|
|
async function handleMapChange(newMap, newMapState) {
|
2021-01-04 09:48:08 +11:00
|
|
|
// Clear map before sending new one
|
|
|
|
|
setCurrentMap(null);
|
|
|
|
|
session.socket?.emit("map", null);
|
|
|
|
|
|
2021-01-03 16:45:55 +11:00
|
|
|
setCurrentMapState(newMapState, true, true);
|
2020-07-16 17:27:39 +10:00
|
|
|
setCurrentMap(newMap);
|
2020-12-11 13:24:39 +11:00
|
|
|
|
|
|
|
|
if (newMap && newMap.type === "file") {
|
2021-02-08 16:53:56 +11:00
|
|
|
const { file, resolutions, thumbnail, ...rest } = newMap;
|
2021-01-01 12:44:56 +11:00
|
|
|
session.socket?.emit("map", rest);
|
2020-12-11 13:24:39 +11:00
|
|
|
} else {
|
2021-01-01 12:44:56 +11:00
|
|
|
session.socket?.emit("map", newMap);
|
2020-12-11 13:24:39 +11:00
|
|
|
}
|
2020-07-18 16:58:29 +10:00
|
|
|
if (!newMap || !newMapState) {
|
2021-03-26 15:48:55 +11:00
|
|
|
setAssetManifest(null, true, true);
|
2020-07-18 16:58:29 +10:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-08 16:53:56 +11:00
|
|
|
await loadAssetManifestFromMap(newMap, newMapState);
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
|
|
|
|
|
2021-02-22 17:14:12 +11:00
|
|
|
function handleMapReset(newMapState) {
|
2021-01-03 16:45:55 +11:00
|
|
|
setCurrentMapState(newMapState, true, true);
|
2021-02-22 17:14:12 +11:00
|
|
|
setMapActions(defaultMapActions);
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
|
|
|
|
|
2021-02-04 09:11:27 +11:00
|
|
|
const [mapActions, setMapActions] = useState(defaultMapActions);
|
|
|
|
|
|
|
|
|
|
function addMapActions(actions, indexKey, actionsKey, shapesKey) {
|
|
|
|
|
setMapActions((prevMapActions) => {
|
2020-07-16 17:27:39 +10:00
|
|
|
const newActions = [
|
2021-02-04 09:11:27 +11:00
|
|
|
...prevMapActions[actionsKey].slice(0, prevMapActions[indexKey] + 1),
|
2020-07-16 17:27:39 +10:00
|
|
|
...actions,
|
|
|
|
|
];
|
|
|
|
|
const newIndex = newActions.length - 1;
|
|
|
|
|
return {
|
2021-02-04 09:11:27 +11:00
|
|
|
...prevMapActions,
|
2020-07-16 17:27:39 +10:00
|
|
|
[actionsKey]: newActions,
|
|
|
|
|
[indexKey]: newIndex,
|
|
|
|
|
};
|
|
|
|
|
});
|
2021-02-04 09:11:27 +11:00
|
|
|
// Update map state by performing the actions on it
|
|
|
|
|
setCurrentMapState((prevMapState) => {
|
|
|
|
|
if (prevMapState) {
|
|
|
|
|
let shapes = prevMapState[shapesKey];
|
|
|
|
|
for (let action of actions) {
|
|
|
|
|
shapes = action.execute(shapes);
|
|
|
|
|
}
|
|
|
|
|
return {
|
|
|
|
|
...prevMapState,
|
|
|
|
|
[shapesKey]: shapes,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
});
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
|
|
|
|
|
2021-02-04 09:11:27 +11:00
|
|
|
function updateActionIndex(change, indexKey, actionsKey, shapesKey) {
|
|
|
|
|
const prevIndex = mapActions[indexKey];
|
2020-07-16 17:27:39 +10:00
|
|
|
const newIndex = Math.min(
|
2021-02-04 09:11:27 +11:00
|
|
|
Math.max(mapActions[indexKey] + change, -1),
|
|
|
|
|
mapActions[actionsKey].length - 1
|
2020-07-16 17:27:39 +10:00
|
|
|
);
|
|
|
|
|
|
2021-02-04 09:11:27 +11:00
|
|
|
setMapActions((prevMapActions) => ({
|
|
|
|
|
...prevMapActions,
|
2020-07-16 17:27:39 +10:00
|
|
|
[indexKey]: newIndex,
|
|
|
|
|
}));
|
2021-02-04 09:11:27 +11:00
|
|
|
|
|
|
|
|
// Update map state by either performing the actions or undoing them
|
|
|
|
|
setCurrentMapState((prevMapState) => {
|
|
|
|
|
if (prevMapState) {
|
|
|
|
|
let shapes = prevMapState[shapesKey];
|
|
|
|
|
if (prevIndex < newIndex) {
|
|
|
|
|
// Redo
|
|
|
|
|
for (let i = prevIndex + 1; i < newIndex + 1; i++) {
|
|
|
|
|
let action = mapActions[actionsKey][i];
|
|
|
|
|
shapes = action.execute(shapes);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Undo
|
|
|
|
|
for (let i = prevIndex; i > newIndex; i--) {
|
|
|
|
|
let action = mapActions[actionsKey][i];
|
|
|
|
|
shapes = action.undo(shapes);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return {
|
|
|
|
|
...prevMapState,
|
|
|
|
|
[shapesKey]: shapes,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2020-07-16 17:27:39 +10:00
|
|
|
return newIndex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleMapDraw(action) {
|
2021-02-04 09:11:27 +11:00
|
|
|
addMapActions(
|
|
|
|
|
[action],
|
|
|
|
|
"mapDrawActionIndex",
|
|
|
|
|
"mapDrawActions",
|
|
|
|
|
"drawShapes"
|
|
|
|
|
);
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleMapDrawUndo() {
|
2021-02-04 09:11:27 +11:00
|
|
|
updateActionIndex(-1, "mapDrawActionIndex", "mapDrawActions", "drawShapes");
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleMapDrawRedo() {
|
2021-02-04 09:11:27 +11:00
|
|
|
updateActionIndex(1, "mapDrawActionIndex", "mapDrawActions", "drawShapes");
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleFogDraw(action) {
|
2021-02-04 09:11:27 +11:00
|
|
|
addMapActions(
|
|
|
|
|
[action],
|
|
|
|
|
"fogDrawActionIndex",
|
|
|
|
|
"fogDrawActions",
|
|
|
|
|
"fogShapes"
|
|
|
|
|
);
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleFogDrawUndo() {
|
2021-02-04 09:11:27 +11:00
|
|
|
updateActionIndex(-1, "fogDrawActionIndex", "fogDrawActions", "fogShapes");
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleFogDrawRedo() {
|
2021-02-04 09:11:27 +11:00
|
|
|
updateActionIndex(1, "fogDrawActionIndex", "fogDrawActions", "fogShapes");
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
|
|
|
|
|
2021-02-11 23:09:00 +11:00
|
|
|
// If map changes clear map actions
|
|
|
|
|
const previousMapIdRef = useRef();
|
2021-02-04 09:11:27 +11:00
|
|
|
useEffect(() => {
|
2021-02-11 23:09:00 +11:00
|
|
|
if (currentMap && currentMap.id !== previousMapIdRef.current) {
|
2021-02-04 09:11:27 +11:00
|
|
|
setMapActions(defaultMapActions);
|
2021-02-11 23:09:00 +11:00
|
|
|
previousMapIdRef.current = currentMap.id;
|
2021-02-04 09:11:27 +11:00
|
|
|
}
|
2021-02-11 23:09:00 +11:00
|
|
|
}, [currentMap]);
|
2021-02-04 09:11:27 +11:00
|
|
|
|
2020-11-04 15:03:34 +11:00
|
|
|
function handleNoteChange(note) {
|
2020-11-03 17:15:39 +11:00
|
|
|
setCurrentMapState((prevMapState) => ({
|
|
|
|
|
...prevMapState,
|
|
|
|
|
notes: {
|
|
|
|
|
...prevMapState.notes,
|
|
|
|
|
[note.id]: note,
|
|
|
|
|
},
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-05 14:41:33 +11:00
|
|
|
function handleNoteRemove(noteId) {
|
|
|
|
|
setCurrentMapState((prevMapState) => ({
|
|
|
|
|
...prevMapState,
|
|
|
|
|
notes: omit(prevMapState.notes, [noteId]),
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-16 17:27:39 +10:00
|
|
|
/**
|
|
|
|
|
* Token state
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
async function handleMapTokenStateCreate(tokenState) {
|
2021-01-21 11:29:39 +11:00
|
|
|
if (!currentMap || !currentMapState) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-07-16 17:27:39 +10:00
|
|
|
// If file type token send the token to the other peers
|
2021-01-25 08:38:50 +11:00
|
|
|
const token = await getTokenFromDB(tokenState.tokenId);
|
2020-07-16 17:27:39 +10:00
|
|
|
if (token && token.type === "file") {
|
2020-12-11 13:24:39 +11:00
|
|
|
const { id, lastModified, owner } = token;
|
|
|
|
|
addAssetIfNeeded({ type: "token", id, lastModified, owner });
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
|
|
|
|
handleMapTokenStateChange({ [tokenState.id]: tokenState });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleMapTokenStateChange(change) {
|
2021-01-21 13:51:23 +11:00
|
|
|
if (!currentMapState) {
|
2020-07-16 17:27:39 +10:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
setCurrentMapState((prevMapState) => ({
|
|
|
|
|
...prevMapState,
|
|
|
|
|
tokens: {
|
|
|
|
|
...prevMapState.tokens,
|
|
|
|
|
...change,
|
|
|
|
|
},
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleMapTokenStateRemove(tokenState) {
|
|
|
|
|
setCurrentMapState((prevMapState) => {
|
|
|
|
|
const { [tokenState.id]: old, ...rest } = prevMapState.tokens;
|
|
|
|
|
return { ...prevMapState, tokens: rest };
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
async function handlePeerData({ id, data, reply }) {
|
|
|
|
|
if (id === "mapRequest") {
|
2020-08-28 17:06:13 +10:00
|
|
|
const map = await getMapFromDB(data);
|
2020-12-11 13:24:39 +11:00
|
|
|
function replyWithMap(preview, resolution) {
|
|
|
|
|
let response = {
|
|
|
|
|
...map,
|
|
|
|
|
resolutions: undefined,
|
|
|
|
|
file: undefined,
|
2021-02-08 16:53:56 +11:00
|
|
|
thumbnail: undefined,
|
2020-12-11 13:24:39 +11:00
|
|
|
// Remove last modified so if there is an error
|
|
|
|
|
// during the map request the cache is invalid
|
|
|
|
|
lastModified: 0,
|
|
|
|
|
// Add last used for cache invalidation
|
|
|
|
|
lastUsed: Date.now(),
|
|
|
|
|
};
|
|
|
|
|
// Send preview if available
|
2020-08-28 17:06:13 +10:00
|
|
|
if (map.resolutions[preview]) {
|
2020-12-11 13:24:39 +11:00
|
|
|
response.resolutions = { [preview]: map.resolutions[preview] };
|
|
|
|
|
reply("mapResponse", response, "map");
|
2020-08-28 17:06:13 +10:00
|
|
|
}
|
2020-12-11 13:24:39 +11:00
|
|
|
// Send full map at the desired resolution if available
|
2020-10-27 19:30:39 +11:00
|
|
|
if (map.resolutions[resolution]) {
|
2020-12-11 13:24:39 +11:00
|
|
|
response.file = map.resolutions[resolution].file;
|
2020-10-27 19:30:39 +11:00
|
|
|
} else if (map.file) {
|
|
|
|
|
// The resolution might not exist for other users so send the file instead
|
2020-12-11 13:24:39 +11:00
|
|
|
response.file = map.file;
|
2020-10-27 19:30:39 +11:00
|
|
|
} else {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-12-11 13:24:39 +11:00
|
|
|
// Add last modified back to file to set cache as valid
|
|
|
|
|
response.lastModified = map.lastModified;
|
|
|
|
|
reply("mapResponse", response, "map");
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (map.quality) {
|
|
|
|
|
case "low":
|
2020-12-11 13:24:39 +11:00
|
|
|
replyWithMap(undefined, "low");
|
2020-07-16 17:27:39 +10:00
|
|
|
break;
|
|
|
|
|
case "medium":
|
2020-12-11 13:24:39 +11:00
|
|
|
replyWithMap("low", "medium");
|
2020-07-16 17:27:39 +10:00
|
|
|
break;
|
|
|
|
|
case "high":
|
2020-12-11 13:24:39 +11:00
|
|
|
replyWithMap("medium", "high");
|
2020-07-16 17:27:39 +10:00
|
|
|
break;
|
|
|
|
|
case "ultra":
|
2020-12-11 13:24:39 +11:00
|
|
|
replyWithMap("medium", "ultra");
|
2020-07-16 17:27:39 +10:00
|
|
|
break;
|
|
|
|
|
case "original":
|
2020-10-30 11:52:23 +11:00
|
|
|
if (map.resolutions) {
|
|
|
|
|
if (map.resolutions.medium) {
|
2020-12-11 13:24:39 +11:00
|
|
|
replyWithMap("medium");
|
2020-10-30 11:52:23 +11:00
|
|
|
} else if (map.resolutions.low) {
|
2020-12-11 13:24:39 +11:00
|
|
|
replyWithMap("low");
|
|
|
|
|
} else {
|
|
|
|
|
replyWithMap();
|
2020-10-30 11:52:23 +11:00
|
|
|
}
|
2020-12-11 13:24:39 +11:00
|
|
|
} else {
|
|
|
|
|
replyWithMap();
|
2020-07-17 15:02:21 +10:00
|
|
|
}
|
2020-07-16 17:27:39 +10:00
|
|
|
break;
|
|
|
|
|
default:
|
2020-12-11 13:24:39 +11:00
|
|
|
replyWithMap();
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
|
|
|
|
}
|
2020-12-11 13:24:39 +11:00
|
|
|
|
2020-07-16 17:27:39 +10:00
|
|
|
if (id === "mapResponse") {
|
2020-12-11 13:24:39 +11:00
|
|
|
const newMap = data;
|
2021-01-24 17:50:52 +11:00
|
|
|
if (newMap?.id) {
|
|
|
|
|
setCurrentMap(newMap);
|
|
|
|
|
await putMap(newMap);
|
2021-01-25 08:38:50 +11:00
|
|
|
// If we have the final map resolution
|
|
|
|
|
if (newMap.lastModified > 0) {
|
|
|
|
|
requestingAssetsRef.current.delete(newMap.id);
|
|
|
|
|
}
|
2021-01-24 17:50:52 +11:00
|
|
|
}
|
2021-01-20 18:08:03 +11:00
|
|
|
assetLoadFinish();
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
2020-12-11 13:24:39 +11:00
|
|
|
|
2020-07-16 17:27:39 +10:00
|
|
|
if (id === "tokenRequest") {
|
2021-01-24 17:50:52 +11:00
|
|
|
const token = await getTokenFromDB(data);
|
2020-09-11 16:56:40 +10:00
|
|
|
// Add a last used property for cache invalidation
|
|
|
|
|
reply("tokenResponse", { ...token, lastUsed: Date.now() }, "token");
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
|
|
|
|
if (id === "tokenResponse") {
|
|
|
|
|
const newToken = data;
|
2021-01-24 17:50:52 +11:00
|
|
|
if (newToken?.id) {
|
|
|
|
|
await putToken(newToken);
|
2021-02-07 14:47:34 +11:00
|
|
|
requestingAssetsRef.current.delete(newToken.id);
|
2021-01-24 17:50:52 +11:00
|
|
|
}
|
2021-01-20 18:08:03 +11:00
|
|
|
assetLoadFinish();
|
2020-07-16 17:27:39 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handlePeerDataProgress({ id, total, count }) {
|
|
|
|
|
if (count === 1) {
|
2021-01-20 19:20:38 +11:00
|
|
|
// Corresponding asset load finished called in token and map response
|
2020-07-16 17:27:39 +10:00
|
|
|
assetLoadStart();
|
|
|
|
|
}
|
|
|
|
|
assetProgressUpdate({ id, total, count });
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-01 13:56:12 +11:00
|
|
|
async function handleSocketMap(map) {
|
2020-12-11 13:24:39 +11:00
|
|
|
if (map) {
|
2021-01-22 14:59:05 +11:00
|
|
|
if (map.type === "file") {
|
2021-01-01 13:56:12 +11:00
|
|
|
const fullMap = await getMapFromDB(map.id);
|
2021-01-22 14:59:05 +11:00
|
|
|
setCurrentMap(fullMap || map);
|
2021-01-01 13:56:12 +11:00
|
|
|
} else {
|
|
|
|
|
setCurrentMap(map);
|
|
|
|
|
}
|
2020-12-11 13:24:39 +11:00
|
|
|
} else {
|
|
|
|
|
setCurrentMap(null);
|
|
|
|
|
}
|
2020-12-05 17:16:06 +11:00
|
|
|
}
|
2021-01-01 13:56:12 +11:00
|
|
|
|
2020-12-12 16:08:10 +11:00
|
|
|
session.on("peerData", handlePeerData);
|
|
|
|
|
session.on("peerDataProgress", handlePeerDataProgress);
|
2021-01-01 12:44:56 +11:00
|
|
|
session.socket?.on("map", handleSocketMap);
|
2020-07-16 17:27:39 +10:00
|
|
|
|
|
|
|
|
return () => {
|
2020-12-12 16:08:10 +11:00
|
|
|
session.off("peerData", handlePeerData);
|
|
|
|
|
session.off("peerDataProgress", handlePeerDataProgress);
|
2021-01-01 12:44:56 +11:00
|
|
|
session.socket?.off("map", handleSocketMap);
|
2020-07-16 17:27:39 +10:00
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
2020-07-17 15:57:52 +10:00
|
|
|
const canChangeMap = !isLoading;
|
|
|
|
|
|
2020-07-16 17:27:39 +10:00
|
|
|
const canEditMapDrawing =
|
2021-01-22 14:59:05 +11:00
|
|
|
currentMap &&
|
|
|
|
|
currentMapState &&
|
2020-07-16 17:27:39 +10:00
|
|
|
(currentMapState.editFlags.includes("drawing") ||
|
|
|
|
|
currentMap.owner === userId);
|
|
|
|
|
|
|
|
|
|
const canEditFogDrawing =
|
2021-01-22 14:59:05 +11:00
|
|
|
currentMap &&
|
|
|
|
|
currentMapState &&
|
2020-07-16 17:27:39 +10:00
|
|
|
(currentMapState.editFlags.includes("fog") || currentMap.owner === userId);
|
|
|
|
|
|
2020-11-05 16:21:52 +11:00
|
|
|
const canEditNotes =
|
2021-01-22 14:59:05 +11:00
|
|
|
currentMap &&
|
|
|
|
|
currentMapState &&
|
2020-11-05 16:21:52 +11:00
|
|
|
(currentMapState.editFlags.includes("notes") ||
|
|
|
|
|
currentMap.owner === userId);
|
|
|
|
|
|
2020-07-16 17:27:39 +10:00
|
|
|
const disabledMapTokens = {};
|
|
|
|
|
// If we have a map and state and have the token permission disabled
|
|
|
|
|
// and are not the map owner
|
|
|
|
|
if (
|
2021-01-22 14:59:05 +11:00
|
|
|
currentMapState &&
|
|
|
|
|
currentMap &&
|
2020-07-16 17:27:39 +10:00
|
|
|
!currentMapState.editFlags.includes("tokens") &&
|
|
|
|
|
currentMap.owner !== userId
|
|
|
|
|
) {
|
|
|
|
|
for (let token of Object.values(currentMapState.tokens)) {
|
|
|
|
|
if (token.owner !== userId) {
|
|
|
|
|
disabledMapTokens[token.id] = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<Map
|
|
|
|
|
map={currentMap}
|
|
|
|
|
mapState={currentMapState}
|
2021-02-04 09:11:27 +11:00
|
|
|
mapActions={mapActions}
|
2020-07-16 17:27:39 +10:00
|
|
|
onMapTokenStateChange={handleMapTokenStateChange}
|
|
|
|
|
onMapTokenStateRemove={handleMapTokenStateRemove}
|
|
|
|
|
onMapChange={handleMapChange}
|
2021-02-22 17:14:12 +11:00
|
|
|
onMapReset={handleMapReset}
|
2020-07-16 17:27:39 +10:00
|
|
|
onMapDraw={handleMapDraw}
|
|
|
|
|
onMapDrawUndo={handleMapDrawUndo}
|
|
|
|
|
onMapDrawRedo={handleMapDrawRedo}
|
|
|
|
|
onFogDraw={handleFogDraw}
|
|
|
|
|
onFogDrawUndo={handleFogDrawUndo}
|
|
|
|
|
onFogDrawRedo={handleFogDrawRedo}
|
2020-11-04 15:03:34 +11:00
|
|
|
onMapNoteChange={handleNoteChange}
|
2020-11-05 14:41:33 +11:00
|
|
|
onMapNoteRemove={handleNoteRemove}
|
2020-07-16 17:27:39 +10:00
|
|
|
allowMapDrawing={canEditMapDrawing}
|
|
|
|
|
allowFogDrawing={canEditFogDrawing}
|
2020-07-17 15:57:52 +10:00
|
|
|
allowMapChange={canChangeMap}
|
2020-11-05 16:21:52 +11:00
|
|
|
allowNoteEditing={canEditNotes}
|
2020-07-16 17:27:39 +10:00
|
|
|
disabledTokens={disabledMapTokens}
|
2020-07-28 17:59:26 +10:00
|
|
|
session={session}
|
2020-07-16 17:27:39 +10:00
|
|
|
/>
|
|
|
|
|
<Tokens onMapTokenStateCreate={handleMapTokenStateCreate} />
|
|
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default NetworkedMapAndTokens;
|