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

Lots of WoW stuff

Added icons to audio and keypress layers
Added text explaining audio and keypress layers
This commit is contained in:
SpoinkyNL 2016-09-07 12:59:11 +02:00
parent 62ef77662e
commit 4b994ee061
54 changed files with 3960 additions and 468 deletions

View File

@ -152,8 +152,8 @@
<Private>True</Private>
</Reference>
<Reference Include="CUE.NET, Version=1.0.3.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\CUE.NET.1.0.3\lib\net45\CUE.NET.dll</HintPath>
<Private>True</Private>
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\CUE.NET\bin\CUE.NET.dll</HintPath>
</Reference>
<Reference Include="DeltaCompressionDotNet, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1d14d6e5194e7f4a, processorArchitecture=MSIL">
<HintPath>..\packages\DeltaCompressionDotNet.1.0.0\lib\net45\DeltaCompressionDotNet.dll</HintPath>
@ -246,6 +246,10 @@
<HintPath>..\packages\squirrel.windows.1.4.4\lib\Net45\NuGet.Squirrel.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Process.NET, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Process.NET.1.0.1\lib\Process.NET.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Splat, Version=1.6.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Splat.1.6.2\lib\Net45\Splat.dll</HintPath>
<Private>True</Private>
@ -331,6 +335,7 @@
<Compile Include="DAL\SettingsProvider.cs" />
<Compile Include="DeviceProviders\Corsair\CorsairMice.cs" />
<Compile Include="DeviceProviders\Corsair\CorsairHeadsets.cs" />
<Compile Include="DeviceProviders\Corsair\CorsairMousemats.cs" />
<Compile Include="DeviceProviders\Corsair\Utilities\KeyMap.cs" />
<Compile Include="DeviceProviders\DeviceProvider.cs" />
<Compile Include="DeviceProviders\Logitech\G810.cs" />
@ -363,7 +368,6 @@
<Compile Include="Managers\ProfileManager.cs" />
<Compile Include="Models\EffectModel.cs" />
<Compile Include="Models\Interfaces\IDataModel.cs" />
<Compile Include="Modules\Effects\AudioVisualizer\AudioVisualization.cs" />
<Compile Include="Modules\Effects\Bubbles\Bubbles.cs" />
<Compile Include="Modules\Effects\WindowsProfile\PerformanceInfo.cs" />
<Compile Include="Modules\Games\EurotruckSimulator2\Data\Ets2TelemetryData.cs" />
@ -385,11 +389,23 @@
<DependentUpon>UnrealTournamentView.xaml</DependentUpon>
</Compile>
<Compile Include="Modules\Games\UnrealTournament\UnrealTournamentViewModel.cs" />
<Compile Include="Modules\Games\WorldofWarcraft\WoWDataModel.cs" />
<Compile Include="Modules\Games\WorldofWarcraft\WoWModel.cs" />
<Compile Include="Modules\Games\WorldofWarcraft\WoWSettings.cs" />
<Compile Include="Modules\Games\WorldofWarcraft\WoWViewModel.cs" />
<Compile Include="Modules\Games\WorldofWarcraft\WoWAddresses.cs" />
<Compile Include="Modules\Games\WoW\Data\Int128.cs" />
<Compile Include="Modules\Games\WoW\Data\WoWEnums.cs" />
<Compile Include="Modules\Games\WoW\Data\WoWOffsets.cs" />
<Compile Include="Modules\Games\WoW\Data\WoWStructs.cs" />
<Compile Include="Modules\Games\WoW\Data\WoWNameCache.cs" />
<Compile Include="Modules\Games\WoW\Data\WoWObjectManager.cs" />
<Compile Include="Modules\Games\WoW\Data\WoWObject.cs" />
<Compile Include="Modules\Games\WoW\Data\WoWPlayer.cs" />
<Compile Include="Modules\Games\WoW\Data\WoWUnit.cs" />
<Compile Include="Modules\Games\WoW\WoWView.xaml.cs">
<DependentUpon>WoWView.xaml</DependentUpon>
</Compile>
<Compile Include="Modules\Games\WoW\WoWDataModel.cs" />
<Compile Include="Modules\Games\WoW\WoWModel.cs" />
<Compile Include="Modules\Games\WoW\WoWSettings.cs" />
<Compile Include="Modules\Games\WoW\WoWViewModel.cs" />
<Compile Include="Modules\Games\WoW\WoWAddresses.cs" />
<Compile Include="Profiles\Layers\Animations\NoneAnimation.cs" />
<Compile Include="Profiles\Layers\Models\EventPropertiesModel.cs" />
<Compile Include="Profiles\Layers\Models\KeyboardEventPropertiesModel.cs" />
@ -410,10 +426,14 @@
</Compile>
<Compile Include="Profiles\Layers\Types\KeyPress\KeyPressPropertiesViewModel.cs" />
<Compile Include="Profiles\Layers\Types\KeyPress\KeyPressType.cs" />
<Compile Include="Profiles\Layers\Types\Mousemat\MousematPropertiesView.xaml.cs">
<DependentUpon>MousematPropertiesView.xaml</DependentUpon>
</Compile>
<Compile Include="Profiles\Layers\Types\Mousemat\MousematPropertiesViewModel.cs" />
<Compile Include="Profiles\Layers\Types\Mousemat\MousematType.cs" />
<Compile Include="Profiles\ProfileModel.cs" />
<Compile Include="Profiles\Layers\Models\SimplePropertiesModel.cs" />
<Compile Include="Profiles\Layers\Types\Keyboard\KeyboardPropertiesModel.cs" />
<Compile Include="Modules\Effects\AudioVisualizer\AudioVisualizerModel.cs" />
<Compile Include="Modules\Effects\AudioVisualizer\Utilities\FftEventArgs.cs" />
<Compile Include="Modules\Effects\AudioVisualizer\Utilities\SampleAggregator.cs" />
<Compile Include="Modules\Effects\Bubbles\Bubble.cs" />
@ -632,6 +652,8 @@
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<None Include="Resources\keypress.png" />
<None Include="Resources\mousemat.png" />
<EmbeddedResource Include="Modules\Games\UnrealTournament\Resources\ut-plugin.zip" />
<EmbeddedResource Include="Modules\Games\Witcher3\Resources\witcher3-mod.zip" />
<None Include="app.manifest">
@ -713,6 +735,10 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Modules\Games\WoW\WoWView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Profiles\Layers\Types\Audio\AudioPropertiesView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@ -725,6 +751,10 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Profiles\Layers\Types\Mousemat\MousematPropertiesView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Resources\Icons.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@ -841,6 +871,7 @@
<None Include="Modules\Games\UnrealTournament\Resources\redeemer.gif" />
<None Include="Modules\Games\EurotruckSimulator2\Resources\Win32\ets2-telemetry-server.dll" />
<None Include="Modules\Games\EurotruckSimulator2\Resources\Win64\ets2-telemetry-server.dll" />
<None Include="Resources\audio.png" />
<Content Include="Resources\CounterStrike\csgoGamestateConfiguration.txt" />
</ItemGroup>
<ItemGroup>

