diff --git a/src/components/map/MapToken.js b/src/components/map/MapToken.js
index e866c89..ccb2770 100644
--- a/src/components/map/MapToken.js
+++ b/src/components/map/MapToken.js
@@ -24,7 +24,6 @@ import TokenLabel from "../token/TokenLabel";
import { tokenSources, unknownSource } from "../../tokens";
function MapToken({
- token,
tokenState,
onTokenStateChange,
onTokenMenuOpen,
@@ -43,7 +42,7 @@ function MapToken({
const gridCellPixelSize = useGridCellPixelSize();
- const tokenSource = useDataURL(token, tokenSources, unknownSource);
+ const tokenSource = useDataURL(tokenState, tokenSources, unknownSource);
const [tokenSourceImage, tokenSourceStatus] = useImage(tokenSource);
const [tokenAspectRatio, setTokenAspectRatio] = useState(1);
@@ -59,7 +58,7 @@ function MapToken({
const tokenGroup = event.target;
const tokenImage = imageRef.current;
- if (token && token.category === "vehicle") {
+ if (tokenState.category === "vehicle") {
// Enable hit detection for .intersects() function
Konva.hitOnDragEnabled = true;
@@ -99,7 +98,7 @@ function MapToken({
const tokenGroup = event.target;
const mountChanges = {};
- if (token && token.category === "vehicle") {
+ if (tokenState.category === "vehicle") {
Konva.hitOnDragEnabled = false;
const parent = tokenGroup.getParent();
@@ -196,8 +195,16 @@ function MapToken({
const canvas = image.getCanvas();
const pixelRatio = canvas.pixelRatio || 1;
- if (tokenSourceStatus === "loaded" && tokenWidth > 0 && tokenHeight > 0) {
- const maxImageSize = token ? Math.max(token.width, token.height) : 512; // Default to 512px
+ if (
+ tokenSourceStatus === "loaded" &&
+ tokenWidth > 0 &&
+ tokenHeight > 0 &&
+ tokenSourceImage
+ ) {
+ const maxImageSize = Math.max(
+ tokenSourceImage.width,
+ tokenSourceImage.height
+ );
const maxTokenSize = Math.max(tokenWidth, tokenHeight);
// Constrain image buffer to original image size
const maxRatio = maxImageSize / maxTokenSize;
@@ -210,7 +217,13 @@ function MapToken({
});
image.drawHitFromCache();
}
- }, [debouncedStageScale, tokenWidth, tokenHeight, tokenSourceStatus, token]);
+ }, [
+ debouncedStageScale,
+ tokenWidth,
+ tokenHeight,
+ tokenSourceStatus,
+ tokenSourceImage,
+ ]);
// Animate to new token positions if edited by others
const tokenX = tokenState.x * mapWidth;
@@ -232,8 +245,8 @@ function MapToken({
// Token name is used by on click to find whether a token is a vehicle or prop
let tokenName = "";
- if (token) {
- tokenName = token.category;
+ if (tokenState) {
+ tokenName = tokenState.category;
}
if (tokenState && tokenState.locked) {
tokenName = tokenName + "-locked";
diff --git a/src/components/map/MapTokens.js b/src/components/map/MapTokens.js
index 426dcfe..957d038 100644
--- a/src/components/map/MapTokens.js
+++ b/src/components/map/MapTokens.js
@@ -1,10 +1,8 @@
-import React, { useEffect } from "react";
+import React from "react";
import { Group } from "react-konva";
import MapToken from "./MapToken";
-import { useTokenData } from "../../contexts/TokenDataContext";
-
function MapTokens({
map,
mapState,
@@ -15,31 +13,6 @@ function MapTokens({
selectedToolId,
disabledTokens,
}) {
- const { tokensById, loadTokens } = useTokenData();
-
- // Ensure tokens files have been loaded into the token data
- useEffect(() => {
- async function loadFileTokens() {
- const tokenIds = new Set(
- Object.values(mapState.tokens).map((state) => state.tokenId)
- );
- const tokensToLoad = [];
- for (let tokenId of tokenIds) {
- const token = tokensById[tokenId];
- if (token && token.type === "file" && !token.file) {
- tokensToLoad.push(tokenId);
- }
- }
- if (tokensToLoad.length > 0) {
- await loadTokens(tokensToLoad);
- }
- }
-
- if (mapState) {
- loadFileTokens();
- }
- }, [mapState, tokensById, loadTokens]);
-
function getMapTokenCategoryWeight(category) {
switch (category) {
case "character":
@@ -55,38 +28,28 @@ function MapTokens({
// Sort so vehicles render below other tokens
function sortMapTokenStates(a, b, tokenDraggingOptions) {
- const tokenA = tokensById[a.tokenId];
- const tokenB = tokensById[b.tokenId];
- if (tokenA && tokenB) {
- // If categories are different sort in order "prop", "vehicle", "character"
- if (tokenB.category !== tokenA.category) {
- const aWeight = getMapTokenCategoryWeight(tokenA.category);
- const bWeight = getMapTokenCategoryWeight(tokenB.category);
- return bWeight - aWeight;
- } else if (
- tokenDraggingOptions &&
- tokenDraggingOptions.dragging &&
- tokenDraggingOptions.tokenState.id === a.id
- ) {
- // If dragging token a move above
- return 1;
- } else if (
- tokenDraggingOptions &&
- tokenDraggingOptions.dragging &&
- tokenDraggingOptions.tokenState.id === b.id
- ) {
- // If dragging token b move above
- return -1;
- } else {
- // Else sort so last modified is on top
- return a.lastModified - b.lastModified;
- }
- } else if (tokenA) {
+ // If categories are different sort in order "prop", "vehicle", "character"
+ if (b.category !== a.category) {
+ const aWeight = getMapTokenCategoryWeight(a.category);
+ const bWeight = getMapTokenCategoryWeight(b.category);
+ return bWeight - aWeight;
+ } else if (
+ tokenDraggingOptions &&
+ tokenDraggingOptions.dragging &&
+ tokenDraggingOptions.tokenState.id === a.id
+ ) {
+ // If dragging token a move above
return 1;
- } else if (tokenB) {
+ } else if (
+ tokenDraggingOptions &&
+ tokenDraggingOptions.dragging &&
+ tokenDraggingOptions.tokenState.id === b.id
+ ) {
+ // If dragging token b move above
return -1;
} else {
- return 0;
+ // Else sort so last modified is on top
+ return a.lastModified - b.lastModified;
}
}
@@ -97,7 +60,6 @@ function MapTokens({
.map((tokenState) => (
-
+
diff --git a/src/components/token/Tokens.js b/src/components/token/Tokens.js
index c56feec..f4bf43c 100644
--- a/src/components/token/Tokens.js
+++ b/src/components/token/Tokens.js
@@ -25,12 +25,13 @@ function Tokens({ onMapTokenStateCreate }) {
function handleProxyDragEnd(isOnMap, token) {
if (isOnMap && onMapTokenStateCreate) {
// Create a token state from the dragged token
- onMapTokenStateCreate({
+ let tokenState = {
id: shortid.generate(),
tokenId: token.id,
owner: userId,
size: token.defaultSize,
- label: "",
+ category: token.defaultCategory,
+ label: token.defaultLabel,
statuses: [],
x: token.x,
y: token.y,
@@ -39,7 +40,15 @@ function Tokens({ onMapTokenStateCreate }) {
rotation: 0,
locked: false,
visible: true,
- });
+ type: token.type,
+ };
+ if (token.type === "file") {
+ tokenState.file = token.file;
+ } else if (token.type === "default") {
+ tokenState.key = token.key;
+ }
+ onMapTokenStateCreate(tokenState);
+ // TODO: Remove when cache is moved to assets
// Update last used for cache invalidation
// Keep last modified the same
updateToken(token.id, {
diff --git a/src/contexts/AssetsContext.js b/src/contexts/AssetsContext.js
index 98bbb2d..8e2c2da 100644
--- a/src/contexts/AssetsContext.js
+++ b/src/contexts/AssetsContext.js
@@ -12,6 +12,7 @@ import { omit } from "../helpers/shared";
* @property {number} height
* @property {Uint8Array} file
* @property {string} mime
+ * @property {string} owner
*/
/**
@@ -25,10 +26,16 @@ import { omit } from "../helpers/shared";
* @param {Asset[]} assets
*/
+/**
+ * @callback putAsset
+ * @param {Asset} asset
+ */
+
/**
* @typedef AssetsContext
* @property {getAsset} getAsset
* @property {addAssets} addAssets
+ * @property {putAsset} putAsset
*/
/**
@@ -54,9 +61,17 @@ export function AssetsProvider({ children }) {
[database]
);
+ const putAsset = useCallback(
+ async (asset) => {
+ return database.table("assets").put(asset);
+ },
+ [database]
+ );
+
const value = {
getAsset,
addAssets,
+ putAsset,
};
return (
diff --git a/src/contexts/TokenDataContext.js b/src/contexts/TokenDataContext.js
index 329a509..345e0f0 100644
--- a/src/contexts/TokenDataContext.js
+++ b/src/contexts/TokenDataContext.js
@@ -20,10 +20,6 @@ export function TokenDataProvider({ children }) {
const { database, databaseStatus, worker } = useDatabase();
const { userId } = useAuth();
- /**
- * Contains all tokens without any file data,
- * to ensure file data is present call loadTokens
- */
const [tokens, setTokens] = useState([]);
const [tokensLoading, setTokensLoading] = useState(true);
@@ -44,7 +40,6 @@ export function TokenDataProvider({ children }) {
return defaultTokensWithIds;
}
- // Loads tokens without the file data to save memory
async function loadTokens() {
let storedTokens = [];
// Try to load tokens with worker, fallback to database if failed
@@ -156,35 +151,6 @@ export function TokenDataProvider({ children }) {
[database, updateCache, userId]
);
- const loadTokens = useCallback(
- async (tokenIds) => {
- const loadedTokens = await database.table("tokens").bulkGet(tokenIds);
- const loadedTokensById = loadedTokens.reduce((obj, token) => {
- obj[token.id] = token;
- return obj;
- }, {});
- setTokens((prevTokens) => {
- return prevTokens.map((prevToken) => {
- if (prevToken.id in loadedTokensById) {
- return loadedTokensById[prevToken.id];
- } else {
- return prevToken;
- }
- });
- });
- },
- [database]
- );
-
- const unloadTokens = useCallback(async () => {
- setTokens((prevTokens) => {
- return prevTokens.map((prevToken) => {
- const { file, ...rest } = prevToken;
- return rest;
- });
- });
- }, []);
-
// Create DB observable to sync creating and deleting
useEffect(() => {
if (!database || databaseStatus === "loading") {
@@ -248,8 +214,6 @@ export function TokenDataProvider({ children }) {
tokensById,
tokensLoading,
getTokenFromDB,
- loadTokens,
- unloadTokens,
};
return (
diff --git a/src/database.js b/src/database.js
index af20c1d..ccdd261 100644
--- a/src/database.js
+++ b/src/database.js
@@ -3,6 +3,7 @@ import Dexie, { Version, DexieOptions } from "dexie";
import "dexie-observable";
import shortid from "shortid";
import { v4 as uuid } from "uuid";
+import Case from "case";
import blobToBuffer from "./helpers/blobToBuffer";
import { getGridDefaultInset } from "./helpers/grid";
@@ -434,7 +435,7 @@ const versions = {
},
// v1.9.0 - Move map assets into new table
23(v) {
- v.stores({ assets: "id" }).upgrade((tx) => {
+ v.stores({ assets: "id, owner" }).upgrade((tx) => {
tx.table("maps").each((map) => {
let assets = [];
assets.push({
@@ -558,9 +559,46 @@ const versions = {
});
});
},
+ 28(v) {
+ v.stores().upgrade((tx) => {
+ tx.table("tokens")
+ .toCollection()
+ .modify((token) => {
+ token.defaultCategory = token.category;
+ delete token.category;
+ token.defaultLabel = "";
+ });
+ });
+ },
+ 29(v) {
+ v.stores().upgrade((tx) => {
+ tx.table("states")
+ .toCollection()
+ .modify(async (state) => {
+ for (let tokenState of Object.values(state.tokens)) {
+ if (!tokenState.tokenId.startsWith("__default")) {
+ const token = await tx.table("tokens").get(tokenState.tokenId);
+ if (token) {
+ tokenState.category = token.defaultCategory;
+ tokenState.file = token.file;
+ tokenState.type = "file";
+ } else {
+ tokenState.category = "character";
+ tokenState.type = "file";
+ tokenState.file = "";
+ }
+ } else {
+ tokenState.category = "character";
+ tokenState.type = "default";
+ tokenState.key = Case.camel(tokenState.tokenId.slice(10));
+ }
+ }
+ });
+ });
+ },
};
-const latestVersion = 27;
+const latestVersion = 29;
/**
* Load versions onto a database up to a specific version number
diff --git a/src/helpers/image.js b/src/helpers/image.js
index fb33712..00f012c 100644
--- a/src/helpers/image.js
+++ b/src/helpers/image.js
@@ -1,5 +1,3 @@
-import { v4 as uuid } from "uuid";
-
import blobToBuffer from "./blobToBuffer";
const lightnessDetectionOffset = 0.1;
@@ -90,8 +88,7 @@ export async function resizeImage(image, size, type, quality) {
}
/**
- * @typedef Asset
- * @property {string} id
+ * @typedef ImageAsset
* @property {number} width
* @property {number} height
* @property {Uint8Array} file
@@ -104,7 +101,7 @@ export async function resizeImage(image, size, type, quality) {
* @param {string} type the mime type of the image
* @param {number} size the width and height of the thumbnail
* @param {number} quality if image is a jpeg or webp this is the quality setting
- * @returns {Promise}
+ * @returns {Promise}
*/
export async function createThumbnail(image, type, size = 300, quality = 0.5) {
let canvas = document.createElement("canvas");
@@ -153,6 +150,5 @@ export async function createThumbnail(image, type, size = 300, quality = 0.5) {
width: thumbnailImage.width,
height: thumbnailImage.height,
mime: type,
- id: uuid(),
};
}
diff --git a/src/helpers/map.js b/src/helpers/map.js
new file mode 100644
index 0000000..b41e029
--- /dev/null
+++ b/src/helpers/map.js
@@ -0,0 +1,27 @@
+/**
+ * Get the asset id of the preview file to send for a map
+ * @param {any} map
+ * @returns {undefined|string}
+ */
+export function getMapPreviewAsset(map) {
+ const res = map.resolutions;
+ switch (map.quality) {
+ case "low":
+ return;
+ case "medium":
+ return res.low;
+ case "high":
+ return res.medium;
+ case "ultra":
+ return res.medium;
+ case "original":
+ if (res.medium) {
+ return res.medium;
+ } else if (res.low) {
+ return res.low;
+ }
+ return;
+ default:
+ return;
+ }
+}
diff --git a/src/modals/SelectMapModal.js b/src/modals/SelectMapModal.js
index f759ac3..a94a1b3 100644
--- a/src/modals/SelectMapModal.js
+++ b/src/modals/SelectMapModal.js
@@ -252,13 +252,15 @@ function SelectMapModal({
height: resized.height,
id: assetId,
mime: file.type,
+ owner: userId,
};
assets.push(asset);
}
}
}
// Create thumbnail
- const thumbnail = await createThumbnail(image, file.type);
+ const thumbnailImage = await createThumbnail(image, file.type);
+ const thumbnail = { ...thumbnailImage, id: uuid(), owner: userId };
assets.push(thumbnail);
const fileAsset = {
@@ -267,6 +269,7 @@ function SelectMapModal({
width: image.width,
height: image.height,
mime: file.type,
+ owner: userId,
};
assets.push(fileAsset);
diff --git a/src/modals/SelectTokensModal.js b/src/modals/SelectTokensModal.js
index 6f04bb9..49e5ccd 100644
--- a/src/modals/SelectTokensModal.js
+++ b/src/modals/SelectTokensModal.js
@@ -163,7 +163,8 @@ function SelectTokensModal({ isOpen, onRequestClose }) {
return new Promise((resolve, reject) => {
image.onload = async function () {
let assets = [];
- const thumbnail = await createThumbnail(image, file.type);
+ const thumbnailImage = await createThumbnail(image, file.type);
+ const thumbnail = { ...thumbnailImage, id: uuid(), owner: userId };
assets.push(thumbnail);
const fileAsset = {
@@ -172,6 +173,7 @@ function SelectTokensModal({ isOpen, onRequestClose }) {
width: image.width,
height: image.height,
mime: file.type,
+ owner: userId,
};
assets.push(fileAsset);
@@ -186,7 +188,8 @@ function SelectTokensModal({ isOpen, onRequestClose }) {
lastUsed: Date.now(),
owner: userId,
defaultSize: 1,
- category: "character",
+ defaultCategory: "character",
+ defaultLabel: "",
hideInSidebar: false,
group: "",
width: image.width,
diff --git a/src/network/NetworkedMapAndTokens.js b/src/network/NetworkedMapAndTokens.js
index d38413a..f0b726f 100644
--- a/src/network/NetworkedMapAndTokens.js
+++ b/src/network/NetworkedMapAndTokens.js
@@ -1,14 +1,15 @@
import React, { useState, useEffect, useRef } from "react";
import { useToasts } from "react-toast-notifications";
-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";
+import { useAssets } from "../contexts/AssetsContext";
import { omit } from "../helpers/shared";
+import { getMapPreviewAsset } from "../helpers/map";
import useDebounce from "../hooks/useDebounce";
import useNetworkedState from "../hooks/useNetworkedState";
@@ -46,8 +47,8 @@ function NetworkedMapAndTokens({ session }) {
isLoading,
} = useMapLoading();
- const { putToken, getTokenFromDB } = useTokenData();
- const { putMap, updateMap, getMapFromDB, updateMapState } = useMapData();
+ const { updateMapState } = useMapData();
+ const { getAsset, putAsset } = useAssets();
const [currentMap, setCurrentMap] = useState(null);
const [currentMapState, setCurrentMapState] = useNetworkedState(
@@ -69,48 +70,39 @@ function NetworkedMapAndTokens({ session }) {
async function loadAssetManifestFromMap(map, mapState) {
const assets = {};
+ const { owner } = map;
if (map.type === "file") {
- const { id, lastModified, owner } = map;
- assets[`map-${id}`] = { type: "map", id, lastModified, owner };
+ const previewId = getMapPreviewAsset(map);
+ if (previewId) {
+ assets[previewId] = { id: previewId, owner };
+ }
+ const qualityId = map.resolutions[map.quality];
+ if (qualityId) {
+ assets[qualityId] = { id: qualityId, owner };
+ } else {
+ assets[map.file] = { id: map.file, owner };
+ }
}
let processedTokens = new Set();
for (let tokenState of Object.values(mapState.tokens)) {
- const token = await getTokenFromDB(tokenState.tokenId);
if (
- token &&
- token.type === "file" &&
- !processedTokens.has(tokenState.tokenId)
+ tokenState.file &&
+ !processedTokens.has(tokenState.file) &&
+ tokenState.owner === owner
) {
- processedTokens.add(tokenState.tokenId);
- // Omit file from token peer will request file if needed
- const { id, lastModified, owner } = token;
- assets[`token-${id}`] = { type: "token", id, lastModified, owner };
+ processedTokens.add(tokenState.file);
+ assets[tokenState.file] = { id: tokenState.file, owner };
}
}
setAssetManifest({ mapId: map.id, assets }, true, true);
}
- 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) &&
- oldAsset.lastModified < newAsset.lastModified
- );
- }
-
function addAssetIfNeeded(asset) {
setAssetManifest((prevManifest) => {
if (prevManifest?.assets) {
- const id =
- asset.type === "map" ? `map-${asset.id}` : `token-${asset.id}`;
+ const id = asset.id;
const exists = id in prevManifest.assets;
- const needsUpdate =
- exists && assetNeedsUpdate(prevManifest.assets[id], asset);
- if (!exists || needsUpdate) {
+ if (!exists) {
return {
...prevManifest,
assets: {
@@ -145,48 +137,28 @@ function NetworkedMapAndTokens({ session }) {
(player) => player.userId === asset.owner
);
+ const cachedAsset = await getAsset(asset.id);
if (!owner) {
- // Add no owner toast if asset is a map and we don't have it in out cache
- if (asset.type === "map") {
- const cachedMap = await getMapFromDB(asset.id);
- if (!cachedMap) {
- addToast("Unable to find owner for map");
- }
+ // Add no owner toast if we don't have asset in out cache
+ if (!cachedAsset) {
+ // TODO: Stop toast from appearing multiple times
+ addToast("Unable to find owner for asset");
}
continue;
}
requestingAssetsRef.current.add(asset.id);
- if (asset.type === "map") {
- const cachedMap = await getMapFromDB(asset.id);
- if (cachedMap && cachedMap.lastModified === asset.lastModified) {
- requestingAssetsRef.current.delete(asset.id);
- } else {
- session.sendTo(owner.sessionId, "mapRequest", asset.id);
- }
- } else if (asset.type === "token") {
- const cachedToken = await getTokenFromDB(asset.id);
- if (cachedToken && cachedToken.lastModified === asset.lastModified) {
- requestingAssetsRef.current.delete(asset.id);
- } else {
- session.sendTo(owner.sessionId, "tokenRequest", asset.id);
- }
+ if (cachedAsset) {
+ requestingAssetsRef.current.delete(asset.id);
+ } else {
+ session.sendTo(owner.sessionId, "assetRequest", asset.id);
}
}
}
requestAssetsIfNeeded();
- }, [
- assetManifest,
- partyState,
- session,
- getMapFromDB,
- getTokenFromDB,
- updateMap,
- userId,
- addToast,
- ]);
+ }, [assetManifest, partyState, session, userId, addToast, getAsset]);
/**
* Map state
@@ -215,12 +187,8 @@ function NetworkedMapAndTokens({ session }) {
setCurrentMapState(newMapState, true, true);
setCurrentMap(newMap);
- if (newMap && newMap.type === "file") {
- const { file, resolutions, thumbnail, ...rest } = newMap;
- session.socket?.emit("map", rest);
- } else {
- session.socket?.emit("map", newMap);
- }
+ session.socket?.emit("map", newMap);
+
if (!newMap || !newMapState) {
setAssetManifest(null, true, true);
return;
@@ -371,11 +339,8 @@ function NetworkedMapAndTokens({ session }) {
if (!currentMap || !currentMapState) {
return;
}
- // If file type token send the token to the other peers
- const token = await getTokenFromDB(tokenState.tokenId);
- if (token && token.type === "file") {
- const { id, lastModified, owner } = token;
- addAssetIfNeeded({ type: "token", id, lastModified, owner });
+ if (tokenState.file) {
+ addAssetIfNeeded({ id: tokenState.file, owner: tokenState.owner });
}
setCurrentMapState((prevMapState) => ({
...prevMapState,
@@ -414,101 +379,21 @@ function NetworkedMapAndTokens({ session }) {
useEffect(() => {
async function handlePeerData({ id, data, reply }) {
- if (id === "mapRequest") {
- const map = await getMapFromDB(data);
- function replyWithMap(preview, resolution) {
- let response = {
- ...map,
- resolutions: undefined,
- file: undefined,
- thumbnail: undefined,
- // 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
- if (map.resolutions[preview]) {
- response.resolutions = { [preview]: map.resolutions[preview] };
- reply("mapResponse", response, "map");
- }
- // Send full map at the desired resolution if available
- if (map.resolutions[resolution]) {
- response.file = map.resolutions[resolution].file;
- } else if (map.file) {
- // The resolution might not exist for other users so send the file instead
- response.file = map.file;
- } else {
- return;
- }
- // Add last modified back to file to set cache as valid
- response.lastModified = map.lastModified;
- reply("mapResponse", response, "map");
- }
-
- switch (map.quality) {
- case "low":
- replyWithMap(undefined, "low");
- break;
- case "medium":
- replyWithMap("low", "medium");
- break;
- case "high":
- replyWithMap("medium", "high");
- break;
- case "ultra":
- replyWithMap("medium", "ultra");
- break;
- case "original":
- if (map.resolutions) {
- if (map.resolutions.medium) {
- replyWithMap("medium");
- } else if (map.resolutions.low) {
- replyWithMap("low");
- } else {
- replyWithMap();
- }
- } else {
- replyWithMap();
- }
- break;
- default:
- replyWithMap();
- }
+ if (id === "assetRequest") {
+ const asset = await getAsset(data);
+ reply("assetResponse", asset);
}
- if (id === "mapResponse") {
- const newMap = data;
- if (newMap?.id) {
- setCurrentMap(newMap);
- await putMap(newMap);
- // If we have the final map resolution
- if (newMap.lastModified > 0) {
- requestingAssetsRef.current.delete(newMap.id);
- }
- }
- assetLoadFinish();
- }
-
- if (id === "tokenRequest") {
- const token = await getTokenFromDB(data);
- // Add a last used property for cache invalidation
- reply("tokenResponse", { ...token, lastUsed: Date.now() }, "token");
- }
- if (id === "tokenResponse") {
- const newToken = data;
- if (newToken?.id) {
- await putToken(newToken);
- requestingAssetsRef.current.delete(newToken.id);
- }
+ if (id === "assetResponse") {
+ await putAsset(data);
+ requestingAssetsRef.current.delete(data.id);
assetLoadFinish();
}
}
function handlePeerDataProgress({ id, total, count }) {
if (count === 1) {
- // Corresponding asset load finished called in token and map response
+ // Corresponding asset load finished called in asset response
assetLoadStart();
}
assetProgressUpdate({ id, total, count });
@@ -516,12 +401,7 @@ function NetworkedMapAndTokens({ session }) {
async function handleSocketMap(map) {
if (map) {
- if (map.type === "file") {
- const fullMap = await getMapFromDB(map.id);
- setCurrentMap(fullMap || map);
- } else {
- setCurrentMap(map);
- }
+ setCurrentMap(map);
} else {
setCurrentMap(null);
}
diff --git a/src/tokens/index.js b/src/tokens/index.js
index 5a16e82..4f6c0f8 100644
--- a/src/tokens/index.js
+++ b/src/tokens/index.js
@@ -85,7 +85,8 @@ export const tokens = Object.keys(tokenSources).map((key) => ({
name: Case.capital(key),
type: "default",
defaultSize: getDefaultTokenSize(key),
- category: "character",
+ defaultLabel: "",
+ defaultCategory: "character",
hideInSidebar: false,
width: 256,
height: 256,