1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Added list support to conditions

This commit is contained in:
SpoinkyNL 2017-09-05 11:49:40 +02:00
parent 04e5943996
commit 681ce58c1e
5 changed files with 290 additions and 64 deletions

View File

@ -1,7 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using Artemis.Modules.Abstract; using Artemis.Modules.Abstract;
using Castle.Components.DictionaryAdapter; using Artemis.Utilities;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
namespace Artemis.Modules.Games.WoW namespace Artemis.Modules.Games.WoW
@ -16,6 +17,7 @@ namespace Artemis.Modules.Games.WoW
public WoWUnit Player { get; set; } public WoWUnit Player { get; set; }
public WoWUnit Target { get; set; } public WoWUnit Target { get; set; }
public string Realm { get; set; } public string Realm { get; set; }
public string Zone { get; set; } public string Zone { get; set; }
public string SubZone { get; set; } public string SubZone { get; set; }
@ -26,7 +28,8 @@ namespace Artemis.Modules.Games.WoW
public WoWUnit() public WoWUnit()
{ {
Buffs = new List<WoWAura>(); Buffs = new List<WoWAura>();
Debuffs = new EditableList<WoWAura>(); Debuffs = new List<WoWAura>();
CastBar = new WoWCastBar();
} }
public string Name { get; set; } public string Name { get; set; }
@ -36,11 +39,12 @@ namespace Artemis.Modules.Games.WoW
public int Power { get; set; } public int Power { get; set; }
public int MaxPower { get; set; } public int MaxPower { get; set; }
public WoWPowerType PowerType { get; set; } public WoWPowerType PowerType { get; set; }
public WoWClass Class { get; set; } public string Class { get; set; }
public WoWRace Race { get; set; } public WoWRace Race { get; set; }
public WoWGender Gender { get; set; } public WoWGender Gender { get; set; }
public List<WoWAura> Buffs { get; set; } public List<WoWAura> Buffs { get; set; }
public List<WoWAura> Debuffs { get; set; } public List<WoWAura> Debuffs { get; set; }
public WoWCastBar CastBar { get; set; }
public void ApplyJson(JObject json) public void ApplyJson(JObject json)
{ {
@ -49,32 +53,40 @@ namespace Artemis.Modules.Games.WoW
Name = json["name"].Value<string>(); Name = json["name"].Value<string>();
Level = json["level"].Value<int>(); Level = json["level"].Value<int>();
Class = (WoWClass) Enum.Parse(typeof(WoWClass), json["class"].Value<string>().Replace(" ", "")); Class = json["class"].Value<string>();
Race = (WoWRace) Enum.Parse(typeof(WoWRace), json["race"].Value<string>().Replace(" ", ""));
Gender = json["gender"].Value<int>() == 3 ? WoWGender.Female : WoWGender.Male; Gender = json["gender"].Value<int>() == 3 ? WoWGender.Female : WoWGender.Male;
if (json["race"] != null)
Race = GeneralHelpers.ParseEnum<WoWRace>(json["race"].Value<string>());
} }
public void ApplyStateJson(JObject json) public void ApplyStateJson(JObject json)
{ {
Health = json["health"].Value<int>(); Health = json["health"].Value<int>();
MaxHealth = json["maxHealth"].Value<int>(); MaxHealth = json["maxHealth"].Value<int>();
PowerType = (WoWPowerType) Enum.Parse(typeof(WoWPowerType), json["powerType"].Value<int>().ToString(), true); PowerType = GeneralHelpers.ParseEnum<WoWPowerType>(json["powerType"].Value<int>().ToString());
Power = json["power"].Value<int>(); Power = json["power"].Value<int>();
MaxPower = json["maxPower"].Value<int>(); MaxPower = json["maxPower"].Value<int>();
Buffs.Clear(); Buffs.Clear();
foreach (var auraJson in json["buffs"].Children()) if (json["buffs"] != null)
{ {
var aura = new WoWAura(); foreach (var auraJson in json["buffs"].Children())
aura.ApplyJson(auraJson); {
Buffs.Add(aura); var aura = new WoWAura();
aura.ApplyJson(auraJson);
Buffs.Add(aura);
}
} }
Debuffs.Clear(); Debuffs.Clear();
foreach (var auraJson in json["debuffs"].Children()) if (json["debuffs"] != null)
{ {
var aura = new WoWAura(); foreach (var auraJson in json["debuffs"].Children())
aura.ApplyJson(auraJson); {
Debuffs.Add(aura); var aura = new WoWAura();
aura.ApplyJson(auraJson);
Debuffs.Add(aura);
}
} }
} }
} }
@ -85,8 +97,8 @@ namespace Artemis.Modules.Games.WoW
public int Id { get; set; } public int Id { get; set; }
public string Caster { get; set; } public string Caster { get; set; }
public int Stacks { get; set; } public int Stacks { get; set; }
public TimeSpan Duration { get; set; } public DateTime StartTime { set; get; }
public TimeSpan Expires { get; set; } public DateTime EndTime { get; set; }
public void ApplyJson(JToken buffJson) public void ApplyJson(JToken buffJson)
{ {
@ -99,6 +111,59 @@ namespace Artemis.Modules.Games.WoW
} }
} }
public class WoWCastBar
{
public void ApplyJson(JToken spellJson)
{
var castMs = spellJson["endTime"].Value<int>() - spellJson["startTime"].Value<int>();
var tickCount = Environment.TickCount;
var difference = tickCount - spellJson["startTime"].Value<int>();
SpellName = spellJson["name"].Value<string>();
SpellId = spellJson["spellID"].Value<int>();
StartTime = new DateTime(DateTime.Now.Ticks + difference);
EndTime = StartTime.AddMilliseconds(castMs);
NonInterruptible = spellJson["notInterruptible"].Value<bool>();
// SpellName = spellJson["name"].Value<string>();
// SpellId = spellJson["spellID"].Value<int>();
// StartTime = DateTime.Now.AddMilliseconds(spellJson["startTime"].Value<long>()/1000.0);
// EndTime = StartTime.AddMilliseconds(spellJson["endTime"].Value<long>()/1000.0);
// NonInterruptible = spellJson["notInterruptible"].Value<bool>();
}
public void UpdateProgress()
{
if (SpellName == null)
return;
var elapsed = DateTime.Now - StartTime;
var total = EndTime - StartTime;
Progress = (float) (elapsed.TotalMilliseconds / total.TotalMilliseconds);
Debug.WriteLine(Progress);
if (Progress > 1)
Clear();
}
public void Clear()
{
SpellName = null;
SpellId = 0;
StartTime = DateTime.MinValue;
EndTime = DateTime.MinValue;
NonInterruptible = false;
Progress = 0;
}
public string SpellName { get; set; }
public int SpellId { get; set; }
public DateTime StartTime { set; get; }
public DateTime EndTime { get; set; }
public bool NonInterruptible { get; set; }
public float Progress { get; set; }
}
public enum WoWPowerType public enum WoWPowerType
{ {
Mana = 0, Mana = 0,

View File

@ -97,19 +97,37 @@ namespace Artemis.Modules.Games.WoW
private void HandleGameData(string command, string data) private void HandleGameData(string command, string data)
{ {
var json = JObject.Parse(data); JObject json = null;
var dataModel = (WoWDataModel) DataModel; if (!data.StartsWith("\"") && !data.EndsWith("\""))
switch (command) json = JObject.Parse(data);
lock (DataModel)
{ {
case "player": var dataModel = (WoWDataModel) DataModel;
ParsePlayer(json, dataModel); switch (command)
break; {
case "target": case "player":
ParseTarget(json, dataModel); ParsePlayer(json, dataModel);
break; break;
case "playerState": case "target":
ParsePlayerState(json, dataModel); ParseTarget(json, dataModel);
break; break;
case "playerState":
ParsePlayerState(json, dataModel);
break;
case "targetState":
ParseTargetState(json, dataModel);
break;
case "spellCast":
ParseSpellCast(json, dataModel);
break;
case "spellCastFailed":
ParseSpellCastFailed(data, dataModel);
break;
case "spellCastInterrupted":
ParseSpellCastInterrupted(data, dataModel);
break;
}
} }
} }
@ -128,6 +146,40 @@ namespace Artemis.Modules.Games.WoW
dataModel.Player.ApplyStateJson(json); dataModel.Player.ApplyStateJson(json);
} }
private void ParseTargetState(JObject json, WoWDataModel dataModel)
{
dataModel.Target.ApplyStateJson(json);
}
private void ParseSpellCast(JObject json, WoWDataModel dataModel)
{
if (json["unitID"].Value<string>() == "player")
dataModel.Player.CastBar.ApplyJson(json);
else if (json["unitID"].Value<string>() == "target")
dataModel.Target.CastBar.ApplyJson(json);
}
private void ParseInstantSpellCast(JObject json, WoWDataModel dataModel)
{
}
private void ParseSpellCastFailed(string data, WoWDataModel dataModel)
{
if (data == "\"player\"")
dataModel.Player.CastBar.Clear();
else if (data == "\"target\"")
dataModel.Target.CastBar.Clear();
}
private void ParseSpellCastInterrupted(string data, WoWDataModel dataModel)
{
if (data == "\"player\"")
dataModel.Player.CastBar.Clear();
else if (data == "\"target\"")
dataModel.Target.CastBar.Clear();
}
public override void Dispose() public override void Dispose()
{ {
_communicator.Break(); _communicator.Break();
@ -137,6 +189,10 @@ namespace Artemis.Modules.Games.WoW
public override void Update() public override void Update()
{ {
var dataModel = (WoWDataModel)DataModel;
dataModel.Player.CastBar.UpdateProgress();
dataModel.Target.CastBar.UpdateProgress();
} }
} }
} }