View File

@ -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;
}
}
}

View File

@ -46,6 +46,7 @@ namespace Artemis.DeviceProviders
Keyboard,
Mouse,
Headset,
Generic
Generic,
Mousemat
}
}

View File

@ -22,6 +22,9 @@ namespace Artemis.InjectionModules
// Headsets
Bind<DeviceProvider>().To<CorsairHeadsets>().InSingletonScope();
// Mousemats
Bind<DeviceProvider>().To<CorsairMousemats>().InSingletonScope();
// Other
Bind<DeviceProvider>().To<LogitechGeneric>().InSingletonScope();
}

View File

@ -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<ILayerType>().To<KeyboardType>();
Bind<ILayerType>().To<KeyboardGifType>();
Bind<ILayerType>().To<MouseType>();
Bind<ILayerType>().To<MousematType>();
Bind<ILayerType>().To<GenericType>();
Bind<ILayerType>().To<KeyPressType>();
Bind<ILayerType>().To<AudioType>();

View File

@ -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<DeviceProvider> MiceProviders { get; set; }
public List<DeviceProvider> HeadsetProviders { get; set; }
public List<DeviceProvider> GenericProviders { get; set; }
public List<DeviceProvider> 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<KeyboardChangedEventArgs> OnKeyboardChangedEvent;
/// <summary>
@ -137,6 +141,8 @@ namespace Artemis.Managers
headsetProvider.TryEnableAsync();
foreach (var genericProvider in GenericProviders)
genericProvider.TryEnableAsync();
foreach (var mousematProviders in MousematProviders)
mousematProviders.TryEnableAsync();
}
/// <summary>

