Core/DataStores: Implemented WorldStateExpression

Port From (https://github.com/TrinityCore/TrinityCore/commit/548d79bb06cfba3517347070dfe606748dda55ab)
This commit is contained in:
hondacrx
2019-09-03 23:44:24 -04:00
parent 995e04b80d
commit 42d9ed78ee
9 changed files with 419 additions and 23 deletions
+81 -1
View File
@@ -1421,7 +1421,7 @@ namespace Framework.Constants
}
// PhaseUseFlags fields in different db2s
public enum PhaseUseFlagsValues : byte
public enum PhaseUseFlagsValues : byte
{
None = 0x0,
AlwaysVisible = 0x1,
@@ -1819,4 +1819,84 @@ namespace Framework.Constants
Micro = 5,
Orphan = 6
}
public enum WorldStateExpressionValueType
{
Constant = 1,
WorldState = 2,
Function = 3
}
public enum WorldStateExpressionLogic
{
None = 0,
And = 1,
Or = 2,
Xor = 3,
}
public enum WorldStateExpressionComparisonType
{
None = 0,
Equal = 1,
NotEqual = 2,
Less = 3,
LessOrEqual = 4,
Greater = 5,
GreaterOrEqual = 6,
}
public enum WorldStateExpressionOperatorType
{
None = 0,
Sum = 1,
Substraction = 2,
Multiplication = 3,
Division = 4,
Remainder = 5,
}
public enum WorldStateExpressionFunctions
{
None = 0,
Random,
Month,
Day,
TimeOfDay,
Region,
ClockHour,
OldDifficultyId,
HolidayStart,
HolidayLeft,
HolidayActive,
TimerCurrentTime,
WeekNumber,
Unk13,
Unk14,
DifficultyId,
WarModeActive,
Unk17,
Unk18,
Unk19,
Unk20,
Unk21,
WorldStateExpression,
KeystoneAffix,
Unk24,
Unk25,
Unk26,
Unk27,
KeystoneLevel,
Unk29,
Unk30,
Unk31,
Unk32,
MersenneRandom,
Unk34,
Unk35,
Unk36,
UiWidgetData,
Max,
}
}
+2 -2
View File
@@ -375,8 +375,8 @@ namespace Framework.Constants
Unk7 = 0x80,
ContestedPVP = 0x100,
InPVP = 0x200,
HideHelm = 0x400,
HideCloak = 0x800,
WarModeActive = 0x400,
WarModeDesired = 0x800,
PlayedLongTime = 0x1000,
PlayedTooLong = 0x2000,
IsOutOfBounds = 0x4000,
@@ -1080,6 +1080,9 @@ namespace Framework.Database
// WorldSafeLocs.db2
PrepareStatement(HotfixStatements.SEL_WORLD_SAFE_LOCS, "SELECT ID, AreaName, LocX, LocY, LocZ, MapID, Facing FROM world_safe_locs ORDER BY ID DESC");
PrepareStatement(HotfixStatements.SEL_WORLD_SAFE_LOCS_LOCALE, "SELECT ID, AreaName_lang FROM world_safe_locs_locale WHERE locale = ?");
// WorldStateExpression.db2
PrepareStatement(HotfixStatements.SEL_WORLD_STATE_EXPRESSION, "SELECT ID, Expression FROM world_state_expression ORDER BY ID DESC");
}
}
@@ -1628,6 +1631,8 @@ namespace Framework.Database
SEL_WORLD_SAFE_LOCS,
SEL_WORLD_SAFE_LOCS_LOCALE,
SEL_WORLD_STATE_EXPRESSION,
MAX_HOTFIXDATABASE_STATEMENTS
}
}
+78 -13
View File
@@ -640,7 +640,7 @@ namespace Game.Chat
[Command("raidreset", RBACPermissions.CommandInstanceUnbind)]
static bool HandleDebugRaidResetCommand(StringArguments args, CommandHandler handler)
{
string map_str = args.NextString();
string map_str = args.NextString();
string difficulty_str = args.NextString();
if (!int.TryParse(map_str, out int map) || map <= 0)
@@ -809,6 +809,82 @@ namespace Game.Chat
return true;
}
[CommandNonGroup("wpgps", RBACPermissions.CommandWpgps)]
static bool HandleWPGPSCommand(StringArguments args, CommandHandler handler)
{
Player player = handler.GetSession().GetPlayer();
Log.outInfo(LogFilter.SqlDev, "(@PATH, XX, {0}, {1}, {2}, 0, 0, 0, 100, 0),", player.GetPositionX(), player.GetPositionY(), player.GetPositionZ());
handler.SendSysMessage("Waypoint SQL written to SQL Developer log");
return true;
}
[Command("worldstate", RBACPermissions.CommandDebug)]
static bool HandleDebugWorldStateCommand(StringArguments args, CommandHandler handler)
{
if (args.Empty())
return false;
string worldStateIdStr = args.NextString();
string valueStr = args.NextString();
if (worldStateIdStr.IsEmpty())
return false;
Player target = handler.getSelectedPlayerOrSelf();
if (target == null)
{
handler.SendSysMessage(CypherStrings.PlayerNotFound);
return false;
}
uint worldStateId = uint.Parse(worldStateIdStr);
uint value = valueStr.IsEmpty() ? 0 : uint.Parse(valueStr);
if (value != 0)
{
Global.WorldMgr.setWorldState(worldStateId, value);
target.SendUpdateWorldState(worldStateId, value);
}
else
handler.SendSysMessage($"Worldstate {worldStateId} actual value : {Global.WorldMgr.getWorldState(worldStateId)}");
return true;
}
[Command("wsexpression", RBACPermissions.CommandDebug)]
static bool HandleDebugWSExpressionCommand(StringArguments args, CommandHandler handler)
{
if (args.Empty())
return false;
string expressionIdStr = args.NextString();
if (expressionIdStr.IsEmpty())
return false;
uint expressionId = uint.Parse(expressionIdStr);
Player target = handler.getSelectedPlayerOrSelf();
if (target == null)
{
handler.SendSysMessage(CypherStrings.PlayerNotFound);
return false;
}
WorldStateExpressionRecord wsExpressionEntry = CliDB.WorldStateExpressionStorage.LookupByKey(expressionId);
if (wsExpressionEntry == null)
return false;
if (ConditionManager.IsPlayerMeetingExpression(target, wsExpressionEntry))
handler.SendSysMessage($"Expression {expressionId} meet");
else
handler.SendSysMessage($"Expression {expressionId} not meet");
return true;
}
[CommandGroup("send", RBACPermissions.CommandDebugSend)]
class SendCommands
{
@@ -948,7 +1024,7 @@ namespace Game.Chat
if (args.Empty())
return false;
if (!byte.TryParse(args.NextString(), out byte failNum) ||failNum == 0)
if (!byte.TryParse(args.NextString(), out byte failNum) || failNum == 0)
return false;
int failArg1 = args.NextInt32();
@@ -1066,16 +1142,5 @@ namespace Game.Chat
return true;
}
}
[CommandNonGroup("wpgps", RBACPermissions.CommandWpgps)]
static bool HandleWPGPSCommand(StringArguments args, CommandHandler handler)
{
Player player = handler.GetSession().GetPlayer();
Log.outInfo(LogFilter.SqlDev, "(@PATH, XX, {0}, {1}, {2}, 0, 0, 0, 100, 0),", player.GetPositionX(), player.GetPositionY(), player.GetPositionZ());
handler.SendSysMessage("Waypoint SQL written to SQL Developer log");
return true;
}
}
}
+234 -1
View File
@@ -26,6 +26,7 @@ using Game.Spells;
using System;
using System.Collections.Generic;
using System.Linq;
using Framework.IO;
namespace Game
{
@@ -1946,7 +1947,17 @@ namespace Game
}
// TODO: time condition
// TODO (or not): world state expression condition
if (condition.WorldStateExpressionID != 0)
{
var worldStateExpression = CliDB.WorldStateExpressionStorage.LookupByKey(condition.WorldStateExpressionID);
if (worldStateExpression == null)
return false;
if (!IsPlayerMeetingExpression(player, worldStateExpression))
return false;
}
// TODO: weather condition
if (condition.Achievement[0] != 0)
@@ -2034,6 +2045,228 @@ namespace Game
return true;
}
public static bool IsPlayerMeetingExpression(Player player, WorldStateExpressionRecord expression)
{
ByteBuffer buffer = new ByteBuffer(expression.Expression.ToByteArray());
if (buffer.GetSize() == 0)
return false;
bool enabled = buffer.ReadBool();
if (!enabled)
return false;
bool finalResult = EvalRelOp(buffer, player);
WorldStateExpressionLogic resultLogic = (WorldStateExpressionLogic)buffer.ReadUInt8();
while (resultLogic != WorldStateExpressionLogic.None)
{
bool secondResult = EvalRelOp(buffer, player);
switch (resultLogic)
{
case WorldStateExpressionLogic.And:
finalResult = finalResult && secondResult;
break;
case WorldStateExpressionLogic.Or:
finalResult = finalResult || secondResult;
break;
case WorldStateExpressionLogic.Xor:
finalResult = finalResult != secondResult;
break;
default:
break;
}
if (buffer.GetCurrentStream().Position < buffer.GetSize())
break;
resultLogic = (WorldStateExpressionLogic)buffer.ReadUInt8();
}
return finalResult;
}
static int EvalSingleValue(ByteBuffer buffer, Player player)
{
WorldStateExpressionValueType valueType = (WorldStateExpressionValueType)buffer.ReadUInt8();
int value = 0;
switch (valueType)
{
case WorldStateExpressionValueType.Constant:
{
value = buffer.ReadInt32();
break;
}
case WorldStateExpressionValueType.WorldState:
{
uint worldStateId = buffer.ReadUInt32();
value = (int)Global.WorldMgr.getWorldState(worldStateId);
break;
}
case WorldStateExpressionValueType.Function:
{
var functionType = (WorldStateExpressionFunctions)buffer.ReadUInt32();
int arg1 = EvalSingleValue(buffer, player);
int arg2 = EvalSingleValue(buffer, player);
if (functionType >= WorldStateExpressionFunctions.Max)
return 0;
value = WorldStateExpressionFunction(functionType, player, arg1, arg2);
break;
}
default:
break;
}
return value;
}
static int WorldStateExpressionFunction(WorldStateExpressionFunctions functionType, Player player, int arg1, int arg2)
{
switch (functionType)
{
case WorldStateExpressionFunctions.Random:
return (int)RandomHelper.URand(Math.Min(arg1, arg2), Math.Max(arg1, arg2));
case WorldStateExpressionFunctions.Month:
return GameTime.GetDateAndTime().Month + 1;
case WorldStateExpressionFunctions.Day:
return GameTime.GetDateAndTime().Day + 1;
case WorldStateExpressionFunctions.TimeOfDay:
DateTime localTime = GameTime.GetDateAndTime();
return localTime.Hour * Time.Minute + localTime.Minute;
case WorldStateExpressionFunctions.Region:
return Global.WorldMgr.GetRealmId().Region;
case WorldStateExpressionFunctions.ClockHour:
int currentHour = GameTime.GetDateAndTime().Hour + 1;
return currentHour <= 12 ? (currentHour != 0 ? currentHour : 12) : currentHour - 12;
case WorldStateExpressionFunctions.OldDifficultyId:
var difficulty = CliDB.DifficultyStorage.LookupByKey(player.GetMap().GetDifficultyID());
if (difficulty != null)
return difficulty.OldEnumValue;
return -1;
case WorldStateExpressionFunctions.HolidayActive:
return Global.GameEventMgr.IsHolidayActive((HolidayIds)arg1) ? 1 : 0;
case WorldStateExpressionFunctions.TimerCurrentTime:
return (int)GameTime.GetGameTime();
case WorldStateExpressionFunctions.WeekNumber:
long now = GameTime.GetGameTime();
uint raidOrigin = 1135695600;
Cfg_RegionsRecord region = CliDB.CfgRegionsStorage.LookupByKey(Global.WorldMgr.GetRealmId().Region);
if (region != null)
raidOrigin = region.Raidorigin;
return (int)(now - raidOrigin) / Time.Week;
case WorldStateExpressionFunctions.DifficultyId:
return (int)player.GetMap().GetDifficultyID();
case WorldStateExpressionFunctions.WarModeActive:
return player.HasPlayerFlag(PlayerFlags.WarModeActive) ? 1 : 0;
case WorldStateExpressionFunctions.WorldStateExpression:
var worldStateExpression = CliDB.WorldStateExpressionStorage.LookupByKey(arg1);
if (worldStateExpression != null)
return IsPlayerMeetingExpression(player, worldStateExpression) ? 1 : 0;
return 0;
case WorldStateExpressionFunctions.MersenneRandom:
if (arg1 == 1)
return 1;
//todo fix me
// init with predetermined seed
//std::mt19937 mt(arg2? arg2 : 1);
//value = mt() % arg1 + 1;
return 0;
case WorldStateExpressionFunctions.None:
case WorldStateExpressionFunctions.HolidayStart:
case WorldStateExpressionFunctions.HolidayLeft:
case WorldStateExpressionFunctions.Unk13:
case WorldStateExpressionFunctions.Unk14:
case WorldStateExpressionFunctions.Unk17:
case WorldStateExpressionFunctions.Unk18:
case WorldStateExpressionFunctions.Unk19:
case WorldStateExpressionFunctions.Unk20:
case WorldStateExpressionFunctions.Unk21:
case WorldStateExpressionFunctions.KeystoneAffix:
case WorldStateExpressionFunctions.Unk24:
case WorldStateExpressionFunctions.Unk25:
case WorldStateExpressionFunctions.Unk26:
case WorldStateExpressionFunctions.Unk27:
case WorldStateExpressionFunctions.KeystoneLevel:
case WorldStateExpressionFunctions.Unk29:
case WorldStateExpressionFunctions.Unk30:
case WorldStateExpressionFunctions.Unk31:
case WorldStateExpressionFunctions.Unk32:
case WorldStateExpressionFunctions.Unk34:
case WorldStateExpressionFunctions.Unk35:
case WorldStateExpressionFunctions.Unk36:
case WorldStateExpressionFunctions.UiWidgetData:
default:
return 0;
}
}
static int EvalValue(ByteBuffer buffer, Player player)
{
int leftValue = EvalSingleValue(buffer, player);
WorldStateExpressionOperatorType operatorType = (WorldStateExpressionOperatorType)buffer.ReadUInt8();
if (operatorType == WorldStateExpressionOperatorType.None)
return leftValue;
int rightValue = EvalSingleValue(buffer, player);
switch (operatorType)
{
case WorldStateExpressionOperatorType.Sum:
return leftValue + rightValue;
case WorldStateExpressionOperatorType.Substraction:
return leftValue - rightValue;
case WorldStateExpressionOperatorType.Multiplication:
return leftValue * rightValue;
case WorldStateExpressionOperatorType.Division:
return rightValue == 0 ? 0 : leftValue / rightValue;
case WorldStateExpressionOperatorType.Remainder:
return rightValue == 0 ? 0 : leftValue % rightValue;
default:
break;
}
return leftValue;
}
static bool EvalRelOp(ByteBuffer buffer, Player player)
{
int leftValue = EvalValue(buffer, player);
WorldStateExpressionComparisonType compareLogic = (WorldStateExpressionComparisonType)buffer.ReadUInt8();
if (compareLogic == WorldStateExpressionComparisonType.None)
return leftValue != 0;
int rightValue = EvalValue(buffer, player);
switch (compareLogic)
{
case WorldStateExpressionComparisonType.Equal:
return leftValue == rightValue;
case WorldStateExpressionComparisonType.NotEqual:
return leftValue != rightValue;
case WorldStateExpressionComparisonType.Less:
return leftValue < rightValue;
case WorldStateExpressionComparisonType.LessOrEqual:
return leftValue <= rightValue;
case WorldStateExpressionComparisonType.Greater:
return leftValue > rightValue;
case WorldStateExpressionComparisonType.GreaterOrEqual:
return leftValue >= rightValue;
default:
break;
}
return false;
}
Dictionary<ConditionSourceType, MultiMap<uint, Condition>> ConditionStore = new Dictionary<ConditionSourceType, MultiMap<uint, Condition>>();
MultiMap<uint, Condition> ConditionReferenceStore = new MultiMap<uint, Condition>();
Dictionary<uint, MultiMap<uint, Condition>> VehicleSpellConditionStore = new Dictionary<uint, MultiMap<uint, Condition>>();
+4
View File
@@ -63,6 +63,7 @@ namespace Game.DataStorage
BattlePetSpeciesStateStorage = DBReader.Read<BattlePetSpeciesStateRecord>("BattlePetSpeciesState.db2", HotfixStatements.SEL_BATTLE_PET_SPECIES_STATE);
BattlemasterListStorage = DBReader.Read<BattlemasterListRecord>("BattlemasterList.db2", HotfixStatements.SEL_BATTLEMASTER_LIST, HotfixStatements.SEL_BATTLEMASTER_LIST_LOCALE);
BroadcastTextStorage = DBReader.Read<BroadcastTextRecord>("BroadcastText.db2", HotfixStatements.SEL_BROADCAST_TEXT, HotfixStatements.SEL_BROADCAST_TEXT_LOCALE);
CfgRegionsStorage = DBReader.Read<Cfg_RegionsRecord>("Cfg_Regions.db2", HotfixStatements.SEL_CFG_REGIONS);
CharacterFacialHairStylesStorage = DBReader.Read<CharacterFacialHairStylesRecord>("CharacterFacialHairStyles.db2", HotfixStatements.SEL_CHARACTER_FACIAL_HAIR_STYLES);
CharBaseSectionStorage = DBReader.Read<CharBaseSectionRecord>("CharBaseSection.db2", HotfixStatements.SEL_CHAR_BASE_SECTION);
CharSectionsStorage = DBReader.Read<CharSectionsRecord>("CharSections.db2", HotfixStatements.SEL_CHAR_SECTIONS);
@@ -273,6 +274,7 @@ namespace Game.DataStorage
WorldEffectStorage = DBReader.Read<WorldEffectRecord>("WorldEffect.db2", HotfixStatements.SEL_WORLD_EFFECT);
WorldMapOverlayStorage = DBReader.Read<WorldMapOverlayRecord>("WorldMapOverlay.db2", HotfixStatements.SEL_WORLD_MAP_OVERLAY);
WorldSafeLocsStorage = DBReader.Read<WorldSafeLocsRecord>("WorldSafeLocs.db2", HotfixStatements.SEL_WORLD_SAFE_LOCS, HotfixStatements.SEL_WORLD_SAFE_LOCS_LOCALE);
WorldStateExpressionStorage = DBReader.Read<WorldStateExpressionRecord>("WorldStateExpression.db2", HotfixStatements.SEL_WORLD_STATE_EXPRESSION);
Global.DB2Mgr.LoadStores();
@@ -406,6 +408,7 @@ namespace Game.DataStorage
public static DB6Storage<BattlePetSpeciesStateRecord> BattlePetSpeciesStateStorage;
public static DB6Storage<BattlemasterListRecord> BattlemasterListStorage;
public static DB6Storage<BroadcastTextRecord> BroadcastTextStorage;
public static DB6Storage<Cfg_RegionsRecord> CfgRegionsStorage;
public static DB6Storage<CharacterFacialHairStylesRecord> CharacterFacialHairStylesStorage;
public static DB6Storage<CharBaseSectionRecord> CharBaseSectionStorage;
public static DB6Storage<CharSectionsRecord> CharSectionsStorage;
@@ -616,6 +619,7 @@ namespace Game.DataStorage
public static DB6Storage<WorldEffectRecord> WorldEffectStorage;
public static DB6Storage<WorldMapOverlayRecord> WorldMapOverlayStorage;
public static DB6Storage<WorldSafeLocsRecord> WorldSafeLocsStorage;
public static DB6Storage<WorldStateExpressionRecord> WorldStateExpressionStorage;
#endregion
#region GameTables
@@ -75,4 +75,10 @@ namespace Game.DataStorage
public ushort MapID;
public float Facing;
}
public sealed class WorldStateExpressionRecord
{
public uint Id;
public string Expression;
}
}
@@ -121,12 +121,6 @@ namespace Game.Network.Packets
if (atLoginFlags.HasAnyFlag(AtLoginFlags.Resurrect))
playerFlags &= ~PlayerFlags.Ghost;
if (playerFlags.HasAnyFlag(PlayerFlags.HideHelm))
Flags |= CharacterFlags.HideHelm;
if (playerFlags.HasAnyFlag(PlayerFlags.HideCloak))
Flags |= CharacterFlags.HideCloak;
if (playerFlags.HasAnyFlag(PlayerFlags.Ghost))
Flags |= CharacterFlags.Ghost;
+9
View File
@@ -12,6 +12,8 @@ public class GameTime
static DateTime _gameTimeSystemPoint = DateTime.MinValue;
static DateTime _gameTimeSteadyPoint = DateTime.MinValue;
static DateTime _dateTime;
public static long GetStartTime()
{
return StartTime;
@@ -42,11 +44,18 @@ public class GameTime
return (uint)(_gameTime - StartTime);
}
public static DateTime GetDateAndTime()
{
return _dateTime;
}
public static void UpdateGameTimers()
{
_gameTime = Time.UnixTime;
_gameMSTime = Time.GetMSTime();
_gameTimeSystemPoint = DateTime.Now;
_gameTimeSteadyPoint = DateTime.Now;
_dateTime = Time.UnixTimeToDateTime(_gameTime);
}
}