View File

@ -1,5 +1,10 @@
using System; using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Documents;
using Artemis.Modules.Abstract; using Artemis.Modules.Abstract;
using Artemis.Utilities; using Artemis.Utilities;
using DynamicExpresso; using DynamicExpresso;
@ -11,10 +16,12 @@ namespace Artemis.Profiles.Layers.Models
{ {
private readonly Interpreter _interpreter; private readonly Interpreter _interpreter;
private object _lastValue; private object _lastValue;
private Regex _rgx;
public LayerConditionModel() public LayerConditionModel()
{ {
_interpreter = new Interpreter(); _interpreter = new Interpreter();
_rgx = new Regex("\\((.*?)\\)");
} }
public string Field { get; set; } public string Field { get; set; }
@ -30,6 +37,53 @@ namespace Artemis.Profiles.Layers.Models
if (string.IsNullOrEmpty(Field) || string.IsNullOrEmpty(Type)) if (string.IsNullOrEmpty(Field) || string.IsNullOrEmpty(Type))
return false; return false;
// If the path points to a collection, look inside this collection
if (Field.Contains("("))
{
// Find the collection in the field path
var collectionField = _rgx.Match(Field).Groups[1].Value;
var collectionInspect = (IEnumerable) GeneralHelpers.GetPropertyValue(subject, collectionField);
var operatorParts = Operator.Split('|');
_lastValue = collectionInspect;
if (operatorParts[0] == "any")
{
var anyMatch = false;
foreach (var collectionValue in collectionInspect)
{
var field = Field.Split(')').Last().Substring(1);
anyMatch = EvaluateOperator(collectionValue, field, operatorParts[1]);
if (anyMatch)
break;
}
return anyMatch;
}
if (operatorParts[0] == "all")
{
var allMatch = true;
foreach (var collectionValue in collectionInspect)
{
var field = Field.Split(')').Last().Substring(1);
allMatch = EvaluateOperator(collectionValue, field, operatorParts[1]);
if (!allMatch)
break;
}
return allMatch;
}
if (operatorParts[0] == "none")
{
var noneMatch = true;
foreach (var collectionValue in collectionInspect)
{
var field = Field.Split(')').Last().Substring(1);
noneMatch = !EvaluateOperator(collectionValue, field, operatorParts[1]);
if (!noneMatch)
break;
}
return noneMatch;
}
}
var inspect = GeneralHelpers.GetPropertyValue(subject, Field); var inspect = GeneralHelpers.GetPropertyValue(subject, Field);
if (inspect == null) if (inspect == null)
{ {
@ -41,7 +95,7 @@ namespace Artemis.Profiles.Layers.Models
if (Operator == "changed" || Operator == "decreased" || Operator == "increased") if (Operator == "changed" || Operator == "decreased" || Operator == "increased")
returnValue = EvaluateEventOperator(subject, inspect); returnValue = EvaluateEventOperator(subject, inspect);
else else
returnValue = EvaluateOperator(subject); returnValue = EvaluateOperator(subject, Field);
_lastValue = inspect; _lastValue = inspect;
return returnValue; return returnValue;
@ -68,8 +122,7 @@ namespace Artemis.Profiles.Layers.Models
changeOperator = ">"; changeOperator = ">";
// Evaluate the result and store it // Evaluate the result and store it
var returnValue = _interpreter.Eval<bool>($"subject.{Field} {changeOperator} value", var returnValue = _interpreter.Eval<bool>($"subject.{Field} {changeOperator} value", new Parameter("subject", subject.GetType(), subject), rightParam);
new Parameter("subject", subject.GetType(), subject), rightParam);
// Set the last value to the new value // Set the last value to the new value
_lastValue = inspect; _lastValue = inspect;
@ -77,25 +130,26 @@ namespace Artemis.Profiles.Layers.Models
return returnValue; return returnValue;
} }
private bool EvaluateOperator(ModuleDataModel subject) private bool EvaluateOperator(object subject, string field, string operatorOverwrite = null)
{ {
// Since _lastValue won't be used, rely on Value to not be null // Since _lastValue won't be used, rely on Value to not be null
if (string.IsNullOrEmpty(Value)) if (string.IsNullOrEmpty(Value))
return false; return false;
// Put the subject in a list, allowing Dynamic Linq to be used.
if (Type == "String") if (Type == "String")
{ {
return _interpreter.Eval<bool>($"subject.{Field}.ToLower(){Operator}(value)", var stringExpressionText = operatorOverwrite == null
new Parameter("subject", subject.GetType(), subject), ? $"subject.{field}.ToLower(){Operator}(value)"
new Parameter("value", Value.ToLower())); : $"subject.{field}.ToLower(){operatorOverwrite}(value)";
return _interpreter.Eval<bool>(stringExpressionText, new Parameter("subject", subject.GetType(), subject), new Parameter("value", Value.ToLower()));
} }
Parameter rightParam = null; Parameter rightParam = null;
switch (Type) switch (Type)
{ {
case "Enum": case "Enum":
var enumType = GeneralHelpers.GetPropertyValue(subject, Field).GetType(); var enumType = GeneralHelpers.GetPropertyValue(subject, field).GetType();
rightParam = new Parameter("value", Enum.Parse(enumType, Value)); rightParam = new Parameter("value", Enum.Parse(enumType, Value));
break; break;
case "Boolean": case "Boolean":
@ -111,8 +165,11 @@ namespace Artemis.Profiles.Layers.Models
break; break;
} }
return _interpreter.Eval<bool>($"subject.{Field} {Operator} value", var expressionText = operatorOverwrite == null
new Parameter("subject", subject.GetType(), subject), rightParam); ? $"subject.{field} {Operator} value"
: $"subject.{field} {operatorOverwrite} value";
return _interpreter.Eval<bool>(expressionText, new Parameter("subject", subject.GetType(), subject), rightParam);
} }
} }
} }

