Restructured dice so it is part of the party
Added initial networking plumbing
This commit is contained in:
parent
795f187782
commit
d20be94059
@ -16,7 +16,7 @@ function StyledModal({
|
||||
isOpen={isOpen}
|
||||
onRequestClose={onRequestClose}
|
||||
style={{
|
||||
overlay: { backgroundColor: "rgba(0, 0, 0, 0.73)" },
|
||||
overlay: { backgroundColor: "rgba(0, 0, 0, 0.73)", zIndex: 100 },
|
||||
content: {
|
||||
backgroundColor: theme.colors.background,
|
||||
top: "50%",
|
||||
|
@ -9,6 +9,8 @@ import D6Icon from "../../icons/D6Icon";
|
||||
import D4Icon from "../../icons/D4Icon";
|
||||
import D100Icon from "../../icons/D100Icon";
|
||||
import ExpandMoreDiceTrayIcon from "../../icons/ExpandMoreDiceTrayIcon";
|
||||
import ShareDiceOnIcon from "../../icons/ShareDiceOnIcon";
|
||||
import ShareDiceOffIcon from "../../icons/ShareDiceOffIcon";
|
||||
|
||||
import DiceButton from "./DiceButton";
|
||||
import SelectDiceButton from "./SelectDiceButton";
|
||||
@ -23,6 +25,8 @@ function DiceButtons({
|
||||
onDiceLoad,
|
||||
diceTraySize,
|
||||
onDiceTraySizeChange,
|
||||
shareDice,
|
||||
onShareDiceChange,
|
||||
}) {
|
||||
const [currentDice, setCurrentDice] = useState(dice[0]);
|
||||
|
||||
@ -129,6 +133,14 @@ function DiceButtons({
|
||||
>
|
||||
<ExpandMoreDiceTrayIcon />
|
||||
</IconButton>
|
||||
<Divider />
|
||||
<IconButton
|
||||
aria-label={shareDice ? "Hide Dice Rolls" : "Share Dice Rolls"}
|
||||
title={shareDice ? "Hide Dice Rolls" : "Share Dice Rolls"}
|
||||
onClick={() => onShareDiceChange(!shareDice)}
|
||||
>
|
||||
{shareDice ? <ShareDiceOnIcon /> : <ShareDiceOffIcon />}
|
||||
</IconButton>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
@ -1,85 +1,20 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import * as BABYLON from "babylonjs";
|
||||
import React from "react";
|
||||
|
||||
import DiceButtons from "./DiceButtons";
|
||||
import DiceResults from "./DiceResults";
|
||||
|
||||
function DiceControls({
|
||||
diceRefs,
|
||||
sceneVisibleRef,
|
||||
onDiceAdd,
|
||||
onDiceClear,
|
||||
onDiceReroll,
|
||||
onDiceLoad,
|
||||
diceTraySize,
|
||||
onDiceTraySizeChange,
|
||||
shareDice,
|
||||
onShareDiceChage,
|
||||
diceRolls,
|
||||
onDiceRollsChange,
|
||||
}) {
|
||||
const [diceRolls, setDiceRolls] = useState([]);
|
||||
|
||||
// Update dice rolls
|
||||
useEffect(() => {
|
||||
// Find the number facing up on a dice object
|
||||
function getDiceRoll(dice) {
|
||||
let number = getDiceInstanceRoll(dice.instance);
|
||||
// If the dice is a d100 add the d10
|
||||
if (dice.type === "d100") {
|
||||
const d10Number = getDiceInstanceRoll(dice.d10Instance);
|
||||
// Both zero set to 100
|
||||
if (d10Number === 0 && number === 0) {
|
||||
number = 100;
|
||||
} else {
|
||||
number += d10Number;
|
||||
}
|
||||
} else if (dice.type === "d10" && number === 0) {
|
||||
number = 10;
|
||||
}
|
||||
return { type: dice.type, roll: number };
|
||||
}
|
||||
|
||||
// Find the number facing up on a mesh instance of a dice
|
||||
function getDiceInstanceRoll(instance) {
|
||||
let highestDot = -1;
|
||||
let highestLocator;
|
||||
for (let locator of instance.getChildTransformNodes()) {
|
||||
let dif = locator
|
||||
.getAbsolutePosition()
|
||||
.subtract(instance.getAbsolutePosition());
|
||||
let direction = dif.normalize();
|
||||
const dot = BABYLON.Vector3.Dot(direction, BABYLON.Vector3.Up());
|
||||
if (dot > highestDot) {
|
||||
highestDot = dot;
|
||||
highestLocator = locator;
|
||||
}
|
||||
}
|
||||
return parseInt(highestLocator.name.slice(12));
|
||||
}
|
||||
|
||||
function updateDiceRolls() {
|
||||
const die = diceRefs.current;
|
||||
const sceneVisible = sceneVisibleRef.current;
|
||||
if (!sceneVisible) {
|
||||
return;
|
||||
}
|
||||
const diceAwake = die.map((dice) => dice.asleep).includes(false);
|
||||
if (!diceAwake) {
|
||||
return;
|
||||
}
|
||||
|
||||
let newRolls = [];
|
||||
for (let i = 0; i < die.length; i++) {
|
||||
const dice = die[i];
|
||||
let roll = getDiceRoll(dice);
|
||||
newRolls[i] = roll;
|
||||
}
|
||||
setDiceRolls(newRolls);
|
||||
}
|
||||
|
||||
const updateInterval = setInterval(updateDiceRolls, 100);
|
||||
return () => {
|
||||
clearInterval(updateInterval);
|
||||
};
|
||||
}, [diceRefs, sceneVisibleRef]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
@ -98,7 +33,7 @@ function DiceControls({
|
||||
diceRolls={diceRolls}
|
||||
onDiceClear={() => {
|
||||
onDiceClear();
|
||||
setDiceRolls([]);
|
||||
onDiceRollsChange([]);
|
||||
}}
|
||||
onDiceReroll={onDiceReroll}
|
||||
/>
|
||||
@ -114,14 +49,13 @@ function DiceControls({
|
||||
diceRolls={diceRolls}
|
||||
onDiceAdd={(style, type) => {
|
||||
onDiceAdd(style, type);
|
||||
setDiceRolls((prevRolls) => [
|
||||
...prevRolls,
|
||||
{ type, roll: "unknown" },
|
||||
]);
|
||||
onDiceRollsChange([...diceRolls, { type, roll: "unknown" }]);
|
||||
}}
|
||||
onDiceLoad={onDiceLoad}
|
||||
onDiceTraySizeChange={onDiceTraySizeChange}
|
||||
diceTraySize={diceTraySize}
|
||||
shareDice={shareDice}
|
||||
onShareDiceChange={onShareDiceChage}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
|
@ -19,7 +19,15 @@ import DiceTray from "../../dice/diceTray/DiceTray";
|
||||
|
||||
import DiceLoadingContext from "../../contexts/DiceLoadingContext";
|
||||
|
||||
function DiceTrayOverlay({ isOpen }) {
|
||||
import { getDiceRoll } from "../../helpers/dice";
|
||||
|
||||
function DiceTrayOverlay({
|
||||
isOpen,
|
||||
shareDice,
|
||||
onShareDiceChage,
|
||||
diceRolls,
|
||||
onDiceRollsChange,
|
||||
}) {
|
||||
const sceneRef = useRef();
|
||||
const shadowGeneratorRef = useRef();
|
||||
const diceRefs = useRef([]);
|
||||
@ -251,6 +259,34 @@ function DiceTrayOverlay({ isOpen }) {
|
||||
};
|
||||
}, [diceTraySize]);
|
||||
|
||||
// Update dice rolls
|
||||
useEffect(() => {
|
||||
function updateDiceRolls() {
|
||||
const die = diceRefs.current;
|
||||
const sceneVisible = sceneVisibleRef.current;
|
||||
if (!sceneVisible) {
|
||||
return;
|
||||
}
|
||||
const diceAwake = die.map((dice) => dice.asleep).includes(false);
|
||||
if (!diceAwake) {
|
||||
return;
|
||||
}
|
||||
|
||||
let newRolls = [];
|
||||
for (let i = 0; i < die.length; i++) {
|
||||
const dice = die[i];
|
||||
let roll = getDiceRoll(dice);
|
||||
newRolls[i] = roll;
|
||||
}
|
||||
onDiceRollsChange(newRolls);
|
||||
}
|
||||
|
||||
const updateInterval = setInterval(updateDiceRolls, 100);
|
||||
return () => {
|
||||
clearInterval(updateInterval);
|
||||
};
|
||||
}, [diceRefs, sceneVisibleRef, onDiceRollsChange]);
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
@ -277,14 +313,16 @@ function DiceTrayOverlay({ isOpen }) {
|
||||
/>
|
||||
</Box>
|
||||
<DiceControls
|
||||
diceRefs={diceRefs}
|
||||
sceneVisibleRef={sceneVisibleRef}
|
||||
onDiceAdd={handleDiceAdd}
|
||||
onDiceClear={handleDiceClear}
|
||||
onDiceReroll={handleDiceReroll}
|
||||
onDiceLoad={handleDiceLoad}
|
||||
diceTraySize={diceTraySize}
|
||||
onDiceTraySizeChange={setDiceTraySize}
|
||||
shareDice={shareDice}
|
||||
onShareDiceChage={onShareDiceChage}
|
||||
diceRolls={diceRolls}
|
||||
onDiceRollsChange={onDiceRollsChange}
|
||||
/>
|
||||
{isLoading && (
|
||||
<Box
|
||||
|
@ -6,7 +6,6 @@ import MapInteraction from "./MapInteraction";
|
||||
import MapToken from "./MapToken";
|
||||
import MapDrawing from "./MapDrawing";
|
||||
import MapFog from "./MapFog";
|
||||
import MapDice from "./MapDice";
|
||||
import MapGrid from "./MapGrid";
|
||||
import MapMeasure from "./MapMeasure";
|
||||
import MapLoadingOverlay from "./MapLoadingOverlay";
|
||||
@ -338,7 +337,6 @@ function Map({
|
||||
{mapControls}
|
||||
{tokenMenu}
|
||||
{tokenDragOverlay}
|
||||
<MapDice />
|
||||
<MapLoadingOverlay />
|
||||
</>
|
||||
}
|
||||
|
@ -6,7 +6,12 @@ import DiceTrayOverlay from "../dice/DiceTrayOverlay";
|
||||
|
||||
import { DiceLoadingProvider } from "../../contexts/DiceLoadingContext";
|
||||
|
||||
function MapDice() {
|
||||
function DiceTrayButton({
|
||||
shareDice,
|
||||
onShareDiceChage,
|
||||
diceRolls,
|
||||
onDiceRollsChange,
|
||||
}) {
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
|
||||
return (
|
||||
@ -37,10 +42,16 @@ function MapDice() {
|
||||
<ExpandMoreDiceIcon isExpanded={isExpanded} />
|
||||
</IconButton>
|
||||
<DiceLoadingProvider>
|
||||
<DiceTrayOverlay isOpen={isExpanded} />
|
||||
<DiceTrayOverlay
|
||||
isOpen={isExpanded}
|
||||
shareDice={shareDice}
|
||||
onShareDiceChage={onShareDiceChage}
|
||||
diceRolls={diceRolls}
|
||||
onDiceRollsChange={onDiceRollsChange}
|
||||
/>
|
||||
</DiceLoadingProvider>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
export default MapDice;
|
||||
export default DiceTrayButton;
|
@ -8,6 +8,7 @@ import StartStreamButton from "./StartStreamButton";
|
||||
import SettingsButton from "../SettingsButton";
|
||||
import StartTimerButton from "./StartTimerButton";
|
||||
import Timer from "./Timer";
|
||||
import DiceTrayButton from "./DiceTrayButton";
|
||||
|
||||
function Party({
|
||||
nickname,
|
||||
@ -22,6 +23,10 @@ function Party({
|
||||
partyTimers,
|
||||
onTimerStart,
|
||||
onTimerStop,
|
||||
shareDice,
|
||||
onShareDiceChage,
|
||||
diceRolls,
|
||||
onDiceRollsChange,
|
||||
}) {
|
||||
return (
|
||||
<Flex
|
||||
@ -31,8 +36,9 @@ function Party({
|
||||
flexDirection: "column",
|
||||
width: "112px",
|
||||
minWidth: "112px",
|
||||
overflowY: "auto",
|
||||
overflow: "visible",
|
||||
alignItems: "center",
|
||||
position: "relative",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
@ -50,7 +56,12 @@ function Party({
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<Nickname nickname={`${nickname} (you)` || ""} />
|
||||
<Nickname
|
||||
nickname={`${nickname} (you) ${
|
||||
shareDice &&
|
||||
diceRolls.reduce((accumulator, dice) => accumulator + dice.roll, 0)
|
||||
}`}
|
||||
/>
|
||||
{Object.entries(partyNicknames).map(([id, partyNickname]) => (
|
||||
<Nickname
|
||||
nickname={partyNickname}
|
||||
@ -83,6 +94,14 @@ function Party({
|
||||
/>
|
||||
<SettingsButton />
|
||||
</Flex>
|
||||
<Box sx={{ position: "absolute", top: 0, right: "0", zIndex: 1 }}>
|
||||
<DiceTrayButton
|
||||
shareDice={shareDice}
|
||||
onShareDiceChage={onShareDiceChage}
|
||||
diceRolls={diceRolls}
|
||||
onDiceRollsChange={onDiceRollsChange}
|
||||
/>
|
||||
</Box>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
43
src/helpers/dice.js
Normal file
43
src/helpers/dice.js
Normal file
@ -0,0 +1,43 @@
|
||||
import * as BABYLON from "babylonjs";
|
||||
|
||||
/**
|
||||
* Find the number facing up on a mesh instance of a dice
|
||||
* @param {Object} instance The dice instance
|
||||
*/
|
||||
export function getDiceInstanceRoll(instance) {
|
||||
let highestDot = -1;
|
||||
let highestLocator;
|
||||
for (let locator of instance.getChildTransformNodes()) {
|
||||
let dif = locator
|
||||
.getAbsolutePosition()
|
||||
.subtract(instance.getAbsolutePosition());
|
||||
let direction = dif.normalize();
|
||||
const dot = BABYLON.Vector3.Dot(direction, BABYLON.Vector3.Up());
|
||||
if (dot > highestDot) {
|
||||
highestDot = dot;
|
||||
highestLocator = locator;
|
||||
}
|
||||
}
|
||||
return parseInt(highestLocator.name.slice(12));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the number facing up on a dice object
|
||||
* @param {Object} dice The Dice object
|
||||
*/
|
||||
export function getDiceRoll(dice) {
|
||||
let number = getDiceInstanceRoll(dice.instance);
|
||||
// If the dice is a d100 add the d10
|
||||
if (dice.type === "d100") {
|
||||
const d10Number = getDiceInstanceRoll(dice.d10Instance);
|
||||
// Both zero set to 100
|
||||
if (d10Number === 0 && number === 0) {
|
||||
number = 100;
|
||||
} else {
|
||||
number += d10Number;
|
||||
}
|
||||
} else if (dice.type === "d10" && number === 0) {
|
||||
number = 10;
|
||||
}
|
||||
return { type: dice.type, roll: number };
|
||||
}
|
18
src/icons/ShareDiceOffIcon.js
Normal file
18
src/icons/ShareDiceOffIcon.js
Normal file
@ -0,0 +1,18 @@
|
||||
import React from "react";
|
||||
|
||||
function ShareDiceOffIcon() {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
fill="currentcolor"
|
||||
>
|
||||
<path d="M24 24H0V0h24z" fill="none" />
|
||||
<path d="M11,8.17L6.49,3.66C8.07,2.61,9.96,2,12,2c5.52,0,10,4.48,10,10c0,2.04-0.61,3.93-1.66,5.51l-1.46-1.46 C19.59,14.87,20,13.48,20,12c0-3.35-2.07-6.22-5-7.41V5c0,1.1-0.9,2-2,2h-2V8.17z M20.49,21.9L20.49,21.9 c-0.39,0.39-1.02,0.39-1.41,0l-1.56-1.56c-2.07,1.37-4.68,2-7.45,1.48c-3.95-0.75-7.13-3.92-7.88-7.88 c-0.52-2.77,0.1-5.38,1.48-7.45L2.1,4.93c-0.39-0.39-0.39-1.02,0-1.41l0,0c0.39-0.39,1.02-0.39,1.41,0l16.97,16.97 C20.88,20.88,20.88,21.51,20.49,21.9z M11,18c-1.1,0-2-0.9-2-2v-1l-4.79-4.79C4.08,10.79,4,11.38,4,12c0,4.08,3.05,7.44,7,7.93V18z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default ShareDiceOffIcon;
|
18
src/icons/ShareDiceOnIcon.js
Normal file
18
src/icons/ShareDiceOnIcon.js
Normal file
@ -0,0 +1,18 @@
|
||||
import React from "react";
|
||||
|
||||
function ShareDiceOnIcon() {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
fill="currentcolor"
|
||||
>
|
||||
<path d="M24 24H0V0h24z" fill="none" />
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default ShareDiceOnIcon;
|
@ -25,6 +25,9 @@ function NetworkedParty({ gameId, session }) {
|
||||
const [partyStreams, setPartyStreams] = useState({});
|
||||
const [timer, setTimer] = useState(null);
|
||||
const [partyTimers, setPartyTimers] = useState({});
|
||||
const [diceRolls, setDiceRolls] = useState([]);
|
||||
const [shareDice, setShareDice] = useState(false);
|
||||
const [partyDiceRolls, setPartyDiceRolls] = useState({});
|
||||
|
||||
function handleNicknameChange(newNickname) {
|
||||
setNickname(newNickname);
|
||||
@ -93,6 +96,14 @@ function NetworkedParty({ gameId, session }) {
|
||||
};
|
||||
}, [timer, session]);
|
||||
|
||||
function handleDiceRollsChange(newDiceRolls) {
|
||||
setDiceRolls(newDiceRolls);
|
||||
}
|
||||
|
||||
function handleShareDiceChange(newShareDice) {
|
||||
setShareDice(newShareDice);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
function handlePeerConnect({ peer, reply }) {
|
||||
reply("nickname", { [session.id]: nickname });
|
||||
@ -191,6 +202,10 @@ function NetworkedParty({ gameId, session }) {
|
||||
partyTimers={partyTimers}
|
||||
onTimerStart={handleTimerStart}
|
||||
onTimerStop={handleTimerStop}
|
||||
shareDice={shareDice}
|
||||
onShareDiceChage={handleShareDiceChange}
|
||||
diceRolls={diceRolls}
|
||||
onDiceRollsChange={handleDiceRollsChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user