-
Notifications
You must be signed in to change notification settings - Fork 29
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
Deterministic Rolls #47
Comments
How do you feel about allowing a method to set the seed for the roll?
Edit: Scratch that, you can't set the seed on getRandomValues. I was misremembering what webcrypto actually exposed. Double Edit: I suppose you could also have a mode where you use a PRNG lib that accepts a seed and potentially seed that with getRandomValues ... or some combination of using the existing algorithm on "clean" rolls and a seeded algorithm on deterministic rolls. |
How is this progressing? Is there anything particular you would like a hand with? This would be a fantastic addition, and I'd be happy to assist however I can. |
So I did a little digging into this code to follow up on the seeded random idea, and it looks like basically everything is doing a As far as the interface goes, I'm thinking something like: const seededRandom = new SeededPRNG(); // This would be a class that conforms to an interface that provides a `.random()` method - either via a drop in replacement package or a
seededRandom.setSeed(newSeed); // get this from the server however it wants to generate the seed.
const box = new DiceBox({
rng: seededRandom,
// Other initialization config
});
(await box.init()).roll('1d6'); Any time you need a new seed you could just do a .setSeed() on the new RNG path to reseed (or provide an interface to change the rng class on the fly, though I think that'd require more changes to the physics engine). Though because the physics engine is a web worker it'd require some trickery to pass a dynamic class to it, so it might need to be a fixed PRNG class and passing the seed via I'll probably tinker with this over the next couple of days, just to get it out of my head. |
How would the server calculate a seed such that e.g. "4d6+2d10" results in given roll, e.g. the d6's coming up 4,4,2,5 and the d10s 6 and 8? Or is your solution assuming that it doesn't matter what the results are, as long as everyone gets the same results? Because that's a slightly different use case to "predictable results". Also, in that case: is the expectation that one client would report back the result to the server for e.g. durable storage in cases where is needed? Also, does the size of the dicebox matter for the physics? Because if so, then different sizes would give different results even with the same seed, which isn't great either. |
Yep, it's this one. In most of my use-cases, the server doesn't so much care what the results of the rolls were so long as every client is seeing the same thing. Notably, I'm not trying to protect against a client reporting to the server that "I got a nat 20" every time - I just want the server to say "here's the thing to start from, all of you play the same physics simulation". So yeah, true - there's the element of "I want the server to be the source of truth for the numerical result" missing from my proposed implementation.
Yeah, I think you'd need something either designated as a "host", or have all of the clients report back and decide what the consensus mechanism is if you're worried about clients manipulating the results. I suppose you could also run the simulation on the server and have it store those results.
That's a good question, I've not dug into the code enough to know how the world's size is being generated - my working assumption is "yes" which would necessitate pinning the size of the canvas element to absolute values rather than allowing it to fill the entire screen. Should be pretty easy to test. I'm also not 100% sure if Babylon / Ammo do different things if the resolution is different. As an aside, the other way I'd thought about solving "I want everyone to see the same thing" problem is by doing |
While an interesting route to explore, each theory is seemingly being faced by more issues and doesn't seem to further the goal of this issue which is externally determined outcomes. It's probably worth splitting off your exploration into a different issue or even a PR if the drop in replacements prove fruitful. That said, if we can solve for pre-determined outcomes, then each person seeing the same thing is mostly irrelevant, as they can see the same outcomes and have their own physics get them there. Overall, the suggestion mentioned in OP seems most sound. When I get a moment I'll have a look and see if I can find any wins to that end. Another option that comes to mind is to capture the movement through the world in 3D space the first time using physics more like a 3D animation. Play that back to the canvas using the same rotated textures concept. Theoretically that would also allow for your use-case @cthos, ensuring players see the same thing and the same outcome. |
Yep, I'm doing some tinkering over in a fork, and initial results an hour in are pretty good - simply using Next up will be to futz with the various bits of the canvas and whatnot and see if the canvas size matters ... but looking through the code it looks like the actual world size / camera distance / etc are static so maybe it'll be alright. I'll keep y'all posted, but won't clutter this issue any further since I do agree that this is a different but relatedish line of thinking. |
Hey guys, |
I plan to use the feature on Game Park for board games adaptations. For my use case, the server do really care for what the result is. |
As a side note, I dug into Teal dice a bit more and found that they handle this a little differently. Their dice models use plain color textures with a text node mapped to the 3D objects' faces. After running the unrestricted simulation and seeing what number is facing up, the module then just swaps the text numbers on the 3D model itself. They do not have to calculate starting rotations. |
It's important to unplug!
And just to be clear, I agree with y'all, I'm just tinkering around with "can I get to repeatable rolls with minimal effort", and I 100% support the proposed approach here. (I can't help with that because I'd need to learn a lot more about babylon + ammo). Though, a seeded PRNG might also be useful if you wanted to do unit tests against the version where the physics engine is doing the rolling, though there's something happening that causes drift even when the inputs are predictable. |
So, I've had trouble getting deterministic rolling done in this project, but I forked Major Victory's repo to make this feature available. It may not be wise of me to have two dice-box projects, but I wanted to get something out there people could use now until I have more availability to work it out here. It also comes with dice sounds which is nice. It's still a work in progress. |
Hey @frankieali thanks for moving this forward. Any updates on your fork? Needing this feature too and evaluating options. |
How are things going and is it worth waiting for updates on this issue in the near future @frankieali ? |
Hi @Vonadise. I am working on a version 2.0 that has a number of new features. Most importantly, I'm switching the physics engine from AmmoJS to RapierJS which makes an explicit effort to implement deterministic simulations. However, progress is slow. Mostly due to lack of time availability. Sorry that things have slowed down. |
I am excited to see v2 when it's ready 👀 For anyone needing this feature now, I have been using the 3d-box threejs package and it works great! Thanks @frankieali for all the work on these libraries! |
Just chiming in with a voice of support. Super excited that you’re working on this! |
Awesome to see - this is a great library and tool for TTRPG projects and I'm excited for the direction. |
Any updates on this feature? I need all users in a room to see the same dice roll. |
@Dragg-io check out this instead: |
It has been requested that dice rolls be made with a pre-determined outcome. This way, numbers can be generated securely server side and the visual effect of the roll could then be triggered based on numbers passed over from the server.
I've looked into how this could be done by investigating Teal Dice, Dice so Nice and this thread on Reddit. Basically, the physics emulation is run once using preset vector inputs. The resulting faces are stored, then the dice are rotated to the desired start position and the 3d engine renders the dice using the same vector inputs again for the physics engine.
I was surprised at how quickly the physics engine can resolve the simulation when the time step is unrestricted. I think I'm able to speed up the AmmoJS simulation by increasing the
stepSimulation
method'ssubsteps
.Overall this would be a pretty heavy lift because I would have to change out a lot of the randomness of the core system. Currently, random values are used for the dice start positions, the dice starting rotation, and the forces used to push the dice out into the box. I think I would have to forgo using an impulse to give the dice a linear velocity. I also have a sleepTimeout for the physics bodies (calculated in real time) which would have to be accounted for (time dilated) in the emulation. I also allow a config option to space out individual die generation (also calculated in real time), which is kind of a silly option. I had to add it early on so the dice were not generated right on top of each other which would cause them to forcefully explode away from one another.
Another big difference between my system and something like Teal, is that this library allows for different dice models with different textures. The faces of the models are variable. I would have to record the rotation of each dice face from the "up" position in order to calculate the desired starting rotation of a die.
In short, this is a big feature request, but probably doable with time.
The text was updated successfully, but these errors were encountered: