DB/WorldStateExpression: Difference between revisions

From wowdev
Jump to navigation Jump to search
mNo edit summary
mNo edit summary
 
(6 intermediate revisions by the same user not shown)
Line 1: Line 1:
expression is a flattened AST. is bytewise.
{{Template:SectionBox/VersionRange|min_expansionlevel=5}}


  enum arith_operand {
= Expression format =
   id = 0,       // lhs; DO NOT READ RHS
 
   add = 1,     // lhs + rhs
* String is a hex printed byte blob.
   sub = 2,     // lhs - rhs
* AST is static in terms of operands. First level is logical, second is relational, third is arithmetic, fourth is values.
   mul = 3,     // lhs * rhs
* 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>.
   div = 4,      // rhs ≠ 0 ? (lhs / rhs) : 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.
  mod = 5,     // rhs ≠ 0 ? (lhs % rhs) : 0
* the whole expression is prefixed by a byte <tt>enabled</tt> which stops the entire thing if <tt>0x00</tt>.
 
== level 0: enabled ==
 
  uint8_t enabled;
if (enabled) {
   LogicalLevel logical;
}
 
If <tt>enabled == 0</tt>, the expression evaluates to <tt>false</tt>.
 
== level 1: logical ==
 
The first level forms a chain of <tt>value_0, operator, [value_1, operator, [value_2, operator, […]]]</tt>. The chain continues until <tt>operator</tt> is <tt>None</tt>.
 
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 <tt>((value_0 or value_1) and value_2) xor <value_3></tt>.
 
=== 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;
  }
  };
  };


  enum log_operand {
So
   id = 0,      // lhs; do not read rhs?
 
<lhs> 00
 
evaluates to <tt>lhs ≠ 0</tt>, and
 
<lhs> 01 <rhs>
 
evaluates to <tt>lhs == rhs</tt>.
 
=== RelationalOperator ===
 
  enum RelationalOperator : uint8_t {
   id = 0,      // lhs; do not read rhs
   eq = 1,      // lhs = rhs
   eq = 1,      // lhs = rhs
   ne = 2,      // lhs ≠ rhs
   ne = 2,      // lhs ≠ rhs
Line 20: Line 79:
  };
  };


  struct value {
== level 3: arithmetic ==
   char type;
 
This level again, is either unary or binary:
 
  struct ArithmeticLevel {
  ValueLevel lhs;
  ArithmeticOperator op;
  if (op ≠ 0) {
    ValueLevel rhs;
  }
};
 
If <tt>op</tt> is 0, the value of <tt>lhs</tt> 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) {
   switch (type) {
    case 0:
      // result = 0
      break;
     case 1:
     case 1:
       int value;
       int32_t value;
       // result = value
       // result = value
       break;
       break;
     case 2:
     case 2:
       int world_state_id;
       int32_t world_state_id;
       // result = current world state value of given state
       // result = current world state value of given state
       break;
       break;
     case 3:
     case 3:
       enum function_id {
       enum function_id : int {
         none = 0,                 //                         => 0
         none = 0,                   //                           => 0
         random = 1,               // min, max                 => random in [min, max)   
         random = 1,                 // min, max                   => random in [min, max)   
         month = 2,               //                         => g_clientGameTime.month + 1
         month = 2,                   //                           => g_clientGameTime.month + 1
         day = 3,                 //                         => g_clientGameTime.day + 1
         day = 3,                     //                           => g_clientGameTime.day + 1
         time_of_day = 4,         //                         => g_clientGameTime.GetHourAndMinutes()  (in minutes)
         time_of_day = 4,             //                           => g_clientGameTime.GetHourAndMinutes()  (in minutes)
         region = 5,               //                         => CGServerInfo::regionID
         region = 5,                 //                           => CGServerInfo::regionID
         clock_hour = 6,           //                         => g_clientGameTime.hours % 12
         clock_hour = 6,             //                           => g_clientGameTime.hours % 12
         difficulty_id = 7,       //                         => CGGameUI::m_instanceDifficultyID
         difficulty_id = 7,           //                           => CGGameUI::m_instanceDifficultyID ("old" id, {{DBField|table=Difficulty|column=OldEnumValue}})
         holiday_start = 8,       // holiday_id, duration_id => minutes to begin
         holiday_start = 8,           // holiday_id, duration_id   => minutes to begin
         holiday_left = 9,         // holiday_id, duration_id => minutes to end
         holiday_left = 9,           // holiday_id, duration_id   => minutes to end
         holiday_active = 10,     // holiday_id               => 1 if any left > 0
         holiday_active = 10,         // holiday_id                 => 1 if any left > 0
         timer_current_time = 11, //                         => time(nullptr)
         timer_current_time = 11,     //                           => time(nullptr)
         week_number = 12,         //                         => weeks since raid origin
         week_number = 12,           //                           => weeks since raid origin
        // added after 6.0.1:
        difficulty_id_new = 15,      //                            => {{DBField|table=Difficulty|column=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,        //                            => {{Unverified|{{DBField|table=KeystoneAffix|column=ID}}}}
        keystone_level = 28,        //                            =>
        random_new = 33,            // max, seed                  => std::mt19937 {seed ? seed : 1}() % max + 1
        ui_widget_data = 37,        // ????????
       };
       };
       function_id type;
       function_id type;
Line 56: Line 155:
  };
  };


First is enabled == always 1. then, operand {0 (disabled), 1 (uint32), 2 (worldStateID (evals to something other than id, likely something in worldStateRec)), 3 (uint8 op, recurse left, recurse right;  where op <=0xc: none, random, month, day, timeofday, region, clockHour, difficultyID, holidayStart, holidayLeft, holidayActive, currentTime, weeknumber)}, then op {1: +, 2:-, 3:*, 4*/, 5:%, 0: no op}, then op2 {…. See CGWorldStateInfo::EvalWorldStateExpression.
{{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;
};