diff --git a/Artemis/Artemis/Artemis.csproj b/Artemis/Artemis/Artemis.csproj
index 884520177..9f1be00a2 100644
--- a/Artemis/Artemis/Artemis.csproj
+++ b/Artemis/Artemis/Artemis.csproj
@@ -404,6 +404,12 @@
TerrariaView.xaml
+
+
+
+
+
+
diff --git a/Artemis/Artemis/Managers/LoopManager.cs b/Artemis/Artemis/Managers/LoopManager.cs
index 598bfa3b1..0e198c4e0 100644
--- a/Artemis/Artemis/Managers/LoopManager.cs
+++ b/Artemis/Artemis/Managers/LoopManager.cs
@@ -16,9 +16,12 @@ namespace Artemis.Managers
{
private readonly DebugViewModel _debugViewModel;
private readonly DeviceManager _deviceManager;
+
private readonly ILogger _logger;
+
//private readonly Timer _loopTimer;
private readonly Task _loopTask;
+
private readonly ModuleManager _moduleManager;
public LoopManager(ILogger logger, ModuleManager moduleManager, DeviceManager deviceManager,
@@ -163,9 +166,7 @@ namespace Artemis.Managers
var keyboardOnly = !mice.Any() && !headsets.Any() && !generics.Any() && !mousemats.Any();
// Setup the frame for this tick
- using (
- var frame = new FrameModel(_deviceManager.ActiveKeyboard, mice.Any(), headsets.Any(), generics.Any(),
- mousemats.Any()))
+ using (var frame = new FrameModel(_deviceManager.ActiveKeyboard, mice.Any(), headsets.Any(), generics.Any(), mousemats.Any()))
{
if (renderModule.IsInitialized)
renderModule.Render(frame, keyboardOnly);
@@ -207,4 +208,4 @@ namespace Artemis.Managers
RenderCompleted?.Invoke(this, EventArgs.Empty);
}
}
-}
\ No newline at end of file
+}
diff --git a/Artemis/Artemis/Models/DeviceVisualModel.cs b/Artemis/Artemis/Models/DeviceVisualModel.cs
index 43d59c3c4..cf64bdef0 100644
--- a/Artemis/Artemis/Models/DeviceVisualModel.cs
+++ b/Artemis/Artemis/Models/DeviceVisualModel.cs
@@ -54,8 +54,7 @@ namespace Artemis.Models
using (var g = Graphics.FromImage(bitmap))
{
g.Clear(Color.Black);
- g.DrawImage(frame, new Rectangle(0, 0, bitmap.Width, bitmap.Height), RelativeRectangle,
- GraphicsUnit.Pixel);
+ g.DrawImage(frame, new Rectangle(0, 0, bitmap.Width, bitmap.Height), RelativeRectangle, GraphicsUnit.Pixel);
}
return bitmap;
@@ -72,4 +71,4 @@ namespace Artemis.Models
_ctx = null;
}
}
-}
\ No newline at end of file
+}
diff --git a/Artemis/Artemis/Modules/Games/WoW/Models/WoWAura.cs b/Artemis/Artemis/Modules/Games/WoW/Models/WoWAura.cs
new file mode 100644
index 000000000..3511e7db7
--- /dev/null
+++ b/Artemis/Artemis/Modules/Games/WoW/Models/WoWAura.cs
@@ -0,0 +1,27 @@
+using System;
+using MoonSharp.Interpreter;
+using Newtonsoft.Json.Linq;
+
+namespace Artemis.Modules.Games.WoW.Models
+{
+ [MoonSharpUserData]
+ public class WoWAura
+ {
+ public string Name { get; set; }
+ public int Id { get; set; }
+ public string Caster { get; set; }
+ public int Stacks { get; set; }
+ public DateTime StartTime { set; get; }
+ public DateTime EndTime { get; set; }
+
+ public void ApplyJson(JToken buffJson)
+ {
+ Name = buffJson["name"].Value();
+ Id = buffJson["spellID"].Value();
+ Stacks = buffJson["count"].Value();
+ Caster = buffJson["caster"]?.Value();
+
+ // TODO: Duration
+ }
+ }
+}
diff --git a/Artemis/Artemis/Modules/Games/WoW/Models/WoWCastBar.cs b/Artemis/Artemis/Modules/Games/WoW/Models/WoWCastBar.cs
new file mode 100644
index 000000000..37cc83c79
--- /dev/null
+++ b/Artemis/Artemis/Modules/Games/WoW/Models/WoWCastBar.cs
@@ -0,0 +1,57 @@
+using System;
+using MoonSharp.Interpreter;
+using Newtonsoft.Json.Linq;
+
+namespace Artemis.Modules.Games.WoW.Models
+{
+ [MoonSharpUserData]
+ public class WoWCastBar
+ {
+ public WoWCastBar()
+ {
+ Spell = new WoWSpell();
+ }
+
+ public WoWSpell Spell { get; set; }
+ public DateTime StartTime { set; get; }
+ public DateTime EndTime { get; set; }
+ public bool NonInterruptible { get; set; }
+ public float Progress { get; set; }
+
+ public void ApplyJson(JToken spellJson)
+ {
+ var castMs = spellJson["endTime"].Value() - spellJson["startTime"].Value();
+ var tickCount = Environment.TickCount;
+ var difference = tickCount - spellJson["startTime"].Value();
+
+ Spell.Name = spellJson["name"].Value();
+ Spell.Id = spellJson["spellID"].Value();
+ StartTime = new DateTime(DateTime.Now.Ticks + difference);
+ EndTime = StartTime.AddMilliseconds(castMs);
+ NonInterruptible = spellJson["notInterruptible"].Value();
+ }
+
+ public void UpdateProgress()
+ {
+ if (Spell.Name == null)
+ return;
+
+ var elapsed = DateTime.Now - StartTime;
+ var total = EndTime - StartTime;
+
+ Progress = (float) (elapsed.TotalMilliseconds / total.TotalMilliseconds);
+ if (Progress > 1)
+ Clear();
+ }
+
+ public void Clear()
+ {
+ Spell.Name = null;
+ Spell.Id = 0;
+ StartTime = DateTime.MinValue;
+ EndTime = DateTime.MinValue;
+ NonInterruptible = false;
+ Progress = 0;
+ }
+ }
+}
diff --git a/Artemis/Artemis/Modules/Games/WoW/Models/WoWEnums.cs b/Artemis/Artemis/Modules/Games/WoW/Models/WoWEnums.cs
new file mode 100644
index 000000000..9a484d508
--- /dev/null
+++ b/Artemis/Artemis/Modules/Games/WoW/Models/WoWEnums.cs
@@ -0,0 +1,44 @@
+namespace Artemis.Modules.Games.WoW.Models
+{
+ public enum WoWRace
+ {
+ Human,
+ Orc,
+ Dwarf,
+ NightElf,
+ Undead,
+ Tauren,
+ Gnome,
+ Troll,
+ BloodElf,
+ Draenei,
+ Goblin,
+ Worgen,
+ Pandaren
+ }
+
+ public enum WoWPowerType
+ {
+ Mana = 0,
+ Rage = 1,
+ Focus = 2,
+ Energy = 3,
+ ComboPoints = 4,
+ Runes = 5,
+ RunicPower = 6,
+ SoulShards = 7,
+ LunarPower = 8,
+ HolyPower = 9,
+ AlternatePower = 10,
+ Maelstrom = 11,
+ Chi = 12,
+ Insanity = 13,
+ ArcaneCharges = 16
+ }
+
+ public enum WoWGender
+ {
+ Male,
+ Female
+ }
+}
diff --git a/Artemis/Artemis/Modules/Games/WoW/Models/WoWSpecialization.cs b/Artemis/Artemis/Modules/Games/WoW/Models/WoWSpecialization.cs
new file mode 100644
index 000000000..63e66fd09
--- /dev/null
+++ b/Artemis/Artemis/Modules/Games/WoW/Models/WoWSpecialization.cs
@@ -0,0 +1,20 @@
+using MoonSharp.Interpreter;
+using Newtonsoft.Json.Linq;
+
+namespace Artemis.Modules.Games.WoW.Models
+{
+ [MoonSharpUserData]
+ public class WoWSpecialization
+ {
+ public string Name { get; set; }
+ public int Id { get; set; }
+ public string Role { get; set; }
+
+ public void ApplyJson(JToken specJson)
+ {
+ Name = specJson["name"].Value();
+ Id = specJson["id"].Value();
+ Role = specJson["role"].Value();
+ }
+ }
+}
diff --git a/Artemis/Artemis/Modules/Games/WoW/Models/WoWSpell.cs b/Artemis/Artemis/Modules/Games/WoW/Models/WoWSpell.cs
new file mode 100644
index 000000000..8210bf2cb
--- /dev/null
+++ b/Artemis/Artemis/Modules/Games/WoW/Models/WoWSpell.cs
@@ -0,0 +1,11 @@
+using MoonSharp.Interpreter;
+
+namespace Artemis.Modules.Games.WoW.Models
+{
+ [MoonSharpUserData]
+ public class WoWSpell
+ {
+ public string Name { get; set; }
+ public int Id { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Artemis/Artemis/Modules/Games/WoW/Models/WoWUnit.cs b/Artemis/Artemis/Modules/Games/WoW/Models/WoWUnit.cs
new file mode 100644
index 000000000..de82392e5
--- /dev/null
+++ b/Artemis/Artemis/Modules/Games/WoW/Models/WoWUnit.cs
@@ -0,0 +1,118 @@
+using System.Collections.Generic;
+using System.Linq;
+using Artemis.Utilities;
+using MoonSharp.Interpreter;
+using Newtonsoft.Json.Linq;
+
+namespace Artemis.Modules.Games.WoW.Models
+{
+ [MoonSharpUserData]
+ public class WoWUnit
+ {
+ private readonly List _currentFrameCasts = new List();
+
+ public WoWUnit()
+ {
+ CastBar = new WoWCastBar();
+ Specialization = new WoWSpecialization();
+
+ Buffs = new List();
+ Debuffs = new List();
+ RecentIntantCasts = new List();
+ }
+
+ public string Name { get; set; }
+ public int Level { get; set; }
+ public int Health { get; set; }
+ public int MaxHealth { get; set; }
+ public int Power { get; set; }
+ public int MaxPower { get; set; }
+ public WoWPowerType PowerType { get; set; }
+ public string Class { get; set; }
+ public WoWRace Race { get; set; }
+ public WoWGender Gender { get; set; }
+
+ public WoWCastBar CastBar { get; set; }
+ public WoWSpecialization Specialization { get; }
+
+ public List Buffs { get; }
+ public List Debuffs { get; }
+ public List RecentIntantCasts { get; private set; }
+
+ public void ApplyJson(JObject json)
+ {
+ if (json["name"] == null)
+ return;
+
+ Name = json["name"].Value();
+ Level = json["level"].Value();
+ Class = json["class"].Value();
+ Gender = json["gender"].Value() == 3 ? WoWGender.Female : WoWGender.Male;
+
+ if (json["race"] != null)
+ Race = GeneralHelpers.ParseEnum(json["race"].Value());
+ if (json["specialization"] != null)
+ Specialization.ApplyJson(json["specialization"]);
+ }
+
+ public void ApplyStateJson(JObject json)
+ {
+ Health = json["health"].Value();
+ MaxHealth = json["maxHealth"].Value();
+ PowerType = GeneralHelpers.ParseEnum(json["powerType"].Value().ToString());
+ Power = json["power"].Value();
+ MaxPower = json["maxPower"].Value();
+ }
+
+ public void ApplyAuraJson(JObject json)
+ {
+ Buffs.Clear();
+ if (json["buffs"] != null)
+ {
+ foreach (var auraJson in json["buffs"].Children())
+ {
+ var aura = new WoWAura();
+ aura.ApplyJson(auraJson);
+ Buffs.Add(aura);
+ }
+ }
+ Debuffs.Clear();
+ if (json["debuffs"] != null)
+ {
+ foreach (var auraJson in json["debuffs"].Children())
+ {
+ var aura = new WoWAura();
+ aura.ApplyJson(auraJson);
+ Debuffs.Add(aura);
+ }
+ }
+ }
+
+ public void AddInstantCast(WoWSpell spell)
+ {
+ lock (_currentFrameCasts)
+ {
+ _currentFrameCasts.Add(spell);
+ }
+ }
+
+ public void ClearInstantCasts()
+ {
+ lock (_currentFrameCasts)
+ {
+ // Remove all casts that weren't cast in the after the last frame
+ RecentIntantCasts.Clear();
+ RecentIntantCasts.AddRange(_currentFrameCasts);
+
+ // Clear the that were after the last frame so that they are removed next frame when this method is called again
+ _currentFrameCasts.Clear();
+ }
+ }
+
+ public void Update()
+ {
+ CastBar.UpdateProgress();
+ ClearInstantCasts();
+ }
+ }
+}
diff --git a/Artemis/Artemis/Modules/Games/WoW/WoWDataModel.cs b/Artemis/Artemis/Modules/Games/WoW/WoWDataModel.cs
index 4d04e2bcc..3e2365362 100644
--- a/Artemis/Artemis/Modules/Games/WoW/WoWDataModel.cs
+++ b/Artemis/Artemis/Modules/Games/WoW/WoWDataModel.cs
@@ -1,12 +1,10 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using Artemis.Modules.Abstract;
-using Artemis.Utilities;
-using Newtonsoft.Json.Linq;
+using Artemis.Modules.Abstract;
+using Artemis.Modules.Games.WoW.Models;
+using MoonSharp.Interpreter;
namespace Artemis.Modules.Games.WoW
{
+ [MoonSharpUserData]
public class WoWDataModel : ModuleDataModel
{
public WoWDataModel()
@@ -22,203 +20,4 @@ namespace Artemis.Modules.Games.WoW
public string Zone { get; set; }
public string SubZone { get; set; }
}
-
- public class WoWUnit
- {
- public WoWUnit()
- {
- Buffs = new List();
- Debuffs = new List();
- CastBar = new WoWCastBar();
- }
-
- public string Name { get; set; }
- public int Level { get; set; }
- public int Health { get; set; }
- public int MaxHealth { get; set; }
- public int Power { get; set; }
- public int MaxPower { get; set; }
- public WoWPowerType PowerType { get; set; }
- public string Class { get; set; }
- public WoWRace Race { get; set; }
- public WoWGender Gender { get; set; }
- public List Buffs { get; set; }
- public List Debuffs { get; set; }
- public WoWCastBar CastBar { get; set; }
-
- public void ApplyJson(JObject json)
- {
- if (json["name"] == null)
- return;
-
- Name = json["name"].Value();
- Level = json["level"].Value();
- Class = json["class"].Value();
- Gender = json["gender"].Value() == 3 ? WoWGender.Female : WoWGender.Male;
-
- if (json["race"] != null)
- Race = GeneralHelpers.ParseEnum(json["race"].Value());
- }
-
- public void ApplyStateJson(JObject json)
- {
- Health = json["health"].Value();
- MaxHealth = json["maxHealth"].Value();
- PowerType = GeneralHelpers.ParseEnum(json["powerType"].Value().ToString());
- Power = json["power"].Value();
- MaxPower = json["maxPower"].Value();
-
- Buffs.Clear();
- if (json["buffs"] != null)
- {
- foreach (var auraJson in json["buffs"].Children())
- {
- var aura = new WoWAura();
- aura.ApplyJson(auraJson);
- Buffs.Add(aura);
- }
- }
- Debuffs.Clear();
- if (json["debuffs"] != null)
- {
- foreach (var auraJson in json["debuffs"].Children())
- {
- var aura = new WoWAura();
- aura.ApplyJson(auraJson);
- Debuffs.Add(aura);
- }
- }
- }
- }
-
- public class WoWAura
- {
- public string Name { get; set; }
- public int Id { get; set; }
- public string Caster { get; set; }
- public int Stacks { get; set; }
- public DateTime StartTime { set; get; }
- public DateTime EndTime { get; set; }
-
- public void ApplyJson(JToken buffJson)
- {
- Name = buffJson["name"].Value();
- Id = buffJson["spellID"].Value();
- Caster = buffJson["caster"].Value();
- Stacks = buffJson["count"].Value();
-
- // TODO: Duration
- }
- }
-
- public class WoWCastBar
- {
- public void ApplyJson(JToken spellJson)
- {
- var castMs = spellJson["endTime"].Value() - spellJson["startTime"].Value();
- var tickCount = Environment.TickCount;
- var difference = tickCount - spellJson["startTime"].Value();
-
- SpellName = spellJson["name"].Value();
- SpellId = spellJson["spellID"].Value();
- StartTime = new DateTime(DateTime.Now.Ticks + difference);
- EndTime = StartTime.AddMilliseconds(castMs);
- NonInterruptible = spellJson["notInterruptible"].Value();
-
-
-// SpellName = spellJson["name"].Value();
-// SpellId = spellJson["spellID"].Value();
-// StartTime = DateTime.Now.AddMilliseconds(spellJson["startTime"].Value()/1000.0);
-// EndTime = StartTime.AddMilliseconds(spellJson["endTime"].Value()/1000.0);
-// NonInterruptible = spellJson["notInterruptible"].Value();
- }
-
- 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,
- Rage = 1,
- Focus = 2,
- Energy = 3,
- ComboPoints = 4,
- Runes = 5,
- RunicPower = 6,
- SoulShards = 7,
- LunarPower = 8,
- HolyPower = 9,
- AlternatePower = 10,
- Maelstrom = 11,
- Chi = 12,
- Insanity = 13,
- ArcaneCharges = 16
- }
-
- public enum WoWClass
- {
- Warrior,
- Paladin,
- Hunter,
- Rogue,
- Priest,
- DeathKnight,
- Shaman,
- Mage,
- Warlock,
- Druid,
- Monk,
- DemonHunter
- }
-
- public enum WoWRace
- {
- Human,
- Orc,
- Dwarf,
- NightElf,
- Undead,
- Tauren,
- Gnome,
- Troll,
- BloodElf,
- Draenei,
- Goblin,
- Worgen,
- Pandaren
- }
-
- public enum WoWGender
- {
- Male,
- Female
- }
}
diff --git a/Artemis/Artemis/Modules/Games/WoW/WoWModel.cs b/Artemis/Artemis/Modules/Games/WoW/WoWModel.cs
index e00838cc0..b3df1a6a5 100644
--- a/Artemis/Artemis/Modules/Games/WoW/WoWModel.cs
+++ b/Artemis/Artemis/Modules/Games/WoW/WoWModel.cs
@@ -1,198 +1,222 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-using Artemis.DAL;
-using Artemis.Managers;
-using Artemis.Modules.Abstract;
-using Newtonsoft.Json.Linq;
-using PcapDotNet.Core;
-using PcapDotNet.Packets;
-
-namespace Artemis.Modules.Games.WoW
-{
- public class WoWModel : ModuleModel
- {
- private readonly Regex _rgx;
- private PacketCommunicator _communicator;
-
- public WoWModel(DeviceManager deviceManager, LuaManager luaManager) : base(deviceManager, luaManager)
- {
- Settings = SettingsProvider.Load();
- DataModel = new WoWDataModel();
- ProcessNames.Add("Wow-64");
-
- _rgx = new Regex("(artemis)\\((.*?)\\)", RegexOptions.Compiled);
- }
-
- public override string Name => "WoW";
- public override bool IsOverlay => false;
- public override bool IsBoundToProcess => true;
-
-
- public override void Enable()
- {
- // Start scanning WoW packets
- // Retrieve the device list from the local machine
- IList allDevices = LivePacketDevice.AllLocalMachine;
-
- if (allDevices.Count == 0)
- {
- Logger.Warn("No interfaces found! Can't scan WoW packets.");
- return;
- }
-
- // Take the selected adapter
- PacketDevice selectedDevice = allDevices.First();
-
- // Open the device
- _communicator = selectedDevice.Open(65536, PacketDeviceOpenAttributes.Promiscuous, 100);
- Logger.Debug("Listening on " + selectedDevice.Description + " for WoW packets");
-
- // Compile the filter
- using (var filter = _communicator.CreateFilter("tcp"))
- {
- // Set the filter
- _communicator.SetFilter(filter);
- }
-
- Task.Run(() => ReceivePackets());
- base.Enable();
- }
-
- private void ReceivePackets()
- {
- // start the capture
- try
- {
- _communicator.ReceivePackets(0, PacketHandler);
- }
- catch (InvalidOperationException)
- {
- // ignored, happens on shutdown
- }
- }
-
- private void PacketHandler(Packet packet)
- {
- // Ignore duplicates
- if (packet.Ethernet.IpV4.Udp.SourcePort == 3724)
- return;
-
- var str = Encoding.Default.GetString(packet.Buffer);
- if (str.ToLower().Contains("artemis"))
- {
- var match = _rgx.Match(str);
- if (match.Groups.Count != 3)
- return;
-
- Logger.Debug("[{0}] {1}", packet.Ethernet.IpV4.Udp.SourcePort, match.Groups[2].Value);
- // Get the command and argument
- var parts = match.Groups[2].Value.Split('|');
- HandleGameData(parts[0], parts[1]);
- }
- }
-
- private void HandleGameData(string command, string data)
- {
- JObject json = null;
- if (!data.StartsWith("\"") && !data.EndsWith("\""))
- json = JObject.Parse(data);
-
- lock (DataModel)
- {
- 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;
- }
- }
- }
-
- private void ParsePlayer(JObject json, WoWDataModel dataModel)
- {
- dataModel.Player.ApplyJson(json);
- }
-
- private void ParseTarget(JObject json, WoWDataModel dataModel)
- {
- dataModel.Target.ApplyJson(json);
- }
-
- private void ParsePlayerState(JObject json, WoWDataModel dataModel)
- {
- 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() == "player")
- dataModel.Player.CastBar.ApplyJson(json);
- else if (json["unitID"].Value() == "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();
- _communicator.Dispose();
- base.Dispose();
- }
-
- public override void Update()
- {
- var dataModel = (WoWDataModel)DataModel;
-
- dataModel.Player.CastBar.UpdateProgress();
- dataModel.Target.CastBar.UpdateProgress();
- }
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using Artemis.DAL;
+using Artemis.Managers;
+using Artemis.Modules.Abstract;
+using Artemis.Modules.Games.WoW.Models;
+using Newtonsoft.Json.Linq;
+using PcapDotNet.Core;
+using PcapDotNet.Packets;
+
+namespace Artemis.Modules.Games.WoW
+{
+ public class WoWModel : ModuleModel
+ {
+ private readonly Regex _rgx;
+ private PacketCommunicator _communicator;
+
+ public WoWModel(DeviceManager deviceManager, LuaManager luaManager) : base(deviceManager, luaManager)
+ {
+ Settings = SettingsProvider.Load();
+ DataModel = new WoWDataModel();
+ ProcessNames.Add("Wow-64");
+
+ _rgx = new Regex("(artemis)\\((.*?)\\)", RegexOptions.Compiled);
+ }
+
+ public override string Name => "WoW";
+ public override bool IsOverlay => false;
+ public override bool IsBoundToProcess => true;
+
+
+ public override void Enable()
+ {
+ // Start scanning WoW packets
+ // Retrieve the device list from the local machine
+ IList allDevices = LivePacketDevice.AllLocalMachine;
+
+ if (allDevices.Count == 0)
+ {
+ Logger.Warn("No interfaces found! Can't scan WoW packets.");
+ return;
+ }
+
+ // Take the selected adapter
+ PacketDevice selectedDevice = allDevices.First();
+
+ // Open the device
+ _communicator = selectedDevice.Open(65536, PacketDeviceOpenAttributes.Promiscuous, 40);
+ Logger.Debug("Listening on " + selectedDevice.Description + " for WoW packets");
+
+ // Compile the filter
+ using (var filter = _communicator.CreateFilter("tcp"))
+ {
+ // Set the filter
+ _communicator.SetFilter(filter);
+ }
+
+ Task.Run(() => ReceivePackets());
+ base.Enable();
+ }
+
+ private void ReceivePackets()
+ {
+ // start the capture
+ try
+ {
+ _communicator.ReceivePackets(0, PacketHandler);
+ }
+ catch (InvalidOperationException)
+ {
+ // ignored, happens on shutdown
+ }
+ }
+
+ private void PacketHandler(Packet packet)
+ {
+ // Ignore duplicates
+ if (packet.Ethernet.IpV4.Udp.SourcePort == 3724)
+ return;
+
+ var str = Encoding.Default.GetString(packet.Buffer);
+ if (str.ToLower().Contains("artemis"))
+ {
+ var match = _rgx.Match(str);
+ if (match.Groups.Count != 3)
+ return;
+
+ Logger.Trace("[{0}] {1}", packet.Ethernet.IpV4.Udp.SourcePort, match.Groups[2].Value);
+ // Get the command and argument
+ var parts = match.Groups[2].Value.Split('|');
+ HandleGameData(parts[0], parts[1]);
+ }
+ }
+
+ private void HandleGameData(string command, string data)
+ {
+ JObject json = null;
+ if (!data.StartsWith("\"") && !data.EndsWith("\""))
+ json = JObject.Parse(data);
+
+ lock (DataModel)
+ {
+ 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 "auras":
+ ParseAuras(json, dataModel);
+ break;
+ case "spellCast":
+ ParseSpellCast(json, dataModel);
+ break;
+ case "instantSpellCast":
+ ParseInstantSpellCast(json, dataModel);
+ break;
+ case "spellCastFailed":
+ ParseSpellCastFailed(data, dataModel);
+ break;
+ case "spellCastInterrupted":
+ ParseSpellCastInterrupted(data, dataModel);
+ break;
+ default:
+ Logger.Warn("The WoW addon sent an unknown command: {0}", command);
+ break;
+ }
+ }
+ }
+
+ private void ParsePlayer(JObject json, WoWDataModel dataModel)
+ {
+ dataModel.Player.ApplyJson(json);
+ }
+
+ private void ParseTarget(JObject json, WoWDataModel dataModel)
+ {
+ dataModel.Target.ApplyJson(json);
+ }
+
+ private void ParsePlayerState(JObject json, WoWDataModel dataModel)
+ {
+ dataModel.Player.ApplyStateJson(json);
+ }
+
+ private void ParseTargetState(JObject json, WoWDataModel dataModel)
+ {
+ dataModel.Target.ApplyStateJson(json);
+ }
+
+ private void ParseAuras(JObject json, WoWDataModel dataModel)
+ {
+ dataModel.Player.ApplyAuraJson(json);
+ }
+
+ private void ParseSpellCast(JObject json, WoWDataModel dataModel)
+ {
+ if (json["unitID"].Value() == "player")
+ dataModel.Player.CastBar.ApplyJson(json);
+ else if (json["unitID"].Value() == "target")
+ dataModel.Target.CastBar.ApplyJson(json);
+ }
+
+ private void ParseInstantSpellCast(JObject json, WoWDataModel dataModel)
+ {
+ var spell = new WoWSpell
+ {
+ Name = json["name"].Value(),
+ Id = json["spellID"].Value()
+ };
+
+ if (json["unitID"].Value() == "player")
+ dataModel.Player.AddInstantCast(spell);
+ else if (json["unitID"].Value() == "target")
+ dataModel.Target.AddInstantCast(spell);
+ }
+
+ 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();
+ _communicator.Dispose();
+ base.Dispose();
+ }
+
+ public override void Update()
+ {
+ var dataModel = (WoWDataModel) DataModel;
+
+ dataModel.Player.Update();
+ dataModel.Target.Update();
+ }
+ }
+}
diff --git a/Artemis/Artemis/Modules/Games/WoW/WoWSettings.cs b/Artemis/Artemis/Modules/Games/WoW/WoWSettings.cs
index 2b2797c93..c4a3f3b5d 100644
--- a/Artemis/Artemis/Modules/Games/WoW/WoWSettings.cs
+++ b/Artemis/Artemis/Modules/Games/WoW/WoWSettings.cs
@@ -5,4 +5,4 @@ namespace Artemis.Modules.Games.WoW
public class WoWSettings : ModuleSettings
{
}
-}
\ No newline at end of file
+}
diff --git a/Artemis/Artemis/Modules/Games/WoW/WoWView.xaml b/Artemis/Artemis/Modules/Games/WoW/WoWView.xaml
index 9537d78fd..032a99375 100644
--- a/Artemis/Artemis/Modules/Games/WoW/WoWView.xaml
+++ b/Artemis/Artemis/Modules/Games/WoW/WoWView.xaml
@@ -1,13 +1,6 @@
-
+
diff --git a/Artemis/Artemis/Modules/Games/WoW/WoWView.xaml.cs b/Artemis/Artemis/Modules/Games/WoW/WoWView.xaml.cs
index 2e0bac541..33c9f8eb0 100644
--- a/Artemis/Artemis/Modules/Games/WoW/WoWView.xaml.cs
+++ b/Artemis/Artemis/Modules/Games/WoW/WoWView.xaml.cs
@@ -12,4 +12,4 @@ namespace Artemis.Modules.Games.WoW
InitializeComponent();
}
}
-}
\ No newline at end of file
+}
diff --git a/Artemis/Artemis/Modules/Games/WoW/WoWViewModel.cs b/Artemis/Artemis/Modules/Games/WoW/WoWViewModel.cs
index eed8a1228..5978f88c2 100644
--- a/Artemis/Artemis/Modules/Games/WoW/WoWViewModel.cs
+++ b/Artemis/Artemis/Modules/Games/WoW/WoWViewModel.cs
@@ -14,4 +14,4 @@ namespace Artemis.Modules.Games.WoW
public override bool UsesProfileEditor => true;
}
-}
\ No newline at end of file
+}
diff --git a/Artemis/Artemis/Profiles/Layers/Conditions/DataModelCondition.cs b/Artemis/Artemis/Profiles/Layers/Conditions/DataModelCondition.cs
index 31aafa17d..265eb7ef3 100644
--- a/Artemis/Artemis/Profiles/Layers/Conditions/DataModelCondition.cs
+++ b/Artemis/Artemis/Profiles/Layers/Conditions/DataModelCondition.cs
@@ -12,6 +12,8 @@ namespace Artemis.Profiles.Layers.Conditions
lock (layerModel.Properties.Conditions)
{
var checkConditions = layerModel.Properties.Conditions.Where(c => c.Field != null).ToList();
+ if (!checkConditions.Any())
+ return true;
switch (layerModel.Properties.ConditionType)
{
case ConditionType.AnyMet:
diff --git a/Artemis/Artemis/Profiles/Layers/Models/LayerConditionModel.cs b/Artemis/Artemis/Profiles/Layers/Models/LayerConditionModel.cs
index 9d7136081..b05d15b13 100644
--- a/Artemis/Artemis/Profiles/Layers/Models/LayerConditionModel.cs
+++ b/Artemis/Artemis/Profiles/Layers/Models/LayerConditionModel.cs
@@ -44,6 +44,8 @@ namespace Artemis.Profiles.Layers.Models
var collectionField = _rgx.Match(Field).Groups[1].Value;
var collectionInspect = (IEnumerable) GeneralHelpers.GetPropertyValue(subject, collectionField);
var operatorParts = Operator.Split('|');
+ var field = Field.Split(')').Last().Substring(1);
+
_lastValue = collectionInspect;
if (operatorParts[0] == "any")
@@ -51,7 +53,6 @@ namespace Artemis.Profiles.Layers.Models
var anyMatch = false;
foreach (var collectionValue in collectionInspect)
{
- var field = Field.Split(')').Last().Substring(1);
anyMatch = EvaluateOperator(collectionValue, field, operatorParts[1]);
if (anyMatch)
break;
@@ -63,7 +64,6 @@ namespace Artemis.Profiles.Layers.Models
var allMatch = true;
foreach (var collectionValue in collectionInspect)
{
- var field = Field.Split(')').Last().Substring(1);
allMatch = EvaluateOperator(collectionValue, field, operatorParts[1]);
if (!allMatch)
break;
@@ -75,7 +75,6 @@ namespace Artemis.Profiles.Layers.Models
var noneMatch = true;
foreach (var collectionValue in collectionInspect)
{
- var field = Field.Split(')').Last().Substring(1);
noneMatch = !EvaluateOperator(collectionValue, field, operatorParts[1]);
if (!noneMatch)
break;