Separated dice loading and dice instance creation and added loading spinner for dice
This commit is contained in:
parent
da84f923d1
commit
7f0b4e32af
@ -4,6 +4,8 @@ import { Flex, IconButton } from "theme-ui";
|
||||
import ExpandMoreDiceIcon from "../../icons/ExpandMoreDiceIcon";
|
||||
import DiceTrayOverlay from "./dice/DiceTrayOverlay";
|
||||
|
||||
import { DiceLoadingProvider } from "../../contexts/DiceLoadingContext";
|
||||
|
||||
function MapDice() {
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
|
||||
@ -32,7 +34,9 @@ function MapDice() {
|
||||
>
|
||||
<ExpandMoreDiceIcon isExpanded={isExpanded} />
|
||||
</IconButton>
|
||||
<DiceTrayOverlay isOpen={isExpanded} />
|
||||
<DiceLoadingProvider>
|
||||
<DiceTrayOverlay isOpen={isExpanded} />
|
||||
</DiceLoadingProvider>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Flex, IconButton } from "theme-ui";
|
||||
|
||||
import D20Icon from "../../../icons/D20Icon";
|
||||
@ -20,10 +20,18 @@ import { dice } from "../../../dice";
|
||||
function DiceButtons({
|
||||
diceRolls,
|
||||
onDiceAdd,
|
||||
onDiceLoad,
|
||||
diceTraySize,
|
||||
onDiceTraySizeChange,
|
||||
}) {
|
||||
const [currentDice, setCurrentDice] = useState(dice[0]);
|
||||
const [currentDice, setCurrentDice] = useState();
|
||||
|
||||
useEffect(() => {
|
||||
const initialDice = dice[0];
|
||||
onDiceLoad(initialDice);
|
||||
setCurrentDice(initialDice);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const diceCounts = {};
|
||||
for (let dice of diceRolls) {
|
||||
@ -34,6 +42,11 @@ function DiceButtons({
|
||||
}
|
||||
}
|
||||
|
||||
async function handleDiceChange(dice) {
|
||||
await onDiceLoad(dice);
|
||||
setCurrentDice(dice);
|
||||
}
|
||||
|
||||
return (
|
||||
<Flex
|
||||
sx={{
|
||||
@ -44,7 +57,7 @@ function DiceButtons({
|
||||
}}
|
||||
>
|
||||
<SelectDiceButton
|
||||
onDiceChange={setCurrentDice}
|
||||
onDiceChange={handleDiceChange}
|
||||
currentDice={currentDice}
|
||||
/>
|
||||
<Divider vertical color="hsl(210, 50%, 96%)" />
|
||||
|
@ -10,6 +10,7 @@ function DiceControls({
|
||||
onDiceAdd,
|
||||
onDiceClear,
|
||||
onDiceReroll,
|
||||
onDiceLoad,
|
||||
diceTraySize,
|
||||
onDiceTraySizeChange,
|
||||
}) {
|
||||
@ -116,6 +117,7 @@ function DiceControls({
|
||||
{ type, roll: "unknown" },
|
||||
]);
|
||||
}}
|
||||
onDiceLoad={onDiceLoad}
|
||||
onDiceTraySizeChange={onDiceTraySizeChange}
|
||||
diceTraySize={diceTraySize}
|
||||
/>
|
||||
|
@ -13,10 +13,12 @@ import environment from "../../../dice/environment.dds";
|
||||
import Scene from "./DiceScene";
|
||||
import DiceControls from "./DiceControls";
|
||||
import Dice from "../../../dice/Dice";
|
||||
import LoadingOverlay from "../../LoadingOverlay";
|
||||
|
||||
import DiceTray from "../../../dice/diceTray/DiceTray";
|
||||
|
||||
import MapInteractionContext from "../../../contexts/MapInteractionContext";
|
||||
import DiceLoadingContext from "../../../contexts/DiceLoadingContext";
|
||||
|
||||
function DiceTrayOverlay({ isOpen }) {
|
||||
const sceneRef = useRef();
|
||||
@ -29,6 +31,10 @@ function DiceTrayOverlay({ isOpen }) {
|
||||
const diceTrayRef = useRef();
|
||||
|
||||
const [diceTraySize, setDiceTraySize] = useState("single");
|
||||
const { assetLoadStart, assetLoadFinish, isLoading } = useContext(
|
||||
DiceLoadingContext
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const diceTray = diceTrayRef.current;
|
||||
let resizeTimout;
|
||||
@ -70,9 +76,11 @@ function DiceTrayOverlay({ isOpen }) {
|
||||
sceneRef.current = scene;
|
||||
initializeScene(scene);
|
||||
engine.runRenderLoop(() => update(scene));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
async function initializeScene(scene) {
|
||||
assetLoadStart();
|
||||
let light = new BABYLON.DirectionalLight(
|
||||
"DirectionalLight",
|
||||
new BABYLON.Vector3(-0.5, -1, -0.5),
|
||||
@ -95,6 +103,7 @@ function DiceTrayOverlay({ isOpen }) {
|
||||
let diceTray = new DiceTray("single", scene, shadowGenerator);
|
||||
await diceTray.load();
|
||||
diceTrayRef.current = diceTray;
|
||||
assetLoadFinish();
|
||||
}
|
||||
|
||||
function update(scene) {
|
||||
@ -194,6 +203,15 @@ function DiceTrayOverlay({ isOpen }) {
|
||||
}
|
||||
}
|
||||
|
||||
async function handleDiceLoad(dice) {
|
||||
assetLoadStart();
|
||||
const scene = sceneRef.current;
|
||||
if (scene) {
|
||||
await dice.class.load(scene);
|
||||
}
|
||||
assetLoadFinish();
|
||||
}
|
||||
|
||||
const { setPreventMapInteraction } = useContext(MapInteractionContext);
|
||||
|
||||
return (
|
||||
@ -229,9 +247,11 @@ function DiceTrayOverlay({ isOpen }) {
|
||||
onDiceAdd={handleDiceAdd}
|
||||
onDiceClear={handleDiceClear}
|
||||
onDiceReroll={handleDiceReroll}
|
||||
onDiceLoad={handleDiceLoad}
|
||||
diceTraySize={diceTraySize}
|
||||
onDiceTraySizeChange={setDiceTraySize}
|
||||
/>
|
||||
{isLoading && <LoadingOverlay />}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
31
src/contexts/DiceLoadingContext.js
Normal file
31
src/contexts/DiceLoadingContext.js
Normal file
@ -0,0 +1,31 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
const DiceLoadingContext = React.createContext();
|
||||
|
||||
export function DiceLoadingProvider({ children }) {
|
||||
const [loadingAssetCount, setLoadingAssetCount] = useState(0);
|
||||
|
||||
function assetLoadStart() {
|
||||
setLoadingAssetCount((prevLoadingAssets) => prevLoadingAssets + 1);
|
||||
}
|
||||
|
||||
function assetLoadFinish() {
|
||||
setLoadingAssetCount((prevLoadingAssets) => prevLoadingAssets - 1);
|
||||
}
|
||||
|
||||
const isLoading = loadingAssetCount > 0;
|
||||
|
||||
const value = {
|
||||
assetLoadStart,
|
||||
assetLoadFinish,
|
||||
isLoading,
|
||||
};
|
||||
|
||||
return (
|
||||
<DiceLoadingContext.Provider value={value}>
|
||||
{children}
|
||||
</DiceLoadingContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export default DiceLoadingContext;
|
@ -8,7 +8,7 @@ class GalaxyDice extends Dice {
|
||||
static meshes;
|
||||
static material;
|
||||
|
||||
static async createInstance(diceType, scene) {
|
||||
static async load(scene) {
|
||||
if (!this.material) {
|
||||
this.material = this.loadMaterial(
|
||||
"galaxy_pbr",
|
||||
@ -19,6 +19,12 @@ class GalaxyDice extends Dice {
|
||||
if (!this.meshes) {
|
||||
this.meshes = await this.loadMeshes(this.material, scene);
|
||||
}
|
||||
}
|
||||
|
||||
static async createInstance(diceType, scene) {
|
||||
if (!this.material || !this.meshes) {
|
||||
throw Error("Dice not loaded, call load before creating an instance");
|
||||
}
|
||||
|
||||
return Dice.createInstance(
|
||||
this.meshes[diceType],
|
||||
|
@ -13,7 +13,7 @@ class IronDice extends Dice {
|
||||
return { mass: properties.mass * 2, friction: properties.friction };
|
||||
}
|
||||
|
||||
static async createInstance(diceType, scene) {
|
||||
static async load(scene) {
|
||||
if (!this.material) {
|
||||
this.material = this.loadMaterial(
|
||||
"iron_pbr",
|
||||
@ -24,6 +24,12 @@ class IronDice extends Dice {
|
||||
if (!this.meshes) {
|
||||
this.meshes = await this.loadMeshes(this.material, scene);
|
||||
}
|
||||
}
|
||||
|
||||
static async createInstance(diceType, scene) {
|
||||
if (!this.material || !this.meshes) {
|
||||
throw Error("Dice not loaded, call load before creating an instance");
|
||||
}
|
||||
|
||||
return Dice.createInstance(
|
||||
this.meshes[diceType],
|
||||
|
@ -8,10 +8,10 @@ class NebulaDice extends Dice {
|
||||
static meshes;
|
||||
static material;
|
||||
|
||||
static async createInstance(diceType, scene) {
|
||||
static async load(scene) {
|
||||
if (!this.material) {
|
||||
this.material = this.loadMaterial(
|
||||
"nebula_pbr",
|
||||
"neubula_pbr",
|
||||
{ albedo, metalRoughness, normal },
|
||||
scene
|
||||
);
|
||||
@ -19,6 +19,12 @@ class NebulaDice extends Dice {
|
||||
if (!this.meshes) {
|
||||
this.meshes = await this.loadMeshes(this.material, scene);
|
||||
}
|
||||
}
|
||||
|
||||
static async createInstance(diceType, scene) {
|
||||
if (!this.material || !this.meshes) {
|
||||
throw Error("Dice not loaded, call load before creating an instance");
|
||||
}
|
||||
|
||||
return Dice.createInstance(
|
||||
this.meshes[diceType],
|
||||
|
@ -8,7 +8,7 @@ class SunriseDice extends Dice {
|
||||
static meshes;
|
||||
static material;
|
||||
|
||||
static async createInstance(diceType, scene) {
|
||||
static async load(scene) {
|
||||
if (!this.material) {
|
||||
this.material = this.loadMaterial(
|
||||
"sunrise_pbr",
|
||||
@ -19,6 +19,12 @@ class SunriseDice extends Dice {
|
||||
if (!this.meshes) {
|
||||
this.meshes = await this.loadMeshes(this.material, scene);
|
||||
}
|
||||
}
|
||||
|
||||
static async createInstance(diceType, scene) {
|
||||
if (!this.material || !this.meshes) {
|
||||
throw Error("Dice not loaded, call load before creating an instance");
|
||||
}
|
||||
|
||||
return Dice.createInstance(
|
||||
this.meshes[diceType],
|
||||
|
@ -8,7 +8,7 @@ class SunsetDice extends Dice {
|
||||
static meshes;
|
||||
static material;
|
||||
|
||||
static async createInstance(diceType, scene) {
|
||||
static async load(scene) {
|
||||
if (!this.material) {
|
||||
this.material = this.loadMaterial(
|
||||
"sunset_pbr",
|
||||
@ -19,6 +19,12 @@ class SunsetDice extends Dice {
|
||||
if (!this.meshes) {
|
||||
this.meshes = await this.loadMeshes(this.material, scene);
|
||||
}
|
||||
}
|
||||
|
||||
static async createInstance(diceType, scene) {
|
||||
if (!this.material || !this.meshes) {
|
||||
throw Error("Dice not loaded, call load before creating an instance");
|
||||
}
|
||||
|
||||
return Dice.createInstance(
|
||||
this.meshes[diceType],
|
||||
|
@ -8,7 +8,7 @@ class WalnutDice extends Dice {
|
||||
static meshes;
|
||||
static material;
|
||||
|
||||
static async createInstance(diceType, scene) {
|
||||
static async load(scene) {
|
||||
if (!this.material) {
|
||||
this.material = this.loadMaterial(
|
||||
"walnut_pbr",
|
||||
@ -19,6 +19,12 @@ class WalnutDice extends Dice {
|
||||
if (!this.meshes) {
|
||||
this.meshes = await this.loadMeshes(this.material, scene);
|
||||
}
|
||||
}
|
||||
|
||||
static async createInstance(diceType, scene) {
|
||||
if (!this.material || !this.meshes) {
|
||||
throw Error("Dice not loaded, call load before creating an instance");
|
||||
}
|
||||
|
||||
return Dice.createInstance(
|
||||
this.meshes[diceType],
|
||||
|
Loading…
x
Reference in New Issue
Block a user