View File

@ -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()
{

View File

@ -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)

View File

@ -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)

View File

@ -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.
}
}
}

View File

@ -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<string>();
SpectrumData = new List<byte>();
Initialized = false;
}
public int Lines { get; set; }
public List<byte> SpectrumData { get; set; }
public List<KeyboardRectangle> SoundRectangles { get; set; }
public List<string> 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<KeyboardRectangle>();
for (var i = 0; i < Lines; i++)
{
SoundRectangles.Add(new KeyboardRectangle(
MainManager.DeviceManager.ActiveKeyboard,
0, 0, new List<Color>
{
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<LayerModel> 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;
}
}
}

View File

@ -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">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<Grid Margin="15, 5, 15, 5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,0,1,0">
<Label FontSize="20" HorizontalAlignment="Left">
<Label.Content>
<AccessText TextWrapping="Wrap"
Text="Visualizes the default audio device on the keyboard." />
</Label.Content>
</Label>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Label Content="Enable effect" Margin="0 3 0 0" HorizontalAlignment="Right" />
<ToggleButton x:Name="EffectEnabled" Margin="0 3 0 0" Width="25" Height="25"
Style="{DynamicResource MetroCircleToggleButtonStyle}"
cal:Message.Attach="[Event Click] = [Action ToggleEffect]"
ToolTip="Note: You can't enable an effect when Artemis is disabled" />
</StackPanel>
</StackPanel>
<!-- Top color -->
<TextBlock Grid.Row="1" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center"
Height="16" Margin="0,8">
Color used on top
</TextBlock>
<xctk:ColorPicker x:Name="TopColor"
SelectedColor="{Binding Path=EffectSettings.TopColor, Mode=TwoWay}"
Grid.Row="1" Grid.Column="1" Width="110" HorizontalAlignment="Right"
VerticalAlignment="Center" Margin="0,5,-1,5" Height="22" />
<Label Grid.Row="0" FontSize="20" MaxWidth="500" HorizontalAlignment="Left">
<Label.Content>
<AccessText TextWrapping="Wrap" Text="Gone!" />
</Label.Content>
</Label>
<!-- Middle color -->
<TextBlock Grid.Row="2" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center"
Height="16" Margin="0,8">
Color used in the middle
<TextBlock Grid.Row="1" VerticalAlignment="Center" Margin="0,8" TextWrapping="Wrap"
HorizontalAlignment="Left" TextAlignment="Justify">
<Run Text="In case you're wondering where these effects went, they are now part of the layer system." />
<LineBreak />
<Run Text="To use them, navigate to the Windows Profile effect and select one of these profiles:" />
<LineBreak /><Run Text="• Default - Key waves" /><LineBreak />
<Run Text="• Default - Audio visualization" /><LineBreak /><Run /><LineBreak />
<Run Text="You can also add these effects to your own profile, even in games! " /><LineBreak />
<Run
Text="To do so, create a new layer, open up its property window and change the type according to what you want it to be, 'key press' or 'audio visualization'." />
</TextBlock>
<xctk:ColorPicker x:Name="MiddleColor"
SelectedColor="{Binding Path=EffectSettings.MiddleColor, Mode=TwoWay}"
Grid.Row="2" Grid.Column="1" Width="110" HorizontalAlignment="Right"
VerticalAlignment="Center" Margin="0,5,-1,5" Height="22" />
<!-- Bottom color -->
<TextBlock Grid.Row="3" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center"
Height="16" Margin="0,8">
Color used on the bottom
</TextBlock>
<xctk:ColorPicker x:Name="Bottom"
SelectedColor="{Binding Path=EffectSettings.BottomColor, Mode=TwoWay}"
Grid.Row="3" Grid.Column="1" Width="110" HorizontalAlignment="Right"
VerticalAlignment="Center" Margin="0,5,-1,5" Height="22" />
<!-- Bar direction -->
<TextBlock Grid.Row="4" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center"
Height="16" Margin="0,9,0,10">
Grow bars bottom
</TextBlock>
<controls:ToggleSwitch IsChecked="{Binding Path=EffectSettings.FromBottom, Mode=TwoWay}"
Grid.Row="4" Grid.Column="1" HorizontalAlignment="Right" OnLabel="Yes"
OffLabel="No" Margin="0,0,-5,0" Width="114" />
<!-- Sensitivity -->
<TextBlock Grid.Row="5" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center"
Height="16" Margin="0,8">
Volume sensitivity multiplier
</TextBlock>
<Slider x:Name="Sensitivity" Grid.Row="5" Grid.Column="1" VerticalAlignment="Center"
HorizontalAlignment="Right" Width="110" TickPlacement="BottomRight" TickFrequency="1"
Value="{Binding Path=EffectSettings.Sensitivity, Mode=TwoWay}" Minimum="1" Maximum="10"
SmallChange="1" IsSnapToTickEnabled="True" />
<!-- Fade speed -->
<TextBlock Grid.Row="6" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center"
Height="16" Margin="0,8">
Bar fade-out speed
</TextBlock>
<Slider x:Name="FadeSpeed" Grid.Row="6" Grid.Column="1" VerticalAlignment="Center"
HorizontalAlignment="Right" Width="110" TickPlacement="BottomRight" TickFrequency="1"
Value="{Binding Path=EffectSettings.FadeSpeed, Mode=TwoWay}" Minimum="1" Maximum="3"
SmallChange="1" IsSnapToTickEnabled="True" />
<!-- Buttons -->
<StackPanel Grid.Column="0" Grid.Row="7" Orientation="Horizontal" VerticalAlignment="Bottom">
<Button x:Name="ResetSettings" Content="Reset effect" VerticalAlignment="Top" Width="100"
Style="{DynamicResource SquareButtonStyle}" />
<Button x:Name="SaveSettings" Content="Save changes" VerticalAlignment="Top" Width="100"
Margin="10,0,0,0"
Style="{DynamicResource SquareButtonStyle}" />
</StackPanel>
</Grid>
</ScrollViewer>
</UserControl>

View File

@ -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";
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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
}
}
}

