Skip to content

Commit

Permalink
Merge pull request #60 from 3d-dice/flexible-dice-names
Browse files Browse the repository at this point in the history
implement more flexible die names for parsing
  • Loading branch information
frankieali authored Sep 21, 2022
2 parents b7d4f3f + f7bfcab commit 3786010
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 29 deletions.
43 changes: 26 additions & 17 deletions src/WorldFacade.js
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ class WorldFacade {
}

// TODO: pass data with roll - such as roll name. Passed back at the end in the results
roll(notation, {theme, themeColor, newStartPoint = true} = {}) {
roll(notation, {theme = this.config.theme, themeColor = this.config.themeColor, newStartPoint = true} = {}) {
// note: to add to a roll on screen use .add method
// reset the offscreen worker and physics worker with each new roll
this.clear()
Expand All @@ -403,14 +403,14 @@ class WorldFacade {
newStartPoint
})

const parsedNotation = this.createNotationArray(notation)
const parsedNotation = this.createNotationArray(notation, this.themesLoadedData[theme].diceAvailable)
this.#makeRoll(parsedNotation, collectionId)

// returns a Promise that is resolved in onRollComplete
return this.rollCollectionData[collectionId].promise
}

add(notation, {theme, themeColor, newStartPoint = true} = {}) {
add(notation, {theme = this.config.theme, themeColor = this.config.themeColor, newStartPoint = true} = {}) {

const collectionId = this.#collectionIndex++

Expand All @@ -422,7 +422,7 @@ class WorldFacade {
newStartPoint
})

const parsedNotation = this.createNotationArray(notation)
const parsedNotation = this.createNotationArray(notation, this.themesLoadedData[theme].diceAvailable)
this.#makeRoll(parsedNotation, collectionId)

// returns a Promise that is resolved in onRollComplete
Expand Down Expand Up @@ -514,8 +514,12 @@ class WorldFacade {
let id = notation.id !== undefined ? notation.id : this.#idIndex++
index = hasGroupId ? notation.groupId : this.#groupIndex

const dieType = Number.isInteger(notation.sides) ? `d${notation.sides}` : notation.sides

notation.sides = dieType

const roll = {
sides: notation.sides,
sides: dieType,
groupId: index,
collectionId: collection.id,
rollId,
Expand All @@ -530,22 +534,23 @@ class WorldFacade {
collection.rolls.push(this.rollDiceData[rollId])

// TODO: eliminate the 'd' for more flexible naming such as 'fate' - ensure numbers are strings
if (roll.sides === 'fate' && (!diceAvailable.includes(`d${roll.sides}`) && !diceExtra.includes(`d${roll.sides}`))){
if (roll.sides === 'fate' && (!diceAvailable.includes(roll.sides) && !diceExtra.includes(roll.sides))){
console.warn(`fate die unavailable in '${theme}' theme. Using fallback.`)
const min = -1
const max = 1
roll.value = Random.range(min,max)
this.#DiceWorld.addNonDie(roll)
} else if(this.config.suspendSimulation || (!diceAvailable.includes(`d${roll.sides}`) && !diceExtra.includes(`d${roll.sides}`))){
}
else if(this.config.suspendSimulation || (!diceAvailable.includes(roll.sides) && !diceExtra.includes(roll.sides))){
// check if the requested roll is available in the current theme, if not then use crypto fallback
console.warn(this.config.suspendSimulation ? "3D simulation suspended. Using fallback." : `${roll.sides} sided die unavailable in '${theme}' theme. Using fallback.`)
console.warn(this.config.suspendSimulation ? "3D simulation suspended. Using fallback." : `${roll.sides} die unavailable in '${theme}' theme. Using fallback.`)
roll.value = Random.range(1, roll.sides)
this.#DiceWorld.addNonDie(roll)
}
else {
let parentTheme
if(diceExtra.includes(`d${roll.sides}`)) {
const parentThemeName = diceInherited[`d${roll.sides}`]
if(diceExtra.includes(roll.sides)) {
const parentThemeName = diceInherited[roll.sides]
parentTheme = this.themesLoadedData[parentThemeName]
}
this.#DiceWorld.add({
Expand Down Expand Up @@ -577,7 +582,7 @@ class WorldFacade {
// accepts array of notations eg: ['4d6','2d10']
// accepts object {sides:int, qty:int}
// accepts array of objects eg: [{sides:int, qty:int, mods:[]}]
createNotationArray(input){
createNotationArray(input, diceAvailable){
const notation = Array.isArray( input ) ? input : [ input ]
let parsedNotation = []

Expand Down Expand Up @@ -620,7 +625,7 @@ class WorldFacade {
// console.log('roll', roll)
// if notation is an array of strings
if ( typeof roll === 'string' ) {
parsedNotation.push( this.parse( roll ) )
parsedNotation.push( this.parse( roll, diceAvailable ) )
} else if ( typeof notation === 'object' ) {
verifyRollId( roll )
verifyObject( roll ) && parsedNotation.push( roll )
Expand All @@ -632,10 +637,12 @@ class WorldFacade {

// parse text die notation such as 2d10+3 => {number:2, type:6, modifier:3}
// taken from https://github.com/ChapelR/dice-notation
parse(notation) {
const diceNotation = /(\d+)[dD](\d+)(.*)$/i
parse(notation, diceAvailable) {
const diceNotation = /(\d+)([dD]{1}\d+)(.*)$/i
const percentNotation = /(\d+)[dD]([0%]+)(.*)$/i
const fudgeNotation = /(\d+)df+(ate)*$/i
const fudgeNotation = /(\d+)[dD](f+[ate]*)(.*)$/i
// const customNotation = /(\d+)[dD](.*)([+-])/i
const customNotation = /(\d+)[dD]([\d\w]+)([+-]{0,1}\d+)?/i
const modifier = /([+-])(\d+)/
const cleanNotation = notation.trim().replace(/\s+/g, '')
const validNumber = (n, err) => {
Expand All @@ -647,7 +654,7 @@ class WorldFacade {
}

// match percentNotation before diceNotation
const roll = cleanNotation.match(percentNotation) || cleanNotation.match(diceNotation) || cleanNotation.match(fudgeNotation);
const roll = cleanNotation.match(percentNotation) || cleanNotation.match(diceNotation) || cleanNotation.match(fudgeNotation) || cleanNotation.match(customNotation);

let mod = 0;
const msg = 'Invalid notation: ' + notation + '';
Expand All @@ -673,8 +680,10 @@ class WorldFacade {
returnObj.sides = '100' // as string, not number
} else if(cleanNotation.match(fudgeNotation)){
returnObj.sides = 'fate' // force lowercase
} else if(diceAvailable.includes(cleanNotation.match(customNotation)[2])){
returnObj.sides = roll[2] // dice type instead of number
} else {
returnObj.sides = validNumber(roll[2], msg);
returnObj.sides = roll[2];
}

return returnObj
Expand Down
17 changes: 13 additions & 4 deletions src/components/Dice.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class Dice {
constructor(options, scene) {
this.config = {...defaultOptions, ...options}
this.id = this.config.id !== undefined ? this.config.id : Date.now()
this.dieType = `d${this.config.sides}`
this.dieType = this.config.sides
this.comboKey = `${this.config.theme}_${this.dieType}`
this.scene = scene
this.createInstance()
Expand All @@ -49,7 +49,11 @@ class Dice {

// start the instance under the floor, out of camera view
dieInstance.position.y = -100
dieInstance.scaling = new Vector3(this.config.scale,this.config.scale,this.config.scale)
dieInstance.scaling = new Vector3(
dieInstance.scaling.x * this.config.scale,
dieInstance.scaling.y * this.config.scale,
dieInstance.scaling.z * this.config.scale
)

if(this.config.enableShadows){
// let's keep this simple for now since we know there's only one directional light
Expand All @@ -72,7 +76,7 @@ class Dice {
const { sides, theme = 'default', meshName, colorSuffix} = options

// create a key for this die type and theme for caching and instance creation
const dieMeshName = meshName + '_d' + sides
const dieMeshName = meshName + '_' + sides
const dieMaterialName = dieMeshName + '_' + theme + colorSuffix
let die = scene.getMeshByName(dieMaterialName)

Expand Down Expand Up @@ -130,7 +134,11 @@ class Dice {
}
// shrink the colliders
if( model.name.includes("collider")) {
model.scaling = new Vector3(.9,.9,.9)
model.scaling = new Vector3(
model.scaling.x * .9,
model.scaling.y * .9,
model.scaling.z * .9
)
}
// check if d100 is available as a mesh - otherwise we'll clone a d10
if (!has_d100) {
Expand All @@ -144,6 +152,7 @@ class Dice {
model.freezeWorldMatrix()
model.isPickable = false
model.doNotSyncBoundingInfo = true
// model.scaling = new Vector3(model.scaling)
// prefix all the meshes ids from this file with the file name so we can find them later e.g.: 'default-dice_d10' and 'default-dice_d10_collider'
// model.id = meshName + '_' + model.id
model.name = meshName + '_' + model.name
Expand Down
19 changes: 11 additions & 8 deletions src/components/physics.worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ let spinScale = 60

const defaultOptions = {
size: 9.5,
startingHeight: 12,
spinForce: 3,
throwForce: 2,
startingHeight: 8,
spinForce: 6,
throwForce: 5,
gravity: 1,
mass: 1,
friction: .8,
restitution: .1,
linearDamping: .4,
linearDamping: .5,
angularDamping: .4,
settleTimeout: 5000,
// TODO: toss: "center", "edge", "allEdges"
Expand Down Expand Up @@ -83,7 +83,8 @@ self.onmessage = (e) => {
if(e.data.options.newStartPoint){
setStartPosition()
}
addDie(e.data.options)
const newDie = addDie(e.data.options)
rollDie(newDie)
break;
case "rollDie":
// TODO: this won't work, need a die object
Expand Down Expand Up @@ -393,7 +394,7 @@ const removeBoxFromWorld = () => {

const addDie = (options) => {
const { sides, id, meshName, scale} = options
let cType = `d${sides}_collider`
let cType = `${sides}_collider`
const comboKey = `${meshName}_${cType}`
const colliderMass = colliders[comboKey]?.physicsMass || .1
const mass = colliderMass * config.mass * config.scale // feature? mass should go up with scale, but it throws off the throwForce and spinForce scaling
Expand All @@ -410,8 +411,10 @@ const addDie = (options) => {
newDie.mass = mass
physicsWorld.addRigidBody(newDie)
bodies.push(newDie)

return newDie
// console.log(`added collider for `, type)
rollDie(newDie)
// rollDie(newDie)
}

const rollDie = (die) => {
Expand Down Expand Up @@ -498,7 +501,7 @@ const update = (delta) => {
const speed = rb.getLinearVelocity().length()
const tilt = rb.getAngularVelocity().length()

if(speed < .01 && tilt < .01 || rb.timeout < 0) {
if(speed < .01 && tilt < .005 || rb.timeout < 0) {
// flag the second param for this body so it can be processed in World, first param will be the roll.id
diceBufferView[(i*8) + 1] = rb.id
diceBufferView[(i*8) + 2] = -1
Expand Down

0 comments on commit 3786010

Please sign in to comment.