diff --git a/Artemis/Artemis/Artemis.csproj b/Artemis/Artemis/Artemis.csproj
index 09fb424d3..065d941fb 100644
--- a/Artemis/Artemis/Artemis.csproj
+++ b/Artemis/Artemis/Artemis.csproj
@@ -152,8 +152,8 @@
True
- ..\packages\CUE.NET.1.0.3\lib\net45\CUE.NET.dll
- True
+ False
+ ..\..\..\CUE.NET\bin\CUE.NET.dll
..\packages\DeltaCompressionDotNet.1.0.0\lib\net45\DeltaCompressionDotNet.dll
@@ -246,6 +246,10 @@
..\packages\squirrel.windows.1.4.4\lib\Net45\NuGet.Squirrel.dll
True
+
+ ..\packages\Process.NET.1.0.1\lib\Process.NET.dll
+ True
+
..\packages\Splat.1.6.2\lib\Net45\Splat.dll
True
@@ -331,6 +335,7 @@
+
@@ -363,7 +368,6 @@
-
@@ -385,11 +389,23 @@
UnrealTournamentView.xaml
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+ WoWView.xaml
+
+
+
+
+
+
@@ -410,10 +426,14 @@
+
+ MousematPropertiesView.xaml
+
+
+
-
@@ -632,6 +652,8 @@
Code
+
+
@@ -713,6 +735,10 @@
MSBuild:Compile
Designer
+
+ MSBuild:Compile
+ Designer
+
MSBuild:Compile
Designer
@@ -725,6 +751,10 @@
MSBuild:Compile
Designer
+
+ MSBuild:Compile
+ Designer
+
MSBuild:Compile
Designer
@@ -841,6 +871,7 @@
+
diff --git a/Artemis/Artemis/DeviceProviders/Corsair/CorsairMousemats.cs b/Artemis/Artemis/DeviceProviders/Corsair/CorsairMousemats.cs
new file mode 100644
index 000000000..63c656c24
--- /dev/null
+++ b/Artemis/Artemis/DeviceProviders/Corsair/CorsairMousemats.cs
@@ -0,0 +1,104 @@
+using System;
+using System.Drawing;
+using System.Linq;
+using System.Threading;
+using CUE.NET;
+using CUE.NET.Devices.Generic.Enums;
+using CUE.NET.Devices.Mousemat.Enums;
+using Ninject.Extensions.Logging;
+
+namespace Artemis.DeviceProviders.Corsair
+{
+ internal class CorsairMousemats : DeviceProvider
+ {
+ public CorsairMousemats(ILogger logger)
+ {
+ Logger = logger;
+ Type = DeviceType.Mousemat;
+ }
+
+ public ILogger Logger { get; set; }
+
+ public override bool TryEnable()
+ {
+ CanUse = CanInitializeSdk();
+ if (CanUse && !CueSDK.IsInitialized)
+ CueSDK.Initialize();
+
+ Logger.Debug("Attempted to enable Corsair mousemat. CanUse: {0}", CanUse);
+
+ if (CanUse)
+ CueSDK.MousematSDK.UpdateMode = UpdateMode.Manual;
+
+ return CanUse;
+ }
+
+ public override void Disable()
+ {
+ throw new NotImplementedException("Can only disable a keyboard");
+ }
+
+ public override void UpdateDevice(Bitmap bitmap)
+ {
+ if (!CanUse || bitmap == null)
+ return;
+ if (bitmap.Width != bitmap.Height)
+ throw new ArgumentException("Bitmap must be a perfect square");
+
+ var yStep = (double) bitmap.Width/5;
+ var xStep = (double) bitmap.Width/7;
+
+ // This approach will break if any mousemats with different LED amounts are released, for now it will do.
+ using (bitmap)
+ {
+ var ledIndex = 1;
+ // Color each LED according to one of the pixels
+ foreach (var corsairLed in CueSDK.MousematSDK.Leds.OrderBy(l => l.ToString()))
+ {
+ Color col;
+ // Left side
+ if (ledIndex < 6)
+ {
+ col = ledIndex != 5
+ ? bitmap.GetPixel(0, (int) (ledIndex*yStep + yStep/2))
+ : bitmap.GetPixel(0, (int) (ledIndex*yStep) - 1);
+ }
+ // Bottom
+ else if (ledIndex < 11)
+ {
+ // Start at index 2 because the corner belongs to the left side
+ var zoneIndex = ledIndex - 4;
+ col = bitmap.GetPixel((int) (zoneIndex*xStep + xStep/2), 0);
+ }
+ // Right side
+ else
+ {
+ var zoneIndex = ledIndex - 10;
+ col = zoneIndex != 5
+ ? bitmap.GetPixel(0, bitmap.Height - ((int) (zoneIndex*yStep + yStep/2)))
+ : bitmap.GetPixel(0, bitmap.Height - ((int) (zoneIndex*yStep) - 1));
+ }
+
+ corsairLed.Color = col;
+ ledIndex++;
+ }
+ }
+ CueSDK.MousematSDK.Update();
+ }
+
+ private static bool CanInitializeSdk()
+ {
+ // This will skip the check-loop if the SDK is initialized
+ if (CueSDK.IsInitialized)
+ return CueSDK.IsSDKAvailable(CorsairDeviceType.Mousemat);
+
+ for (var tries = 0; tries < 9; tries++)
+ {
+ if (CueSDK.IsSDKAvailable(CorsairDeviceType.Mousemat))
+ return true;
+ Thread.Sleep(2000);
+ }
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Artemis/Artemis/DeviceProviders/DeviceProvider.cs b/Artemis/Artemis/DeviceProviders/DeviceProvider.cs
index 970fa50ad..9399328e0 100644
--- a/Artemis/Artemis/DeviceProviders/DeviceProvider.cs
+++ b/Artemis/Artemis/DeviceProviders/DeviceProvider.cs
@@ -46,6 +46,7 @@ namespace Artemis.DeviceProviders
Keyboard,
Mouse,
Headset,
- Generic
+ Generic,
+ Mousemat
}
}
\ No newline at end of file
diff --git a/Artemis/Artemis/InjectionModules/DeviceModules.cs b/Artemis/Artemis/InjectionModules/DeviceModules.cs
index 32e101b64..86ecdcc59 100644
--- a/Artemis/Artemis/InjectionModules/DeviceModules.cs
+++ b/Artemis/Artemis/InjectionModules/DeviceModules.cs
@@ -22,6 +22,9 @@ namespace Artemis.InjectionModules
// Headsets
Bind().To().InSingletonScope();
+ // Mousemats
+ Bind().To().InSingletonScope();
+
// Other
Bind().To().InSingletonScope();
}
diff --git a/Artemis/Artemis/InjectionModules/ProfileModules.cs b/Artemis/Artemis/InjectionModules/ProfileModules.cs
index e5e99ee50..a31c40b5d 100644
--- a/Artemis/Artemis/InjectionModules/ProfileModules.cs
+++ b/Artemis/Artemis/InjectionModules/ProfileModules.cs
@@ -9,6 +9,7 @@ using Artemis.Profiles.Layers.Types.Keyboard;
using Artemis.Profiles.Layers.Types.KeyboardGif;
using Artemis.Profiles.Layers.Types.KeyPress;
using Artemis.Profiles.Layers.Types.Mouse;
+using Artemis.Profiles.Layers.Types.Mousemat;
using Ninject.Modules;
namespace Artemis.InjectionModules
@@ -36,6 +37,7 @@ namespace Artemis.InjectionModules
Bind().To();
Bind().To();
Bind().To();
+ Bind().To();
Bind().To();
Bind().To();
Bind().To();
diff --git a/Artemis/Artemis/Managers/DeviceManager.cs b/Artemis/Artemis/Managers/DeviceManager.cs
index 676d3da13..362f5cc11 100644
--- a/Artemis/Artemis/Managers/DeviceManager.cs
+++ b/Artemis/Artemis/Managers/DeviceManager.cs
@@ -31,6 +31,7 @@ namespace Artemis.Managers
MiceProviders = deviceProviders.Where(d => d.Type == DeviceType.Mouse).ToList();
HeadsetProviders = deviceProviders.Where(d => d.Type == DeviceType.Headset).ToList();
GenericProviders = deviceProviders.Where(d => d.Type == DeviceType.Generic).ToList();
+ MousematProviders = deviceProviders.Where(d => d.Type == DeviceType.Mousemat).ToList();
_logger.Info("Intialized DeviceManager with {0} device providers", deviceProviders.Count);
}
@@ -38,6 +39,7 @@ namespace Artemis.Managers
public List MiceProviders { get; set; }
public List HeadsetProviders { get; set; }
public List GenericProviders { get; set; }
+ public List MousematProviders { get; set; }
[Inject]
public MetroDialogService DialogService { get; set; }
@@ -47,6 +49,8 @@ namespace Artemis.Managers
public KeyboardProvider ActiveKeyboard { get; set; }
public bool ChangingKeyboard { get; private set; }
+
+
public event EventHandler OnKeyboardChangedEvent;
///
@@ -137,6 +141,8 @@ namespace Artemis.Managers
headsetProvider.TryEnableAsync();
foreach (var genericProvider in GenericProviders)
genericProvider.TryEnableAsync();
+ foreach (var mousematProviders in MousematProviders)
+ mousematProviders.TryEnableAsync();
}
///
diff --git a/Artemis/Artemis/Managers/LoopManager.cs b/Artemis/Artemis/Managers/LoopManager.cs
index b4c3e40a3..cda3dec0a 100644
--- a/Artemis/Artemis/Managers/LoopManager.cs
+++ b/Artemis/Artemis/Managers/LoopManager.cs
@@ -132,18 +132,20 @@ namespace Artemis.Managers
var mice = _deviceManager.MiceProviders.Where(m => m.CanUse).ToList();
var headsets = _deviceManager.HeadsetProviders.Where(m => m.CanUse).ToList();
var generics = _deviceManager.GenericProviders.Where(m => m.CanUse).ToList();
+ var mousemats = _deviceManager.MousematProviders.Where(m => m.CanUse).ToList();
+ var keyboardOnly = !mice.Any() && !headsets.Any() && !generics.Any() && !mousemats.Any();
// Setup the frame for this tick
using (var frame = new RenderFrame(_deviceManager.ActiveKeyboard))
{
if (renderEffect.Initialized)
- renderEffect.Render(frame, !mice.Any() && !headsets.Any() && !generics.Any());
+ renderEffect.Render(frame, keyboardOnly);
// Draw enabled overlays on top of the renderEffect
foreach (var overlayModel in _effectManager.EnabledOverlays)
{
overlayModel.Update();
- overlayModel.RenderOverlay(frame, !mice.Any() && !headsets.Any() && !generics.Any());
+ overlayModel.RenderOverlay(frame, keyboardOnly);
}
// Update the keyboard
@@ -156,6 +158,8 @@ namespace Artemis.Managers
headset.UpdateDevice(frame.HeadsetBitmap);
foreach (var generic in generics)
generic.UpdateDevice(frame.GenericBitmap);
+ foreach (var mousemat in mousemats)
+ mousemat.UpdateDevice(frame.MousematBitmap);
}
}
}
@@ -177,6 +181,9 @@ namespace Artemis.Managers
GenericBitmap = new Bitmap(40, 40);
GenericBitmap.SetResolution(96, 96);
+ MousematBitmap = new Bitmap(40, 40);
+ MousematBitmap.SetResolution(96, 96);
+
using (var g = Graphics.FromImage(KeyboardBitmap))
g.Clear(Color.Black);
using (var g = Graphics.FromImage(MouseBitmap))
@@ -185,12 +192,15 @@ namespace Artemis.Managers
g.Clear(Color.Black);
using (var g = Graphics.FromImage(GenericBitmap))
g.Clear(Color.Black);
+ using (var g = Graphics.FromImage(MousematBitmap))
+ g.Clear(Color.Black);
}
public Bitmap KeyboardBitmap { get; set; }
public Bitmap MouseBitmap { get; set; }
public Bitmap HeadsetBitmap { get; set; }
public Bitmap GenericBitmap { get; set; }
+ public Bitmap MousematBitmap { get; set; }
public void Dispose()
{
diff --git a/Artemis/Artemis/Managers/MainManager.cs b/Artemis/Artemis/Managers/MainManager.cs
index b0d8fe146..3c28c588e 100644
--- a/Artemis/Artemis/Managers/MainManager.cs
+++ b/Artemis/Artemis/Managers/MainManager.cs
@@ -114,7 +114,7 @@ namespace Artemis.Managers
if (!ProgramEnabled)
return;
- var runningProcesses = Process.GetProcesses();
+ var runningProcesses = System.Diagnostics.Process.GetProcesses();
// If the currently active effect is a disabled game, get rid of it.
if (EffectManager.ActiveEffect != null)
diff --git a/Artemis/Artemis/Models/EffectModel.cs b/Artemis/Artemis/Models/EffectModel.cs
index c0ec5cbb6..eb81fd9de 100644
--- a/Artemis/Artemis/Models/EffectModel.cs
+++ b/Artemis/Artemis/Models/EffectModel.cs
@@ -88,6 +88,12 @@ namespace Artemis.Models
Profile?.DrawLayers(g, renderLayers.Where(rl => rl.LayerType.DrawType == DrawType.Generic),
DataModel, devRec, false, true);
}
+ // Render mousemats layer-by-layer
+ using (var g = Graphics.FromImage(frame.MousematBitmap))
+ {
+ Profile?.DrawLayers(g, renderLayers.Where(rl => rl.LayerType.DrawType == DrawType.Mousemat),
+ DataModel, devRec, false, true);
+ }
// Trace debugging
if (DateTime.Now.AddSeconds(-2) <= LastTrace)
diff --git a/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualization.cs b/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualization.cs
deleted file mode 100644
index 677970011..000000000
--- a/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualization.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using System.ComponentModel;
-using System.Configuration;
-
-namespace Artemis.Modules.Effects.AudioVisualizer
-{
- // This class allows you to handle specific events on the settings class:
- // The SettingChanging event is raised before a setting's value is changed.
- // The PropertyChanged event is raised after a setting's value is changed.
- // The SettingsLoaded event is raised after the setting values are loaded.
- // The SettingsSaving event is raised before the setting values are saved.
- internal sealed partial class AudioVisualization
- {
- private void SettingChangingEventHandler(object sender, SettingChangingEventArgs e)
- {
- // Add code to handle the SettingChangingEvent event here.
- }
-
- private void SettingsSavingEventHandler(object sender, CancelEventArgs e)
- {
- // Add code to handle the SettingsSaving event here.
- }
- }
-}
\ No newline at end of file
diff --git a/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerModel.cs b/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerModel.cs
deleted file mode 100644
index 90ede32ce..000000000
--- a/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerModel.cs
+++ /dev/null
@@ -1,206 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Drawing.Drawing2D;
-using System.Linq;
-using Artemis.Managers;
-using Artemis.Models;
-using Artemis.Modules.Effects.AudioVisualizer.Utilities;
-using Artemis.Profiles.Layers.Models;
-using Artemis.Utilities;
-using Artemis.Utilities.Keyboard;
-using NAudio.CoreAudioApi;
-using NAudio.Wave;
-
-namespace Artemis.Modules.Effects.AudioVisualizer
-{
- public class AudioVisualizerModel : EffectModel
- {
- private const int FftLength = 2048;
- private readonly SampleAggregator _sampleAggregator = new SampleAggregator(FftLength);
- private bool _fromBottom;
- private bool _generating;
- private int _sensitivity;
- private IWaveIn _waveIn;
-
- public AudioVisualizerModel(MainManager mainManager) : base(mainManager, null, null)
- {
- Name = "Audiovisualizer";
- DeviceIds = new List();
- SpectrumData = new List();
- Initialized = false;
- }
-
- public int Lines { get; set; }
-
- public List SpectrumData { get; set; }
- public List SoundRectangles { get; set; }
-
- public List DeviceIds { get; set; }
- public string SelectedDeviceId { get; set; }
-
- public override void Dispose()
- {
- Initialized = false;
- _sampleAggregator.PerformFFT = false;
- _sampleAggregator.FftCalculated -= FftCalculated;
-
- if (_waveIn == null)
- return;
- _waveIn.StopRecording();
- _waveIn.DataAvailable -= OnDataAvailable;
- _waveIn = null;
- }
-
- public override void Enable()
- {
- Initialized = false;
- Lines = MainManager.DeviceManager.ActiveKeyboard.Width;
-
- // TODO: Device selection
- SelectedDeviceId = new MMDeviceEnumerator()
- .EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active)
- .FirstOrDefault()?.ID;
-
- // Apply settings
- SoundRectangles = new List();
- for (var i = 0; i < Lines; i++)
- {
- SoundRectangles.Add(new KeyboardRectangle(
- MainManager.DeviceManager.ActiveKeyboard,
- 0, 0, new List
- {
- Color.Red,
- Color.Yellow,
- Color.Lime
- },
- LinearGradientMode.Vertical)
- {ContainedBrush = false, Height = 0});
- }
- _sensitivity = 2;
- _fromBottom = true;
- _sampleAggregator.FftCalculated += FftCalculated;
- _sampleAggregator.PerformFFT = true;
-
- // Start listening for sound data
- _waveIn = new WasapiLoopbackCapture();
- _waveIn.DataAvailable += OnDataAvailable;
- _waveIn.StartRecording();
-
- Initialized = true;
- }
-
- public override void Update()
- {
- // TODO: Use lock instead of a bool
- // Start filling the model
- _generating = true;
-
- if (SelectedDeviceId == null)
- return;
-
- var device = new MMDeviceEnumerator()
- .EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active)
- .FirstOrDefault(d => d.ID == SelectedDeviceId);
-
- if (device == null || SpectrumData == null)
- return;
- if (!SpectrumData.Any())
- return;
-
- // Parse spectrum data
- for (var i = 0; i < Lines; i++)
- {
- int height;
- if (SpectrumData.Count - 1 < i || SpectrumData[i] == 0)
- height = 0;
- else
- height = (int) Math.Round(SpectrumData[i]/2.55);
-
- // Apply Sensitivity setting
- height = height*_sensitivity;
- var keyboardHeight =
- (int) Math.Round(MainManager.DeviceManager.ActiveKeyboard.Height/100.00*height*KeyboardScale);
- if (keyboardHeight > SoundRectangles[i].Height)
- SoundRectangles[i].Height = keyboardHeight;
- else
- SoundRectangles[i].Height = SoundRectangles[i].Height -
- 5; // was FadeSpeed setting
- // Apply Bars setting
- SoundRectangles[i].X = i*KeyboardScale;
- SoundRectangles[i].Width = KeyboardScale;
-
- if (_fromBottom)
- SoundRectangles[i].Y = MainManager.DeviceManager.ActiveKeyboard.Height*KeyboardScale -
- SoundRectangles[i].Height;
- }
- _generating = false;
- }
-
- private void OnDataAvailable(object sender, WaveInEventArgs e)
- {
- var buffer = e.Buffer;
- var bytesRecorded = e.BytesRecorded;
- var bufferIncrement = _waveIn.WaveFormat.BlockAlign;
-
- for (var index = 0; index < bytesRecorded; index += bufferIncrement)
- {
- var sample32 = BitConverter.ToSingle(buffer, index);
- _sampleAggregator.Add(sample32);
- }
- }
-
- private void FftCalculated(object sender, FftEventArgs e)
- {
- if (_generating)
- return;
-
- int x;
- var b0 = 0;
-
- SpectrumData.Clear();
- for (x = 0; x < Lines; x++)
- {
- float peak = 0;
- var b1 = (int) Math.Pow(2, x*10.0/(Lines - 1));
- if (b1 > 2047)
- b1 = 2047;
- if (b1 <= b0)
- b1 = b0 + 1;
- for (; b0 < b1; b0++)
- {
- if (peak < e.Result[1 + b0].X)
- peak = e.Result[1 + b0].X;
- }
- var y = (int) (Math.Sqrt(peak)*3*255 - 4);
- if (y > 255)
- y = 255;
- if (y < 0)
- y = 0;
- SpectrumData.Add((byte) y);
- }
- }
-
- public override List GetRenderLayers(bool keyboardOnly)
- {
- return null;
- }
-
- public override void Render(RenderFrame frame, bool keyboardOnly)
- {
- if (SpectrumData == null || SoundRectangles == null)
- return;
-
- // Lock the _spectrumData array while busy with it
- _generating = true;
-
- using (var g = Graphics.FromImage(frame.KeyboardBitmap))
- {
- foreach (var soundRectangle in SoundRectangles)
- soundRectangle.Draw(g);
- }
-
- _generating = false;
- }
- }
-}
\ No newline at end of file
diff --git a/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerView.xaml b/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerView.xaml
index 0884c7690..efdc30bd3 100644
--- a/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerView.xaml
+++ b/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerView.xaml
@@ -3,110 +3,31 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
- xmlns:cal="http://www.caliburnproject.org"
- xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls"
mc:Ignorable="d"
d:DesignHeight="476.986" d:DesignWidth="538.772">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Color used on top
-
-
+
-
-
- Color used in the middle
+
+
+
+
+
+
+
+
-
-
-
-
- Color used on the bottom
-
-
-
-
-
- Grow bars bottom
-
-
-
-
-
- Volume sensitivity multiplier
-
-
-
-
-
- Bar fade-out speed
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerViewModel.cs b/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerViewModel.cs
index 92614ef8d..702d6610d 100644
--- a/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerViewModel.cs
+++ b/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerViewModel.cs
@@ -1,13 +1,14 @@
using Artemis.Managers;
+using Artemis.Modules.Effects.ProfilePreview;
using Artemis.ViewModels.Abstract;
namespace Artemis.Modules.Effects.AudioVisualizer
{
public sealed class AudioVisualizerViewModel : EffectViewModel
{
- public AudioVisualizerViewModel(MainManager main, AudioVisualizerModel model) : base(main, model)
+ public AudioVisualizerViewModel(MainManager main, ProfilePreviewModel model) : base(main, model)
{
- DisplayName = "Audio Visualization";
+ DisplayName = "Audio Visualization / Key waves";
}
}
}
\ No newline at end of file
diff --git a/Artemis/Artemis/Modules/Effects/ProfilePreview/ProfilePreviewModel.cs b/Artemis/Artemis/Modules/Effects/ProfilePreview/ProfilePreviewModel.cs
index d2d05ce38..90d53c22c 100644
--- a/Artemis/Artemis/Modules/Effects/ProfilePreview/ProfilePreviewModel.cs
+++ b/Artemis/Artemis/Modules/Effects/ProfilePreview/ProfilePreviewModel.cs
@@ -79,6 +79,13 @@ namespace Artemis.Modules.Effects.ProfilePreview
DataModel,
devRec, true, true);
}
+ // Render mousemats layer-by-layer
+ using (var g = Graphics.FromImage(frame.MousematBitmap))
+ {
+ Profile?.DrawLayers(g, renderLayers.Where(rl => rl.LayerType.DrawType == DrawType.Mousemat),
+ DataModel,
+ devRec, true, true);
+ }
}
}
}
diff --git a/Artemis/Artemis/Modules/Games/Witcher3/Witcher3ViewModel.cs b/Artemis/Artemis/Modules/Games/Witcher3/Witcher3ViewModel.cs
index fd46158ec..433b4c0a0 100644
--- a/Artemis/Artemis/Modules/Games/Witcher3/Witcher3ViewModel.cs
+++ b/Artemis/Artemis/Modules/Games/Witcher3/Witcher3ViewModel.cs
@@ -74,8 +74,7 @@ namespace Artemis.Modules.Games.Witcher3
archive.ExtractToDirectory(folder + @"witcher3-mod", true);
- Process.Start(
- new ProcessStartInfo("https://github.com/SpoinkyNL/Artemis/wiki/The-Witcher-3"));
+ System.Diagnostics.Process.Start(new ProcessStartInfo("https://github.com/SpoinkyNL/Artemis/wiki/The-Witcher-3"));
return;
}
}
diff --git a/Artemis/Artemis/Modules/Games/WoW/Data/Int128.cs b/Artemis/Artemis/Modules/Games/WoW/Data/Int128.cs
new file mode 100644
index 000000000..4a66ecc0f
--- /dev/null
+++ b/Artemis/Artemis/Modules/Games/WoW/Data/Int128.cs
@@ -0,0 +1,2256 @@
+using System;
+using System.ComponentModel;
+using System.Globalization;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Text;
+using Microsoft.SqlServer.Server;
+
+namespace Artemis.Modules.Games.WoW.Data
+{
+ namespace WowSharp.Client.Patchables
+ {
+ ///
+ /// Represents a 128-bit signed integer.
+ ///
+#if !WINDOWS_PHONE && !SILVERLIGHT
+ [Serializable]
+#endif
+ [StructLayout(LayoutKind.Sequential)]
+ [TypeConverter(typeof(Int128Converter))]
+ public struct Int128 : IComparable, IComparable, IEquatable, IConvertible, IFormattable
+#if !WINDOWS_PHONE && !SILVERLIGHT
+ , IBinarySerialize
+#endif
+ {
+ private ulong _hi;
+ private ulong _lo;
+
+ private const ulong HiNeg = 0x8000000000000000;
+
+ ///
+ /// Gets a value that represents the number 0 (zero).
+ ///
+ public static Int128 Zero = GetZero();
+
+ ///
+ /// Represents the largest possible value of an Int128.
+ ///
+ public static Int128 MaxValue = GetMaxValue();
+
+ ///
+ /// Represents the smallest possible value of an Int128.
+ ///
+ public static Int128 MinValue = GetMinValue();
+
+ private static Int128 GetMaxValue()
+ {
+ return new Int128(long.MaxValue, ulong.MaxValue);
+ }
+
+ private static Int128 GetMinValue()
+ {
+ return new Int128(HiNeg, 0);
+ }
+
+ private static Int128 GetZero()
+ {
+ return new Int128();
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The value.
+ public Int128(byte value)
+ {
+ _hi = 0;
+ _lo = value;
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// if set to true [value].
+ public Int128(bool value)
+ {
+ _hi = 0;
+ _lo = (ulong) (value ? 1 : 0);
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The value.
+ public Int128(char value)
+ {
+ _hi = 0;
+ _lo = value;
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The value.
+ public Int128(decimal value)
+ {
+ if (value < 0)
+ {
+ var n = -new Int128(-value);
+ _hi = n._hi;
+ _lo = n._lo;
+ return;
+ }
+
+ var bits = decimal.GetBits(value);
+ _hi = (uint) bits[2];
+ _lo = (uint) bits[0] | ((ulong) bits[1] << 32);
+
+ var scale = (bits[3] >> 16) & 31;
+ if (scale > 0)
+ {
+ var i = new Int128(_hi, _lo);
+ for (var s = 0; s < scale; s++)
+ i = i/10;
+ _hi = i._hi;
+ _lo = i._lo;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The value.
+ public Int128(double value)
+ : this((decimal) value)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The value.
+ public Int128(float value)
+ : this((decimal) value)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The value.
+ public Int128(short value)
+ : this((int) value)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The value.
+ public Int128(int value)
+ : this((long) value)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The value.
+ public Int128(long value)
+ {
+ if (value < 0)
+ {
+ // long.MinValue = -long.MinValue
+ if (value == long.MinValue)
+ {
+ _hi = HiNeg;
+ _lo = HiNeg;
+ return;
+ }
+
+ var n = -new Int128(-value);
+ _hi = n._hi;
+ _lo = n._lo;
+ return;
+ }
+
+ _hi = 0;
+ _lo = (ulong) value;
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The value.
+ public Int128(sbyte value)
+ : this((long) value)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The value.
+ public Int128(ushort value)
+ {
+ _hi = 0;
+ _lo = value;
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The value.
+ public Int128(uint value)
+ {
+ _hi = 0;
+ _lo = value;
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The value.
+ public Int128(ulong value)
+ {
+ _hi = 0;
+ _lo = value;
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The value.
+ public Int128(Guid value)
+ : this(value.ToByteArray())
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The value.
+ public Int128(byte[] value)
+ {
+ if (value == null)
+ throw new ArgumentNullException("value");
+
+ if (value.Length != 16)
+ throw new ArgumentException(null, "value");
+
+ _hi = BitConverter.ToUInt64(value, 8);
+ _lo = BitConverter.ToUInt64(value, 0);
+ }
+
+ public Int128(ulong hi, ulong lo)
+ {
+ _hi = hi;
+ _lo = lo;
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The sign.
+ /// The ints.
+ public Int128(int sign, uint[] ints)
+ {
+ if (ints == null)
+ throw new ArgumentNullException("ints");
+
+ var lo = new byte[8];
+ var hi = new byte[8];
+
+ if (ints.Length > 0)
+ {
+ Array.Copy(BitConverter.GetBytes(ints[0]), 0, lo, 0, 4);
+ if (ints.Length > 1)
+ {
+ Array.Copy(BitConverter.GetBytes(ints[1]), 0, lo, 4, 4);
+ if (ints.Length > 2)
+ {
+ Array.Copy(BitConverter.GetBytes(ints[2]), 0, hi, 0, 4);
+ if (ints.Length > 3)
+ Array.Copy(BitConverter.GetBytes(ints[3]), 0, hi, 4, 4);
+ }
+ }
+ }
+
+ _lo = BitConverter.ToUInt64(lo, 0);
+ _hi = BitConverter.ToUInt64(hi, 0);
+
+ if (sign < 0)
+ _hi |= HiNeg;
+ else
+ _hi &= ~HiNeg;
+ }
+
+ ///
+ /// Gets a number that indicates the sign (negative, positive, or zero) of the current Int128 object.
+ ///
+ /// A number that indicates the sign of the Int128 object
+ public int Sign
+ {
+ get
+ {
+ if ((_hi == 0) && (_lo == 0))
+ return 0;
+
+ return (_hi & HiNeg) == 0 ? 1 : -1;
+ }
+ }
+
+ ///
+ /// Returns a hash code for this instance.
+ ///
+ ///
+ /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
+ ///
+ public override int GetHashCode()
+ {
+ return _hi.GetHashCode() ^ _lo.GetHashCode();
+ }
+
+ ///
+ /// Returns a value indicating whether this instance is equal to a specified object.
+ ///
+ /// An object to compare with this instance.
+ ///
+ /// true if obj has the same value as this instance; otherwise, false.
+ ///
+ public override bool Equals(object obj)
+ {
+ return base.Equals(obj);
+ }
+
+ ///
+ /// Returns a value indicating whether this instance is equal to a specified Int64 value.
+ ///
+ /// The obj.
+ ///
+ /// true if obj has the same value as this instance; otherwise, false.
+ ///
+ public bool Equals(Int128 obj)
+ {
+ return (_hi == obj._hi) && (_lo == obj._lo);
+ }
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ ///
+ /// A that represents this instance.
+ ///
+ public override string ToString()
+ {
+ return ToString(null, null);
+ }
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ /// The format. Only x, X, g, G, d, D are supported.
+ ///
+ /// A that represents this instance.
+ ///
+ public string ToString(string format)
+ {
+ return ToString(format, null);
+ }
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ /// The format. Only x, X, g, G, d, D are supported.
+ /// An object that supplies culture-specific formatting information about this instance.
+ ///
+ /// A that represents this instance.
+ ///
+ public string ToString(string format, IFormatProvider formatProvider)
+ {
+ if (formatProvider == null)
+ formatProvider = CultureInfo.CurrentCulture;
+
+ if (!string.IsNullOrEmpty(format))
+ {
+ var ch = format[0];
+ if ((ch == 'x') || (ch == 'X'))
+ {
+ int min;
+ int.TryParse(format.Substring(1).Trim(), out min);
+ return ToHexaString(ch == 'X', min);
+ }
+
+ if ((ch != 'G') && (ch != 'g') && (ch != 'D') && (ch != 'd'))
+ throw new NotSupportedException("Not supported format: " + format);
+ }
+
+ return ToString((NumberFormatInfo) formatProvider.GetFormat(typeof(NumberFormatInfo)));
+ }
+
+ private string ToHexaString(bool caps, int min)
+ {
+ var sb = new StringBuilder();
+ var x = caps ? "X" : "x";
+ if ((min < 0) || (min > 16) || (_hi != 0))
+ {
+ sb.Append(min > 16 ? _hi.ToString(x + (min - 16)) : _hi.ToString(x));
+ sb.Append(_lo.ToString(x + "16"));
+ }
+ else
+ {
+ sb.Append(_lo.ToString(x + min));
+ }
+ return sb.ToString();
+ }
+
+ private string ToString(NumberFormatInfo info)
+ {
+ if (Sign == 0)
+ return "0";
+
+ var sb = new StringBuilder();
+ var ten = new Int128(10);
+ var current = this;
+ current._hi &= ~HiNeg;
+ Int128 r;
+ while (true)
+ {
+ current = DivRem(current, ten, out r);
+ if ((r._lo > 0) || (current.Sign != 0) || (sb.Length == 0))
+ {
+#if !WINDOWS_PHONE && !SILVERLIGHT
+ sb.Insert(0, (char) ('0' + r._lo));
+#else
+ sb.Insert(0, new[] { (char)('0' + r._lo) });
+#endif
+ }
+ if (current.Sign == 0)
+ break;
+ }
+
+ var s = sb.ToString();
+ if ((Sign < 0) && (s != "0"))
+ return info.NegativeSign + s;
+
+ return s;
+ }
+
+ ///
+ /// Returns the for this instance.
+ ///
+ ///
+ /// The enumerated constant that is the of the class or value type that implements
+ /// this interface.
+ ///
+ TypeCode IConvertible.GetTypeCode()
+ {
+ return TypeCode.Object;
+ }
+
+ ///
+ /// Converts the value of this instance to an equivalent Boolean value using the specified culture-specific formatting
+ /// information.
+ ///
+ ///
+ /// An interface implementation that supplies
+ /// culture-specific formatting information.
+ ///
+ ///
+ /// A Boolean value equivalent to the value of this instance.
+ ///
+ bool IConvertible.ToBoolean(IFormatProvider provider)
+ {
+ return (bool) this;
+ }
+
+ ///
+ /// Converts the value of this instance to an equivalent 8-bit unsigned integer using the specified culture-specific
+ /// formatting information.
+ ///
+ ///
+ /// An interface implementation that supplies
+ /// culture-specific formatting information.
+ ///
+ ///
+ /// An 8-bit unsigned integer equivalent to the value of this instance.
+ ///
+ byte IConvertible.ToByte(IFormatProvider provider)
+ {
+ return (byte) this;
+ }
+
+ ///
+ /// Converts the value of this instance to an equivalent Unicode character using the specified culture-specific
+ /// formatting information.
+ ///
+ ///
+ /// An interface implementation that supplies
+ /// culture-specific formatting information.
+ ///
+ ///
+ /// A Unicode character equivalent to the value of this instance.
+ ///
+ char IConvertible.ToChar(IFormatProvider provider)
+ {
+ return (char) this;
+ }
+
+ ///
+ /// Converts the value of this instance to an equivalent using the specified
+ /// culture-specific formatting information.
+ ///
+ ///
+ /// An interface implementation that supplies
+ /// culture-specific formatting information.
+ ///
+ ///
+ /// A instance equivalent to the value of this instance.
+ ///
+ DateTime IConvertible.ToDateTime(IFormatProvider provider)
+ {
+ throw new InvalidCastException();
+ }
+
+ ///
+ /// Converts the value of this instance to an equivalent number using the specified
+ /// culture-specific formatting information.
+ ///
+ ///
+ /// An interface implementation that supplies
+ /// culture-specific formatting information.
+ ///
+ ///
+ /// A number equivalent to the value of this instance.
+ ///
+ decimal IConvertible.ToDecimal(IFormatProvider provider)
+ {
+ return (decimal) this;
+ }
+
+ ///
+ /// Converts the value of this instance to an equivalent double-precision floating-point number using the specified
+ /// culture-specific formatting information.
+ ///
+ ///
+ /// An interface implementation that supplies
+ /// culture-specific formatting information.
+ ///
+ ///
+ /// A double-precision floating-point number equivalent to the value of this instance.
+ ///
+ double IConvertible.ToDouble(IFormatProvider provider)
+ {
+ return (double) this;
+ }
+
+ ///
+ /// Converts the value of this instance to an equivalent 16-bit signed integer using the specified culture-specific
+ /// formatting information.
+ ///
+ ///
+ /// An interface implementation that supplies
+ /// culture-specific formatting information.
+ ///
+ ///
+ /// An 16-bit signed integer equivalent to the value of this instance.
+ ///
+ short IConvertible.ToInt16(IFormatProvider provider)
+ {
+ return (short) this;
+ }
+
+ ///
+ /// Converts the value of this instance to an equivalent 32-bit signed integer using the specified culture-specific
+ /// formatting information.
+ ///
+ ///
+ /// An interface implementation that supplies
+ /// culture-specific formatting information.
+ ///
+ ///
+ /// An 32-bit signed integer equivalent to the value of this instance.
+ ///
+ int IConvertible.ToInt32(IFormatProvider provider)
+ {
+ return (int) this;
+ }
+
+ ///
+ /// Converts the value of this instance to an equivalent 64-bit signed integer using the specified culture-specific
+ /// formatting information.
+ ///
+ ///
+ /// An interface implementation that supplies
+ /// culture-specific formatting information.
+ ///
+ ///
+ /// An 64-bit signed integer equivalent to the value of this instance.
+ ///
+ long IConvertible.ToInt64(IFormatProvider provider)
+ {
+ return (int) this;
+ }
+
+ ///
+ /// Converts the value of this instance to an equivalent 8-bit signed integer using the specified culture-specific
+ /// formatting information.
+ ///
+ ///
+ /// An interface implementation that supplies
+ /// culture-specific formatting information.
+ ///
+ ///
+ /// An 8-bit signed integer equivalent to the value of this instance.
+ ///
+ sbyte IConvertible.ToSByte(IFormatProvider provider)
+ {
+ return (sbyte) this;
+ }
+
+ ///
+ /// Converts the value of this instance to an equivalent single-precision floating-point number using the specified
+ /// culture-specific formatting information.
+ ///
+ ///
+ /// An interface implementation that supplies
+ /// culture-specific formatting information.
+ ///
+ ///
+ /// A single-precision floating-point number equivalent to the value of this instance.
+ ///
+ float IConvertible.ToSingle(IFormatProvider provider)
+ {
+ return (float) this;
+ }
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ /// The provider.
+ ///
+ /// A that represents this instance.
+ ///
+ string IConvertible.ToString(IFormatProvider provider)
+ {
+ return ToString(null, provider);
+ }
+
+ ///
+ /// Converts the numeric value to an equivalent object. The return value indicates whether the conversion succeeded.
+ ///
+ /// The target conversion type.
+ /// An object that supplies culture-specific information about the conversion.
+ ///
+ /// When this method returns, contains the value that is equivalent to the numeric value, if the
+ /// conversion succeeded, or is null if the conversion failed. This parameter is passed uninitialized.
+ ///
+ /// true if this value was converted successfully; otherwise, false.
+ public bool TryConvert(Type conversionType, IFormatProvider provider, out object value)
+ {
+ if (conversionType == typeof(bool))
+ {
+ value = (bool) this;
+ return true;
+ }
+
+ if (conversionType == typeof(byte))
+ {
+ value = (byte) this;
+ return true;
+ }
+
+ if (conversionType == typeof(char))
+ {
+ value = (char) this;
+ return true;
+ }
+
+ if (conversionType == typeof(decimal))
+ {
+ value = (decimal) this;
+ return true;
+ }
+
+ if (conversionType == typeof(double))
+ {
+ value = (double) this;
+ return true;
+ }
+
+ if (conversionType == typeof(short))
+ {
+ value = (short) this;
+ return true;
+ }
+
+ if (conversionType == typeof(int))
+ {
+ value = (int) this;
+ return true;
+ }
+
+ if (conversionType == typeof(long))
+ {
+ value = (long) this;
+ return true;
+ }
+
+ if (conversionType == typeof(sbyte))
+ {
+ value = (sbyte) this;
+ return true;
+ }
+
+ if (conversionType == typeof(float))
+ {
+ value = (float) this;
+ return true;
+ }
+
+ if (conversionType == typeof(string))
+ {
+ value = ToString(null, provider);
+ return true;
+ }
+
+ if (conversionType == typeof(ushort))
+ {
+ value = (ushort) this;
+ return true;
+ }
+
+ if (conversionType == typeof(uint))
+ {
+ value = (uint) this;
+ return true;
+ }
+
+ if (conversionType == typeof(ulong))
+ {
+ value = (ulong) this;
+ return true;
+ }
+
+ if (conversionType == typeof(byte[]))
+ {
+ value = ToByteArray();
+ return true;
+ }
+
+ if (conversionType == typeof(Guid))
+ {
+ value = new Guid(ToByteArray());
+ return true;
+ }
+
+ value = null;
+ return false;
+ }
+
+ ///
+ /// Converts the string representation of a number to its Int128 equivalent.
+ ///
+ /// A string that contains a number to convert.
+ ///
+ /// A value that is equivalent to the number specified in the value parameter.
+ ///
+ public static Int128 Parse(string value)
+ {
+ return Parse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
+ }
+
+ ///
+ /// Converts the string representation of a number in a specified style format to its Int128 equivalent.
+ ///
+ /// A string that contains a number to convert.
+ /// A bitwise combination of the enumeration values that specify the permitted format of value.
+ ///
+ /// A value that is equivalent to the number specified in the value parameter.
+ ///
+ public static Int128 Parse(string value, NumberStyles style)
+ {
+ return Parse(value, style, NumberFormatInfo.CurrentInfo);
+ }
+
+ ///
+ /// Converts the string representation of a number in a culture-specific format to its Int128 equivalent.
+ ///
+ /// A string that contains a number to convert.
+ /// An object that provides culture-specific formatting information about value.
+ ///
+ /// A value that is equivalent to the number specified in the value parameter.
+ ///
+ public static Int128 Parse(string value, IFormatProvider provider)
+ {
+ return Parse(value, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
+ }
+
+ ///
+ /// Converts the string representation of a number in a specified style and culture-specific format to its Int128
+ /// equivalent.
+ ///
+ /// A string that contains a number to convert.
+ /// A bitwise combination of the enumeration values that specify the permitted format of value.
+ /// An object that provides culture-specific formatting information about value.
+ /// A value that is equivalent to the number specified in the value parameter.
+ public static Int128 Parse(string value, NumberStyles style, IFormatProvider provider)
+ {
+ Int128 result;
+ if (!TryParse(value, style, provider, out result))
+ throw new ArgumentException(null, "value");
+
+ return result;
+ }
+
+ ///
+ /// Tries to convert the string representation of a number to its Int128 equivalent, and returns a value that indicates
+ /// whether the conversion succeeded..
+ ///
+ /// The string representation of a number.
+ ///
+ /// When this method returns, contains the Int128 equivalent to the number that is contained in value,
+ /// or Int128.Zero if the conversion failed. This parameter is passed uninitialized.
+ ///
+ ///
+ /// true if the value parameter was converted successfully; otherwise, false.
+ ///
+ public static bool TryParse(string value, out Int128 result)
+ {
+ return TryParse(value, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result);
+ }
+
+ ///
+ /// Tries to convert the string representation of a number in a specified style and culture-specific format to its
+ /// Int128 equivalent, and returns a value that indicates whether the conversion succeeded..
+ ///
+ ///
+ /// The string representation of a number. The string is interpreted using the style specified by
+ /// style.
+ ///
+ ///
+ /// A bitwise combination of enumeration values that indicates the style elements that can be present
+ /// in value. A typical value to specify is NumberStyles.Integer.
+ ///
+ /// An object that supplies culture-specific formatting information about value.
+ ///
+ /// When this method returns, contains the Int128 equivalent to the number that is contained in value,
+ /// or Int128.Zero if the conversion failed. This parameter is passed uninitialized.
+ ///
+ /// true if the value parameter was converted successfully; otherwise, false.
+ public static bool TryParse(string value, NumberStyles style, IFormatProvider provider, out Int128 result)
+ {
+ result = Zero;
+ if (string.IsNullOrEmpty(value))
+ return false;
+
+ if (value.StartsWith("x", StringComparison.OrdinalIgnoreCase))
+ {
+ style |= NumberStyles.AllowHexSpecifier;
+ value = value.Substring(1);
+ }
+ else if (value.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
+ {
+ style |= NumberStyles.AllowHexSpecifier;
+ value = value.Substring(2);
+ }
+
+ if ((style & NumberStyles.AllowHexSpecifier) == NumberStyles.AllowHexSpecifier)
+ return TryParseHex(value, out result);
+
+ return TryParseNum(value, out result);
+ }
+
+ private static bool TryParseHex(string value, out Int128 result)
+ {
+ if (value.Length > 32)
+ throw new OverflowException();
+
+ result = Zero;
+ var hi = false;
+ var pos = 0;
+ for (var i = value.Length - 1; i >= 0; i--)
+ {
+ var ch = value[i];
+ ulong b;
+ if ((ch >= '0') && (ch <= '9'))
+ b = (ulong) (ch - '0');
+ else if ((ch >= 'A') && (ch <= 'F'))
+ b = (ulong) (ch - 'A' + 10);
+ else if ((ch >= 'a') && (ch <= 'f'))
+ b = (ulong) (ch - 'a' + 10);
+ else
+ return false;
+
+ if (hi)
+ {
+ result._hi |= b << pos;
+ pos += 4;
+ }
+ else
+ {
+ result._lo |= b << pos;
+ pos += 4;
+ if (pos == 64)
+ {
+ pos = 0;
+ hi = true;
+ }
+ }
+ }
+ return true;
+ }
+
+ private static bool TryParseNum(string value, out Int128 result)
+ {
+ result = Zero;
+ foreach (var ch in value)
+ {
+ byte b;
+ if ((ch >= '0') && (ch <= '9'))
+ b = (byte) (ch - '0');
+ else
+ return false;
+
+ result = 10*result;
+ result += b;
+ }
+ return true;
+ }
+
+ ///
+ /// Converts the value of this instance to an of the specified
+ /// that has an equivalent value, using the specified culture-specific formatting
+ /// information.
+ ///
+ /// The to which the value of this instance is converted.
+ ///
+ /// An interface implementation that supplies
+ /// culture-specific formatting information.
+ ///
+ ///
+ /// An instance of type whose value is equivalent to
+ /// the value of this instance.
+ ///
+ public object ToType(Type conversionType, IFormatProvider provider)
+ {
+ object value;
+ if (TryConvert(conversionType, provider, out value))
+ return value;
+
+ throw new InvalidCastException();
+ }
+
+ ///
+ /// Converts the value of this instance to an equivalent 16-bit unsigned integer using the specified culture-specific
+ /// formatting information.
+ ///
+ ///
+ /// An interface implementation that supplies
+ /// culture-specific formatting information.
+ ///
+ ///
+ /// An 16-bit unsigned integer equivalent to the value of this instance.
+ ///
+ ushort IConvertible.ToUInt16(IFormatProvider provider)
+ {
+ if (_hi != 0)
+ throw new OverflowException();
+
+ return Convert.ToUInt16(_lo);
+ }
+
+ ///
+ /// Converts the value of this instance to an equivalent 32-bit unsigned integer using the specified culture-specific
+ /// formatting information.
+ ///
+ ///
+ /// An interface implementation that supplies
+ /// culture-specific formatting information.
+ ///
+ ///
+ /// An 32-bit unsigned integer equivalent to the value of this instance.
+ ///
+ uint IConvertible.ToUInt32(IFormatProvider provider)
+ {
+ if (_hi != 0)
+ throw new OverflowException();
+
+ return Convert.ToUInt32(_lo);
+ }
+
+ ///
+ /// Converts the value of this instance to an equivalent 64-bit unsigned integer using the specified culture-specific
+ /// formatting information.
+ ///
+ ///
+ /// An interface implementation that supplies
+ /// culture-specific formatting information.
+ ///
+ ///
+ /// An 64-bit unsigned integer equivalent to the value of this instance.
+ ///
+ ulong IConvertible.ToUInt64(IFormatProvider provider)
+ {
+ if (_hi != 0)
+ throw new OverflowException();
+
+ return _lo;
+ }
+
+ ///
+ /// Compares the current instance with another object of the same type and returns an integer that indicates whether
+ /// the current instance precedes, follows, or occurs in the same position in the sort order as the other object.
+ ///
+ /// An object to compare with this instance.
+ ///
+ /// A value that indicates the relative order of the objects being compared. The return value has these meanings: Value
+ /// Meaning Less than zero This instance is less than . Zero This instance is equal to
+ /// . Greater than zero This instance is greater than .
+ ///
+ ///
+ /// is not the same type as this instance.
+ ///
+ int IComparable.CompareTo(object obj)
+ {
+ return Compare(this, obj);
+ }
+
+ ///
+ /// Compares two Int128 values and returns an integer that indicates whether the first value is less than, equal to, or
+ /// greater than the second value.
+ ///
+ /// The first value to compare.
+ /// The second value to compare.
+ /// A signed integer that indicates the relative values of left and right, as shown in the following table.
+ public static int Compare(Int128 left, object right)
+ {
+ if (right is Int128)
+ return Compare(left, (Int128) right);
+
+ // NOTE: this could be optimized type per type
+ if (right is bool)
+ return Compare(left, new Int128((bool) right));
+
+ if (right is byte)
+ return Compare(left, new Int128((byte) right));
+
+ if (right is char)
+ return Compare(left, new Int128((char) right));
+
+ if (right is decimal)
+ return Compare(left, new Int128((decimal) right));
+
+ if (right is double)
+ return Compare(left, new Int128((double) right));
+
+ if (right is short)
+ return Compare(left, new Int128((short) right));
+
+ if (right is int)
+ return Compare(left, new Int128((int) right));
+
+ if (right is long)
+ return Compare(left, new Int128((long) right));
+
+ if (right is sbyte)
+ return Compare(left, new Int128((sbyte) right));
+
+ if (right is float)
+ return Compare(left, new Int128((float) right));
+
+ if (right is ushort)
+ return Compare(left, new Int128((ushort) right));
+
+ if (right is uint)
+ return Compare(left, new Int128((uint) right));
+
+ if (right is ulong)
+ return Compare(left, new Int128((ulong) right));
+
+ var bytes = right as byte[];
+ if ((bytes != null) && (bytes.Length != 16))
+ return Compare(left, new Int128(bytes));
+
+ if (right is Guid)
+ return Compare(left, new Int128((Guid) right));
+
+ throw new ArgumentException();
+ }
+
+ ///
+ /// Converts an Int128 value to a byte array.
+ ///
+ /// The value of the current Int128 object converted to an array of bytes.
+ public byte[] ToByteArray()
+ {
+ var bytes = new byte[16];
+ Buffer.BlockCopy(BitConverter.GetBytes(_lo), 0, bytes, 0, 8);
+ Buffer.BlockCopy(BitConverter.GetBytes(_hi), 0, bytes, 8, 8);
+ return bytes;
+ }
+
+ ///
+ /// Compares two 128-bit signed integer values and returns an integer that indicates whether the first value is less
+ /// than, equal to, or greater than the second value.
+ ///
+ /// The first value to compare.
+ /// The second value to compare.
+ ///
+ /// A signed number indicating the relative values of this instance and value.
+ ///
+ public static int Compare(Int128 left, Int128 right)
+ {
+ if (left.Sign < 0)
+ {
+ if (right.Sign >= 0)
+ return -1;
+
+ var xhi = left._hi & ~HiNeg;
+ var yhi = right._hi & ~HiNeg;
+ if (xhi != yhi)
+ return -xhi.CompareTo(yhi);
+
+ return -left._lo.CompareTo(right._lo);
+ }
+
+ if (right.Sign < 0)
+ return 1;
+
+ if (left._hi != right._hi)
+ return left._hi.CompareTo(right._hi);
+
+ return left._lo.CompareTo(right._lo);
+ }
+
+ ///
+ /// Compares this instance to a specified 128-bit signed integer and returns an indication of their relative values.
+ ///
+ /// An integer to compare.
+ /// A signed number indicating the relative values of this instance and value.
+ public int CompareTo(Int128 value)
+ {
+ return Compare(this, value);
+ }
+
+ ///
+ /// Performs an implicit conversion from to .
+ ///
+ /// if set to true [value].
+ ///
+ /// The result of the conversion.
+ ///
+ public static implicit operator Int128(bool value)
+ {
+ return new Int128(value);
+ }
+
+ ///
+ /// Performs an implicit conversion from to .
+ ///
+ /// The value.
+ ///
+ /// The result of the conversion.
+ ///
+ public static implicit operator Int128(byte value)
+ {
+ return new Int128(value);
+ }
+
+ ///
+ /// Performs an implicit conversion from to .
+ ///
+ /// The value.
+ ///
+ /// The result of the conversion.
+ ///
+ public static implicit operator Int128(char value)
+ {
+ return new Int128(value);
+ }
+
+ ///
+ /// Performs an explicit conversion from to .
+ ///
+ /// The value.
+ ///
+ /// The result of the conversion.
+ ///
+ public static explicit operator Int128(decimal value)
+ {
+ return new Int128(value);
+ }
+
+ ///
+ /// Performs an explicit conversion from to .
+ ///
+ /// The value.
+ ///
+ /// The result of the conversion.
+ ///
+ public static explicit operator Int128(double value)
+ {
+ return new Int128(value);
+ }
+
+ ///
+ /// Performs an implicit conversion from to .
+ ///
+ /// The value.
+ ///
+ /// The result of the conversion.
+ ///
+ public static implicit operator Int128(short value)
+ {
+ return new Int128(value);
+ }
+
+ ///
+ /// Performs an implicit conversion from to .
+ ///
+ /// The value.
+ ///
+ /// The result of the conversion.
+ ///
+ public static implicit operator Int128(int value)
+ {
+ return new Int128(value);
+ }
+
+ ///
+ /// Performs an implicit conversion from to .
+ ///
+ /// The value.
+ ///
+ /// The result of the conversion.
+ ///
+ public static implicit operator Int128(long value)
+ {
+ return new Int128(value);
+ }
+
+ ///
+ /// Performs an implicit conversion from to .
+ ///
+ /// The value.
+ ///
+ /// The result of the conversion.
+ ///
+ public static implicit operator Int128(sbyte value)
+ {
+ return new Int128(value);
+ }
+
+ ///
+ /// Performs an explicit conversion from to .
+ ///
+ /// The value.
+ ///
+ /// The result of the conversion.
+ ///
+ public static explicit operator Int128(float value)
+ {
+ return new Int128(value);
+ }
+
+ ///
+ /// Performs an implicit conversion from to .
+ ///
+ /// The value.
+ ///
+ /// The result of the conversion.
+ ///
+ public static implicit operator Int128(ushort value)
+ {
+ return new Int128(value);
+ }
+
+ ///
+ /// Performs an implicit conversion from to .
+ ///
+ /// The value.
+ ///
+ /// The result of the conversion.
+ ///
+ public static implicit operator Int128(uint value)
+ {
+ return new Int128(value);
+ }
+
+ ///
+ /// Performs an implicit conversion from to .
+ ///
+ /// The value.
+ ///
+ /// The result of the conversion.
+ ///
+ public static implicit operator Int128(ulong value)
+ {
+ return new Int128(value);
+ }
+
+ ///
+ /// Performs an explicit conversion from to .
+ ///
+ /// The value.
+ ///
+ /// The result of the conversion.
+ ///
+ public static explicit operator bool(Int128 value)
+ {
+ return value.Sign != 0;
+ }
+
+ ///
+ /// Performs an explicit conversion from to .
+ ///
+ /// The value.
+ ///
+ /// The result of the conversion.
+ ///
+ public static explicit operator byte(Int128 value)
+ {
+ if (value.Sign == 0)
+ return 0;
+
+ if ((value.Sign < 0) || (value._lo > 0xFF))
+ throw new OverflowException();
+
+ return (byte) value._lo;
+ }
+
+ ///
+ /// Performs an explicit conversion from to .
+ ///
+ /// The value.
+ ///
+ /// The result of the conversion.
+ ///
+ public static explicit operator char(Int128 value)
+ {
+ if (value.Sign == 0)
+ return (char) 0;
+
+ if ((value.Sign < 0) || (value._lo > 0xFFFF))
+ throw new OverflowException();
+
+ return (char) (ushort) value._lo;
+ }
+
+ ///
+ /// Performs an explicit conversion from to .
+ ///
+ /// The value.
+ ///
+ /// The result of the conversion.
+ ///
+ public static explicit operator decimal(Int128 value)
+ {
+ if (value.Sign == 0)
+ return 0;
+
+ return new decimal((int) (value._lo & 0xFFFFFFFF), (int) (value._lo >> 32),
+ (int) (value._hi & 0xFFFFFFFF),
+ value.Sign < 0, 0);
+ }
+
+ ///
+ /// Performs an explicit conversion from to .
+ ///
+ /// The value.
+ ///
+ /// The result of the conversion.
+ ///
+ public static explicit operator double(Int128 value)
+ {
+ if (value.Sign == 0)
+ return 0;
+
+ double d;
+ var nfi = CultureInfo.InvariantCulture.NumberFormat;
+ if (!double.TryParse(value.ToString(nfi), NumberStyles.Number, nfi, out d))
+ throw new OverflowException();
+
+ return d;
+ }
+
+ ///
+ /// Performs an explicit conversion from to .
+ ///
+ /// The value.
+ ///
+ /// The result of the conversion.
+ ///
+ public static explicit operator float(Int128 value)
+ {
+ if (value.Sign == 0)
+ return 0;
+
+ float f;
+ var nfi = CultureInfo.InvariantCulture.NumberFormat;
+ if (!float.TryParse(value.ToString(nfi), NumberStyles.Number, nfi, out f))
+ throw new OverflowException();
+
+ return f;
+ }
+
+ ///
+ /// Performs an explicit conversion from to .
+ ///
+ /// The value.
+ ///
+ /// The result of the conversion.
+ ///
+ public static explicit operator short(Int128 value)
+ {
+ if (value.Sign == 0)
+ return 0;
+
+ if (value._lo > 0x8000)
+ throw new OverflowException();
+
+ if ((value._lo == 0x8000) && (value.Sign > 0))
+ throw new OverflowException();
+
+ return (short) ((int) value._lo*value.Sign);
+ }
+
+ ///
+ /// Performs an explicit conversion from to .
+ ///
+ /// The value.
+ ///
+ /// The result of the conversion.
+ ///
+ public static explicit operator int(Int128 value)
+ {
+ if (value.Sign == 0)
+ return 0;
+
+ if (value._lo > 0x80000000)
+ throw new OverflowException();
+
+ if ((value._lo == 0x80000000) && (value.Sign > 0))
+ throw new OverflowException();
+
+ return (int) value._lo*value.Sign;
+ }
+
+ ///
+ /// Performs an explicit conversion from to .
+ ///
+ /// The value.
+ ///
+ /// The result of the conversion.
+ ///
+ public static explicit operator long(Int128 value)
+ {
+ if (value.Sign == 0)
+ return 0;
+
+ if (value._lo > long.MaxValue)
+ throw new OverflowException();
+
+ return (long) value._lo*value.Sign;
+ }
+
+ ///
+ /// Performs an explicit conversion from to .
+ ///
+ /// The value.
+ ///
+ /// The result of the conversion.
+ ///
+ public static explicit operator uint(Int128 value)
+ {
+ if (value.Sign == 0)
+ return 0;
+
+ if ((value.Sign < 0) || (value._lo > uint.MaxValue))
+ throw new OverflowException();
+
+ return (uint) value._lo;
+ }
+
+ ///
+ /// Performs an explicit conversion from to .
+ ///
+ /// The value.
+ ///
+ /// The result of the conversion.
+ ///
+ public static explicit operator ushort(Int128 value)
+ {
+ if (value.Sign == 0)
+ return 0;
+
+ if ((value.Sign < 0) || (value._lo > ushort.MaxValue))
+ throw new OverflowException();
+
+ return (ushort) value._lo;
+ }
+
+ ///
+ /// Performs an explicit conversion from to .
+ ///
+ /// The value.
+ ///
+ /// The result of the conversion.
+ ///
+ public static explicit operator ulong(Int128 value)
+ {
+ if ((value.Sign < 0) || (value._hi != 0))
+ throw new OverflowException();
+
+ return value._lo;
+ }
+
+ ///
+ /// Implements the operator >.
+ ///
+ /// The x.
+ /// The y.
+ ///
+ /// The result of the operator.
+ ///
+ public static bool operator >(Int128 left, Int128 right)
+ {
+ return Compare(left, right) > 0;
+ }
+
+ ///
+ /// Implements the operator <.
+ ///
+ /// The x.
+ /// The y.
+ ///
+ /// The result of the operator.
+ ///
+ public static bool operator <(Int128 left, Int128 right)
+ {
+ return Compare(left, right) < 0;
+ }
+
+ ///
+ /// Implements the operator >=.
+ ///
+ /// The x.
+ /// The y.
+ ///
+ /// The result of the operator.
+ ///
+ public static bool operator >=(Int128 left, Int128 right)
+ {
+ return Compare(left, right) >= 0;
+ }
+
+ ///
+ /// Implements the operator <=.
+ ///
+ /// The x.
+ /// The y.
+ ///
+ /// The result of the operator.
+ ///
+ public static bool operator <=(Int128 left, Int128 right)
+ {
+ return Compare(left, right) <= 0;
+ }
+
+ ///
+ /// Implements the operator !=.
+ ///
+ /// The x.
+ /// The y.
+ ///
+ /// The result of the operator.
+ ///
+ public static bool operator !=(Int128 left, Int128 right)
+ {
+ return Compare(left, right) != 0;
+ }
+
+ ///
+ /// Implements the operator ==.
+ ///
+ /// The x.
+ /// The y.
+ ///
+ /// The result of the operator.
+ ///
+ public static bool operator ==(Int128 left, Int128 right)
+ {
+ return Compare(left, right) == 0;
+ }
+
+ ///
+ /// Implements the operator +.
+ ///
+ /// The value.
+ ///
+ /// The result of the operator.
+ ///
+ public static Int128 operator +(Int128 value)
+ {
+ return value;
+ }
+
+ ///
+ /// Implements the operator -.
+ ///
+ /// The value.
+ ///
+ /// The result of the operator.
+ ///
+ public static Int128 operator -(Int128 value)
+ {
+ return Negate(value);
+ }
+
+ ///
+ /// Negates a specified Int128 value.
+ ///
+ /// The value to negate.
+ /// The result of the value parameter multiplied by negative one (-1).
+ public static Int128 Negate(Int128 value)
+ {
+ var neg = value;
+ var sign = value.Sign;
+ if (sign < 0)
+ neg._hi &= ~HiNeg;
+ else
+ neg._hi |= HiNeg;
+ return neg;
+ }
+
+ ///
+ /// Gets the absolute value this object.
+ ///
+ /// The absolute value.
+ public Int128 ToAbs()
+ {
+ return Abs(this);
+ }
+
+ ///
+ /// Gets the absolute value of an Int128 object.
+ ///
+ /// A number.
+ ///
+ /// The absolute value.
+ ///
+ public static Int128 Abs(Int128 value)
+ {
+ if (value.Sign < 0)
+ return -value;
+
+ return value;
+ }
+
+ ///
+ /// Implements the operator +.
+ ///
+ /// The x.
+ /// The y.
+ ///
+ /// The result of the operator.
+ ///
+ public static Int128 operator +(Int128 left, Int128 right)
+ {
+ var add = left;
+ add._hi += right._hi;
+ add._lo += right._lo;
+ if (add._lo < left._lo)
+ add._hi++;
+ return add;
+ }
+
+ ///
+ /// Implements the operator -.
+ ///
+ /// The x.
+ /// The y.
+ ///
+ /// The result of the operator.
+ ///
+ public static Int128 operator -(Int128 left, Int128 right)
+ {
+ return left + -right;
+ }
+
+ ///
+ /// Adds two Int128 values and returns the result.
+ ///
+ /// The first value to add.
+ /// The second value to add.
+ /// The sum of left and right.
+ public static Int128 Add(Int128 left, Int128 right)
+ {
+ return left + right;
+ }
+
+ ///
+ /// Subtracts one Int128 value from another and returns the result.
+ ///
+ /// The value to subtract from (the minuend).
+ /// The value to subtract (the subtrahend).
+ /// The result of subtracting right from left.
+ public static Int128 Subtract(Int128 left, Int128 right)
+ {
+ return left - right;
+ }
+
+ ///
+ /// Divides one Int128 value by another and returns the result.
+ ///
+ /// The value to be divided.
+ /// The value to divide by.
+ /// The quotient of the division.
+ public static Int128 Divide(Int128 dividend, Int128 divisor)
+ {
+ Int128 integer;
+ return DivRem(dividend, divisor, out integer);
+ }
+
+ ///
+ /// Divides one Int128 value by another, returns the result, and returns the remainder in an output parameter.
+ ///
+ /// The value to be divided.
+ /// The value to divide by.
+ ///
+ /// When this method returns, contains an Int128 value that represents the remainder from the
+ /// division. This parameter is passed uninitialized.
+ ///
+ ///
+ /// The quotient of the division.
+ ///
+ public static Int128 DivRem(Int128 dividend, Int128 divisor, out Int128 remainder)
+ {
+ if (divisor == 0)
+ throw new DivideByZeroException();
+
+ uint[] quotient;
+ uint[] rem;
+ DivRem(dividend.ToUIn32Array(), divisor.ToUIn32Array(), out quotient, out rem);
+ remainder = new Int128(1, rem);
+ return new Int128(dividend.Sign*divisor.Sign, quotient);
+ }
+
+ private static void DivRem(uint[] dividend, uint[] divisor, out uint[] quotient, out uint[] remainder)
+ {
+ const ulong hiBit = 0x100000000;
+ var divisorLen = GetLength(divisor);
+ var dividendLen = GetLength(dividend);
+ if (divisorLen <= 1)
+ {
+ ulong rem = 0;
+ var div = divisor[0];
+ quotient = new uint[dividendLen];
+ remainder = new uint[1];
+ for (var i = dividendLen - 1; i >= 0; i--)
+ {
+ rem *= hiBit;
+ rem += dividend[i];
+ var q = rem/div;
+ rem -= q*div;
+ quotient[i] = (uint) q;
+ }
+ remainder[0] = (uint) rem;
+ return;
+ }
+
+ if (dividendLen >= divisorLen)
+ {
+ var shift = GetNormalizeShift(divisor[divisorLen - 1]);
+ var normDividend = new uint[dividendLen + 1];
+ var normDivisor = new uint[divisorLen];
+ Normalize(dividend, dividendLen, normDividend, shift);
+ Normalize(divisor, divisorLen, normDivisor, shift);
+ quotient = new uint[dividendLen - divisorLen + 1];
+ for (var j = dividendLen - divisorLen; j >= 0; j--)
+ {
+ var dx = hiBit*normDividend[j + divisorLen] + normDividend[j + divisorLen - 1];
+ var qj = dx/normDivisor[divisorLen - 1];
+ dx -= qj*normDivisor[divisorLen - 1];
+ do
+ {
+ if ((qj < hiBit) &&
+ (qj*normDivisor[divisorLen - 2] <= dx*hiBit + normDividend[j + divisorLen - 2]))
+ break;
+
+ qj -= 1L;
+ dx += normDivisor[divisorLen - 1];
+ } while (dx < hiBit);
+
+ long di = 0;
+ long dj;
+ var index = 0;
+ while (index < divisorLen)
+ {
+ var dqj = normDivisor[index]*qj;
+ dj = normDividend[index + j] - (uint) dqj - di;
+ normDividend[index + j] = (uint) dj;
+ dqj = dqj >> 32;
+ dj = dj >> 32;
+ di = (long) dqj - dj;
+ index++;
+ }
+
+ dj = normDividend[j + divisorLen] - di;
+ normDividend[j + divisorLen] = (uint) dj;
+ quotient[j] = (uint) qj;
+
+ if (dj < 0)
+ {
+ quotient[j]--;
+ ulong sum = 0;
+ for (index = 0; index < divisorLen; index++)
+ {
+ sum = normDivisor[index] + normDividend[j + index] + sum;
+ normDividend[j + index] = (uint) sum;
+ sum = sum >> 32;
+ }
+ sum += normDividend[j + divisorLen];
+ normDividend[j + divisorLen] = (uint) sum;
+ }
+ }
+ remainder = Unnormalize(normDividend, shift);
+ return;
+ }
+
+ quotient = new uint[0];
+ remainder = dividend;
+ }
+
+ private static int GetLength(uint[] uints)
+ {
+ var index = uints.Length - 1;
+ while ((index >= 0) && (uints[index] == 0))
+ index--;
+ return index + 1;
+ }
+
+ private static int GetNormalizeShift(uint ui)
+ {
+ var shift = 0;
+ if ((ui & 0xffff0000) == 0)
+ {
+ ui = ui << 16;
+ shift += 16;
+ }
+
+ if ((ui & 0xff000000) == 0)
+ {
+ ui = ui << 8;
+ shift += 8;
+ }
+
+ if ((ui & 0xf0000000) == 0)
+ {
+ ui = ui << 4;
+ shift += 4;
+ }
+
+ if ((ui & 0xc0000000) == 0)
+ {
+ ui = ui << 2;
+ shift += 2;
+ }
+
+ if ((ui & 0x80000000) == 0)
+ shift++;
+ return shift;
+ }
+
+ private static uint[] Unnormalize(uint[] normalized, int shift)
+ {
+ var len = GetLength(normalized);
+ var unormalized = new uint[len];
+ if (shift > 0)
+ {
+ var rshift = 32 - shift;
+ uint r = 0;
+ for (var i = len - 1; i >= 0; i--)
+ {
+ unormalized[i] = (normalized[i] >> shift) | r;
+ r = normalized[i] << rshift;
+ }
+ }
+ else
+ {
+ for (var j = 0; j < len; j++)
+ unormalized[j] = normalized[j];
+ }
+ return unormalized;
+ }
+
+ private static void Normalize(uint[] unormalized, int len, uint[] normalized, int shift)
+ {
+ int i;
+ uint n = 0;
+ if (shift > 0)
+ {
+ var rshift = 32 - shift;
+ for (i = 0; i < len; i++)
+ {
+ normalized[i] = (unormalized[i] << shift) | n;
+ n = unormalized[i] >> rshift;
+ }
+ }
+ else
+ {
+ i = 0;
+ while (i < len)
+ {
+ normalized[i] = unormalized[i];
+ i++;
+ }
+ }
+
+ while (i < normalized.Length)
+ normalized[i++] = 0;
+
+ if (n != 0)
+ normalized[len] = n;
+ }
+
+ ///
+ /// Performs integer division on two Int128 values and returns the remainder.
+ ///
+ /// The value to be divided.
+ /// The value to divide by.
+ /// The remainder after dividing dividend by divisor.
+ public static Int128 Remainder(Int128 dividend, Int128 divisor)
+ {
+ Int128 remainder;
+ DivRem(dividend, divisor, out remainder);
+ return remainder;
+ }
+
+ ///
+ /// Implements the operator %.
+ ///
+ /// The dividend.
+ /// The divisor.
+ ///
+ /// The result of the operator.
+ ///
+ public static Int128 operator %(Int128 dividend, Int128 divisor)
+ {
+ return Remainder(dividend, divisor);
+ }
+
+ ///
+ /// Implements the operator /.
+ ///
+ /// The dividend.
+ /// The divisor.
+ ///
+ /// The result of the operator.
+ ///
+ public static Int128 operator /(Int128 dividend, Int128 divisor)
+ {
+ return Divide(dividend, divisor);
+ }
+
+ ///
+ /// Converts an int128 value to an unsigned long array.
+ ///
+ ///
+ /// The value of the current Int128 object converted to an array of unsigned integers.
+ ///
+ public ulong[] ToUIn64Array()
+ {
+ return new[] {_hi, _lo};
+ }
+
+ ///
+ /// Converts an int128 value to an unsigned integer array.
+ ///
+ /// The value of the current Int128 object converted to an array of unsigned integers.
+ public uint[] ToUIn32Array()
+ {
+ var ints = new uint[4];
+ var lob = BitConverter.GetBytes(_lo);
+ var hib = BitConverter.GetBytes(_hi);
+
+ Buffer.BlockCopy(lob, 0, ints, 0, 4);
+ Buffer.BlockCopy(lob, 4, ints, 4, 4);
+ Buffer.BlockCopy(hib, 0, ints, 8, 4);
+ Buffer.BlockCopy(hib, 4, ints, 12, 4);
+ return ints;
+ }
+
+ ///
+ /// Returns the product of two Int128 values.
+ ///
+ /// The first number to multiply.
+ /// The second number to multiply.
+ /// The product of the left and right parameters.
+ public static Int128 Multiply(Int128 left, Int128 right)
+ {
+ var xInts = left.ToUIn32Array();
+ var yInts = right.ToUIn32Array();
+ var mulInts = new uint[8];
+
+ for (var i = 0; i < xInts.Length; i++)
+ {
+ var index = i;
+ ulong remainder = 0;
+ foreach (var yi in yInts)
+ {
+ remainder = remainder + (ulong) xInts[i]*yi + mulInts[index];
+ mulInts[index++] = (uint) remainder;
+ remainder = remainder >> 32;
+ }
+
+ while (remainder != 0)
+ {
+ remainder += mulInts[index];
+ mulInts[index++] = (uint) remainder;
+ remainder = remainder >> 32;
+ }
+ }
+ return new Int128(left.Sign*right.Sign, mulInts);
+ }
+
+ ///
+ /// Implements the operator *.
+ ///
+ /// The x.
+ /// The y.
+ ///
+ /// The result of the operator.
+ ///
+ public static Int128 operator *(Int128 left, Int128 right)
+ {
+ return Multiply(left, right);
+ }
+
+ ///
+ /// Implements the operator >>.
+ ///
+ /// The value.
+ /// The shift.
+ /// The result of the operator.
+ public static Int128 operator >>(Int128 value, int shift)
+ {
+ if (shift == 0)
+ return value;
+
+ if (shift < 0)
+ return value << -shift;
+
+ shift = shift%128;
+
+ var shifted = new Int128();
+
+ if (shift > 63)
+ {
+ shifted._lo = value._hi >> (shift - 64);
+ shifted._hi = 0;
+ }
+ else
+ {
+ shifted._hi = value._hi >> shift;
+ shifted._lo = (value._hi << (64 - shift)) | (value._lo >> shift);
+ }
+ return shifted;
+ }
+
+ ///
+ /// Implements the operator <<.
+ ///
+ /// The value.
+ /// The shift.
+ /// The result of the operator.
+ public static Int128 operator <<(Int128 value, int shift)
+ {
+ if (shift == 0)
+ return value;
+
+ if (shift < 0)
+ return value >> -shift;
+
+ shift = shift%128;
+
+ var shifted = new Int128();
+
+ if (shift > 63)
+ {
+ shifted._hi = value._lo << (shift - 64);
+ shifted._lo = 0;
+ }
+ else
+ {
+ var ul = value._lo >> (64 - shift);
+ shifted._hi = ul | (value._hi << shift);
+ shifted._lo = value._lo << shift;
+ }
+ return shifted;
+ }
+
+ ///
+ /// Implements the operator |.
+ ///
+ /// The left.
+ /// The right.
+ /// The result of the operator.
+ public static Int128 operator |(Int128 left, Int128 right)
+ {
+ if (left == 0)
+ return right;
+
+ if (right == 0)
+ return left;
+
+ var result = left;
+ result._hi |= right._hi;
+ result._lo |= right._lo;
+ return result;
+ }
+
+ ///
+ /// Implements the operator ~.
+ ///
+ /// The left.
+ /// The right.
+ /// The result of the operator.
+ public static Int128 operator ~(Int128 value)
+ {
+ Int128 result = 0;
+ result._hi = ~value._hi;
+ result._lo = ~value._lo;
+ return result;
+ }
+
+ ///
+ /// Implements the operator &.
+ ///
+ /// The left.
+ /// The right.
+ /// The result of the operator.
+ public static Int128 operator &(Int128 left, Int128 right)
+ {
+ if ((left == 0) || (right == 0))
+ return Zero;
+
+ var result = left;
+ result._hi &= right._hi;
+ result._lo &= right._lo;
+ return result;
+ }
+
+#if !WINDOWS_PHONE && !SILVERLIGHT
+ void IBinarySerialize.Read(BinaryReader reader)
+ {
+ if (reader == null)
+ throw new ArgumentNullException("reader");
+
+ _hi = reader.ReadUInt64();
+ _lo = reader.ReadUInt64();
+ }
+
+ void IBinarySerialize.Write(BinaryWriter writer)
+ {
+ if (writer == null)
+ throw new ArgumentNullException("writer");
+
+ writer.Write(_hi);
+ writer.Write(_lo);
+ }
+#endif
+
+ ///
+ /// Converts a String type to a Int128 type, and vice versa.
+ ///
+ public class Int128Converter : TypeConverter
+ {
+ ///
+ /// Returns whether this converter can convert an object of the given type to the type of this converter, using the
+ /// specified context.
+ ///
+ /// An that provides a format context.
+ /// A that represents the type you want to convert from.
+ ///
+ /// true if this converter can perform the conversion; otherwise, false.
+ ///
+ public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
+ {
+ if (sourceType == typeof(string))
+ return true;
+
+ return base.CanConvertFrom(context, sourceType);
+ }
+
+ ///
+ /// Converts the given object to the type of this converter, using the specified context and culture information.
+ ///
+ /// An that provides a format context.
+ /// The to use as the current culture.
+ /// The to convert.
+ ///
+ /// An that represents the converted value.
+ ///
+ ///
+ /// The conversion cannot be performed.
+ ///
+ public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
+ {
+ if (value != null)
+ {
+ Int128 i;
+ if (TryParse(string.Format("{0}", value), out i))
+ return i;
+ }
+ return new Int128();
+ }
+
+ ///
+ /// Returns whether this converter can convert the object to the specified type, using the specified context.
+ ///
+ /// An that provides a format context.
+ /// A that represents the type you want to convert to.
+ ///
+ /// true if this converter can perform the conversion; otherwise, false.
+ ///
+ public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
+ {
+ if (destinationType == typeof(string))
+ return true;
+
+ return base.CanConvertTo(context, destinationType);
+ }
+
+ ///
+ /// Converts the given value object to the specified type, using the specified context and culture information.
+ ///
+ /// An that provides a format context.
+ ///
+ /// A . If null is passed, the current culture is
+ /// assumed.
+ ///
+ /// The to convert.
+ /// The to convert the parameter to.
+ ///
+ /// An that represents the converted value.
+ ///
+ ///
+ /// The parameter is null.
+ ///
+ ///
+ /// The conversion cannot be performed.
+ ///
+ public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value,
+ Type destinationType)
+ {
+ if (destinationType == typeof(string))
+ return string.Format("{0}", value);
+
+ return base.ConvertTo(context, culture, value, destinationType);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Artemis/Artemis/Modules/Games/WoW/Data/WoWEnums.cs b/Artemis/Artemis/Modules/Games/WoW/Data/WoWEnums.cs
new file mode 100644
index 000000000..24fa676fa
--- /dev/null
+++ b/Artemis/Artemis/Modules/Games/WoW/Data/WoWEnums.cs
@@ -0,0 +1,157 @@
+namespace Artemis.Modules.Games.WoW.Data
+{
+ public static class WoWEnums
+ {
+ public enum GuidType : byte
+ {
+ Null = 0,
+ Uniq = 1,
+ Player = 2,
+ Item = 3,
+ StaticDoor = 4,
+ Transport = 5,
+ Conversation = 6,
+ Creature = 7,
+ Vehicle = 8,
+ Pet = 9,
+ GameObject = 10,
+ DynamicObject = 11,
+ AreaTrigger = 12,
+ Corpse = 13,
+ LootObject = 14,
+ SceneObject = 15,
+ Scenario = 16,
+ AiGroup = 17,
+ DynamicDoor = 18,
+ ClientActor = 19,
+ Vignette = 20,
+ CallForHelp = 21,
+ AiResource = 22,
+ AiLock = 23,
+ AiLockTicket = 24,
+ ChatChannel = 25,
+ Party = 26,
+ Guild = 27,
+ WowAccount = 28,
+ BNetAccount = 29,
+ GmTask = 30,
+ MobileSession = 31,
+ RaidGroup = 32,
+ Spell = 33,
+ Mail = 34,
+ WebObj = 35,
+ LfgObject = 36,
+ LfgList = 37,
+ UserRouter = 38,
+ PvpQueueGroup = 39,
+ UserClient = 40,
+ PetBattle = 41,
+ UniqueUserClient = 42,
+ BattlePet = 43
+ }
+
+ public enum ObjectType
+ {
+ Object = 0,
+ Item = 1,
+ Container = 2,
+ Unit = 3,
+ Player = 4,
+ GameObject = 5,
+ DynamicObject = 6,
+ Corpse = 7,
+ AreaTrigger = 8,
+ SceneObject = 9,
+ Conversation = 10
+ }
+
+ public enum PowerType
+ {
+ Mana = 0,
+ Rage = 1,
+ Focus = 2,
+ Energy = 3,
+ Happiness = 4,
+ RunicPower = 5,
+ Runes = 6,
+ Health = 7,
+ Maelstrom = 11,
+ Insanity = 13,
+ Fury = 17,
+ Pain = 18,
+ UNKNOWN
+ }
+
+ public enum Reaction
+ {
+ Hostile = 1,
+ Neutral = 3,
+ Friendly = 4
+ }
+
+ public enum ShapeshiftForm
+ {
+ Normal = 0,
+ Cat = 1,
+ TreeOfLife = 2,
+ Travel = 3,
+ Aqua = 4,
+ Bear = 5,
+ Ambient = 6,
+ Ghoul = 7,
+ DireBear = 8,
+ CreatureBear = 14,
+ CreatureCat = 15,
+ GhostWolf = 16,
+ BattleStance = 17,
+ DefensiveStance = 18,
+ BerserkerStance = 19,
+ EpicFlightForm = 27,
+ Shadow = 28,
+ Stealth = 30,
+ Moonkin = 31,
+ SpiritOfRedemption = 32
+ }
+
+ public enum WoWClass
+ {
+ None = 0,
+ Warrior = 1,
+ Paladin = 2,
+ Hunter = 3,
+ Rogue = 4,
+ Priest = 5,
+ DeathKnight = 6,
+ Shaman = 7,
+ Mage = 8,
+ Warlock = 9,
+ Druid = 11
+ }
+
+ public enum WoWRace
+ {
+ Human = 1,
+ Orc = 2,
+ Dwarf = 3,
+ NightElf = 4,
+ Undead = 5,
+ Tauren = 6,
+ Gnome = 7,
+ Troll = 8,
+ Goblin = 9,
+ BloodElf = 10,
+ Draenei = 11,
+ FelOrc = 12,
+ Naga = 13,
+ Broken = 14,
+ Skeleton = 15,
+ Worgen = 22
+ }
+
+ public enum WoWType
+ {
+ Player,
+ Npc
+ }
+ }
+}
\ No newline at end of file
diff --git a/Artemis/Artemis/Modules/Games/WoW/Data/WoWNameCache.cs b/Artemis/Artemis/Modules/Games/WoW/Data/WoWNameCache.cs
new file mode 100644
index 000000000..78677f117
--- /dev/null
+++ b/Artemis/Artemis/Modules/Games/WoW/Data/WoWNameCache.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Text;
+using Process.NET;
+
+namespace Artemis.Modules.Games.WoW.Data
+{
+ public class WoWNameCache
+ {
+ public WoWNameCache(ProcessSharp process, IntPtr baseAddress)
+ {
+ Process = process;
+ CurrentCacheAddress = process.Native.MainModule.BaseAddress + baseAddress.ToInt32();
+ }
+
+ public ProcessSharp Process { get; set; }
+
+ public IntPtr CurrentCacheAddress { get; set; }
+
+ public WoWDetails GetNameByGuid(Guid searchGuid)
+ {
+ var current = Process.Memory.Read(CurrentCacheAddress);
+ var index = 0;
+ while (current != IntPtr.Zero)
+ {
+ var guid = Process.Memory.Read(current + 0x20);
+ if (guid.Equals(searchGuid))
+ {
+ var pRace = Process.Memory.Read(current + 0x88);
+ var pClass = Process.Memory.Read(current + 0x90);
+ var pName = Process.Memory.Read(current + 0x31, Encoding.ASCII, 48);
+
+ var name = new WoWDetails(guid, pRace, pClass, WoWEnums.WoWType.Player, pName);
+ return name;
+ }
+
+ if (index > 20000)
+ return null;
+
+ index++;
+ current = Process.Memory.Read(current);
+ }
+ return null;
+ }
+ }
+
+ public class WoWDetails
+ {
+ public WoWDetails(Guid guid, int race, int @class, WoWEnums.WoWType type, string name)
+ {
+ Guid = guid;
+ Race = (WoWEnums.WoWRace) race;
+ Class = (WoWEnums.WoWClass) @class;
+ Type = type;
+ Name = name;
+ }
+
+ public Guid Guid { get; set; }
+ public WoWEnums.WoWRace Race { get; set; }
+ public WoWEnums.WoWClass Class { get; set; }
+ public WoWEnums.WoWType Type { get; set; }
+ public string Name { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Artemis/Artemis/Modules/Games/WoW/Data/WoWObject.cs b/Artemis/Artemis/Modules/Games/WoW/Data/WoWObject.cs
new file mode 100644
index 000000000..a8db9114c
--- /dev/null
+++ b/Artemis/Artemis/Modules/Games/WoW/Data/WoWObject.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Text;
+using Newtonsoft.Json;
+using Process.NET;
+
+namespace Artemis.Modules.Games.WoW.Data
+{
+ public class WoWObject
+ {
+ private readonly bool _readPointer;
+
+ public WoWObject(IProcess process, IntPtr baseAddress, bool readPointer = false)
+ {
+ Process = process;
+ BaseAddress = baseAddress;
+ _readPointer = readPointer;
+
+ Guid = ReadField(0x00);
+ }
+
+ [JsonIgnore]
+ public IntPtr BaseAddress { get; set; }
+
+ [JsonIgnore]
+ public IProcess Process { get; set; }
+
+ public Guid Guid { get; set; }
+
+ [JsonIgnore]
+ public WoWStructs.ObjectData Data { get; set; }
+
+ public T ReadField(int offset)
+ {
+ var address = GetAddress();
+ if (address == IntPtr.Zero)
+ return default(T);
+
+ var ptr = Process.Memory.Read(address + 0x10);
+ return Process.Memory.Read(ptr + offset);
+ }
+
+ public T ReadField(Enum offset)
+ {
+ var address = GetAddress();
+ if (address == IntPtr.Zero)
+ return default(T);
+
+ var ptr = Process.Memory.Read(address + 0x10);
+ return Process.Memory.Read(ptr + Convert.ToInt32(offset));
+ }
+
+ private IntPtr GetAddress()
+ {
+ return _readPointer
+ ? Process.Memory.Read(Process.Native.MainModule.BaseAddress + BaseAddress.ToInt32())
+ : BaseAddress;
+ }
+
+ public WoWDetails GetNpcDetails()
+ {
+ var address = GetAddress();
+ if (address == IntPtr.Zero)
+ return null;
+
+ var npcCachePtr = Process.Memory.Read(address + 0x1760);
+ if (npcCachePtr == IntPtr.Zero)
+ return null;
+
+ var npcName = Process.Memory.Read(Process.Memory.Read(npcCachePtr + 0x00A0), Encoding.ASCII, 48);
+ return new WoWDetails(Guid, 0, 0, WoWEnums.WoWType.Npc, npcName);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Artemis/Artemis/Modules/Games/WoW/Data/WoWObjectManager.cs b/Artemis/Artemis/Modules/Games/WoW/Data/WoWObjectManager.cs
new file mode 100644
index 000000000..e47ff61ec
--- /dev/null
+++ b/Artemis/Artemis/Modules/Games/WoW/Data/WoWObjectManager.cs
@@ -0,0 +1,92 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using Process.NET;
+
+namespace Artemis.Modules.Games.WoW.Data
+{
+ public class WoWObjectManager
+ {
+ public WoWObjectManager(IProcess process, IntPtr baseAddress)
+ {
+ Process = process;
+ CurrentManagerAddress = process.Native.MainModule.BaseAddress + baseAddress.ToInt32();
+ }
+
+ public IProcess Process { get; set; }
+
+ public IntPtr CurrentManagerAddress { get; set; }
+
+ public Dictionary WoWObjects { get; set; }
+
+ public IntPtr GetFirstObject()
+ {
+ var mgr = GetCurrentManager();
+ return mgr.VisibleObjects.m_fulllist.baseClass.m_terminator.m_next;
+ }
+
+ public WoWStructs.CurrentManager GetCurrentManager()
+ {
+ return Process.Memory.Read(Process.Memory.Read(CurrentManagerAddress));
+ }
+
+ public IntPtr GetNextObjectFromCurrent(IntPtr current)
+ {
+ var mgr = GetCurrentManager();
+
+ return Process.Memory.Read(
+ current + mgr.VisibleObjects.m_fulllist.baseClass.m_linkoffset + IntPtr.Size);
+ }
+
+ public void Update()
+ {
+ WoWObjects.Clear();
+ var wowObjects = EnumVisibleObjects();
+ foreach (var wowObject in wowObjects)
+ WoWObjects[wowObject.Data.Guid] = wowObject;
+
+ OnObjectsUpdated(WoWObjects);
+ }
+
+ public event EventHandler> ObjectsUpdated;
+
+ // Loop through the games object list.
+ public IEnumerable EnumVisibleObjects()
+ {
+ var first = GetFirstObject();
+ var typeOffset = Marshal.OffsetOf(typeof(WoWStructs.ObjectData), "ObjectType").ToInt32();
+
+ while (((first.ToInt64() & 1) == 0) && (first != IntPtr.Zero))
+ {
+ var type = (WoWEnums.ObjectType) Process.Memory.Read(first + typeOffset);
+
+ // Fix below with other object types as added.
+ // ReSharper disable once SwitchStatementMissingSomeCases
+ switch (type)
+ {
+ case WoWEnums.ObjectType.Object:
+ yield return new WoWObject(Process, first);
+ break;
+ case WoWEnums.ObjectType.Container:
+ break;
+ case WoWEnums.ObjectType.Unit:
+ yield return new WoWUnit(Process, first);
+ break;
+ case WoWEnums.ObjectType.Player:
+ yield return new WoWPlayer(Process, first, new IntPtr(0x179A6E0));
+ break;
+ default:
+ yield return new WoWObject(Process, first);
+ break;
+ }
+
+ first = GetNextObjectFromCurrent(first);
+ }
+ }
+
+ protected virtual void OnObjectsUpdated(Dictionary e)
+ {
+ ObjectsUpdated?.Invoke(this, e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Artemis/Artemis/Modules/Games/WoW/Data/WoWOffsets.cs b/Artemis/Artemis/Modules/Games/WoW/Data/WoWOffsets.cs
new file mode 100644
index 000000000..b4037a419
--- /dev/null
+++ b/Artemis/Artemis/Modules/Games/WoW/Data/WoWOffsets.cs
@@ -0,0 +1,368 @@
+namespace Artemis.Modules.Games.WoW.Data
+{
+ internal static class WoWOffsets
+ {
+ internal enum AreaTriggerData
+ {
+ OverrideScaleCurve = 0x30, // Size: 0x7, Flags: 0x201
+ ExtraScaleCurve = 0x4C, // Size: 0x7, Flags: 0x201
+ Caster = 0x68, // Size: 0x4, Flags: 0x1
+ Duration = 0x78, // Size: 0x1, Flags: 0x1
+ TimeToTarget = 0x7C, // Size: 0x1, Flags: 0x201
+ TimeToTargetScale = 0x80, // Size: 0x1, Flags: 0x201
+ TimeToTargetExtraScale = 0x84, // Size: 0x1, Flags: 0x201
+ SpellId = 0x88, // Size: 0x1, Flags: 0x1
+ SpellVisualId = 0x8C, // Size: 0x1, Flags: 0x80
+ BoundsRadius2D = 0x90, // Size: 0x1, Flags: 0x280
+ DecalPropertiesId = 0x94 // Size: 0x1, Flags: 0x1
+ }
+
+ internal enum ContainerData
+ {
+ Slots = 0x150, // Size: 0x90, Flags: 0x1
+ NumSlots = 0x390 // Size: 0x1, Flags: 0x1
+ }
+
+ internal enum ConversationData
+ {
+ LastLineDuration = 0x30 // Size: 0x1, Flags: 0x80
+ }
+
+ internal enum CorpseData
+ {
+ Owner = 0x30, // Size: 0x4, Flags: 0x1
+ PartyGuid = 0x40, // Size: 0x4, Flags: 0x1
+ DisplayId = 0x50, // Size: 0x1, Flags: 0x1
+ Items = 0x54, // Size: 0x13, Flags: 0x1
+ SkinId = 0xA0, // Size: 0x1, Flags: 0x1
+ FacialHairStyleId = 0xA4, // Size: 0x1, Flags: 0x1
+ Flags = 0xA8, // Size: 0x1, Flags: 0x1
+ DynamicFlags = 0xAC, // Size: 0x1, Flags: 0x80
+ FactionTemplate = 0xB0, // Size: 0x1, Flags: 0x1
+ CustomDisplayOption = 0xB4 // Size: 0x1, Flags: 0x1
+ }
+
+ internal enum DynamicObjectData
+ {
+ Caster = 0x30, // Size: 0x4, Flags: 0x1
+ TypeAndVisualId = 0x40, // Size: 0x1, Flags: 0x80
+ SpellId = 0x44, // Size: 0x1, Flags: 0x1
+ Radius = 0x48, // Size: 0x1, Flags: 0x1
+ CastTime = 0x4C // Size: 0x1, Flags: 0x1
+ }
+
+ internal enum GameObjectData
+ {
+ CreatedBy = 0x30, // Size: 0x4, Flags: 0x1
+ DisplayId = 0x40, // Size: 0x1, Flags: 0x280
+ Flags = 0x44, // Size: 0x1, Flags: 0x201
+ ParentRotation = 0x48, // Size: 0x4, Flags: 0x1
+ FactionTemplate = 0x58, // Size: 0x1, Flags: 0x1
+ Level = 0x5C, // Size: 0x1, Flags: 0x1
+ PercentHealth = 0x60, // Size: 0x1, Flags: 0x201
+ SpellVisualId = 0x64, // Size: 0x1, Flags: 0x281
+ StateSpellVisualId = 0x68, // Size: 0x1, Flags: 0x280
+ StateAnimId = 0x6C, // Size: 0x1, Flags: 0x280
+ StateAnimKitId = 0x70, // Size: 0x1, Flags: 0x280
+ StateWorldEffectId = 0x74 // Size: 0x4, Flags: 0x280
+ }
+
+ internal enum ItemData
+ {
+ Owner = 0x30, // Size: 0x4, Flags: 0x1
+ ContainedIn = 0x40, // Size: 0x4, Flags: 0x1
+ Creator = 0x50, // Size: 0x4, Flags: 0x1
+ GiftCreator = 0x60, // Size: 0x4, Flags: 0x1
+ StackCount = 0x70, // Size: 0x1, Flags: 0x4
+ Expiration = 0x74, // Size: 0x1, Flags: 0x4
+ SpellCharges = 0x78, // Size: 0x5, Flags: 0x4
+ DynamicFlags = 0x8C, // Size: 0x1, Flags: 0x1
+ Enchantment = 0x90, // Size: 0x27, Flags: 0x1
+ PropertySeed = 0x12C, // Size: 0x1, Flags: 0x1
+ RandomPropertiesId = 0x130, // Size: 0x1, Flags: 0x1
+ Durability = 0x134, // Size: 0x1, Flags: 0x4
+ MaxDurability = 0x138, // Size: 0x1, Flags: 0x4
+ CreatePlayedTime = 0x13C, // Size: 0x1, Flags: 0x1
+ ModifiersMask = 0x140, // Size: 0x1, Flags: 0x4
+ Context = 0x144, // Size: 0x1, Flags: 0x1
+ ArtifactXp = 0x148, // Size: 0x1, Flags: 0x4
+ ItemAppearanceModId = 0x14C // Size: 0x1, Flags: 0x4
+ }
+
+ internal enum KeyBinding
+ {
+ NumKeyBindings = 0x1700030, // -0x17C0
+ First = 0xC8,
+ Next = 0xB8,
+ Key = 0x30,
+ Command = 0x58
+ }
+
+ internal enum ObjectData
+ {
+ Guid = 0x0, // Size: 0x4, Flags: 0x1
+ Data = 0x10, // Size: 0x4, Flags: 0x1
+ Type = 0x20, // Size: 0x1, Flags: 0x1
+ EntryId = 0x24, // Size: 0x1, Flags: 0x80
+ DynamicFlags = 0x28, // Size: 0x1, Flags: 0x280
+ Scale = 0x2C // Size: 0x1, Flags: 0x1
+ }
+
+ internal enum PlayerData
+ {
+ DuelArbiter = 0x360, // Size: 0x4, Flags: 0x1
+ WowAccount = 0x370, // Size: 0x4, Flags: 0x1
+ LootTargetGuid = 0x380, // Size: 0x4, Flags: 0x1
+ PlayerFlags = 0x390, // Size: 0x1, Flags: 0x1
+ PlayerFlagsEx = 0x394, // Size: 0x1, Flags: 0x1
+ GuildRankId = 0x398, // Size: 0x1, Flags: 0x1
+ GuildDeleteDate = 0x39C, // Size: 0x1, Flags: 0x1
+ GuildLevel = 0x3A0, // Size: 0x1, Flags: 0x1
+ HairColorId = 0x3A4, // Size: 0x1, Flags: 0x1
+ CustomDisplayOption = 0x3A8, // Size: 0x1, Flags: 0x1
+ Inebriation = 0x3AC, // Size: 0x1, Flags: 0x1
+ ArenaFaction = 0x3B0, // Size: 0x1, Flags: 0x1
+ DuelTeam = 0x3B4, // Size: 0x1, Flags: 0x1
+ GuildTimeStamp = 0x3B8, // Size: 0x1, Flags: 0x1
+ QuestLog = 0x3BC, // Size: 0x320, Flags: 0x20
+ VisibleItems = 0x103C, // Size: 0x26, Flags: 0x1
+ PlayerTitle = 0x10D4, // Size: 0x1, Flags: 0x1
+ FakeInebriation = 0x10D8, // Size: 0x1, Flags: 0x1
+ VirtualPlayerRealm = 0x10DC, // Size: 0x1, Flags: 0x1
+ CurrentSpecId = 0x10E0, // Size: 0x1, Flags: 0x1
+ TaxiMountAnimKitId = 0x10E4, // Size: 0x1, Flags: 0x1
+ AvgItemLevel = 0x10E8, // Size: 0x4, Flags: 0x1
+ CurrentBattlePetBreedQuality = 0x10F8, // Size: 0x1, Flags: 0x1
+ Prestige = 0x10FC, // Size: 0x1, Flags: 0x1
+ HonorLevel = 0x1100, // Size: 0x1, Flags: 0x1
+ InvSlots = 0x1104, // Size: 0x2EC, Flags: 0x2
+ FarsightObject = 0x1CB4, // Size: 0x4, Flags: 0x2
+ SummonedBattlePetGuid = 0x1CC4, // Size: 0x4, Flags: 0x2
+ KnownTitles = 0x1CD4, // Size: 0xC, Flags: 0x2
+ Coinage = 0x1D04, // Size: 0x2, Flags: 0x2
+ Xp = 0x1D0C, // Size: 0x1, Flags: 0x2
+ NextLevelXp = 0x1D10, // Size: 0x1, Flags: 0x2
+ Skill = 0x1D14, // Size: 0x1C0, Flags: 0x2
+ CharacterPoints = 0x2414, // Size: 0x1, Flags: 0x2
+ MaxTalentTiers = 0x2418, // Size: 0x1, Flags: 0x2
+ TrackCreatureMask = 0x241C, // Size: 0x1, Flags: 0x2
+ TrackResourceMask = 0x2420, // Size: 0x1, Flags: 0x2
+ MainhandExpertise = 0x2424, // Size: 0x1, Flags: 0x2
+ OffhandExpertise = 0x2428, // Size: 0x1, Flags: 0x2
+ RangedExpertise = 0x242C, // Size: 0x1, Flags: 0x2
+ CombatRatingExpertise = 0x2430, // Size: 0x1, Flags: 0x2
+ BlockPercentage = 0x2434, // Size: 0x1, Flags: 0x2
+ DodgePercentage = 0x2438, // Size: 0x1, Flags: 0x2
+ ParryPercentage = 0x243C, // Size: 0x1, Flags: 0x2
+ CritPercentage = 0x2440, // Size: 0x1, Flags: 0x2
+ RangedCritPercentage = 0x2444, // Size: 0x1, Flags: 0x2
+ OffhandCritPercentage = 0x2448, // Size: 0x1, Flags: 0x2
+ SpellCritPercentage = 0x244C, // Size: 0x1, Flags: 0x2
+ ShieldBlock = 0x2450, // Size: 0x1, Flags: 0x2
+ ShieldBlockCritPercentage = 0x2454, // Size: 0x1, Flags: 0x2
+ Mastery = 0x2458, // Size: 0x1, Flags: 0x2
+ Speed = 0x245C, // Size: 0x1, Flags: 0x2
+ Lifesteal = 0x2460, // Size: 0x1, Flags: 0x2
+ Avoidance = 0x2464, // Size: 0x1, Flags: 0x2
+ Sturdiness = 0x2468, // Size: 0x1, Flags: 0x2
+ Versatility = 0x246C, // Size: 0x1, Flags: 0x2
+ VersatilityBonus = 0x2470, // Size: 0x1, Flags: 0x2
+ PvpPowerDamage = 0x2474, // Size: 0x1, Flags: 0x2
+ PvpPowerHealing = 0x2478, // Size: 0x1, Flags: 0x2
+ ExploredZones = 0x247C, // Size: 0x100, Flags: 0x2
+ RestInfo = 0x287C, // Size: 0x4, Flags: 0x2
+ ModDamageDonePos = 0x288C, // Size: 0x7, Flags: 0x2
+ ModDamageDoneNeg = 0x28A8, // Size: 0x7, Flags: 0x2
+ ModDamageDonePercent = 0x28C4, // Size: 0x7, Flags: 0x2
+ ModHealingDonePos = 0x28E0, // Size: 0x1, Flags: 0x2
+ ModHealingPercent = 0x28E4, // Size: 0x1, Flags: 0x2
+ ModHealingDonePercent = 0x28E8, // Size: 0x1, Flags: 0x2
+ ModPeriodicHealingDonePercent = 0x28EC, // Size: 0x1, Flags: 0x2
+ WeaponDmgMultipliers = 0x28F0, // Size: 0x3, Flags: 0x2
+ WeaponAtkSpeedMultipliers = 0x28FC, // Size: 0x3, Flags: 0x2
+ ModSpellPowerPercent = 0x2908, // Size: 0x1, Flags: 0x2
+ ModResiliencePercent = 0x290C, // Size: 0x1, Flags: 0x2
+ OverrideSpellPowerByApPercent = 0x2910, // Size: 0x1, Flags: 0x2
+ OverrideApBySpellPowerPercent = 0x2914, // Size: 0x1, Flags: 0x2
+ ModTargetResistance = 0x2918, // Size: 0x1, Flags: 0x2
+ ModTargetPhysicalResistance = 0x291C, // Size: 0x1, Flags: 0x2
+ LocalFlags = 0x2920, // Size: 0x1, Flags: 0x2
+ NumRespecs = 0x2924, // Size: 0x1, Flags: 0x2
+ SelfResSpell = 0x2928, // Size: 0x1, Flags: 0x2
+ PvpMedals = 0x292C, // Size: 0x1, Flags: 0x2
+ BuybackPrice = 0x2930, // Size: 0xC, Flags: 0x2
+ BuybackTimestamp = 0x2960, // Size: 0xC, Flags: 0x2
+ YesterdayHonorableKills = 0x2990, // Size: 0x1, Flags: 0x2
+ LifetimeHonorableKills = 0x2994, // Size: 0x1, Flags: 0x2
+ WatchedFactionIndex = 0x2998, // Size: 0x1, Flags: 0x2
+ CombatRatings = 0x299C, // Size: 0x20, Flags: 0x2
+ PvpInfo = 0x2A1C, // Size: 0x24, Flags: 0x2
+ MaxLevel = 0x2AAC, // Size: 0x1, Flags: 0x2
+ ScalingPlayerLevelDelta = 0x2AB0, // Size: 0x1, Flags: 0x2
+ MaxCreatureScalingLevel = 0x2AB4, // Size: 0x1, Flags: 0x2
+ NoReagentCostMask = 0x2AB8, // Size: 0x4, Flags: 0x2
+ PetSpellPower = 0x2AC8, // Size: 0x1, Flags: 0x2
+ Researching = 0x2ACC, // Size: 0xA, Flags: 0x2
+ ProfessionSkillLine = 0x2AF4, // Size: 0x2, Flags: 0x2
+ UiHitModifier = 0x2AFC, // Size: 0x1, Flags: 0x2
+ UiSpellHitModifier = 0x2B00, // Size: 0x1, Flags: 0x2
+ HomeRealmTimeOffset = 0x2B04, // Size: 0x1, Flags: 0x2
+ ModPetHaste = 0x2B08, // Size: 0x1, Flags: 0x2
+ OverrideSpellsId = 0x2B0C, // Size: 0x1, Flags: 0x402
+ LfgBonusFactionId = 0x2B10, // Size: 0x1, Flags: 0x2
+ LootSpecId = 0x2B14, // Size: 0x1, Flags: 0x2
+ OverrideZonePvpType = 0x2B18, // Size: 0x1, Flags: 0x402
+ BagSlotFlags = 0x2B1C, // Size: 0x4, Flags: 0x2
+ BankBagSlotFlags = 0x2B2C, // Size: 0x7, Flags: 0x2
+ InsertItemsLeftToRight = 0x2B48, // Size: 0x1, Flags: 0x2
+ QuestCompleted = 0x2B4C, // Size: 0x36B, Flags: 0x2
+ Honor = 0x38F8, // Size: 0x1, Flags: 0x2
+ HonorNextLevel = 0x38FC // Size: 0x1, Flags: 0x2
+ }
+
+ internal enum SceneObjectData
+ {
+ ScriptPackageId = 0x30, // Size: 0x1, Flags: 0x1
+ RndSeedVal = 0x34, // Size: 0x1, Flags: 0x1
+ CreatedBy = 0x38, // Size: 0x4, Flags: 0x1
+ SceneType = 0x48 // Size: 0x1, Flags: 0x1
+ }
+
+ internal enum Unit
+ {
+ CurrentCastId = 0x1B98,
+ CurrentChanneledId = 0x1BB8,
+ AuraTable = 0x1D10,
+ AuraCount = 0x2390,
+ AuraSize = 0x68,
+ ClientRace = 0x2670,
+ DisplayData = 0x1718
+ }
+
+ // Note: Invalid possibly!
+ internal enum UnitAuras : uint
+ {
+ AuraCount1 = 0x2390,
+ AuraCount2 = 0x1D10,
+ AuraTable1 = 0x1D14,
+ AuraTable2 = 0x1D18,
+ AuraSize = 0x68,
+
+ OwnerGuid = 0x40,
+ AuraSpellId = 0x50,
+ //AuraFlags = 0x54, //Not exactly sure here.
+ //AuraLevel = 0x58, //Not exactly sure here.
+ AuraStack = 0x59,
+ TimeLeft = 0x60,
+ //In case I need it:
+ DruidEclipse = 0x2694
+ }
+
+ // Below is all of the World of Warcraft in-game object field offsets.
+ // Commenting is not used on purpose and enums below should remain internal.
+ internal enum UnitData
+ {
+ Charm = 0x30, // Size: 0x4, Flags: 0x1
+ Summon = 0x40, // Size: 0x4, Flags: 0x1
+ Critter = 0x50, // Size: 0x4, Flags: 0x2
+ CharmedBy = 0x60, // Size: 0x4, Flags: 0x1
+ SummonedBy = 0x70, // Size: 0x4, Flags: 0x1
+ CreatedBy = 0x80, // Size: 0x4, Flags: 0x1
+ DemonCreator = 0x90, // Size: 0x4, Flags: 0x1
+ Target = 0xA0, // Size: 0x4, Flags: 0x1
+ BattlePetCompanionGuid = 0xB0, // Size: 0x4, Flags: 0x1
+ BattlePetDbid = 0xC0, // Size: 0x2, Flags: 0x1
+ ChannelObject = 0xC8, // Size: 0x4, Flags: 0x201
+ ChannelSpell = 0xD8, // Size: 0x1, Flags: 0x201
+ ChannelSpellXSpellVisual = 0xDC, // Size: 0x1, Flags: 0x201
+ SummonedByHomeRealm = 0xE0, // Size: 0x1, Flags: 0x1
+ Sex = 0xE4, // Size: 0x1, Flags: 0x1
+ DisplayPower = 0xE8, // Size: 0x1, Flags: 0x1
+ OverrideDisplayPowerId = 0xEC, // Size: 0x1, Flags: 0x1
+ Health = 0xF0, // Size: 0x2, Flags: 0x1
+ Power = 0xF8, // Size: 0x6, Flags: 0x401
+ TertiaryPower = 0xFC,
+ SecondaryPower = 0x100,
+ MaxHealth = 0x110, // Size: 0x2, Flags: 0x1
+ MaxPower = 0x118, // Size: 0x6, Flags: 0x1
+ PowerRegenFlatModifier = 0x130, // Size: 0x6, Flags: 0x46
+ PowerRegenInterruptedFlatModifier = 0x148, // Size: 0x6, Flags: 0x46
+ Level = 0x160, // Size: 0x1, Flags: 0x1
+ EffectiveLevel = 0x164, // Size: 0x1, Flags: 0x1
+ ScalingLevelMin = 0x168, // Size: 0x1, Flags: 0x1
+ ScalingLevelMax = 0x16C, // Size: 0x1, Flags: 0x1
+ ScalingLevelDelta = 0x170, // Size: 0x1, Flags: 0x1
+ FactionTemplate = 0x174, // Size: 0x1, Flags: 0x1
+ VirtualItems = 0x178, // Size: 0x6, Flags: 0x1
+ Flags = 0x190, // Size: 0x1, Flags: 0x201
+ Flags2 = 0x194, // Size: 0x1, Flags: 0x201
+ Flags3 = 0x198, // Size: 0x1, Flags: 0x201
+ AuraState = 0x19C, // Size: 0x1, Flags: 0x1
+ AttackRoundBaseTime = 0x1A0, // Size: 0x2, Flags: 0x1
+ RangedAttackRoundBaseTime = 0x1A8, // Size: 0x1, Flags: 0x2
+ BoundingRadius = 0x1AC, // Size: 0x1, Flags: 0x1
+ CombatReach = 0x1B0, // Size: 0x1, Flags: 0x1
+ DisplayId = 0x1B4, // Size: 0x1, Flags: 0x280
+ NativeDisplayId = 0x1B8, // Size: 0x1, Flags: 0x201
+ MountDisplayId = 0x1BC, // Size: 0x1, Flags: 0x201
+ MinDamage = 0x1C0, // Size: 0x1, Flags: 0x16
+ MaxDamage = 0x1C4, // Size: 0x1, Flags: 0x16
+ MinOffHandDamage = 0x1C8, // Size: 0x1, Flags: 0x16
+ MaxOffHandDamage = 0x1CC, // Size: 0x1, Flags: 0x16
+ AnimTier = 0x1D0, // Size: 0x1, Flags: 0x1
+ PetNumber = 0x1D4, // Size: 0x1, Flags: 0x1
+ PetNameTimestamp = 0x1D8, // Size: 0x1, Flags: 0x1
+ PetExperience = 0x1DC, // Size: 0x1, Flags: 0x4
+ PetNextLevelExperience = 0x1E0, // Size: 0x1, Flags: 0x4
+ ModCastingSpeed = 0x1E4, // Size: 0x1, Flags: 0x1
+ ModSpellHaste = 0x1E8, // Size: 0x1, Flags: 0x1
+ ModHaste = 0x1EC, // Size: 0x1, Flags: 0x1
+ ModRangedHaste = 0x1F0, // Size: 0x1, Flags: 0x1
+ ModHasteRegen = 0x1F4, // Size: 0x1, Flags: 0x1
+ ModTimeRate = 0x1F8, // Size: 0x1, Flags: 0x1
+ CreatedBySpell = 0x1FC, // Size: 0x1, Flags: 0x1
+ NpcFlags = 0x200, // Size: 0x2, Flags: 0x81
+ EmoteState = 0x208, // Size: 0x1, Flags: 0x1
+ Stats = 0x20C, // Size: 0x4, Flags: 0x6
+ StatPosBuff = 0x21C, // Size: 0x4, Flags: 0x6
+ StatNegBuff = 0x22C, // Size: 0x4, Flags: 0x6
+ Resistances = 0x23C, // Size: 0x7, Flags: 0x16
+ ResistanceBuffModsPositive = 0x258, // Size: 0x7, Flags: 0x6
+ ResistanceBuffModsNegative = 0x274, // Size: 0x7, Flags: 0x6
+ ModBonusArmor = 0x290, // Size: 0x1, Flags: 0x6
+ BaseMana = 0x294, // Size: 0x1, Flags: 0x1
+ BaseHealth = 0x298, // Size: 0x1, Flags: 0x6
+ ShapeshiftForm = 0x29C, // Size: 0x1, Flags: 0x1
+ AttackPower = 0x2A0, // Size: 0x1, Flags: 0x6
+ AttackPowerModPos = 0x2A4, // Size: 0x1, Flags: 0x6
+ AttackPowerModNeg = 0x2A8, // Size: 0x1, Flags: 0x6
+ AttackPowerMultiplier = 0x2AC, // Size: 0x1, Flags: 0x6
+ RangedAttackPower = 0x2B0, // Size: 0x1, Flags: 0x6
+ RangedAttackPowerModPos = 0x2B4, // Size: 0x1, Flags: 0x6
+ RangedAttackPowerModNeg = 0x2B8, // Size: 0x1, Flags: 0x6
+ RangedAttackPowerMultiplier = 0x2BC, // Size: 0x1, Flags: 0x6
+ SetAttackSpeedAura = 0x2C0, // Size: 0x1, Flags: 0x6
+ MinRangedDamage = 0x2C4, // Size: 0x1, Flags: 0x6
+ MaxRangedDamage = 0x2C8, // Size: 0x1, Flags: 0x6
+ PowerCostModifier = 0x2CC, // Size: 0x7, Flags: 0x6
+ PowerCostMultiplier = 0x2E8, // Size: 0x7, Flags: 0x6
+ MaxHealthModifier = 0x304, // Size: 0x1, Flags: 0x6
+ HoverHeight = 0x308, // Size: 0x1, Flags: 0x1
+ MinItemLevelCutoff = 0x30C, // Size: 0x1, Flags: 0x1
+ MinItemLevel = 0x310, // Size: 0x1, Flags: 0x1
+ MaxItemLevel = 0x314, // Size: 0x1, Flags: 0x1
+ WildBattlePetLevel = 0x318, // Size: 0x1, Flags: 0x1
+ BattlePetCompanionNameTimestamp = 0x31C, // Size: 0x1, Flags: 0x1
+ InteractSpellId = 0x320, // Size: 0x1, Flags: 0x1
+ StateSpellVisualId = 0x324, // Size: 0x1, Flags: 0x280
+ StateAnimId = 0x328, // Size: 0x1, Flags: 0x280
+ StateAnimKitId = 0x32C, // Size: 0x1, Flags: 0x280
+ StateWorldEffectId = 0x330, // Size: 0x4, Flags: 0x280
+ ScaleDuration = 0x340, // Size: 0x1, Flags: 0x1
+ LooksLikeMountId = 0x344, // Size: 0x1, Flags: 0x1
+ LooksLikeCreatureId = 0x348, // Size: 0x1, Flags: 0x1
+ LookAtControllerId = 0x34C, // Size: 0x1, Flags: 0x1
+ LookAtControllerTarget = 0x350 // Size: 0x4, Flags: 0x1
+ }
+ }
+}
\ No newline at end of file
diff --git a/Artemis/Artemis/Modules/Games/WoW/Data/WoWPlayer.cs b/Artemis/Artemis/Modules/Games/WoW/Data/WoWPlayer.cs
new file mode 100644
index 000000000..b7eba53bb
--- /dev/null
+++ b/Artemis/Artemis/Modules/Games/WoW/Data/WoWPlayer.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Linq;
+using Process.NET;
+
+namespace Artemis.Modules.Games.WoW.Data
+{
+ public class WoWPlayer : WoWUnit
+ {
+ private readonly IntPtr _targetIntPtr;
+
+ public WoWPlayer(IProcess process, IntPtr baseAddress, IntPtr targetIntPtr, bool readPointer = false)
+ : base(process, baseAddress, readPointer)
+ {
+ _targetIntPtr = targetIntPtr;
+ }
+
+ public WoWObject GetTarget(WoWObjectManager manager)
+ {
+ var targetGuid = Process.Memory.Read(Process.Native.MainModule.BaseAddress + _targetIntPtr.ToInt32());
+ return manager.EnumVisibleObjects().FirstOrDefault(o => o.Guid == targetGuid);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Artemis/Artemis/Modules/Games/WoW/Data/WoWStructs.cs b/Artemis/Artemis/Modules/Games/WoW/Data/WoWStructs.cs
new file mode 100644
index 000000000..b16179265
--- /dev/null
+++ b/Artemis/Artemis/Modules/Games/WoW/Data/WoWStructs.cs
@@ -0,0 +1,181 @@
+using System;
+using System.Runtime.InteropServices;
+using Artemis.Modules.Games.WoW.Data.WowSharp.Client.Patchables;
+
+namespace Artemis.Modules.Games.WoW.Data
+{
+ public static class WoWStructs
+ {
+ [StructLayout(LayoutKind.Explicit)]
+ public struct ObjectData
+ {
+ // x32 : x64
+ [FieldOffset(0)] private readonly IntPtr vtable; // 0x00 0x00
+ [FieldOffset(10)] public IntPtr Descriptors; // 0x04 0x10
+ [FieldOffset(18)] private readonly IntPtr unk1; // 0x08 0x18
+ [FieldOffset(20)] public int ObjectType; // 0x0C 0x20
+ [FieldOffset(24)] private readonly IntPtr unk3; // 0x10 0x24
+ [FieldOffset(28)] private readonly IntPtr unk4; // 0x14 0x28
+ [FieldOffset(30)] private readonly IntPtr unk5; // 0x18 0x30
+ [FieldOffset(38)] private readonly IntPtr unk6; // 0x1C 0x38
+ [FieldOffset(40)] private readonly IntPtr unk7; // 0x20 0x40
+ [FieldOffset(48)] private readonly IntPtr unk8; // 0x24 0x48
+ [FieldOffset(50)] public Guid Guid; // 0x28 0x50
+ }
+
+ public struct Guid
+ {
+ private readonly Int128 _mGuid;
+
+ public static readonly Guid Zero = new Guid(0);
+
+ public Guid(Int128 guid)
+ {
+ _mGuid = guid;
+ }
+
+ public override string ToString()
+ {
+ // ReSharper disable once SwitchStatementMissingSomeCases
+ switch (Type)
+ {
+ case WoWEnums.GuidType.Creature:
+ case WoWEnums.GuidType.Vehicle:
+ case WoWEnums.GuidType.Pet:
+ case WoWEnums.GuidType.GameObject:
+ case WoWEnums.GuidType.AreaTrigger:
+ case WoWEnums.GuidType.DynamicObject:
+ case WoWEnums.GuidType.Corpse:
+ case WoWEnums.GuidType.LootObject:
+ case WoWEnums.GuidType.SceneObject:
+ case WoWEnums.GuidType.Scenario:
+ case WoWEnums.GuidType.AiGroup:
+ case WoWEnums.GuidType.DynamicDoor:
+ case WoWEnums.GuidType.Vignette:
+ case WoWEnums.GuidType.Conversation:
+ case WoWEnums.GuidType.CallForHelp:
+ case WoWEnums.GuidType.AiResource:
+ case WoWEnums.GuidType.AiLock:
+ case WoWEnums.GuidType.AiLockTicket:
+ return $"{Type}-{SubType}-{RealmId}-{MapId}-{ServerId}-{Id}-{CreationBits:X10}";
+ case WoWEnums.GuidType.Player:
+ return $"{Type}-{RealmId}-{(ulong) (_mGuid >> 64):X8}";
+ case WoWEnums.GuidType.Item:
+ return $"{Type}-{RealmId}-{(uint) ((_mGuid >> 18) & 0xFFFFFF)}-{(ulong) (_mGuid >> 64):X10}";
+ //case GuidType.ClientActor:
+ // return String.Format("{0}-{1}-{2}", Type, RealmId, CreationBits);
+ //case GuidType.Transport:
+ //case GuidType.StaticDoor:
+ // return String.Format("{0}-{1}-{2}", Type, RealmId, CreationBits);
+ default:
+ return $"{Type}-{_mGuid:X32}";
+ }
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Guid)
+ return _mGuid == ((Guid) obj)._mGuid;
+ return false;
+ }
+
+ public override int GetHashCode()
+ {
+ return _mGuid.GetHashCode();
+ }
+
+ public WoWEnums.GuidType Type => (WoWEnums.GuidType) (byte) ((_mGuid >> 58) & 0x3F);
+
+ public byte SubType => (byte) ((_mGuid >> 120) & 0x3F);
+
+ public ushort RealmId => (ushort) ((_mGuid >> 42) & 0x1FFF);
+
+ public ushort ServerId => (ushort) ((_mGuid >> 104) & 0x1FFF);
+
+ public ushort MapId => (ushort) ((_mGuid >> 29) & 0x1FFF);
+
+ // Creature, Pet, Vehicle
+ public uint Id => (uint) ((_mGuid >> 6) & 0x7FFFFF);
+
+ public ulong CreationBits => (ulong) ((_mGuid >> 64) & 0xFFFFFFFFFF);
+ }
+
+ #region Manager
+
+ // Region is here due to the large amount of structs-
+ // the CurremtManager struct depends on.
+ [StructLayout(LayoutKind.Sequential)]
+ public struct CurrentManager
+ {
+ public TsHashTable VisibleObjects; // m_objects
+ public TsHashTable LazyCleanupObjects; // m_lazyCleanupObjects
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 13)]
+ // m_lazyCleanupFifo, m_freeObjects, m_visibleObjects, m_reenabledObjects, whateverObjects...
+ public TsExplicitList[] Links; // Links[13] has all objects stored in VisibleObjects it seems
+
+#if !X64
+ public int Unknown1; // wtf is that and why x86 only?
+#endif
+ public Int128 ActivePlayer;
+ public int MapId;
+ public IntPtr ClientConnection;
+ public IntPtr MovementGlobals;
+ public int Unk1;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct Ts
+ {
+ public IntPtr vtable;
+ public uint m_alloc;
+ public uint m_count;
+ public IntPtr m_data; //TSExplicitList* m_data;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct TsExplicitList
+ {
+ public TsList baseClass;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct TsFixedArray
+ {
+ public Ts baseClass;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct TsGrowableArray
+ {
+ public TsFixedArray baseclass;
+ public uint m_chunk;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct TsHashTable
+ {
+ public IntPtr vtable;
+ public TsExplicitList m_fulllist;
+ public int m_fullnessIndicator;
+ public TsGrowableArray m_slotlistarray;
+ public int m_slotmask;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct TsLink
+ {
+ public IntPtr m_prevlink; //TSLink *m_prevlink
+ public IntPtr m_next; // C_OBJECTHASH *m_next
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct TsList
+ {
+ public int m_linkoffset;
+ public TsLink m_terminator;
+ }
+
+ #endregion;
+ }
+}
\ No newline at end of file
diff --git a/Artemis/Artemis/Modules/Games/WoW/Data/WoWUnit.cs b/Artemis/Artemis/Modules/Games/WoW/Data/WoWUnit.cs
new file mode 100644
index 000000000..c0c0f45bd
--- /dev/null
+++ b/Artemis/Artemis/Modules/Games/WoW/Data/WoWUnit.cs
@@ -0,0 +1,31 @@
+using System;
+using Process.NET;
+using static Artemis.Modules.Games.WoW.Data.WoWEnums;
+using static Artemis.Modules.Games.WoW.Data.WoWOffsets;
+
+namespace Artemis.Modules.Games.WoW.Data
+{
+ public class WoWUnit : WoWObject
+ {
+ public WoWUnit(IProcess process, IntPtr baseAddress, bool readPointer = false)
+ : base(process, baseAddress, readPointer)
+ {
+ }
+
+ public int Health => ReadField(UnitData.Health);
+ public int MaxHealth => ReadField(UnitData.MaxHealth);
+ public int Power => ReadField(UnitData.Power);
+ public int SecondaryPower => ReadField(UnitData.SecondaryPower);
+ public int TertiaryPower => ReadField(UnitData.TertiaryPower);
+ public int MaxPower => ReadField(UnitData.MaxPower);
+ public PowerType PowerType => (PowerType) ReadField(UnitData.DisplayPower);
+ public int Level => ReadField(UnitData.Level);
+
+ public WoWDetails Details { get; set; }
+
+ public void UpdateDetails(WoWNameCache nameCache)
+ {
+ Details = GetNpcDetails() ?? nameCache.GetNameByGuid(Guid);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Artemis/Artemis/Modules/Games/WorldofWarcraft/WoWAddresses.cs b/Artemis/Artemis/Modules/Games/WoW/WoWAddresses.cs
similarity index 99%
rename from Artemis/Artemis/Modules/Games/WorldofWarcraft/WoWAddresses.cs
rename to Artemis/Artemis/Modules/Games/WoW/WoWAddresses.cs
index 3abc6f8fc..487eeab04 100644
--- a/Artemis/Artemis/Modules/Games/WorldofWarcraft/WoWAddresses.cs
+++ b/Artemis/Artemis/Modules/Games/WoW/WoWAddresses.cs
@@ -1,4 +1,4 @@
-namespace Artemis.Modules.Games.WorldofWarcraft
+namespace Artemis.Modules.Games.WoW
{
public static class WoWAddresses
{
diff --git a/Artemis/Artemis/Modules/Games/WoW/WoWDataModel.cs b/Artemis/Artemis/Modules/Games/WoW/WoWDataModel.cs
new file mode 100644
index 000000000..346317eda
--- /dev/null
+++ b/Artemis/Artemis/Modules/Games/WoW/WoWDataModel.cs
@@ -0,0 +1,11 @@
+using Artemis.Models.Interfaces;
+using Artemis.Modules.Games.WoW.Data;
+
+namespace Artemis.Modules.Games.WoW
+{
+ public class WoWDataModel : IDataModel
+ {
+ public WoWUnit Player { get; set; }
+ public WoWUnit Target { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Artemis/Artemis/Modules/Games/WoW/WoWModel.cs b/Artemis/Artemis/Modules/Games/WoW/WoWModel.cs
new file mode 100644
index 000000000..16ceebc01
--- /dev/null
+++ b/Artemis/Artemis/Modules/Games/WoW/WoWModel.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Artemis.DAL;
+using Artemis.Managers;
+using Artemis.Models;
+using Artemis.Modules.Games.WoW.Data;
+using Artemis.Profiles.Layers.Models;
+using Artemis.Utilities.Memory;
+using Process.NET;
+
+namespace Artemis.Modules.Games.WoW
+{
+ public class WoWModel : GameModel
+ {
+ private readonly GamePointersCollection _pointer;
+ private ProcessSharp _process;
+
+ public WoWModel(MainManager mainManager)
+ : base(mainManager, SettingsProvider.Load(), new WoWDataModel())
+ {
+ Name = "WoW";
+ ProcessName = "Wow-64";
+ Scale = 4;
+ Enabled = Settings.Enabled;
+ Initialized = false;
+
+ // TODO: Retrieve from GitHub
+ _pointer = new GamePointersCollection
+ {
+ Game = "WorldOfWarcraft",
+ GameVersion = "7.0.3.22522",
+ GameAddresses = new List
+ {
+ new GamePointer
+ {
+ Description = "ObjectManager",
+ BasePointer = new IntPtr(0x1575E10)
+ },
+ new GamePointer
+ {
+ Description = "LocalPlayer",
+ BasePointer = new IntPtr(0x169BCB0)
+ }
+ }
+ };
+ }
+
+ public int Scale { get; set; }
+
+ public override void Dispose()
+ {
+ Initialized = false;
+
+ _process.Dispose();
+ _process = null;
+ }
+
+ public override void Enable()
+ {
+ var tempProcess = MemoryHelpers.GetProcessIfRunning(ProcessName);
+ if (tempProcess == null)
+ return;
+
+ _process = new ProcessSharp(tempProcess);
+ _process.Memory = new ExternalProcessMemory(_process.Handle);
+
+ Initialized = true;
+ }
+
+ public override void Update()
+ {
+ if ((Profile == null) || (DataModel == null) || (_process == null))
+ return;
+
+ var dataModel = (WoWDataModel) DataModel;
+
+ var objectManager = new WoWObjectManager(_process,
+ _pointer.GameAddresses.First(a => a.Description == "ObjectManager").BasePointer);
+ var nameCache = new WoWNameCache(_process, new IntPtr(0x151BA88));
+ var player = new WoWPlayer(_process,
+ _pointer.GameAddresses.First(a => a.Description == "LocalPlayer").BasePointer, new IntPtr(0x179A6E0),
+ true);
+
+ dataModel.Player = player;
+ if (dataModel.Player != null && dataModel.Player.Guid != Guid.Empty)
+ {
+ dataModel.Player.UpdateDetails(nameCache);
+ var target = player.GetTarget(objectManager);
+ if (target == null)
+ return;
+
+ dataModel.Target = new WoWUnit(target.Process, target.BaseAddress);
+ dataModel.Target.UpdateDetails(nameCache);
+ }
+ else
+ {
+ dataModel.Target = null;
+ }
+ }
+
+ public override List GetRenderLayers(bool keyboardOnly)
+ {
+ return Profile.GetRenderLayers(DataModel, keyboardOnly);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Artemis/Artemis/Modules/Games/WoW/WoWSettings.cs b/Artemis/Artemis/Modules/Games/WoW/WoWSettings.cs
new file mode 100644
index 000000000..a4d0f76c4
--- /dev/null
+++ b/Artemis/Artemis/Modules/Games/WoW/WoWSettings.cs
@@ -0,0 +1,8 @@
+using Artemis.Settings;
+
+namespace Artemis.Modules.Games.WoW
+{
+ public class WoWSettings : GameSettings
+ {
+ }
+}
\ No newline at end of file
diff --git a/Artemis/Artemis/Modules/Games/WoW/WoWView.xaml b/Artemis/Artemis/Modules/Games/WoW/WoWView.xaml
new file mode 100644
index 000000000..a04b13e3e
--- /dev/null
+++ b/Artemis/Artemis/Modules/Games/WoW/WoWView.xaml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Artemis/Artemis/Modules/Games/WoW/WoWView.xaml.cs b/Artemis/Artemis/Modules/Games/WoW/WoWView.xaml.cs
new file mode 100644
index 000000000..2e0bac541
--- /dev/null
+++ b/Artemis/Artemis/Modules/Games/WoW/WoWView.xaml.cs
@@ -0,0 +1,15 @@
+using System.Windows.Controls;
+
+namespace Artemis.Modules.Games.WoW
+{
+ ///
+ /// Interaction logic for WoWView.xaml
+ ///
+ public partial class WoWView : UserControl
+ {
+ public WoWView()
+ {
+ 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
new file mode 100644
index 000000000..f5bffcedd
--- /dev/null
+++ b/Artemis/Artemis/Modules/Games/WoW/WoWViewModel.cs
@@ -0,0 +1,15 @@
+using Artemis.InjectionFactories;
+using Artemis.Managers;
+using Artemis.ViewModels.Abstract;
+
+namespace Artemis.Modules.Games.WoW
+{
+ public sealed class WoWViewModel : GameViewModel
+ {
+ public WoWViewModel(MainManager main, IProfileEditorVmFactory pFactory, WoWModel model)
+ : base(main, model, pFactory)
+ {
+ DisplayName = "WoW";
+ }
+ }
+}
\ No newline at end of file
diff --git a/Artemis/Artemis/Modules/Games/WorldofWarcraft/WoWDataModel.cs b/Artemis/Artemis/Modules/Games/WorldofWarcraft/WoWDataModel.cs
deleted file mode 100644
index aeeb5421a..000000000
--- a/Artemis/Artemis/Modules/Games/WorldofWarcraft/WoWDataModel.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using Artemis.Models.Interfaces;
-
-namespace Artemis.Modules.Games.WorldofWarcraft
-{
- public class WoWDataModel : IDataModel
- {
- public Player Player { get; set; } = new Player();
- }
-
-
- public class Player
- {
- public string Name { get; set; }
- public int Health { get; set; }
- public int MaxHealth { get; set; }
- }
-}
\ No newline at end of file
diff --git a/Artemis/Artemis/Modules/Games/WorldofWarcraft/WoWModel.cs b/Artemis/Artemis/Modules/Games/WorldofWarcraft/WoWModel.cs
deleted file mode 100644
index b2d33b702..000000000
--- a/Artemis/Artemis/Modules/Games/WorldofWarcraft/WoWModel.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-//using System.Collections.Generic;
-//using Artemis.Managers;
-//using Artemis.Models;
-//using Artemis.Profiles.Layers.Models;
-//using Artemis.Utilities.Memory;
-//
-//namespace Artemis.Modules.Games.WorldofWarcraft
-//{
-// public class WoWModel : GameModel
-// {
-// private Memory _memory;
-//
-// public WoWModel(MainManager mainManager): base(mainManager, SettingsProvider.Load(), new WoWDataModel())
-// {
-// Name = "WoW";
-// ProcessName = "Wow-64";
-// Scale = 4;
-// Enabled = Settings.Enabled;
-// Initialized = false;
-// }
-//
-// public int Scale { get; set; }
-//
-// public override void Dispose()
-// {
-// Initialized = false;
-// }
-//
-// public override void Enable()
-// {
-// var tempProcess = MemoryHelpers.GetProcessIfRunning(ProcessName);
-// if (tempProcess == null)
-// return;
-//
-// _memory = new Memory(tempProcess);
-//
-// Initialized = true;
-// }
-//
-// public override void Update()
-// {
-// if (Profile == null || DataModel == null || _memory == null)
-// return;
-//
-//// _memory.ReadMemory();
-// }
-//
-// public override List GetRenderLayers(bool keyboardOnly)
-// {
-// return Profile.GetRenderLayers(DataModel, keyboardOnly);
-// }
-// }
-//}
-
diff --git a/Artemis/Artemis/Modules/Games/WorldofWarcraft/WoWSettings.cs b/Artemis/Artemis/Modules/Games/WorldofWarcraft/WoWSettings.cs
deleted file mode 100644
index 1672b160d..000000000
--- a/Artemis/Artemis/Modules/Games/WorldofWarcraft/WoWSettings.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using Artemis.Settings;
-
-namespace Artemis.Modules.Games.WorldofWarcraft
-{
- public class WoWSettings : GameSettings
- {
- private WoWSettings()
- {
- }
- }
-}
\ No newline at end of file
diff --git a/Artemis/Artemis/Modules/Games/WorldofWarcraft/WoWViewModel.cs b/Artemis/Artemis/Modules/Games/WorldofWarcraft/WoWViewModel.cs
deleted file mode 100644
index 143875c80..000000000
--- a/Artemis/Artemis/Modules/Games/WorldofWarcraft/WoWViewModel.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-//using Artemis.InjectionFactories;
-//using Artemis.Managers;
-//using Artemis.ViewModels.Abstract;
-//
-//namespace Artemis.Modules.Games.WorldofWarcraft
-//{
-// public sealed class WoWViewModel : GameViewModel
-// {
-// public WoWViewModel(MainManager main, IProfileEditorVmFactory pFactory, WoWModel model): base(main, model, pFactory)
-// {
-// DisplayName = "WoW";
-// }
-// }
-//}
-
diff --git a/Artemis/Artemis/Profiles/Layers/Interfaces/ILayerType.cs b/Artemis/Artemis/Profiles/Layers/Interfaces/ILayerType.cs
index 02a5bfb56..ee840be41 100644
--- a/Artemis/Artemis/Profiles/Layers/Interfaces/ILayerType.cs
+++ b/Artemis/Artemis/Profiles/Layers/Interfaces/ILayerType.cs
@@ -70,6 +70,7 @@ namespace Artemis.Profiles.Layers.Interfaces
Keyboard,
Mouse,
Headset,
- Generic
+ Generic,
+ Mousemat
}
}
\ No newline at end of file
diff --git a/Artemis/Artemis/Profiles/Layers/Types/Audio/AudioType.cs b/Artemis/Artemis/Profiles/Layers/Types/Audio/AudioType.cs
index 0b455fe7b..c84cd92b2 100644
--- a/Artemis/Artemis/Profiles/Layers/Types/Audio/AudioType.cs
+++ b/Artemis/Artemis/Profiles/Layers/Types/Audio/AudioType.cs
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Media;
-using Artemis.Managers;
using Artemis.Models.Interfaces;
using Artemis.Modules.Effects.AudioVisualizer.Utilities;
using Artemis.Profiles.Layers.Abstract;
@@ -28,10 +27,10 @@ namespace Artemis.Profiles.Layers.Types.Audio
private int _lines;
private AudioPropertiesModel _previousSettings;
- public AudioType(MainManager mainManager)
+ public AudioType()
{
- _device =
- new MMDeviceEnumerator().EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active).FirstOrDefault();
+ _device = new MMDeviceEnumerator()
+ .EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active).FirstOrDefault();
_sampleAggregator.FftCalculated += FftCalculated;
_sampleAggregator.PerformFFT = true;
@@ -55,7 +54,7 @@ namespace Artemis.Profiles.Layers.Types.Audio
var visual = new DrawingVisual();
using (var c = visual.RenderOpen())
{
- c.DrawImage(ImageUtilities.BitmapToBitmapImage(Resources.gif), thumbnailRect);
+ c.DrawImage(ImageUtilities.BitmapToBitmapImage(Resources.audio), thumbnailRect);
}
var image = new DrawingImage(visual.Drawing);
diff --git a/Artemis/Artemis/Profiles/Layers/Types/KeyPress/KeyPressPropertiesView.xaml b/Artemis/Artemis/Profiles/Layers/Types/KeyPress/KeyPressPropertiesView.xaml
index 49378d184..52df04289 100644
--- a/Artemis/Artemis/Profiles/Layers/Types/KeyPress/KeyPressPropertiesView.xaml
+++ b/Artemis/Artemis/Profiles/Layers/Types/KeyPress/KeyPressPropertiesView.xaml
@@ -33,7 +33,7 @@
-
diff --git a/Artemis/Artemis/Profiles/Layers/Types/KeyPress/KeyPressType.cs b/Artemis/Artemis/Profiles/Layers/Types/KeyPress/KeyPressType.cs
index d67996403..896592b2e 100644
--- a/Artemis/Artemis/Profiles/Layers/Types/KeyPress/KeyPressType.cs
+++ b/Artemis/Artemis/Profiles/Layers/Types/KeyPress/KeyPressType.cs
@@ -42,7 +42,7 @@ namespace Artemis.Profiles.Layers.Types.KeyPress
var visual = new DrawingVisual();
using (var c = visual.RenderOpen())
{
- c.DrawImage(ImageUtilities.BitmapToBitmapImage(Resources.gif), thumbnailRect);
+ c.DrawImage(ImageUtilities.BitmapToBitmapImage(Resources.keypress), thumbnailRect);
}
var image = new DrawingImage(visual.Drawing);
@@ -87,7 +87,20 @@ namespace Artemis.Profiles.Layers.Types.KeyPress
if (layerModel.Properties is KeyPressPropertiesModel)
return;
- layerModel.Properties = new KeyPressPropertiesModel(layerModel.Properties);
+ // Setup brush as a radial
+ layerModel.Properties = new KeyPressPropertiesModel(layerModel.Properties)
+ {
+ Brush = new RadialGradientBrush(new GradientStopCollection
+ {
+ new GradientStop(Colors.Red, 0.85),
+ new GradientStop(Color.FromArgb(0, 255, 0, 0), 0.95),
+ new GradientStop(Colors.Red, 0.55),
+ new GradientStop(Color.FromArgb(0, 255, 0, 0), 0.45)
+ })
+ };
+ // Setup defaults
+ ((KeyPressPropertiesModel) layerModel.Properties).AnimationSpeed = 2.5;
+ ((KeyPressPropertiesModel) layerModel.Properties).Scale = 8;
}
public LayerPropertiesViewModel SetupViewModel(LayerEditorViewModel layerEditorViewModel,
diff --git a/Artemis/Artemis/Profiles/Layers/Types/Mousemat/MousematPropertiesView.xaml b/Artemis/Artemis/Profiles/Layers/Types/Mousemat/MousematPropertiesView.xaml
new file mode 100644
index 000000000..6af2267bc
--- /dev/null
+++ b/Artemis/Artemis/Profiles/Layers/Types/Mousemat/MousematPropertiesView.xaml
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Artemis/Artemis/Profiles/Layers/Types/Mousemat/MousematPropertiesView.xaml.cs b/Artemis/Artemis/Profiles/Layers/Types/Mousemat/MousematPropertiesView.xaml.cs
new file mode 100644
index 000000000..5a32dfcf7
--- /dev/null
+++ b/Artemis/Artemis/Profiles/Layers/Types/Mousemat/MousematPropertiesView.xaml.cs
@@ -0,0 +1,15 @@
+using System.Windows.Controls;
+
+namespace Artemis.Profiles.Layers.Types.Mousemat
+{
+ ///
+ /// Interaction logic for MousematPropertiesView.xaml
+ ///
+ public partial class MousematPropertiesView : UserControl
+ {
+ public MousematPropertiesView()
+ {
+ InitializeComponent();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Artemis/Artemis/Profiles/Layers/Types/Mousemat/MousematPropertiesViewModel.cs b/Artemis/Artemis/Profiles/Layers/Types/Mousemat/MousematPropertiesViewModel.cs
new file mode 100644
index 000000000..65c42d6a2
--- /dev/null
+++ b/Artemis/Artemis/Profiles/Layers/Types/Mousemat/MousematPropertiesViewModel.cs
@@ -0,0 +1,44 @@
+using System.Linq;
+using Artemis.Profiles.Layers.Abstract;
+using Artemis.Profiles.Layers.Interfaces;
+using Artemis.ViewModels.Profiles;
+using Caliburn.Micro;
+
+namespace Artemis.Profiles.Layers.Types.Mousemat
+{
+ public class MousematPropertiesViewModel : LayerPropertiesViewModel
+ {
+ private ILayerAnimation _selectedLayerAnimation;
+
+ public MousematPropertiesViewModel(LayerEditorViewModel editorVm) : base(editorVm)
+ {
+ LayerAnimations = new BindableCollection(editorVm.LayerAnimations);
+ OpacityProperties = new LayerDynamicPropertiesViewModel("Opacity", editorVm);
+
+ SelectedLayerAnimation =
+ LayerAnimations.FirstOrDefault(l => l.Name == editorVm.ProposedLayer.LayerAnimation?.Name) ??
+ LayerAnimations.First(l => l.Name == "None");
+ }
+
+ public BindableCollection LayerAnimations { get; set; }
+ public LayerDynamicPropertiesViewModel OpacityProperties { get; set; }
+
+ public ILayerAnimation SelectedLayerAnimation
+ {
+ get { return _selectedLayerAnimation; }
+ set
+ {
+ if (Equals(value, _selectedLayerAnimation)) return;
+ _selectedLayerAnimation = value;
+ NotifyOfPropertyChange(() => SelectedLayerAnimation);
+ }
+ }
+
+ public override void ApplyProperties()
+ {
+ OpacityProperties.Apply(LayerModel);
+ LayerModel.Properties.Brush = Brush;
+ LayerModel.LayerAnimation = SelectedLayerAnimation;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Artemis/Artemis/Profiles/Layers/Types/Mousemat/MousematType.cs b/Artemis/Artemis/Profiles/Layers/Types/Mousemat/MousematType.cs
new file mode 100644
index 000000000..121596b3f
--- /dev/null
+++ b/Artemis/Artemis/Profiles/Layers/Types/Mousemat/MousematType.cs
@@ -0,0 +1,95 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows;
+using System.Windows.Media;
+using Artemis.Models.Interfaces;
+using Artemis.Profiles.Layers.Abstract;
+using Artemis.Profiles.Layers.Animations;
+using Artemis.Profiles.Layers.Interfaces;
+using Artemis.Profiles.Layers.Models;
+using Artemis.Properties;
+using Artemis.Utilities;
+using Artemis.ViewModels.Profiles;
+
+namespace Artemis.Profiles.Layers.Types.Mousemat
+{
+ public class MousematType : ILayerType
+ {
+ public string Name { get; } = "Mousemat";
+ public bool ShowInEdtor { get; } = false;
+ public DrawType DrawType { get; } = DrawType.Mousemat;
+
+ public ImageSource DrawThumbnail(LayerModel layer)
+ {
+ var thumbnailRect = new Rect(0, 0, 18, 18);
+ var visual = new DrawingVisual();
+ using (var c = visual.RenderOpen())
+ c.DrawImage(ImageUtilities.BitmapToBitmapImage(Resources.mousemat), thumbnailRect);
+
+ var image = new DrawingImage(visual.Drawing);
+ return image;
+ }
+
+ public void Draw(LayerModel layer, DrawingContext c)
+ {
+ // If an animation is present, let it handle the drawing
+ if (layer.LayerAnimation != null && !(layer.LayerAnimation is NoneAnimation))
+ {
+ layer.LayerAnimation.Draw(layer.Properties, layer.AppliedProperties, c);
+ return;
+ }
+
+ // Otherwise draw the rectangle with its applied dimensions and brush
+ var rect = new Rect(layer.AppliedProperties.X*4,
+ layer.AppliedProperties.Y*4,
+ layer.AppliedProperties.Width*4,
+ layer.AppliedProperties.Height*4);
+
+ c.PushClip(new RectangleGeometry(rect));
+ c.DrawRectangle(layer.AppliedProperties.Brush, null, rect);
+ c.Pop();
+ }
+
+ public void Update(LayerModel layerModel, IDataModel dataModel, bool isPreview = false)
+ {
+ // Mousemat layers are always drawn 10*10 (which is 40*40 when scaled up)
+ layerModel.Properties.Width = 10;
+ layerModel.Properties.Height = 10;
+ layerModel.Properties.X = 0;
+ layerModel.Properties.Y = 0;
+ layerModel.Properties.Contain = true;
+
+ layerModel.AppliedProperties = new SimplePropertiesModel(layerModel.Properties);
+
+ if (isPreview || dataModel == null)
+ return;
+
+ // If not previewing, apply dynamic properties according to datamodel
+ var props = (SimplePropertiesModel) layerModel.AppliedProperties;
+ foreach (var dynamicProperty in props.DynamicProperties)
+ dynamicProperty.ApplyProperty(dataModel, layerModel.AppliedProperties);
+ }
+
+ public void SetupProperties(LayerModel layerModel)
+ {
+ if (layerModel.Properties is SimplePropertiesModel)
+ return;
+
+ layerModel.Properties = new SimplePropertiesModel(layerModel.Properties);
+
+ // Remove height and width dynamic properties since they are not applicable
+ layerModel.Properties.DynamicProperties.Remove(
+ layerModel.Properties.DynamicProperties.FirstOrDefault(d => d.LayerProperty == "Height"));
+ layerModel.Properties.DynamicProperties.Remove(
+ layerModel.Properties.DynamicProperties.FirstOrDefault(d => d.LayerProperty == "Width"));
+ }
+
+ public LayerPropertiesViewModel SetupViewModel(LayerEditorViewModel layerEditorViewModel,
+ LayerPropertiesViewModel layerPropertiesViewModel)
+ {
+ if (layerPropertiesViewModel is MousematPropertiesViewModel)
+ return layerPropertiesViewModel;
+ return new MousematPropertiesViewModel(layerEditorViewModel);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Artemis/Artemis/Properties/AssemblyInfo.cs b/Artemis/Artemis/Properties/AssemblyInfo.cs
index ff4156bb9..8bdcdc28e 100644
--- a/Artemis/Artemis/Properties/AssemblyInfo.cs
+++ b/Artemis/Artemis/Properties/AssemblyInfo.cs
@@ -52,5 +52,5 @@ using System.Windows;
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.3.2.0")]
-[assembly: AssemblyFileVersion("1.3.2.0")]
\ No newline at end of file
+[assembly: AssemblyVersion("1.3.3.0")]
+[assembly: AssemblyFileVersion("1.3.3.0")]
\ No newline at end of file
diff --git a/Artemis/Artemis/Properties/Resources.Designer.cs b/Artemis/Artemis/Properties/Resources.Designer.cs
index a1f8932ac..d414ddf78 100644
--- a/Artemis/Artemis/Properties/Resources.Designer.cs
+++ b/Artemis/Artemis/Properties/Resources.Designer.cs
@@ -60,6 +60,16 @@ namespace Artemis.Properties {
}
}
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap audio {
+ get {
+ object obj = ResourceManager.GetObject("audio", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
///
/// Looks up a localized resource of type System.Drawing.Bitmap.
///
@@ -258,6 +268,16 @@ namespace Artemis.Properties {
}
}
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap keypress {
+ get {
+ object obj = ResourceManager.GetObject("keypress", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
///
/// Looks up a localized resource of type System.Byte[].
///
@@ -298,6 +318,16 @@ namespace Artemis.Properties {
}
}
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap mousemat {
+ get {
+ object obj = ResourceManager.GetObject("mousemat", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
///
/// Looks up a localized resource of type System.Drawing.Bitmap.
///
diff --git a/Artemis/Artemis/Properties/Resources.resx b/Artemis/Artemis/Properties/Resources.resx
index 4c504efcb..6bb8fcb3d 100644
--- a/Artemis/Artemis/Properties/Resources.resx
+++ b/Artemis/Artemis/Properties/Resources.resx
@@ -199,4 +199,13 @@
..\Modules\Games\EurotruckSimulator2\Resources\Win32\ets2-telemetry-server.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ ..\Resources\mousemat.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\keypress.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Resources\audio.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
\ No newline at end of file
diff --git a/Artemis/Artemis/Resources/audio.png b/Artemis/Artemis/Resources/audio.png
new file mode 100644
index 000000000..908c2c717
Binary files /dev/null and b/Artemis/Artemis/Resources/audio.png differ
diff --git a/Artemis/Artemis/Resources/keypress.png b/Artemis/Artemis/Resources/keypress.png
new file mode 100644
index 000000000..9ef284e89
Binary files /dev/null and b/Artemis/Artemis/Resources/keypress.png differ
diff --git a/Artemis/Artemis/Resources/mousemat.png b/Artemis/Artemis/Resources/mousemat.png
new file mode 100644
index 000000000..94657a7cc
Binary files /dev/null and b/Artemis/Artemis/Resources/mousemat.png differ
diff --git a/Artemis/Artemis/Utilities/GeneralHelpers.cs b/Artemis/Artemis/Utilities/GeneralHelpers.cs
index 54b025218..ead9146ae 100644
--- a/Artemis/Artemis/Utilities/GeneralHelpers.cs
+++ b/Artemis/Artemis/Utilities/GeneralHelpers.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using Microsoft.Win32;
@@ -76,9 +77,14 @@ namespace Artemis.Utilities
if (friendlyName != Empty)
list.Add(parent);
- if (propertyInfo.PropertyType.Name != "String" && propertyInfo.PropertyType.Name != "DateTime")
+ // Don't go into Strings, DateTimes or anything with JsonIgnore on it
+ if (propertyInfo.PropertyType.Name != "String" &&
+ propertyInfo.PropertyType.Name != "DateTime" &&
+ propertyInfo.CustomAttributes.All(a => a.AttributeType != typeof(JsonIgnoreAttribute)))
+ {
list.AddRange(GenerateTypeMap(propertyInfo.PropertyType.GetProperties(),
path + $"{propertyInfo.Name}."));
+ }
}
return list;
}
diff --git a/Artemis/Artemis/ViewModels/Flyouts/FlyoutSettingsViewModel.cs b/Artemis/Artemis/ViewModels/Flyouts/FlyoutSettingsViewModel.cs
index 826d6fdca..941165ded 100644
--- a/Artemis/Artemis/ViewModels/Flyouts/FlyoutSettingsViewModel.cs
+++ b/Artemis/Artemis/ViewModels/Flyouts/FlyoutSettingsViewModel.cs
@@ -212,7 +212,7 @@ namespace Artemis.ViewModels.Flyouts
public void NavigateTo(string url)
{
- Process.Start(new ProcessStartInfo(url));
+ System.Diagnostics.Process.Start(new ProcessStartInfo(url));
}
protected override void HandleOpen()
diff --git a/Artemis/Artemis/ViewModels/Profiles/LayerEditorViewModel.cs b/Artemis/Artemis/ViewModels/Profiles/LayerEditorViewModel.cs
index 8158da854..839e84abc 100644
--- a/Artemis/Artemis/ViewModels/Profiles/LayerEditorViewModel.cs
+++ b/Artemis/Artemis/ViewModels/Profiles/LayerEditorViewModel.cs
@@ -31,6 +31,7 @@ namespace Artemis.ViewModels.Profiles
{
Layer = layer;
ProposedLayer = Clone(layer);
+ ProposedLayer.Children.Clear();
DataModel = DataModel;
LayerTypes = new BindableCollection(types);
LayerAnimations = layerAnimations;
@@ -201,7 +202,7 @@ namespace Artemis.ViewModels.Profiles
ProposedLayer.Properties.Conditions.Add(conditionViewModel.LayerConditionModel);
// If not a keyboard, ignore size and position
- if (ProposedLayer.LayerType.DrawType != DrawType.Keyboard)
+ if (ProposedLayer.LayerType.DrawType != DrawType.Keyboard || !ProposedLayer.LayerType.ShowInEdtor)
{
ProposedLayer.Properties.Width = Layer.Properties.Width;
ProposedLayer.Properties.Height = Layer.Properties.Height;
@@ -209,9 +210,9 @@ namespace Artemis.ViewModels.Profiles
ProposedLayer.Properties.Y = Layer.Properties.Y;
ProposedLayer.Properties.Contain = Layer.Properties.Contain;
}
-
+
// Ignore the children, can't just temporarily add them to the proposed layer because
- // that would upset the child layers' relations (sounds like an episode of Dr. Phil amirite?)
+ // that would upset the child layers' relations (sounds like Dr. Phil amirite?)
var currentObj = Clone(Layer);
currentObj.Children.Clear();
var current = JsonConvert.SerializeObject(currentObj, Formatting.Indented);
diff --git a/Artemis/Artemis/Views/WelcomeView.xaml b/Artemis/Artemis/Views/WelcomeView.xaml
index 3914660b9..5383ceab9 100644
--- a/Artemis/Artemis/Views/WelcomeView.xaml
+++ b/Artemis/Artemis/Views/WelcomeView.xaml
@@ -7,29 +7,18 @@
d:DesignHeight="476.986" d:DesignWidth="538.772">
-
-
-
-
-
-
-
-
-
-