Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dddice integration POC 1 #353

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ export default function getReplayChoicesInputProvider(actionId: string, decision
},
// To roll dice, ignore the user and use the deterministic dice roller again
rollDice(dice) {
decisionStack.pop();
return dRoller(dice);
return Promise.resolve(decisionStack.pop());
},
choose() {
return Promise.resolve(decisionStack.pop());
Expand Down
4 changes: 3 additions & 1 deletion app/imports/client/ui/creature/actions/ActionDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ import EngineActions from '/imports/api/engine/action/EngineActions';
import LogContent from '/imports/client/ui/log/LogContent.vue';
//import RollInput from '/imports/client/ui/creature/actions/input/RollInput.vue';
import TargetsInput from '/imports/client/ui/creature/actions/input/TargetsInput.vue';
import {rollDice} from "/imports/client/ui/creature/actions/input/diceProviders/dddice";

export default {
components: {
Expand Down Expand Up @@ -215,7 +216,7 @@ export default {
return this.promiseInput();
},
async rollDice(dice) {
return Promise.resolve(this.deterministicDiceRoller(dice));
//return Promise.resolve(this.deterministicDiceRoller(dice));
/* Dice Animation and user control goes here:
this.activeInputParams = {
deterministicDiceRoller: this.deterministicDiceRoller,
Expand All @@ -224,6 +225,7 @@ export default {
this.activeInput = 'roll-input';
return this.promiseInput();
*/
return Promise.resolve(rollDice(dice));
},
async nextStep(task) {
return this.promiseInput();
Expand Down
2 changes: 1 addition & 1 deletion app/imports/client/ui/creature/actions/doAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ function getErrorOnInputRequestProvider(actionId) {
const errorOnInputRequest: InputProvider = {
targetIds: throwInputRequestedError,
nextStep: throwInputRequestedError,
rollDice: getDeterministicDiceRoller(actionId),
rollDice: throwInputRequestedError,
choose: throwInputRequestedError,
advantage: throwInputRequestedError,
check: throwInputRequestedError,
Expand Down
132 changes: 132 additions & 0 deletions app/imports/client/ui/creature/actions/input/diceProviders/dddice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import {ThreeDDice, ThreeDDiceAPI, ThreeDDiceRollEvent, IDiceRoll} from 'dddice-js';

let dddice;
const RENDER_MODE = 'on';
const APP_NAME = 'Dice Cloud'
const theme = 'dddice-bees';
const room ='4qR_jcc';

async function createGuestUserIfNeeded() {
let apiKey = window.localStorage.getItem('dddice.apiKey') as string;
if (!apiKey) {
console.log('creating guest account');
apiKey = (await new ThreeDDiceAPI(undefined, APP_NAME).user.guest()).data;
await window.localStorage.setItem('dddice.apiKey', apiKey);

}
return apiKey;
}

const waitForRoll = () =>
{
return new Promise(resolve => {
dddice.off(ThreeDDiceRollEvent.RollFinished);
dddice.on(ThreeDDiceRollEvent.RollFinished, () => resolve());
});
}

const rollDice = async (
dice: { number: number, diceSize: number }[]
): Promise<number[][]> => {

const diceToRoll: IDiceRoll[] = [];
dice.forEach(die =>{
for(let i = 0; i < die.number; i++){
diceToRoll.push({type:'d'+die.diceSize,theme})
}
})

const roll = await dddice.api.roll.create(diceToRoll,{
room: room,
});
await waitForRoll();
console.log(roll.data.values.map(value=>value.value_to_display));
return [roll.data.values.map(value=>value.value_to_display)];
};


async function setUpDddiceSdk() {
console.log('setting up dddice sdk');
const apiKey = await createGuestUserIfNeeded();
if (apiKey && room && !dddice) {
try {
api = new ThreeDDiceAPI(apiKey, 'Dice Cloud');
const user: IUser = (await api.user.get()).data;

let canvas: HTMLCanvasElement = document.getElementById('dddice-canvas') as HTMLCanvasElement;

if (dddice) {
// clear the board
if (canvas) {
canvas.remove();
canvas = undefined;
}
// disconnect from echo
if (dddice.api?.connection) dddice.api.connection.disconnect();
// stop the animation loop
dddice.stop();
}

if (RENDER_MODE === 'on') {
console.log('render mode is on');
if (!canvas) {
// add canvas element to document
canvas = document.createElement('canvas');
canvas.id = 'dddice-canvas';
// if the css fails to load for any reason, using tailwinds classes here
// will disable the whole interface
canvas.style.top = '0px';
canvas.style.position = 'fixed';
canvas.style.pointerEvents = 'none';
canvas.style.zIndex = '100000';
canvas.style.opacity = '100';
canvas.style.height = '100vh';
canvas.style.width = '100vw';
document.body.appendChild(canvas);
window.addEventListener(
'resize',
() => dddice && dddice.renderer && dddice.resize(window.innerWidth, window.innerHeight),
);
}
dddice = new ThreeDDice().initialize(canvas, apiKey, undefined, APP_NAME);
dddice.start();
try {
dddice.api.room.join(room);
} catch (error) {
log.warn('eating error', error.response?.data?.data?.message);
}
dddice.connect(room, undefined, user.uuid);
//dddice.on(ThreeDDiceRollEvent.RollCreated, (roll: IRoll) => rollCreated(roll));
dddice.off(ThreeDDiceRollEvent.RollFinished);
dddice.on(ThreeDDiceRollEvent.RollFinished, (roll: IRoll) => rollFinished(roll));
} else {
console.log('render mode is off');
dddice = new ThreeDDice();
dddice.api = new ThreeDDiceAPI(apiKey, APP_NAME);
try {
dddice.api.room.join(room);
} catch (error) {
log.warn('eating error', error.response?.data?.data?.message);
}
dddice.api.connect(room, undefined, user.uuid);
//dddice.api.listen(ThreeDDiceRollEvent.RollCreated, (roll: IRoll) => rollCreated(roll));
}


console.log('dddice is ready to roll!');
} catch (e) {
console.error(e);
console.error(`dddice | ${e.response?.data?.data?.message ?? e}`);
return;
}
}
if (dddice) {
document.body.addEventListener('click', () => {
if (dddice && !dddice?.isDiceThrowing) {
dddice.clear();
}
});
}
}

export {setUpDddiceSdk, rollDice};
2 changes: 2 additions & 0 deletions app/imports/client/ui/creature/character/CharacterSheet.vue
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ import { snackbar } from '/imports/client/ui/components/snackbars/SnackbarQueue'
import CharacterSheetFab from '/imports/client/ui/creature/character/CharacterSheetFab.vue';
import ActionsTab from '/imports/client/ui/creature/character/characterSheetTabs/ActionsTab.vue';
import CharacterSheetInitiative from '/imports/client/ui/creature/character/CharacterSheetInitiative.vue';
import {setUpDddiceSdk} from "/imports/client/ui/creature/actions/input/diceProviders/dddice";

export default {
components: {
Expand Down Expand Up @@ -186,6 +187,7 @@ export default {
},
},
mounted() {
setUpDddiceSdk();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This call sets up the dddice sdk, inserts the canvas, and creates a connection to the dddice servers.

There is probably a way better place to call this from, I'm just not sure where is the correct place. For the sake of the POC i thought this was good enough.

this.$store.commit('setPageTitle', this.creature && this.creature.name || 'Character Sheet');
this.nameObserver = Creatures.find({
creatureId: this.creatureId,
Expand Down
2 changes: 1 addition & 1 deletion app/imports/client/ui/dialogStack/DialogStack.vue
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@
// If the source and the hidden Element are different
// hide the source and reveal the hidden element
let originalSourceTransition = source.style.transition;
if (hiddenElement !== source){
if (hiddenElement && hiddenElement !== source){
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this because after a roll I got a hiddenElement undefined error which prevented the action buttons from resetting after the roll

source.style.transition = 'none';
source.style.opacity = '0';
hiddenElement.style.opacity = null;
Expand Down
21 changes: 21 additions & 0 deletions app/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"cytoscape-klay": "^3.1.4",
"dagre": "^0.8.5",
"date-fns": "^1.30.1",
"dddice-js": "^0.19.16",
"ddp-rate-limiter-mixin": "^1.1.10",
"discord.js": "^12.5.3",
"dompurify": "^2.4.7",
Expand Down