Advice on best solution for mod: ensuring id_msg is sent during "Preview" action

Started by skyschemer, July 05, 2019, 04:19:18 PM

Previous topic - Next topic

skyschemer

I am working on a dice rolling mod for RPG games. Yes, there is one already, but it has issues: namely, you can't preview the results, and you effectively can't edit a post afterwards (as an anti-tempering mechanism) since it saves the dice roll result in BBCode and alters the BBCode on an edit.

My approach is to generate a pseudorandom seed using a repeatable (determininstic) algorithm when a member makes a new post, and then store that seed and its associated message id (id_msg column from {dbprefix}messages) in the database. Then I can store the dice roll as BBCode and regenerate the same random number sequence dynamically when the message is viewed and even edited, so dice rolls don't change. This works.

My quandry

I had to insert a few bits of code into the Source since SMF 2.0.x (I am on 2.0.15) doesn't have per-post/per-message context hooks. This also works...except for when you modify an existing post, and then hit preview. When you first modify a post, $context['destination'] is set in order to properly define the action for the "Save" button...but that destination info is not part of $_REQUEST if you hit "Preview".

So what happens is, the goes to user modify their old post, hits "Preview" to preview the results before saving, and the id_msg association is lost. The dice roller then thinks it's a new post because there's no message id and it generates a new random seed. As a result, the dice roll preview results end up being wrong. Saving works, it's just preview that's broken.

My solution so far

My answer to this was to set a 'msg' key in $context before a preview is generated, and then...to modify Themes/default/Post.template.php and insert the 'msg' parameter with the message ID into the query string, thus ensuring the "preview" action sends id_msg to the page update.

Here's the specific modification to the template from the install XML:

        <file name="$themedir/Post.template.php">
                <operation>
                        <search position="after"><![CDATA[
                                        sendXMLDocument(smf_prepareScriptUrl]]></search>
                        <add><![CDATA[
                                        ';
                // RPG Dice Roller: Add the msg id as a parameter if it's set.
                if (array_key_exists('msg', $context)) {
                        echo '
                                        x[x.length] = \'msg=\' + parseInt(', $context['msg'], ');
                                        ';
                }
                echo '
]]></add>
                </operation>
        </file>


What I don't know is whether this is a good idea. Part of me says it's not a great approach, but ... do people really override Post.template.php in their themes?

What I also don't know is if there's a better way to do this. This section of the code is not so easy to follow because it's complicated. :) That's not intended to be a criticism, just an admission that I don't have a full grasp of it yet. I can't see any other obvious way to pass that message ID parameter in the query. And it has to get passed as part of the query, as that's the only way the PHP code can figure out the message ID associated with the preview.

Any suggestions for a better approach?

Sesquipedalian

I'm on my phone at the moment, so this is just from memory and may be incorrect, but I believe $_REQUEST['msg'] will be set when previewing edits to an existing message. That should contain the value of id_msg.

If my memory is mistaken and that doesn't work, then another option would be to simply output some placeholder text when previewing instead of executing the code you use to generate a dice roll.
I promise you nothing.

Sesqu... Sesqui... what?
Sesquipedalian, the best word in the English language.

skyschemer

Quote from: Sesquipedalian on July 06, 2019, 12:17:32 PM
I'm on my phone at the moment, so this is just from memory and may be incorrect, but I believe $_REQUEST['msg'] will be set when previewing edits to an existing message.

It's not. Or rather, there are some circumstances where it is, and some where it's not. Again, not an expert on the code, but sometimes a full request is sent which results in a page reload, and sometimes an AJAX request is sent that does a partial load. It's the latter that does not include a 'msg' parameter.

I've seen similar behavior when modifying a message inline from the topic listing instead of using "Modify" to edit a post on its own page.

Quoteanother option would be to simply output some placeholder text

Alas, that's not a viable option as it prevents previewing the dice roll on a new post, too.

Sesquipedalian

In that case, your best options are either to do what you already thought of, or to use placeholder text.

If you stick with the first option (i.e. appending a parameter to the query), I suggest that you use a custom parameter name instead of 'msg', since SMF itself uses that parameter and makes decisions based on it. Something like 'diceid' would be fine.
I promise you nothing.

Sesqu... Sesqui... what?
Sesquipedalian, the best word in the English language.

skyschemer

Quote from: Sesquipedalian on July 06, 2019, 12:36:16 PMIf you stick with the first option (i.e. appending a parameter to the query), I suggest that you use a custom parameter name instead of 'msg', since SMF itself uses that parameter and makes decisions based on it.

This is very helpful. Thank you!

skyschemer

Quote from: skyschemer on July 06, 2019, 12:24:59 PM
I've seen similar behavior when modifying a message inline from the topic listing instead of using "Modify" to edit a post on its own page.

Turns out this was a different issue. When you do a quick modify, the msg ID is sent in the request but on the server side the message seems to be loaded and then parsed twice. Because the same message twice looks like one message to the dice seed routine, what I had to do was check $context['current_action']. If it's set to 'jsmodify', then only seed the PRNG if $context['sub_template'] is set to 'modifydone'.

Sesquipedalian

I promise you nothing.

Sesqu... Sesqui... what?
Sesquipedalian, the best word in the English language.

Advertisement: