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.Collections.Generic;
using System.Diagnostics;
using Artemis.Modules.Abstract;
using Castle.Components.DictionaryAdapter;
using Artemis.Utilities;
using Newtonsoft.Json.Linq;
namespace Artemis.Modules.Games.WoW
@ -16,6 +17,7 @@ namespace Artemis.Modules.Games.WoW
public WoWUnit Player { get; set; }
public WoWUnit Target { get; set; }
public string Realm { get; set; }
public string Zone { get; set; }
public string SubZone { get; set; }
@ -26,7 +28,8 @@ namespace Artemis.Modules.Games.WoW
public WoWUnit()
{
Buffs = new List<WoWAura>();
Debuffs = new EditableList<WoWAura>();
Debuffs = new List<WoWAura>();
CastBar = new WoWCastBar();
}
public string Name { get; set; }
@ -36,11 +39,12 @@ namespace Artemis.Modules.Games.WoW
public int Power { get; set; }
public int MaxPower { get; set; }
public WoWPowerType PowerType { get; set; }
public WoWClass Class { get; set; }
public string Class { get; set; }
public WoWRace Race { get; set; }
public WoWGender Gender { get; set; }
public List<WoWAura> Buffs { get; set; }
public List<WoWAura> Debuffs { get; set; }
public WoWCastBar CastBar { get; set; }
public void ApplyJson(JObject json)
{
@ -49,32 +53,40 @@ namespace Artemis.Modules.Games.WoW
Name = json["name"].Value<string>();
Level = json["level"].Value<int>();
Class = (WoWClass) Enum.Parse(typeof(WoWClass), json["class"].Value<string>().Replace(" ", ""));
Race = (WoWRace) Enum.Parse(typeof(WoWRace), json["race"].Value<string>().Replace(" ", ""));
Class = json["class"].Value<string>();
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)
{
Health = json["health"].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>();
MaxPower = json["maxPower"].Value<int>();
Buffs.Clear();
foreach (var auraJson in json["buffs"].Children())
if (json["buffs"] != null)
{
var aura = new WoWAura();
aura.ApplyJson(auraJson);
Buffs.Add(aura);
foreach (var auraJson in json["buffs"].Children())
{
var aura = new WoWAura();
aura.ApplyJson(auraJson);
Buffs.Add(aura);
}
}
Debuffs.Clear();
foreach (var auraJson in json["debuffs"].Children())
if (json["debuffs"] != null)
{
var aura = new WoWAura();
aura.ApplyJson(auraJson);
Debuffs.Add(aura);
foreach (var auraJson in json["debuffs"].Children())
{
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 string Caster { get; set; }
public int Stacks { get; set; }
public TimeSpan Duration { get; set; }
public TimeSpan Expires { get; set; }
public DateTime StartTime { set; get; }
public DateTime EndTime { get; set; }
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
{
Mana = 0,

View File

@ -97,19 +97,37 @@ namespace Artemis.Modules.Games.WoW
private void HandleGameData(string command, string data)
{
var json = JObject.Parse(data);
var dataModel = (WoWDataModel) DataModel;
switch (command)
JObject json = null;
if (!data.StartsWith("\"") && !data.EndsWith("\""))
json = JObject.Parse(data);
lock (DataModel)
{
case "player":
ParsePlayer(json, dataModel);
break;
case "target":
ParseTarget(json, dataModel);
break;
case "playerState":
ParsePlayerState(json, dataModel);
break;
var dataModel = (WoWDataModel) DataModel;
switch (command)
{
case "player":
ParsePlayer(json, dataModel);
break;
case "target":
ParseTarget(json, dataModel);
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);
}
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()
{
_communicator.Break();
@ -137,6 +189,10 @@ namespace Artemis.Modules.Games.WoW
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.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Documents;
using Artemis.Modules.Abstract;
using Artemis.Utilities;
using DynamicExpresso;
@ -11,10 +16,12 @@ namespace Artemis.Profiles.Layers.Models
{
private readonly Interpreter _interpreter;
private object _lastValue;
private Regex _rgx;
public LayerConditionModel()
{
_interpreter = new Interpreter();
_rgx = new Regex("\\((.*?)\\)");
}
public string Field { get; set; }
@ -30,6 +37,53 @@ namespace Artemis.Profiles.Layers.Models
if (string.IsNullOrEmpty(Field) || string.IsNullOrEmpty(Type))
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);
if (inspect == null)
{
@ -41,7 +95,7 @@ namespace Artemis.Profiles.Layers.Models
if (Operator == "changed" || Operator == "decreased" || Operator == "increased")
returnValue = EvaluateEventOperator(subject, inspect);
else
returnValue = EvaluateOperator(subject);
returnValue = EvaluateOperator(subject, Field);
_lastValue = inspect;
return returnValue;
@ -68,8 +122,7 @@ namespace Artemis.Profiles.Layers.Models
changeOperator = ">";
// Evaluate the result and store it
var returnValue = _interpreter.Eval<bool>($"subject.{Field} {changeOperator} value",
new Parameter("subject", subject.GetType(), subject), rightParam);
var returnValue = _interpreter.Eval<bool>($"subject.{Field} {changeOperator} value", new Parameter("subject", subject.GetType(), subject), rightParam);
// Set the last value to the new value
_lastValue = inspect;
@ -77,25 +130,26 @@ namespace Artemis.Profiles.Layers.Models
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
if (string.IsNullOrEmpty(Value))
return false;
// Put the subject in a list, allowing Dynamic Linq to be used.
if (Type == "String")
{
return _interpreter.Eval<bool>($"subject.{Field}.ToLower(){Operator}(value)",
new Parameter("subject", subject.GetType(), subject),
new Parameter("value", Value.ToLower()));
var stringExpressionText = operatorOverwrite == null
? $"subject.{field}.ToLower(){Operator}(value)"
: $"subject.{field}.ToLower(){operatorOverwrite}(value)";
return _interpreter.Eval<bool>(stringExpressionText, new Parameter("subject", subject.GetType(), subject), new Parameter("value", Value.ToLower()));
}
Parameter rightParam = null;
switch (Type)
{
case "Enum":
var enumType = GeneralHelpers.GetPropertyValue(subject, Field).GetType();
var enumType = GeneralHelpers.GetPropertyValue(subject, field).GetType();
rightParam = new Parameter("value", Enum.Parse(enumType, Value));
break;
case "Boolean":
@ -111,8 +165,11 @@ namespace Artemis.Profiles.Layers.Models
break;
}
return _interpreter.Eval<bool>($"subject.{Field} {Operator} value",
new Parameter("subject", subject.GetType(), subject), rightParam);
var expressionText = operatorOverwrite == null
? $"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.Text.RegularExpressions;
using System.Threading;
using System.Windows;
using Microsoft.Win32;
using Newtonsoft.Json;
using static System.String;
@ -42,10 +41,12 @@ namespace Artemis.Utilities
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,
string path = "")
private static List<PropertyCollection> GenerateTypeMap(IEnumerable<PropertyInfo> getProperties, string path = "", bool inList = false)
{
var list = new List<PropertyCollection>();
foreach (var propInfo in getProperties)
@ -62,13 +63,28 @@ namespace Artemis.Utilities
if (propInfo.PropertyType.BaseType?.Name == "Enum")
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,
DisplayType = friendlyName,
Display = $"{path.Replace(".", " ")}{propInfo.Name}",
Path = $"{path}{propInfo.Name}"
};
parent = new PropertyCollection
{
Type = propInfo.PropertyType.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")
{
@ -80,10 +96,19 @@ namespace Artemis.Utilities
list.Add(parent);
// Don't go into Strings, DateTimes or anything with JsonIgnore on it
if (propInfo.PropertyType.Name != "String" &&
if (propInfo.PropertyType.Name != "String" &&
propInfo.PropertyType.Name != "DateTime" &&
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;
}
@ -114,6 +139,21 @@ namespace Artemis.Utilities
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 string Display { get; set; }
@ -128,13 +168,5 @@ namespace Artemis.Utilities
public List<PropertyCollection> Children { 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 Artemis.Profiles.Layers.Models;
using Artemis.Utilities;
@ -41,6 +42,13 @@ namespace Artemis.ViewModels.Profiles
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 bool _keybindIsVisible;
private GeneralHelpers.PropertyCollection _selectedDataModelProp;
@ -205,7 +213,6 @@ namespace Artemis.ViewModels.Profiles
{
Operators.Clear();
DropdownValues.Clear();
switch (SelectedDataModelProp.Type)
{
case "Int32":
@ -228,7 +235,16 @@ namespace Artemis.ViewModels.Profiles
UserValueIsVisible = true;
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
if (_editorViewModel.ProposedLayer.IsEvent)
{