View File

@ -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<IntPtr>(CurrentCacheAddress);
var index = 0;
while (current != IntPtr.Zero)
{
var guid = Process.Memory.Read<Guid>(current + 0x20);
if (guid.Equals(searchGuid))
{
var pRace = Process.Memory.Read<int>(current + 0x88);
var pClass = Process.Memory.Read<int>(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<IntPtr>(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; }
}
}

View File

@ -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<Guid>(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<T>(int offset)
{
var address = GetAddress();
if (address == IntPtr.Zero)
return default(T);
var ptr = Process.Memory.Read<IntPtr>(address + 0x10);
return Process.Memory.Read<T>(ptr + offset);
}
public T ReadField<T>(Enum offset)
{
var address = GetAddress();
if (address == IntPtr.Zero)
return default(T);
var ptr = Process.Memory.Read<IntPtr>(address + 0x10);
return Process.Memory.Read<T>(ptr + Convert.ToInt32(offset));
}
private IntPtr GetAddress()
{
return _readPointer
? Process.Memory.Read<IntPtr>(Process.Native.MainModule.BaseAddress + BaseAddress.ToInt32())
: BaseAddress;
}
public WoWDetails GetNpcDetails()
{
var address = GetAddress();
if (address == IntPtr.Zero)
return null;
var npcCachePtr = Process.Memory.Read<IntPtr>(address + 0x1760);
if (npcCachePtr == IntPtr.Zero)
return null;
var npcName = Process.Memory.Read(Process.Memory.Read<IntPtr>(npcCachePtr + 0x00A0), Encoding.ASCII, 48);
return new WoWDetails(Guid, 0, 0, WoWEnums.WoWType.Npc, npcName);
}
}
}

