seastan / dragncards

Multiplayer online card game platform written in Elixir, Phoenix, and React. Drag and Drop provided by React-Beautiful-DND.
https://dragncards.com/
79 stars 41 forks source link

Passive rule problem and game_old bug in general #106

Open morvael opened 1 month ago

morvael commented 1 month ago

Passive rules use game_old state (alongside game_new state) to determine whether they should turn on (moving from false evaluation of their condition in game_old state to true evaluation in game_new state) or turn off (moving from true evaluation of their condition in game_old state to false evaluation in game_new state). However game_old state may be incorrect for the moment the check runs, because it may have been superseded by state changes caused by nested reactions. So the game uses very old game_old state in the outer level reaction, oblivious to the fact that there's completely new game_new state and thus previous game_new state should be demoted to current game_old state. I think the example below explains it:

(a passive rule R requires property X to have value A)
property X has value A, so passive rule is "on"
property X is set to value B
automation runs
    trigger rule S listening to property X reacts
        trigger rule S sets property X to value C
            automation runs
                passive rule R listening to property X reacts
                    passive rule R runs offDo
            automation ends
    passive rule R listening to property X reacts
        passive rule R runs offDo
automation ends
morvael commented 1 month ago

I don't think the goal of passive rules was to run onDo or offDo 2+ times in sucession if there are nested changes to the same property, but maybe I'm wrong? Because it's kind of giving unbalanced calls, and rules like this should imho be balanced.

morvael commented 1 month ago

Perhaps the solution is to stop processing further listeners if the value changes in nested reactions? Because it makes no sense to react to value being set to previous value if you have already reacted to it being set to newer value. So now you're reacting to old event that is no longer true.