DB/WorldStateExpression: Difference between revisions

From wowdev
Jump to navigation Jump to search
mNo edit summary
 
Line 1: Line 1:
expression is a flattened AST. is hex byte strings.
{{Template:SectionBox/VersionRange|min_expansionlevel=5}}


= Expression format =
= Expression format =


* String is a hex printed byte blob.
* AST is static in terms of operands. First level is logical, second is relational, third is arithmetic, fourth is values.
* AST is static in terms of operands. First level is logical, second is relational, third is arithmetic, fourth is values.
* The first three levels are each of form <tt>value_0, operator, [value_1, operator, [value_2, operator, […]]]</tt>. The chain continues until <tt>operator</tt> is <tt>0</tt>.
* The first three levels are each of form <tt>value_0, operator, [value_1, operator, [value_2, operator, […]]]</tt>. The chain continues until <tt>operator</tt> is <tt>0</tt>.
Line 154: Line 155:
  };
  };


{{Template:Sandbox/VersionRange|min_expansionlevel=5}}


==6.0.1.18179==
==6.0.1.18179==

Latest revision as of 16:41, 5 April 2020

This section only applies to versions ≥ Mists.

Expression format

  • String is a hex printed byte blob.
  • AST is static in terms of operands. First level is logical, second is relational, third is arithmetic, fourth is values.
  • The first three levels are each of form value_0, operator, [value_1, operator, [value_2, operator, […]]]. The chain continues until operator is 0.
  • The last level, values, is either a constant, a world state id or a binary function that recursively has a value again as operands.
  • the whole expression is prefixed by a byte enabled which stops the entire thing if 0x00.

level 0: enabled

uint8_t enabled;
if (enabled) {
  LogicalLevel logical;
}

If enabled == 0, the expression evaluates to false.

level 1: logical

The first level forms a chain of value_0, operator, [value_1, operator, [value_2, operator, […]]]. The chain continues until operator is None.

struct LogicalLevel {
  RelationalLevel value_0;
  LogicalOperator op;
  if (op ≠ 0) {
    LogicalLevel value_1;
  }
};

The operations are left associative, i.e.

<value_0> 02 <value_1> 01 <value_2> 03 <value_3> 00

results in ((value_0 or value_1) and value_2) xor <value_3>.

LogicalOperator

enum LogicalOperator : uint8_t {
  None = 0,
  And = 1,
  Or = 2,
  Xor = 3,
};

level 2: relational

This level is either unary -- to degrade to top level constants -- or binary:

struct RelationalLevel {
  ArithmeticLevel lhs;
  RelationalOperator op;
  if (op ≠ 0) {
    ArithmeticLevel rhs;
  }
};

So

<lhs> 00

evaluates to lhs ≠ 0, and

<lhs> 01 <rhs>

evaluates to lhs == rhs.

RelationalOperator

enum RelationalOperator : uint8_t {
  id = 0,       // lhs; do not read rhs
  eq = 1,       // lhs = rhs
  ne = 2,       // lhs ≠ rhs
  lt = 3,       // lhs < rhs
  le = 4,       // lhs ≤ rhs
  gt = 5,       // lhs > rhs
  ge = 6,       // lhs ≥ rhs 
};

level 3: arithmetic

This level again, is either unary or binary:

struct ArithmeticLevel {
  ValueLevel lhs;
  ArithmeticOperator op;
  if (op ≠ 0) {
    ValueLevel rhs;
  }
};

If op is 0, the value of lhs is the result of the "operation".

ArithmeticOperator

enum ArithmeticOperator : uint8_t {
  id = 0,       // lhs; do not read rhs
  add = 1,      // lhs + rhs
  sub = 2,      // lhs - rhs
  mul = 3,      // lhs * rhs
  div = 4,      // rhs ≠ 0 ? (lhs / rhs) : 0
  mod = 5,      // rhs ≠ 0 ? (lhs % rhs) : 0
};

level 4…: values

The leaf level is a value: a constant, world state (i.e. variable) or a binary function of values.

struct ValueLevel {
  uint8_t type;
  switch (type) {
    case 0:
      // result = 0
      break;
    case 1:
      int32_t value;
      // result = value
      break;
    case 2:
      int32_t world_state_id;
      // result = current world state value of given state
      break;
    case 3:
      enum function_id : int {
        none = 0,                    //                            => 0
        random = 1,                  // min, max                   => random in [min, max)  
        month = 2,                   //                            => g_clientGameTime.month + 1
        day = 3,                     //                            => g_clientGameTime.day + 1
        time_of_day = 4,             //                            => g_clientGameTime.GetHourAndMinutes()   (in minutes)
        region = 5,                  //                            => CGServerInfo::regionID
        clock_hour = 6,              //                            => g_clientGameTime.hours % 12
        difficulty_id = 7,           //                            => CGGameUI::m_instanceDifficultyID ("old" id, DifficultyRec::OldEnumValue)
        holiday_start = 8,           // holiday_id, duration_id    => minutes to begin
        holiday_left = 9,            // holiday_id, duration_id    => minutes to end
        holiday_active = 10,         // holiday_id                 => 1 if any left > 0
        timer_current_time = 11,     //                            => time(nullptr)
        week_number = 12,            //                            => weeks since raid origin
        // added after 6.0.1:
        difficulty_id_new = 15,      //                            => DifficultyRec::ID
        war_mode_active = 16,        //                            => 1 if war mode currently enabled on player
        world_state_expression = 22, // world_state_expression_id  => eval (world_state_expression_id)
        keystone_affix = 23,         //                            => KeystoneAffixRec::ID
        keystone_level = 28,         //                            => 
        random_new = 33,             // max, seed                  => std::mt19937 {seed ? seed : 1}() % max + 1
        ui_widget_data = 37,         // ????????
      };
      function_id type;
      value lhs; // note: regardless of number of used arguments!
      value rhs;
      // result = fun(lhs, rhs)
      break;
    }
  }
};


6.0.1.18179

struct WorldStateExpressionRec {
  uint32_t m_ID;
  stringref m_expression;
};