Menu

15. Dynamic state

Rhett

This engine has a dynamic state. A state is the value of all the fields in all the traits at any given moment. Since the module developer is free to add fields (key/value pairs) to new or existing traits, it follows that the state is not fixed but dynamic.

The dynamic state must be transferred to the C++ part of the engine. Since state is a Lua table, transferring the state means that C++ must have a representation of a Lua table. It is not necessary to have a complete representation, only this:

  • a field's key
  • a field's value
  • the type of the key
  • the type of the value
  • a way of representing nested tables (tables within tables)

Only those values of the table that may change are needed, so no meta values or function values.

The data type for a C++ Lua table looks like this:

class Table;

typedef std::variant<int, std::string> Leftside;
typedef std::variant<int, double, bool, std::string, Table> Rightside;

class Table : public std::map<Leftside, Rightside> {};

It is used like this:

Counter::Leftside left;
Counter::Rightside right;
Counter::Table table;


table[left] = right;

Note that the right side can be another Table (nested table).

Even if the state is dynamic the values that the C++ part need to render a counter must be fixed. This means for example that the value of the x,y coordinates of a counter must be identified. The coordinates must have a fixed position so that they may be found by the C++ part. struct State is a subset of the fields in the dynamic state.

struct State            // the subset of fields needed to render the counter/card
{
    int x;                  
    int y;
    bool moved;         // only true if trait       
    int degrees;        // only not zero if trait
    std::string image;      // name of current (flipped) image
    int zorder;         // position in a stack
                // masks
                // labels
};

These fields are assigned values from the dynamic state table. C++ needs to know where to find them.

// constructor for map

Counter::Counter(int id, Table *state)

{

    this->id = id;

    Counter::counters[this->id] = this;



    this->name = std::to_string(id);


    this->state.x = (int)std::get<double>((*state)["x"]);       
    this->state.y = (int)std::get<double>((*state)["y"]);

    Table images = std::get<Table>(std::get<Table>((*state)["Image"])["images"]);
    int index = (int)std::get<double>(std::get<Table>((*state)["Image"])["imageIndex"]);
    this->state.image = std::get<std::string>(images[index]);


    // optional fields

    if ((*state).find("MarkMoved") != (*state).end())   
        this->state.moved = std::get<bool>(std::get<Table>((*state)["MarkMoved"])["moved"]);
    else
        this->state.moved = false;

    if ((*state).find("Rotate") != (*state).end())      
    this->state.degrees = (int)std::get<double>(std::get<Table>((*state)["Rotate"])["degrees"]);
    else
    this->state.degrees = 0;

    if ((*state).find("zorder") != (*state).end())      
    this->state.zorder = (int)std::get<double>((*state)["zorder"]);
    else
    this->state.zorder = topZorder();

    .
    .
    .

Code found in a new branch here.

CPLUS_INCLUDE_PATH=/home/me/Qt/6.6.2/gcc_64/include;export CPLUS_INCLUDE_PATH

LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu:/home/me/Qt/6.6.2/gcc_64/lib;export LD_LIBRARY_PATH

g++ -Wall -o main main.cpp luau.cpp counter.cpp window.cpp frame.cpp overlay.cpp io.cpp scale.cpp -I/home/me/luau/VM/include -I/home/me/luau/Compiler/include -I/home/me/Qt/6.6.2/gcc_64/include/QtWidgets -Wl,--copy-dt-needed-entries -L/home/me/Qt/6.6.2/gcc_64/lib -lQt6Core -lQt6Widgets -L/home/me/luau -lLuau.VM -lLuau.Compiler -lLuau.Ast -lisocline