View File

@ -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<WoWStructs.Guid, WoWObject> 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<WoWStructs.CurrentManager>(Process.Memory.Read<IntPtr>(CurrentManagerAddress));
}
public IntPtr GetNextObjectFromCurrent(IntPtr current)
{
var mgr = GetCurrentManager();
return Process.Memory.Read<IntPtr>(
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<Dictionary<WoWStructs.Guid, WoWObject>> ObjectsUpdated;
// Loop through the games object list.
public IEnumerable<WoWObject> 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<int>(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<WoWStructs.Guid, WoWObject> e)
{
ObjectsUpdated?.Invoke(this, e);
}
}
}

View File

@ -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
}
}
}

View File

@ -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<Guid>(Process.Native.MainModule.BaseAddress + _targetIntPtr.ToInt32());
return manager.EnumVisibleObjects().FirstOrDefault(o => o.Guid == targetGuid);
}
}
}

View File

@ -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;
}
}

View File

@ -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<int>(UnitData.Health);
public int MaxHealth => ReadField<int>(UnitData.MaxHealth);
public int Power => ReadField<int>(UnitData.Power);
public int SecondaryPower => ReadField<int>(UnitData.SecondaryPower);
public int TertiaryPower => ReadField<int>(UnitData.TertiaryPower);
public int MaxPower => ReadField<int>(UnitData.MaxPower);
public PowerType PowerType => (PowerType) ReadField<int>(UnitData.DisplayPower);
public int Level => ReadField<int>(UnitData.Level);
public WoWDetails Details { get; set; }
public void UpdateDetails(WoWNameCache nameCache)
{
Details = GetNpcDetails() ?? nameCache.GetNameByGuid(Guid);
}
}
}

View File

@ -1,4 +1,4 @@
namespace Artemis.Modules.Games.WorldofWarcraft
namespace Artemis.Modules.Games.WoW
{
public static class WoWAddresses
{

View File

@ -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; }
}
}

View File

@ -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<WoWSettings>(), 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<GamePointer>
{
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<LayerModel> GetRenderLayers(bool keyboardOnly)
{
return Profile.GetRenderLayers(DataModel, keyboardOnly);
}
}
}

View File

@ -0,0 +1,8 @@
using Artemis.Settings;
namespace Artemis.Modules.Games.WoW
{
public class WoWSettings : GameSettings
{
}
}

View File

@ -0,0 +1,56 @@
<UserControl x:Class="Artemis.Modules.Games.WoW.WoWView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<Grid Margin="15, 5, 15, 5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,0,1,0">
<Label FontSize="20" HorizontalAlignment="Left">
<Label.Content>
<AccessText TextWrapping="Wrap"
Text="For Azeroth" />
</Label.Content>
</Label>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Label Content="Enable effect" Margin="0 3 0 0" HorizontalAlignment="Right" />
<ToggleButton x:Name="EffectEnabled" Margin="0 3 0 0" Width="25" Height="25"
IsChecked="{Binding Path=GameSettings.Enabled, Mode=TwoWay}"
Style="{DynamicResource MetroCircleToggleButtonStyle}"
cal:Message.Attach="[Event Click] = [Action ToggleEffect]" />
</StackPanel>
</StackPanel>
<!-- Profile editor -->
<ContentControl Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" x:Name="ProfileEditor" Margin="0,0,-30,0" />
<!-- Buttons -->
<StackPanel Grid.Column="0" Grid.Row="9" Orientation="Horizontal" VerticalAlignment="Bottom">
<Button x:Name="ResetSettings" Content="Reset effect" VerticalAlignment="Top" Width="100"
Style="{DynamicResource SquareButtonStyle}" />
<Button x:Name="SaveSettings" Content="Save changes" VerticalAlignment="Top" Width="100"
Margin="10,0,0,0"
Style="{DynamicResource SquareButtonStyle}" />
</StackPanel>
</Grid>
</ScrollViewer>
</UserControl>