View File

@ -5,7 +5,6 @@ using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using System.Windows;
using Microsoft.Win32; using Microsoft.Win32;
using Newtonsoft.Json; using Newtonsoft.Json;
using static System.String; using static System.String;
@ -42,10 +41,12 @@ namespace Artemis.Utilities
return GetPropertyValue(value, path.Replace(propertyNames[0] + ".", "")); return GetPropertyValue(value, path.Replace(propertyNames[0] + ".", ""));
} }
public static List<PropertyCollection> GenerateTypeMap(object o) => GenerateTypeMap(o.GetType().GetProperties()); public static List<PropertyCollection> GenerateTypeMap(object o)
{
return GenerateTypeMap(o.GetType().GetProperties());
}
private static List<PropertyCollection> GenerateTypeMap(IEnumerable<PropertyInfo> getProperties, private static List<PropertyCollection> GenerateTypeMap(IEnumerable<PropertyInfo> getProperties, string path = "", bool inList = false)
string path = "")
{ {
var list = new List<PropertyCollection>(); var list = new List<PropertyCollection>();
foreach (var propInfo in getProperties) foreach (var propInfo in getProperties)
@ -62,13 +63,28 @@ namespace Artemis.Utilities
if (propInfo.PropertyType.BaseType?.Name == "Enum") if (propInfo.PropertyType.BaseType?.Name == "Enum")
friendlyName = "(Choice)"; friendlyName = "(Choice)";
var parent = new PropertyCollection // At this point the loop is in the item type contained in the list
PropertyCollection parent;
if (path.Contains("Item") && inList)
{ {
Type = propInfo.PropertyType.Name, parent = new PropertyCollection
DisplayType = friendlyName, {
Display = $"{path.Replace(".", " ")}{propInfo.Name}", Type = propInfo.PropertyType.Name,
Path = $"{path}{propInfo.Name}" DisplayType = friendlyName,
}; Display = $"{path.Replace("Item.", "").Replace(".", " ")}{propInfo.Name}",
Path = $"{path.Replace("Item.", "")}{propInfo.Name}"
};
}
else
{
parent = new PropertyCollection
{
Type = propInfo.PropertyType.Name,
DisplayType = friendlyName,
Display = $"{path.Replace(".", " ")}{propInfo.Name}",
Path = $"{path}{propInfo.Name}"
};
}
if (propInfo.PropertyType.BaseType?.Name == "Enum") if (propInfo.PropertyType.BaseType?.Name == "Enum")
{ {
@ -83,7 +99,16 @@ namespace Artemis.Utilities
if (propInfo.PropertyType.Name != "String" && if (propInfo.PropertyType.Name != "String" &&
propInfo.PropertyType.Name != "DateTime" && propInfo.PropertyType.Name != "DateTime" &&
propInfo.CustomAttributes.All(a => a.AttributeType != typeof(JsonIgnoreAttribute))) propInfo.CustomAttributes.All(a => a.AttributeType != typeof(JsonIgnoreAttribute)))
list.AddRange(GenerateTypeMap(propInfo.PropertyType.GetProperties(), path + $"{propInfo.Name}.")); {
var newPath = $"{path}{propInfo.Name}.";
var toInList = propInfo.PropertyType.Name == "List`1";
if (toInList)
{
inList = true;
newPath = $"({path}{propInfo.Name}).";
}
list.AddRange(GenerateTypeMap(propInfo.PropertyType.GetProperties(), newPath, inList));
}
} }
return list; return list;
} }
@ -114,6 +139,21 @@ namespace Artemis.Utilities
return null; return null;
} }
public static void ExecuteSta(Action action)
{
var thread = new Thread(action.Invoke);
thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
thread.Start();
thread.Join();
}
public static T ParseEnum<T>(string value, bool ignoreCase = true, bool stripWhitespaces = true)
{
if (stripWhitespaces)
value = value.Replace(" ", "");
return (T) Enum.Parse(typeof(T), value, true);
}
public struct PropertyCollection public struct PropertyCollection
{ {
public string Display { get; set; } public string Display { get; set; }
@ -128,13 +168,5 @@ namespace Artemis.Utilities
public List<PropertyCollection> Children { get; set; } public List<PropertyCollection> Children { get; set; }
public string DisplayType { get; set; } public string DisplayType { get; set; }
} }
public static void ExecuteSta(Action action)
{
var thread = new Thread(action.Invoke);
thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
thread.Start();
thread.Join();
}
} }
} }

