Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

[API] sendChat() returns bad results to callback with rollable tables expressions with inline rolls.

September 08 (6 years ago)
The Aaron
Pro
API Scripter

Given an expression comprised of the following in this order:

  • (Group A) Some number of dice rolls [[ XdX ]], minimum 1
  • (Group B) Some number of rollable table expressions with an inline roll [[ [[XdX]]t[table] ]], minimum 1
  • (Group C) Some number of rollable table expressions without an inline roll [[ Xt[table] ]], minimum 1

There is a high probability that the returned message contents will have some $[[X]] markers replaced with 0 and the first item in Group B with an incorrect $[[X]] index.  The larger the number of entries in Group A, the more likely the event is to occur.  With 9 entries in Group A, I haven't seen it not result in failure.

Example:

 

Incidentally, during my testing at one point I received this API error:

There was an error communicating with the QuantumRoll server. undefined


Here is a reproduction script that will generate the error fairly consistently.  It has quite a few test cases of varying complexity.  Currently, it only shows failures, but you can uncomment line 102 to also see successes: 
on('ready',()=>{

    assureTestTable = ()=>{
        let t = findObjs({
            type: 'rollabletable',
            name: 'test-table'
        })[0];
        if(!t){
            t = createObj('rollabletable',{
                name: 'test-table'
            });
            createObj('tableitem',{
                rollabletableid: t.id,
                name: 'table-row'
            });
        }
    };

    const U = (t) => t.replace(/\[/g,`${'&'}lbrack;`).replace(/\]/g,`${'&'}rbrack;`);
    const S = (t) => `<div style="display:inline-block;border: 1px solid #00cc00; border-radius: 1em; background-color: #006600; padding: .25em;font-weight:bold;color:white;">${t}</div>`;
    const F = (t) => `<div style="display:inline-block;border: 1px solid #cc0000; border-radius: 1em; background-color: #660000; padding: .25em;font-weight:bold;color:white;">${t}</div>`;
    const B = (t) => `<div style="padding: .25em; border: 1px solid black; border-radius: .25em; margin: .25em;">${t}</div>`;
    const E = (t) => `<span style="color: #990000;">${t}</span>`;

    const cases = [
            {
              msg: "[[1d6]] [[[[1d8]]t[test-table]]]",
              rolls: 2
            },
            {
              msg: "[[1t[test-table]]] [[[[1d8]]t[test-table]]] [[1t[test-table]]]",
              rolls: 3
            },
            {
              msg: "[[[[1d8]]t[test-table]]] [[1t[test-table]]]",
              rolls: 2
            },
            {
              msg: "[[[[[[[[1d3]]d6]]d8]]t[test-table]]]",
              rolls: 1
            },
            {
              msg: "[[[[[[1d6]]d8]]t[test-table]]]",
              rolls: 1
            },
            {
              msg: "[[[[1d8]]t[test-table]]]",
              rolls: 1
            },
            {
              msg: "[[1d6]] [[1t[test-table]]] [[1t[test-table]]]",
              rolls: 3
            },
            
            {
              msg: "[[1d6]] [[[[1d8]]t[test-table]]] [[1t[test-table]]]",
              rolls: 3
            },
            {
              msg: "[[1d8]] [[1d6]] [[[[1d2]]t[test-table]]] [[1t[test-table]]]",
              rolls: 4
            },
            {
              msg: "[[1d8]] [[1d6]] [[1t[test-table]]] [[[[1d2]]t[test-table]]]",
              rolls: 4
            },
            {
              msg: "[[1t[test-table]]] [[1d6]] [[1t[test-table]]] [[[[1d2]]t[test-table]]]",
              rolls: 4
            },
            {
              msg: "[[1d8]] [[1d6]] [[1t[test-table]]] [[[[1d2]]t[test-table]]] [[1t[test-table]]]",
              rolls: 5
            },
            {
              msg: "[[1d8]] [[1d6]] [[1d3]] [[[[1d2]]t[test-table]]] [[1t[test-table]]]",
              rolls: 5
            },
            {
              msg: "[[1d8]] [[1d6]] [[1d3]] [[1d8]] [[1d6]] [[1d3]] [[1d8]] [[1d6]] [[1d3]] [[[[1d2]]t[test-table]]] [[1t[test-table]]] [[1t[test-table]]] [[1t[test-table]]]",
              rolls:13 
            },
            {
              msg: "[[1d8]] [[1d6]] [[1d3]] [[1d8]] [[1d6]] [[1d3]] [[1d8]] [[1d6]] [[1d3]] [[[[1d2]]t[test-table]]] [[[[1d1]]t[test-table]]]",
              rolls:11 
            },
            {
              msg: "[[1d8]] [[1d6]] [[1d3]] [[[[1d2]]t[test-table]]] [[1t[test-table]]] [[1t[test-table]]]",
              rolls: 6
            },
            {
              msg: "[[1d8]] [[1d6]] [[1d3]] [[[[1d2]]t[test-table]]] [[[[1d3]]t[test-table]]] [[1t[test-table]]]",
              rolls: 6
            }
    ];

    const checkCase = (c,msg) => {
        let match = msg.content.match(/\$\[\[\d+\]\]/g);
        if(match.length !== c.rolls){
            sendChat('',B(`${E(`${F('Failure')}: Expected ${c.rolls} markers, found ${match.length}`)}<br><code>${U(c.msg)}</code><br><code>${msg.content}</code>`));
        } else {
            //sendChat('',B(`${S('Success')}: <code>${U(c.msg)}</code><br><code>${U(msg.content)}</code>`));
        }
    };

    on('chat:message', (msg)=>{
        if('api' === msg.type && /^!test\b/i.test(msg.content)) {
            sendChat('','<div style="text-align: center;background-color: #ffcccc;font-weight:bold;font-size:1.5em;border-bottom: 3px solid red;padding: .25em;">Begin Test Battery</div>');
            cases.forEach((c) => {
                sendChat('',c.msg,(res) => checkCase(c,res[0]));
            });
        }
    });



    assureTestTable();
    sendChat('TestRollableTable', 'Use <code>!test</code> to test');
});

It will create the table it needs and print instructions.  Run the API command !test to run the test cases.

Sample output:


September 08 (6 years ago)
The Aaron
Pro
API Scripter

Original discussion: https://app.roll20.net/forum/post/6773749/recursivetable-macro-returns-0-randomly

September 08 (6 years ago)
The Aaron
Pro
API Scripter

Possibly related to this bug: https://app.roll20.net/forum/post/2466383/bug-api-groups-of-complex-inline-rolls-are-not-properly-handled-by-sendchat


September 08 (6 years ago)
The Aaron
Pro
API Scripter

Possibly related to this bug: https://app.roll20.net/forum/post/2217884/api-regressions-for-inline-dice-expression-in-the-sendchat-api-function#post-2486312

September 08 (6 years ago)
Drespar
Roll20 Team

Hi Aaron! :)

Thank you for all of this information, I have submitted a ticket to the devs so they can take a closer look.