View File

@ -0,0 +1,15 @@
using System.Windows.Controls;
namespace Artemis.Modules.Games.WoW
{
/// <summary>
/// Interaction logic for WoWView.xaml
/// </summary>
public partial class WoWView : UserControl
{
public WoWView()
{
InitializeComponent();
}
}
}

View File

@ -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";
}
}
}

View File

@ -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; }
}
}

View File

@ -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<WoWSettings>(), 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<LayerModel> GetRenderLayers(bool keyboardOnly)
// {
// return Profile.GetRenderLayers(DataModel, keyboardOnly);
// }
// }
//}

View File

@ -1,11 +0,0 @@
using Artemis.Settings;
namespace Artemis.Modules.Games.WorldofWarcraft
{
public class WoWSettings : GameSettings
{
private WoWSettings()
{
}
}
}

View File

@ -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";
// }
// }
//}

View File

@ -70,6 +70,7 @@ namespace Artemis.Profiles.Layers.Interfaces
Keyboard,
Mouse,
Headset,
Generic
Generic,
Mousemat
}
}

View File

@ -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);

View File

@ -33,7 +33,7 @@
<!-- Animation Speed -->
<TextBlock Grid.Row="0" Grid.Column="2" Margin="10,13,10,10" FontSize="13.333" Text="Animation speed:"
VerticalAlignment="Top" Height="18" />
<Slider x:Name="RotationSpeed" Grid.Row="0" Grid.Column="3" VerticalAlignment="Top"
<Slider x:Name="AnimationSpeed" Grid.Row="0" Grid.Column="3" VerticalAlignment="Top"
TickPlacement="None" TickFrequency="0.05"
Value="{Binding Path=LayerModel.Properties.AnimationSpeed, Mode=TwoWay}" Minimum="0.5" Maximum="5"
SmallChange="0" IsSnapToTickEnabled="True" Margin="10,12,10,2" Height="24" />

View File

@ -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,

View File

@ -0,0 +1,68 @@
<UserControl x:Class="Artemis.Profiles.Layers.Types.Mousemat.MousematPropertiesView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:ncore="http://schemas.ncore.com/wpf/xaml/colorbox"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<!-- Animation -->
<TextBlock Grid.Row="0" Grid.Column="0" Margin="10" FontSize="13.333" Text="Animation:"
VerticalAlignment="Center"
Height="18" />
<ComboBox Grid.Row="0" Grid.Column="1" Margin="10,10,10,0" x:Name="LayerAnimations" VerticalAlignment="Top"
Height="22">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name, Mode=OneWay}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<!-- Animation Speed -->
<TextBlock Grid.Row="0" Grid.Column="2" Margin="10" FontSize="13.333" Text="Animation speed:"
VerticalAlignment="Center" Height="18" />
<Slider x:Name="RotationSpeed" Grid.Row="0" Grid.Column="3" VerticalAlignment="Center"
TickPlacement="None" TickFrequency="0.05"
Value="{Binding Path=LayerModel.Properties.AnimationSpeed, Mode=TwoWay}" Minimum="0.05" Maximum="3"
SmallChange="0" IsSnapToTickEnabled="True" Margin="10,12,10,2" Height="24" />
<!-- Colors -->
<StackPanel Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Orientation="Horizontal" x:Name="ShowBrush">
<TextBlock Margin="10,13,10,0" FontSize="13.333" Text="Color(s):"
VerticalAlignment="Top" Height="18" Width="130" />
<Border Margin="10" BorderBrush="{StaticResource ControlBorderBrush}"
BorderThickness="1" SnapsToDevicePixels="True" ToolTip="Click to edit">
<ncore:ColorBox Brush="{Binding Path=Brush, Mode=TwoWay}" Height="24" Width="134" />
</Border>
</StackPanel>
<!-- Dynamic -->
<Label Grid.Row="3" Grid.Column="0" FontSize="20" HorizontalAlignment="Left"
Content="Dynamic" Width="97" VerticalAlignment="Bottom" />
<!-- Dynamic property views -->
<ContentControl Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="4" x:Name="OpacityProperties" />
<!-- Note -->
<TextBlock Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="4" Margin="10,2,10,10" FontSize="13.333"
Foreground="{DynamicResource HighlightBrush}"
Text="Note: If your mousemat has multiple controllable LEDs you can create a gradient. Artemis will take the colors in the gradient and assign them to the LEDs"
VerticalAlignment="Top" Height="Auto" TextWrapping="Wrap" />
</Grid>
</UserControl>

