mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Add support for multiple processes per module
Add ATS support
This commit is contained in:
parent
d7bf26a738
commit
07f7ae263d
@ -1,271 +1,271 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.DeviceProviders;
|
||||
using Artemis.ViewModels;
|
||||
using Ninject.Extensions.Logging;
|
||||
using Color = System.Drawing.Color;
|
||||
|
||||
namespace Artemis.Managers
|
||||
{
|
||||
/// <summary>
|
||||
/// Manages the main programn loop
|
||||
/// </summary>
|
||||
public class LoopManager : IDisposable
|
||||
{
|
||||
private readonly DebugViewModel _debugViewModel;
|
||||
private readonly DeviceManager _deviceManager;
|
||||
private readonly ILogger _logger;
|
||||
//private readonly Timer _loopTimer;
|
||||
private readonly Task _loopTask;
|
||||
private readonly ModuleManager _moduleManager;
|
||||
|
||||
public LoopManager(ILogger logger, ModuleManager moduleManager, DeviceManager deviceManager,
|
||||
DebugViewModel debugViewModel)
|
||||
{
|
||||
_logger = logger;
|
||||
_moduleManager = moduleManager;
|
||||
_deviceManager = deviceManager;
|
||||
_debugViewModel = debugViewModel;
|
||||
|
||||
// Setup timers
|
||||
_loopTask = Task.Factory.StartNew(ProcessLoop);
|
||||
_logger.Info("Intialized LoopManager");
|
||||
}
|
||||
|
||||
public DebugViewModel DebugViewModel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the loop is running
|
||||
/// </summary>
|
||||
public bool Running { get; private set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_loopTask.Dispose();
|
||||
}
|
||||
|
||||
private void ProcessLoop()
|
||||
{
|
||||
//TODO DarthAffe 14.01.2017: A stop-condition and a real cleanup instead of just aborting might be better
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
long preUpdateTicks = DateTime.Now.Ticks;
|
||||
|
||||
Render();
|
||||
|
||||
int sleep = (int)(40f - ((DateTime.Now.Ticks - preUpdateTicks) / 10000f));
|
||||
if (sleep > 0)
|
||||
Thread.Sleep(sleep);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Warn(e, "Exception in render loop");
|
||||
}
|
||||
}
|
||||
// ReSharper disable once FunctionNeverReturns
|
||||
}
|
||||
|
||||
public Task StartAsync()
|
||||
{
|
||||
return Task.Run(() => Start());
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (Running)
|
||||
return;
|
||||
|
||||
_logger.Debug("Starting LoopManager");
|
||||
|
||||
if (_deviceManager.ActiveKeyboard == null)
|
||||
_deviceManager.EnableLastKeyboard();
|
||||
|
||||
while (_deviceManager.ChangingKeyboard)
|
||||
Thread.Sleep(200);
|
||||
|
||||
// If still null, no last keyboard, so stop.
|
||||
if (_deviceManager.ActiveKeyboard == null)
|
||||
{
|
||||
_logger.Debug("Cancel LoopManager start, no keyboard");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_moduleManager.ActiveModule == null)
|
||||
{
|
||||
var lastModule = _moduleManager.GetLastModule();
|
||||
if (lastModule == null)
|
||||
{
|
||||
_logger.Debug("Cancel LoopManager start, no module");
|
||||
return;
|
||||
}
|
||||
_moduleManager.ChangeActiveModule(lastModule);
|
||||
}
|
||||
|
||||
Running = true;
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (!Running)
|
||||
return;
|
||||
|
||||
_logger.Debug("Stopping LoopManager");
|
||||
Running = false;
|
||||
|
||||
_deviceManager.ReleaseActiveKeyboard();
|
||||
}
|
||||
|
||||
private void Render()
|
||||
{
|
||||
if (!Running || _deviceManager.ChangingKeyboard)
|
||||
return;
|
||||
|
||||
// Stop if no active module
|
||||
if (_moduleManager.ActiveModule == null)
|
||||
{
|
||||
_logger.Debug("No active module, stopping");
|
||||
Stop();
|
||||
return;
|
||||
}
|
||||
var renderModule = _moduleManager.ActiveModule;
|
||||
|
||||
// Stop if no active keyboard
|
||||
if (_deviceManager.ActiveKeyboard == null)
|
||||
{
|
||||
_logger.Debug("No active keyboard, stopping");
|
||||
Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_deviceManager.ActiveKeyboard)
|
||||
{
|
||||
// Skip frame if module is still initializing
|
||||
if (renderModule.IsInitialized == false)
|
||||
return;
|
||||
|
||||
// ApplyProperties the current module
|
||||
if (renderModule.IsInitialized)
|
||||
renderModule.Update();
|
||||
|
||||
// Get the devices that must be rendered to
|
||||
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, mice.Any(), headsets.Any(), generics.Any(), mousemats.Any()))
|
||||
{
|
||||
if (renderModule.IsInitialized)
|
||||
renderModule.Render(frame, keyboardOnly);
|
||||
|
||||
// Draw enabled overlays on top of the renderModule
|
||||
foreach (var overlayModel in _moduleManager.OverlayModules.Where(o => o.Settings.IsEnabled))
|
||||
{
|
||||
overlayModel.Update();
|
||||
overlayModel.Render(frame, keyboardOnly);
|
||||
}
|
||||
|
||||
// Update the keyboard
|
||||
_deviceManager.ActiveKeyboard?.DrawBitmap(frame.KeyboardBitmap);
|
||||
|
||||
// Update the other devices
|
||||
foreach (var mouse in mice)
|
||||
mouse.UpdateDevice(frame.MouseBitmap);
|
||||
foreach (var headset in headsets)
|
||||
headset.UpdateDevice(frame.HeadsetBitmap);
|
||||
foreach (var generic in generics)
|
||||
generic.UpdateDevice(frame.GenericBitmap);
|
||||
foreach (var mousemat in mousemats)
|
||||
mousemat.UpdateDevice(frame.MousematBitmap);
|
||||
|
||||
_debugViewModel.DrawFrame(frame);
|
||||
|
||||
OnRenderCompleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler RenderCompleted;
|
||||
|
||||
protected virtual void OnRenderCompleted()
|
||||
{
|
||||
RenderCompleted?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
public class RenderFrame : IDisposable
|
||||
{
|
||||
public RenderFrame(KeyboardProvider keyboard, bool renderMice, bool renderHeadsets, bool renderGenerics, bool renderMousemats)
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.DeviceProviders;
|
||||
using Artemis.ViewModels;
|
||||
using Ninject.Extensions.Logging;
|
||||
using Color = System.Drawing.Color;
|
||||
|
||||
namespace Artemis.Managers
|
||||
{
|
||||
/// <summary>
|
||||
/// Manages the main programn loop
|
||||
/// </summary>
|
||||
public class LoopManager : IDisposable
|
||||
{
|
||||
private readonly DebugViewModel _debugViewModel;
|
||||
private readonly DeviceManager _deviceManager;
|
||||
private readonly ILogger _logger;
|
||||
//private readonly Timer _loopTimer;
|
||||
private readonly Task _loopTask;
|
||||
private readonly ModuleManager _moduleManager;
|
||||
|
||||
public LoopManager(ILogger logger, ModuleManager moduleManager, DeviceManager deviceManager,
|
||||
DebugViewModel debugViewModel)
|
||||
{
|
||||
if (keyboard == null)
|
||||
return;
|
||||
|
||||
KeyboardBitmap = keyboard.KeyboardBitmap();
|
||||
_logger = logger;
|
||||
_moduleManager = moduleManager;
|
||||
_deviceManager = deviceManager;
|
||||
_debugViewModel = debugViewModel;
|
||||
|
||||
// Setup timers
|
||||
_loopTask = Task.Factory.StartNew(ProcessLoop);
|
||||
_logger.Info("Intialized LoopManager");
|
||||
}
|
||||
|
||||
public DebugViewModel DebugViewModel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the loop is running
|
||||
/// </summary>
|
||||
public bool Running { get; private set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_loopTask.Dispose();
|
||||
}
|
||||
|
||||
private void ProcessLoop()
|
||||
{
|
||||
//TODO DarthAffe 14.01.2017: A stop-condition and a real cleanup instead of just aborting might be better
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
long preUpdateTicks = DateTime.Now.Ticks;
|
||||
|
||||
Render();
|
||||
|
||||
int sleep = (int)(40f - ((DateTime.Now.Ticks - preUpdateTicks) / 10000f));
|
||||
if (sleep > 0)
|
||||
Thread.Sleep(sleep);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Warn(e, "Exception in render loop");
|
||||
}
|
||||
}
|
||||
// ReSharper disable once FunctionNeverReturns
|
||||
}
|
||||
|
||||
public Task StartAsync()
|
||||
{
|
||||
return Task.Run(() => Start());
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (Running)
|
||||
return;
|
||||
|
||||
_logger.Debug("Starting LoopManager");
|
||||
|
||||
if (_deviceManager.ActiveKeyboard == null)
|
||||
_deviceManager.EnableLastKeyboard();
|
||||
|
||||
while (_deviceManager.ChangingKeyboard)
|
||||
Thread.Sleep(200);
|
||||
|
||||
// If still null, no last keyboard, so stop.
|
||||
if (_deviceManager.ActiveKeyboard == null)
|
||||
{
|
||||
_logger.Debug("Cancel LoopManager start, no keyboard");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_moduleManager.ActiveModule == null)
|
||||
{
|
||||
var lastModule = _moduleManager.GetLastModule();
|
||||
if (lastModule == null)
|
||||
{
|
||||
_logger.Debug("Cancel LoopManager start, no module");
|
||||
return;
|
||||
}
|
||||
_moduleManager.ChangeActiveModule(lastModule);
|
||||
}
|
||||
|
||||
Running = true;
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (!Running)
|
||||
return;
|
||||
|
||||
_logger.Debug("Stopping LoopManager");
|
||||
Running = false;
|
||||
|
||||
_deviceManager.ReleaseActiveKeyboard();
|
||||
}
|
||||
|
||||
private void Render()
|
||||
{
|
||||
if (!Running || _deviceManager.ChangingKeyboard)
|
||||
return;
|
||||
|
||||
// Stop if no active module
|
||||
if (_moduleManager.ActiveModule == null)
|
||||
{
|
||||
_logger.Debug("No active module, stopping");
|
||||
Stop();
|
||||
return;
|
||||
}
|
||||
var renderModule = _moduleManager.ActiveModule;
|
||||
|
||||
// Stop if no active keyboard
|
||||
if (_deviceManager.ActiveKeyboard == null)
|
||||
{
|
||||
_logger.Debug("No active keyboard, stopping");
|
||||
Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_deviceManager.ActiveKeyboard)
|
||||
{
|
||||
// Skip frame if module is still initializing
|
||||
if (renderModule.IsInitialized == false)
|
||||
return;
|
||||
|
||||
// ApplyProperties the current module
|
||||
if (renderModule.IsInitialized)
|
||||
renderModule.Update();
|
||||
|
||||
// Get the devices that must be rendered to
|
||||
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, mice.Any(), headsets.Any(), generics.Any(), mousemats.Any()))
|
||||
{
|
||||
if (renderModule.IsInitialized)
|
||||
renderModule.Render(frame, keyboardOnly);
|
||||
|
||||
// Draw enabled overlays on top of the renderModule
|
||||
foreach (var overlayModel in _moduleManager.OverlayModules.Where(o => o.Settings.IsEnabled))
|
||||
{
|
||||
overlayModel.Update();
|
||||
overlayModel.Render(frame, keyboardOnly);
|
||||
}
|
||||
|
||||
// Update the keyboard
|
||||
_deviceManager.ActiveKeyboard?.DrawBitmap(frame.KeyboardBitmap);
|
||||
|
||||
// Update the other devices
|
||||
foreach (var mouse in mice)
|
||||
mouse.UpdateDevice(frame.MouseBitmap);
|
||||
foreach (var headset in headsets)
|
||||
headset.UpdateDevice(frame.HeadsetBitmap);
|
||||
foreach (var generic in generics)
|
||||
generic.UpdateDevice(frame.GenericBitmap);
|
||||
foreach (var mousemat in mousemats)
|
||||
mousemat.UpdateDevice(frame.MousematBitmap);
|
||||
|
||||
_debugViewModel.DrawFrame(frame);
|
||||
|
||||
OnRenderCompleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler RenderCompleted;
|
||||
|
||||
protected virtual void OnRenderCompleted()
|
||||
{
|
||||
RenderCompleted?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
public class RenderFrame : IDisposable
|
||||
{
|
||||
public RenderFrame(KeyboardProvider keyboard, bool renderMice, bool renderHeadsets, bool renderGenerics, bool renderMousemats)
|
||||
{
|
||||
if (keyboard == null)
|
||||
return;
|
||||
|
||||
KeyboardBitmap = keyboard.KeyboardBitmap();
|
||||
KeyboardBitmap.SetResolution(96, 96);
|
||||
using (var g = Graphics.FromImage(KeyboardBitmap))
|
||||
{
|
||||
g.Clear(Color.Black);
|
||||
}
|
||||
|
||||
if (renderMice)
|
||||
{
|
||||
MouseBitmap = new Bitmap(10, 10);
|
||||
MouseBitmap.SetResolution(96, 96);
|
||||
using (var g = Graphics.FromImage(MouseBitmap))
|
||||
{
|
||||
g.Clear(Color.Black);
|
||||
}
|
||||
}
|
||||
if (renderHeadsets)
|
||||
{
|
||||
HeadsetBitmap = new Bitmap(10, 10);
|
||||
HeadsetBitmap.SetResolution(96, 96);
|
||||
using (var g = Graphics.FromImage(HeadsetBitmap))
|
||||
{
|
||||
g.Clear(Color.Black);
|
||||
}
|
||||
}
|
||||
if (renderGenerics)
|
||||
{
|
||||
GenericBitmap = new Bitmap(10, 10);
|
||||
GenericBitmap.SetResolution(96, 96);
|
||||
using (var g = Graphics.FromImage(GenericBitmap))
|
||||
{
|
||||
g.Clear(Color.Black);
|
||||
}
|
||||
}
|
||||
if (renderMousemats)
|
||||
{
|
||||
MousematBitmap = new Bitmap(10, 10);
|
||||
MousematBitmap.SetResolution(96, 96);
|
||||
using (var g = Graphics.FromImage(KeyboardBitmap))
|
||||
{
|
||||
g.Clear(Color.Black);
|
||||
}
|
||||
|
||||
if (renderMice)
|
||||
{
|
||||
MouseBitmap = new Bitmap(10, 10);
|
||||
MouseBitmap.SetResolution(96, 96);
|
||||
using (var g = Graphics.FromImage(MouseBitmap))
|
||||
{
|
||||
g.Clear(Color.Black);
|
||||
}
|
||||
}
|
||||
if (renderHeadsets)
|
||||
{
|
||||
HeadsetBitmap = new Bitmap(10, 10);
|
||||
HeadsetBitmap.SetResolution(96, 96);
|
||||
using (var g = Graphics.FromImage(HeadsetBitmap))
|
||||
{
|
||||
g.Clear(Color.Black);
|
||||
}
|
||||
}
|
||||
if (renderGenerics)
|
||||
{
|
||||
GenericBitmap = new Bitmap(10, 10);
|
||||
GenericBitmap.SetResolution(96, 96);
|
||||
using (var g = Graphics.FromImage(GenericBitmap))
|
||||
{
|
||||
g.Clear(Color.Black);
|
||||
}
|
||||
}
|
||||
if (renderMousemats)
|
||||
{
|
||||
MousematBitmap = new Bitmap(10, 10);
|
||||
MousematBitmap.SetResolution(96, 96);
|
||||
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()
|
||||
{
|
||||
KeyboardBitmap?.Dispose();
|
||||
MouseBitmap?.Dispose();
|
||||
HeadsetBitmap?.Dispose();
|
||||
GenericBitmap?.Dispose();
|
||||
MousematBitmap?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
KeyboardBitmap?.Dispose();
|
||||
MouseBitmap?.Dispose();
|
||||
HeadsetBitmap?.Dispose();
|
||||
GenericBitmap?.Dispose();
|
||||
MousematBitmap?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -144,7 +144,7 @@ namespace Artemis.Managers
|
||||
if (!ProgramEnabled)
|
||||
return;
|
||||
|
||||
var processes = System.Diagnostics.Process.GetProcesses();
|
||||
var processes = System.Diagnostics.Process.GetProcesses().Where(p => !p.HasExited).ToList();
|
||||
var module = ModuleManager.ActiveModule;
|
||||
|
||||
// If the current active module is in preview-mode, leave it alone
|
||||
@ -158,7 +158,7 @@ namespace Artemis.Managers
|
||||
ModuleManager.DisableProcessBoundModule();
|
||||
|
||||
// If the currently active effect is a no longer running game, get rid of it.
|
||||
if (!processes.Any(p => p.ProcessName == module.ProcessName && p.HasExited == false))
|
||||
if (!processes.Any(p => module.ProcessNames.Contains(p.ProcessName)))
|
||||
{
|
||||
Logger.Info("Disabling process bound module because process stopped: {0}", module.Name);
|
||||
ModuleManager.DisableProcessBoundModule();
|
||||
@ -167,7 +167,7 @@ namespace Artemis.Managers
|
||||
|
||||
// Look for running games, stopping on the first one that's found.
|
||||
var newModule = ModuleManager.ProcessModules.Where(g => g.Settings.IsEnabled && g.Settings.IsEnabled)
|
||||
.FirstOrDefault(g => processes.Any(p => p.ProcessName == g.ProcessName && p.HasExited == false));
|
||||
.FirstOrDefault(g => processes.Any(p => g.ProcessNames.Contains(p.ProcessName)));
|
||||
|
||||
if (newModule == null || module == newModule)
|
||||
return;
|
||||
|
||||
@ -79,9 +79,9 @@ namespace Artemis.Modules.Abstract
|
||||
public List<LayerModel> PreviewLayers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The process the module is bound to
|
||||
/// The processes the module is bound to
|
||||
/// </summary>
|
||||
public string ProcessName { get; protected set; }
|
||||
public List<string> ProcessNames { get; protected set; } = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// The currently active profile of the module
|
||||
|
||||
@ -28,7 +28,7 @@ namespace Artemis.Modules.Games.CounterStrike
|
||||
|
||||
Settings = SettingsProvider.Load<CounterStrikeSettings>();
|
||||
DataModel = new CounterStrikeDataModel();
|
||||
ProcessName = "csgo";
|
||||
ProcessNames.Add("csgo");
|
||||
|
||||
FindGameDir();
|
||||
PlaceConfigFile();
|
||||
|
||||
@ -48,7 +48,7 @@
|
||||
cal:Message.Attach="[Event LostFocus] = [Action PlaceConfigFile]" />
|
||||
<Button x:Name="BrowseDirectory" Content="..." RenderTransformOrigin="-0.039,-0.944"
|
||||
HorizontalAlignment="Right" Width="25"
|
||||
Style="{DynamicResource SquareButtonStyle}" Height="26" Margin="0,-2,0,0" />
|
||||
Style="{DynamicResource SquareButtonStyle}" Height="26" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@ namespace Artemis.Modules.Games.Dota2
|
||||
|
||||
Settings = SettingsProvider.Load<Dota2Settings>();
|
||||
DataModel = new Dota2DataModel();
|
||||
ProcessName = "dota2";
|
||||
ProcessNames.Add("dota2");
|
||||
|
||||
FindGameDir();
|
||||
PlaceConfigFile();
|
||||
|
||||
@ -47,7 +47,7 @@
|
||||
cal:Message.Attach="[Event LostFocus] = [Action PlaceConfigFile]" />
|
||||
<Button x:Name="BrowseDirectory" Content="..." RenderTransformOrigin="-0.039,-0.944"
|
||||
HorizontalAlignment="Right" Width="25"
|
||||
Style="{DynamicResource SquareButtonStyle}" Height="26" Margin="0,-2,0,0" />
|
||||
Style="{DynamicResource SquareButtonStyle}" Height="26" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
|
||||
|
||||
@ -22,9 +22,11 @@ namespace Artemis.Modules.Games.EurotruckSimulator2
|
||||
|
||||
Settings = SettingsProvider.Load<EurotruckSimulator2Settings>();
|
||||
DataModel = new EurotruckSimulator2DataModel();
|
||||
ProcessName = "eurotrucks2";
|
||||
ProcessNames.Add("eurotrucks2");
|
||||
ProcessNames.Add("amtrucks");
|
||||
|
||||
FindGameDir();
|
||||
FindEts2GameDir();
|
||||
FindAtsGameDir();
|
||||
}
|
||||
|
||||
public override string Name => "EurotruckSimulator2";
|
||||
@ -43,7 +45,7 @@ namespace Artemis.Modules.Games.EurotruckSimulator2
|
||||
dataModel.Truck = telemetryData.Truck;
|
||||
}
|
||||
|
||||
public void FindGameDir()
|
||||
public void FindEts2GameDir()
|
||||
{
|
||||
// Demo is also supported but resides in a different directory, the full game can also be 64-bits
|
||||
var dir = GeneralHelpers.FindSteamGame(@"\Euro Truck Simulator 2\bin\win_x64\eurotrucks2.exe") ??
|
||||
@ -53,31 +55,58 @@ namespace Artemis.Modules.Games.EurotruckSimulator2
|
||||
if (string.IsNullOrEmpty(dir))
|
||||
return;
|
||||
|
||||
((EurotruckSimulator2Settings) Settings).GameDirectory = dir;
|
||||
((EurotruckSimulator2Settings) Settings).Ets2GameDirectory = dir;
|
||||
Settings.Save();
|
||||
|
||||
if (!File.Exists(dir + "/plugins/ets2-telemetry-server.dll"))
|
||||
PlacePlugin();
|
||||
PlacePlugins();
|
||||
}
|
||||
|
||||
public void PlacePlugin()
|
||||
public void FindAtsGameDir()
|
||||
{
|
||||
if (((EurotruckSimulator2Settings) Settings).GameDirectory == string.Empty)
|
||||
// Demo is also supported but resides in a different directory, the full game can also be 64-bits
|
||||
var dir = GeneralHelpers.FindSteamGame(@"\American Truck Simulator\bin\win_x64\amtrucks.exe") ??
|
||||
GeneralHelpers.FindSteamGame(@"\American Truck Simulator\bin\win_x86\amtrucks.exe") ??
|
||||
GeneralHelpers.FindSteamGame(@"\American Truck Simulator Demo\bin\win_x86\amtrucks.exe");
|
||||
|
||||
if (string.IsNullOrEmpty(dir))
|
||||
return;
|
||||
|
||||
var path = ((EurotruckSimulator2Settings) Settings).GameDirectory;
|
||||
((EurotruckSimulator2Settings) Settings).AtsGameDirectory = dir;
|
||||
Settings.Save();
|
||||
|
||||
if (!File.Exists(dir + "/plugins/ets2-telemetry-server.dll"))
|
||||
PlacePlugins();
|
||||
}
|
||||
|
||||
public void PlacePlugins()
|
||||
{
|
||||
var ets2Path = ((EurotruckSimulator2Settings) Settings).Ets2GameDirectory;
|
||||
if (!string.IsNullOrEmpty(ets2Path))
|
||||
PlaceTruckSimulatorPlugin(ets2Path, "eurotrucks2.exe");
|
||||
|
||||
var atsPath = ((EurotruckSimulator2Settings) Settings).AtsGameDirectory;
|
||||
if (!string.IsNullOrEmpty(atsPath))
|
||||
PlaceTruckSimulatorPlugin(atsPath, "amtrucks.exe");
|
||||
}
|
||||
|
||||
private void PlaceTruckSimulatorPlugin(string path, string game)
|
||||
{
|
||||
// Ensure the selected directory exists
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
_dialogService.ShowErrorMessageBox($"Directory '{path}' not found.");
|
||||
return;
|
||||
}
|
||||
// Ensure it's the ETS2 directory by looking for the executable
|
||||
if (!File.Exists(path + "/eurotrucks2.exe"))
|
||||
// Ensure it's the proper directory by looking for the executable
|
||||
if (!File.Exists(path + "/" + game))
|
||||
{
|
||||
_dialogService.ShowErrorMessageBox("Please select a valid Eurotruck Simulator 2 directory\n\n" +
|
||||
@"By default ETS2 is in \SteamApps\common\Euro Truck Simulator 2\bin\win_x64");
|
||||
if (game == "eurotrucks2.exe")
|
||||
_dialogService.ShowErrorMessageBox("Please select a valid Eurotruck Simulator 2 directory\n\n" +
|
||||
@"By default ETS2 is in \SteamApps\common\Euro Truck Simulator 2\bin\win_x64");
|
||||
else
|
||||
_dialogService.ShowErrorMessageBox("Please select a valid American Truck Simulator directory\n\n" +
|
||||
@"By default ATS is in \SteamApps\common\American Truck Simulator\bin\win_x64");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -92,11 +121,11 @@ namespace Artemis.Modules.Games.EurotruckSimulator2
|
||||
else
|
||||
File.WriteAllBytes(path + "/plugins/ets2-telemetry-server.dll", Resources.ets2_telemetry_server_x86);
|
||||
|
||||
Logger?.Debug("Installed ETS2 plugin in {0}", path);
|
||||
Logger?.Debug("Installed Truck Simulator plugin in {0}", path);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger?.Error(e, "Failed to install ETS2 plugin in {0}", path);
|
||||
Logger?.Error(e, "Failed to install Truck Simulator plugin in {0}", path);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ namespace Artemis.Modules.Games.EurotruckSimulator2
|
||||
{
|
||||
public class EurotruckSimulator2Settings : ModuleSettings
|
||||
{
|
||||
public string GameDirectory { get; set; }
|
||||
public string Ets2GameDirectory { get; set; }
|
||||
public string AtsGameDirectory { get; set; }
|
||||
}
|
||||
}
|
||||
@ -17,6 +17,7 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
@ -39,7 +40,7 @@
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Bottom"
|
||||
TextWrapping="Wrap" HorizontalAlignment="Left" FontFamily="Segoe UI Semibold"
|
||||
TextAlignment="Justify" Margin="5,0,0,10">
|
||||
The Euro Truck Simulator 2 module uses code from the
|
||||
The Truck Simulator module uses code from the
|
||||
<Hyperlink RequestNavigate="Hyperlink_RequestNavigate"
|
||||
NavigateUri="https://github.com/Funbit/ets2-telemetry-server">
|
||||
ETS2 Telemetry Web Server
|
||||
@ -56,26 +57,41 @@
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<StackPanel Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2" Margin="0,0,1,0">
|
||||
|
||||
<Label FontSize="20" HorizontalAlignment="Left" Content="Euro Truck Simulator 2 directory" />
|
||||
<Grid>
|
||||
<TextBox x:Name="GameDirectory" Height="23" TextWrapping="Wrap" Margin="5,0,30,0"
|
||||
Text="{Binding Path=Settings.GameDirectory, Mode=TwoWay}"
|
||||
cal:Message.Attach="[Event LostFocus] = [Action PlacePlugin]" />
|
||||
<Button x:Name="BrowseDirectory" Content="..." RenderTransformOrigin="-0.039,-0.944"
|
||||
HorizontalAlignment="Right" Width="25"
|
||||
Style="{DynamicResource SquareButtonStyle}" Height="26" Margin="0,-2,0,0" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
|
||||
<Grid Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2">
|
||||
<!-- ETS2 dir -->
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Margin="0,0,1,0" Grid.Column="0">
|
||||
<Label FontSize="16" HorizontalAlignment="Left" Content="Euro Truck Simulator 2 directory" />
|
||||
<Grid>
|
||||
<TextBox x:Name="Ets2GameDirectory" Height="23" TextWrapping="Wrap" Margin="5,0,30,0"
|
||||
Text="{Binding Path=Settings.Ets2GameDirectory, Mode=TwoWay}"
|
||||
cal:Message.Attach="[Event LostFocus] = [Action PlacePlugins]" />
|
||||
<Button x:Name="Ets2BrowseDirectory" Content="..." RenderTransformOrigin="-0.039,-0.944"
|
||||
HorizontalAlignment="Right" Width="25"
|
||||
Style="{DynamicResource SquareButtonStyle}" Height="26" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
<!-- ATS dir -->
|
||||
<StackPanel Margin="0,0,1,0" Grid.Column="1">
|
||||
<Label FontSize="16" HorizontalAlignment="Left" Content="American Truck Simulator directory" />
|
||||
<Grid>
|
||||
<TextBox x:Name="AtsGameDirectory" Height="23" TextWrapping="Wrap" Margin="5,0,30,0"
|
||||
Text="{Binding Path=Settings.AtsGameDirectory, Mode=TwoWay}"
|
||||
cal:Message.Attach="[Event LostFocus] = [Action PlacePlugins]" />
|
||||
<Button x:Name="AtsBrowseDirectory" Content="..." RenderTransformOrigin="-0.039,-0.944"
|
||||
HorizontalAlignment="Right" Width="25"
|
||||
Style="{DynamicResource SquareButtonStyle}" Height="26" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<!-- Profile editor -->
|
||||
<ContentControl Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" x:Name="ProfileEditor" Margin="0,0,-20,0" />
|
||||
<ContentControl Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="2" x:Name="ProfileEditor" Margin="0,0,-20,0" />
|
||||
|
||||
<!-- Buttons -->
|
||||
<StackPanel Grid.Column="0" Grid.Row="4" Orientation="Horizontal" VerticalAlignment="Bottom">
|
||||
<StackPanel Grid.Column="0" Grid.Row="5" 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"
|
||||
|
||||
@ -12,24 +12,44 @@ namespace Artemis.Modules.Games.EurotruckSimulator2
|
||||
[Named(nameof(EurotruckSimulator2Model))] ModuleModel moduleModel,
|
||||
IKernel kernel) : base(mainManager, moduleModel, kernel)
|
||||
{
|
||||
DisplayName = "ETS 2";
|
||||
DisplayName = "Truck Simulator";
|
||||
}
|
||||
|
||||
public override bool UsesProfileEditor => true;
|
||||
public new EurotruckSimulator2Settings Settings { get; set; }
|
||||
|
||||
public void BrowseDirectory()
|
||||
public void PlacePlugins()
|
||||
{
|
||||
var dialog = new FolderBrowserDialog {SelectedPath = Settings.GameDirectory};
|
||||
((EurotruckSimulator2Model) ModuleModel).PlacePlugins();
|
||||
}
|
||||
|
||||
public void Ets2BrowseDirectory()
|
||||
{
|
||||
var settings = (EurotruckSimulator2Settings) Settings;
|
||||
var dialog = new FolderBrowserDialog {SelectedPath = settings.Ets2GameDirectory};
|
||||
var result = dialog.ShowDialog();
|
||||
if (result != DialogResult.OK)
|
||||
return;
|
||||
|
||||
Settings.GameDirectory = Path.GetDirectoryName(dialog.SelectedPath);
|
||||
settings.Ets2GameDirectory = Path.GetDirectoryName(dialog.SelectedPath);
|
||||
NotifyOfPropertyChange(() => Settings);
|
||||
Settings.Save();
|
||||
|
||||
((EurotruckSimulator2Model) ModuleModel).PlacePlugin();
|
||||
((EurotruckSimulator2Model) ModuleModel).PlacePlugins();
|
||||
}
|
||||
|
||||
public void AtsBrowseDirectory()
|
||||
{
|
||||
var settings = (EurotruckSimulator2Settings) Settings;
|
||||
var dialog = new FolderBrowserDialog {SelectedPath = settings.AtsGameDirectory};
|
||||
var result = dialog.ShowDialog();
|
||||
if (result != DialogResult.OK)
|
||||
return;
|
||||
|
||||
settings.AtsGameDirectory = Path.GetDirectoryName(dialog.SelectedPath);
|
||||
NotifyOfPropertyChange(() => Settings);
|
||||
Settings.Save();
|
||||
|
||||
((EurotruckSimulator2Model) ModuleModel).PlacePlugins();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -20,7 +20,7 @@ namespace Artemis.Modules.Games.GtaV
|
||||
|
||||
Settings = SettingsProvider.Load<GtaVSettings>();
|
||||
DataModel = new GtaVDataModel();
|
||||
ProcessName = "GTA5";
|
||||
ProcessNames.Add("GTA5");
|
||||
}
|
||||
|
||||
public override string Name => "GTAV";
|
||||
|
||||
@ -15,7 +15,7 @@ namespace Artemis.Modules.Games.LightFx
|
||||
{
|
||||
Settings = SettingsProvider.Load<LightFxSettings>();
|
||||
DataModel = new LightFxDataModel();
|
||||
ProcessName = "LoL";
|
||||
ProcessNames.Add("LoL");
|
||||
|
||||
// This model can enable itself by changing its process name to the currently running Light FX game.
|
||||
pipeServer.PipeMessage += PipeServerOnPipeMessage;
|
||||
@ -43,7 +43,9 @@ namespace Artemis.Modules.Games.LightFx
|
||||
}
|
||||
|
||||
// Setup process name
|
||||
ProcessName = Path.GetFileNameWithoutExtension(((LightFxDataModel) DataModel).LightFxState.game);
|
||||
var processName = Path.GetFileNameWithoutExtension(((LightFxDataModel) DataModel).LightFxState.game);
|
||||
if (!ProcessNames.Contains(processName))
|
||||
ProcessNames.Add(processName);
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
|
||||
@ -38,7 +38,7 @@ namespace Artemis.Modules.Games.Overwatch
|
||||
|
||||
Settings = SettingsProvider.Load<OverwatchSettings>();
|
||||
DataModel = new OverwatchDataModel();
|
||||
ProcessName = "Overwatch";
|
||||
ProcessNames.Add("Overwatch");
|
||||
|
||||
LoadOverwatchCharacters();
|
||||
FindOverwatch();
|
||||
|
||||
@ -66,7 +66,7 @@
|
||||
cal:Message.Attach="[Event LostFocus] = [Action PlaceDll]" />
|
||||
<Button x:Name="BrowseDirectory" Content="..." RenderTransformOrigin="-0.039,-0.944"
|
||||
HorizontalAlignment="Right" Width="25"
|
||||
Style="{DynamicResource SquareButtonStyle}" Height="26" Margin="0,-2,0,0" />
|
||||
Style="{DynamicResource SquareButtonStyle}" Height="26" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ namespace Artemis.Modules.Games.ProjectCars
|
||||
{
|
||||
Settings = SettingsProvider.Load<ProjectCarsSettings>();
|
||||
DataModel = new ProjectCarsDataModel();
|
||||
ProcessName = "pCARS64";
|
||||
ProcessNames.Add("pCARS64");
|
||||
}
|
||||
|
||||
public override string Name => "ProjectCars";
|
||||
|
||||
@ -18,7 +18,7 @@ namespace Artemis.Modules.Games.RocketLeague
|
||||
{
|
||||
Settings = SettingsProvider.Load<RocketLeagueSettings>();
|
||||
DataModel = new RocketLeagueDataModel();
|
||||
ProcessName = "RocketLeague";
|
||||
ProcessNames.Add("RocketLeague");
|
||||
|
||||
// Generate a new offset when the game is updated
|
||||
//var offset = new GamePointersCollection
|
||||
@ -62,7 +62,7 @@ namespace Artemis.Modules.Games.RocketLeague
|
||||
{
|
||||
if (_memory == null)
|
||||
{
|
||||
var tempProcess = MemoryHelpers.GetProcessIfRunning(ProcessName);
|
||||
var tempProcess = MemoryHelpers.GetProcessIfRunning(ProcessNames[0]);
|
||||
if (tempProcess == null)
|
||||
return;
|
||||
|
||||
|
||||
@ -32,8 +32,6 @@ namespace Artemis.Modules.Games.RocketLeague
|
||||
}
|
||||
}
|
||||
|
||||
public RocketLeagueModel RocketLeagueModel { get; set; }
|
||||
|
||||
private void SetVersionText()
|
||||
{
|
||||
if (!SettingsProvider.Load<GeneralSettings>().EnablePointersUpdate)
|
||||
|
||||
@ -22,7 +22,7 @@ namespace Artemis.Modules.Games.TheDivision
|
||||
|
||||
Settings = SettingsProvider.Load<TheDivisionSettings>();
|
||||
DataModel = new TheDivisionDataModel();
|
||||
ProcessName = "TheDivision";
|
||||
ProcessNames.Add("TheDivision");
|
||||
}
|
||||
|
||||
public override string Name => "TheDivision";
|
||||
|
||||
@ -30,7 +30,7 @@ namespace Artemis.Modules.Games.UnrealTournament
|
||||
|
||||
Settings = SettingsProvider.Load<UnrealTournamentSettings>();
|
||||
DataModel = new UnrealTournamentDataModel();
|
||||
ProcessName = "UE4-Win64-Shipping";
|
||||
ProcessNames.Add("UE4-Win64-Shipping");
|
||||
|
||||
_killTimer = new Timer(3500);
|
||||
_killTimer.Elapsed += KillTimerOnElapsed;
|
||||
|
||||
@ -50,7 +50,7 @@
|
||||
cal:Message.Attach="[Event LostFocus] = [Action PlaceFiles]" />
|
||||
<Button x:Name="BrowseDirectory" Content="..." RenderTransformOrigin="-0.039,-0.944"
|
||||
HorizontalAlignment="Right" Width="25"
|
||||
Style="{DynamicResource SquareButtonStyle}" Height="26" Margin="0,-2,0,0" />
|
||||
Style="{DynamicResource SquareButtonStyle}" Height="26" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
|
||||
|
||||
@ -22,7 +22,7 @@ namespace Artemis.Modules.Games.Witcher3
|
||||
|
||||
Settings = SettingsProvider.Load<Witcher3Settings>();
|
||||
DataModel = new Witcher3DataModel();
|
||||
ProcessName = "witcher3";
|
||||
ProcessNames.Add("witcher3");
|
||||
}
|
||||
|
||||
public override string Name => "Witcher3";
|
||||
|
||||
@ -21,7 +21,7 @@ namespace Artemis.Modules.Games.WoW
|
||||
{
|
||||
Settings = SettingsProvider.Load<WoWSettings>();
|
||||
DataModel = new WoWDataModel();
|
||||
ProcessName = "Wow-64";
|
||||
ProcessNames.Add("Wow-64");
|
||||
|
||||
// Currently WoW is locked behind a hidden trigger (obviously not that hidden since you're reading this)
|
||||
// It is using memory reading and lets first try to contact Blizzard
|
||||
@ -76,7 +76,7 @@ namespace Artemis.Modules.Games.WoW
|
||||
{
|
||||
if (_process == null)
|
||||
{
|
||||
var tempProcess = MemoryHelpers.GetProcessIfRunning(ProcessName);
|
||||
var tempProcess = MemoryHelpers.GetProcessIfRunning(ProcessNames[0]);
|
||||
if (tempProcess == null)
|
||||
return;
|
||||
|
||||
|
||||
@ -67,6 +67,7 @@ namespace Artemis.Utilities
|
||||
if (_rBmp?.PixelHeight != height || _rBmp?.PixelWidth != width)
|
||||
_rBmp = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
|
||||
|
||||
_rBmp.Clear();
|
||||
_rBmp.Render(visual);
|
||||
return GetBitmap(_rBmp);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user