View File

@ -1,4 +1,5 @@
using System.ComponentModel; using System.Collections.Generic;
using System.ComponentModel;
using System.Linq; using System.Linq;
using Artemis.Profiles.Layers.Models; using Artemis.Profiles.Layers.Models;
using Artemis.Utilities; using Artemis.Utilities;
@ -41,6 +42,13 @@ namespace Artemis.ViewModels.Profiles
new NamedOperator("Ends with", ".EndsWith") new NamedOperator("Ends with", ".EndsWith")
}; };
private readonly NamedOperator[] _listOperatorsPrefixes =
{
new NamedOperator("Any", "any"),
new NamedOperator("All", "all"),
new NamedOperator("None", "none")
};
private HotKey _hotKey; private HotKey _hotKey;
private bool _keybindIsVisible; private bool _keybindIsVisible;
private GeneralHelpers.PropertyCollection _selectedDataModelProp; private GeneralHelpers.PropertyCollection _selectedDataModelProp;
@ -205,7 +213,6 @@ namespace Artemis.ViewModels.Profiles
{ {
Operators.Clear(); Operators.Clear();
DropdownValues.Clear(); DropdownValues.Clear();
switch (SelectedDataModelProp.Type) switch (SelectedDataModelProp.Type)
{ {
case "Int32": case "Int32":
@ -228,7 +235,16 @@ namespace Artemis.ViewModels.Profiles
UserValueIsVisible = true; UserValueIsVisible = true;
break; break;
} }
// If the selected value is in a list, prefix all choices with list choices
if (SelectedDataModelProp.Path != null && SelectedDataModelProp.Path.Contains("("))
{
var listOperators = new List<NamedOperator>();
foreach (var o in Operators)
listOperators.AddRange(_listOperatorsPrefixes.Select(p => new NamedOperator(p.Display + " " + o.Display.ToLower(), p.Value + "|" + o.Value)));
Operators.Clear();
Operators.AddRange(listOperators);
}
// Add Changed operator is the type is event // Add Changed operator is the type is event
if (_editorViewModel.ProposedLayer.IsEvent) if (_editorViewModel.ProposedLayer.IsEvent)
{ {