View File

@ -0,0 +1,15 @@
using System.Windows.Controls;
namespace Artemis.Profiles.Layers.Types.Mousemat
{
/// <summary>
/// Interaction logic for MousematPropertiesView.xaml
/// </summary>
public partial class MousematPropertiesView : UserControl
{
public MousematPropertiesView()
{
InitializeComponent();
}
}
}

View File

@ -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<ILayerAnimation>(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<ILayerAnimation> 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;
}
}
}

View File

@ -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);
}
}
}

View File

@ -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")]
[assembly: AssemblyVersion("1.3.3.0")]
[assembly: AssemblyFileVersion("1.3.3.0")]

View File

@ -60,6 +60,16 @@ namespace Artemis.Properties {
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap audio {
get {
object obj = ResourceManager.GetObject("audio", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
@ -258,6 +268,16 @@ namespace Artemis.Properties {
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap keypress {
get {
object obj = ResourceManager.GetObject("keypress", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
@ -298,6 +318,16 @@ namespace Artemis.Properties {
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap mousemat {
get {
object obj = ResourceManager.GetObject("mousemat", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>

View File

@ -199,4 +199,13 @@
<data name="ets2_telemetry_server_x86" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Modules\Games\EurotruckSimulator2\Resources\Win32\ets2-telemetry-server.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="mousemat" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\mousemat.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="keypress" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\keypress.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="audio" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\audio.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -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;
}

View File

@ -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()

View File

@ -31,6 +31,7 @@ namespace Artemis.ViewModels.Profiles
{
Layer = layer;
ProposedLayer = Clone(layer);
ProposedLayer.Children.Clear();
DataModel = DataModel;
LayerTypes = new BindableCollection<ILayerType>(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);

View File

@ -7,29 +7,18 @@
d:DesignHeight="476.986" d:DesignWidth="538.772">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<Grid Margin="15, 5, 15, 5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" FontSize="20" MaxWidth="500"
HorizontalAlignment="Left">
<Label Grid.Row="0" FontSize="20" MaxWidth="500" HorizontalAlignment="Left">
<Label.Content>
<AccessText TextWrapping="Wrap" Text="Welcome to Artemis" />
</Label.Content>
</Label>
<TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" VerticalAlignment="Center" Margin="0,8"
TextWrapping="Wrap" HorizontalAlignment="Left"
MaxWidth="520" TextAlignment="Justify">
<TextBlock Grid.Row="1" VerticalAlignment="Center" Margin="0,8" TextWrapping="Wrap"
HorizontalAlignment="Left" MaxWidth="520" TextAlignment="Justify">
Hello, <LineBreak /><LineBreak />
Thanks a bunch for downloading this application. You're going to enjoy this! :)<LineBreak />
<LineBreak />

View File

@ -23,6 +23,7 @@
<package id="Ninject.Extensions.Logging.nlog4" version="3.2.3.0" targetFramework="net452" />
<package id="NLog" version="4.3.7" targetFramework="net461" />
<package id="NLog.Schema" version="4.3.7" targetFramework="net461" />
<package id="Process.NET" version="1.0.1" targetFramework="net461" />
<package id="Splat" version="1.6.2" targetFramework="net461" />
<package id="SpotifyAPI-NET" version="2.11.0" targetFramework="net461" />
<package id="squirrel.windows" version="1.4.4" targetFramework="net461" />