Event Command Tree - the RM event equivalent of HTML DOM trees

● ARCHIVED · READ-ONLY
Started by Tsukihime 3 posts View original ↗
  1. I have a need to quickly manipulate event lists.

    I need to know where a branch starts and where a branch ends.

    For example, consider two Show Choice commands:

    eventcmdtree1.jpg
    This is how it looks as a set of event commands:



    Code:
    102 SHOW_CHOICE "yes, no"
    402 When "yes"
    0     END_BRANCH
    402 When "no"
    0     END_BRANCH
    404 END_SHOW_CHOICE
    102 SHOW_CHOICE "yes 2, no 2"
    402 when "yes 1"
    0     END_BRANCH
    402 when "no 1"
    0     END_BRANCH
    404 END_SHOW_CHOICE
    In my Large Choices script, I want to know whether the next non-choice-related command is another Show Choice command. How would you do this? You'd probably just iterate over each command, skipping any branches until you reach the matching END_SHOW_CHOICE command, and check if the next command is 102.

    Which is easy; that is how I am doing it.

    But what if you want to insert commands? Re-arrange branches? Indent entire branches?

    If I decided to put those two show choice blocks into a huge loop, I would need to iterate over all commands and increment their indents by 1. And make sure I don't indent unrelated commands.

    So instead, I convert it into a binary tree.

    The tree will be traversed in BFS, pre-order.

    All children on the right are "next" commands of the same level.

    All children on the left are branch commands.

    Converting the two show choices commands into a tree, we have

    eventcmdtree2.jpg
    Which makes sense: if you follow the right children down the tree, you will see that they are all commands with indent = 0, and all of the children on the left have indent = 1.

    This means that if I want to check whether the next non-choice-related command is 102, I can simply iterate across the right side of the tree skipping all 402, 403, and once I see a 404, I just need to check whether the next child on the right is a 102.

    Now let us revisit the case where I wanted to put the whole event in a loop.

    The loop command is composed of two codes



    Code:
    112 BEGIN LOOP
    413 END LOOP
    What if I just take my tree and move it around?

    eventcmdtree3.jpg
    First I start by adding the new commands and setting up their indents.

    Then I go through the left tree and simply recurse through all the nodes, increasing their indents by 1.

    This design makes it easy to re-arrange event commands without having to do too much parsing.

    And finally, flattening the tree is a matter of traversing it BFS pre-order and returning the resulting list of commands, which is your original command list.

    An implementation of this is provided here: http://db.tt/U6zolW7h

    This structure will likely make it much easier to manipulate event command lists. It should be developed further to make it easier to search for nodes and perform queries with various conditions.

    For example, suppose I want to know whether the next command on the same level is a Show Choice command, I might say



    Code:
    node = t.get_current_node
    if t.next_command(node, filter_list=[402,403,404]) == 102
      p "Next command, ignoring all choice branching, is another show choice command
    end
    No more need to manually iterate over all commands starting from the current command, having to deal with all of the branches and whatnot.

    Suppose I wanted to replace all comments with a particular string with a loop.

    I could run a query to return all comment nodes with that string, replace them with loop command pairs, and then take the subtrees and toss them into the loops. Ideally, this would be an effortless operation on the dev's end.

    Possibilities are endless.

    Just like how HTML DOM trees have the jquery library, we can have a library to work with this event command tree that will make it easy to manipulate events.

    And in the end, simply flatten the tree to get your event list back.

    I am thinking of writing a separate module that will provide functions to manipulate the tree, rather than writing functions directly into the tree class. Basic functions will be needed to do the actual tree-related work like indenting, re-arranging, inserting, etc.

    Oh, and what should we call the event command querying library? evQuery? Lol

    Anyone interested in developing this idea is welcome to contribute.

    I am kind of out of ideas when it comes to actually manipulating the tree.
  2. Are you thinking in terms of generating event command lists, or working with lists already generated?

    Obviously, there's two slightly different pieces of (the same) code to write here.

    I do like the idea of being able to work with event command lists in a tree format. One thing I'd do though, in the case of a loop, for instance, is to collapse the 112 and 413 into the same node of the tree.

    Perhaps one could write an EventCommandWrapper class, that by default, would just hold an event command as-is. It would only need to have a new subclass for a very small subset of the event commands: namely, all the ones dealing with flow control.

    So, you have something like this (pseudocode, just to give an idea what I mean):



    Code:
    class EventCommandWrapper
      def GetEventCommandList
        # return event command as is
      end
    end
    
    class EventCommandLoop < EventCommandWrapper
      def GetEventCommandList
        return [command112] + subtree.GetEventCommandList + [command413]
      end
    end
  3. Both, since usually when you modify a list, unless you are doing something trivial, you would have to generate new commands. Plus insert, delete, search, ... sound like standard methods that should be implemented in this kind of script.

    The wrapper idea sounds great: I pass in an event command tree, and get an event command tree back.

    Though, would I have to change how the nodes are currently implemented? Since they are just RPG::EventCommand objects extended to support pointers.

    I have not used decorators too much, but my understanding is that if I am wrapping an EventCommandTree (ECT) object, and each sub-tree is also an ECT object, then the EventCommandWrapper would inherit the ECT class so that it will be treated just like any other event command tree?