1
0
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:
SpoinkyNL 2017-01-22 00:31:51 +01:00
parent d7bf26a738
commit 07f7ae263d
24 changed files with 396 additions and 329 deletions

View File

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

View File

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

View File

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

View File

@ -28,7 +28,7 @@ namespace Artemis.Modules.Games.CounterStrike
Settings = SettingsProvider.Load<CounterStrikeSettings>();
DataModel = new CounterStrikeDataModel();
ProcessName = "csgo";
ProcessNames.Add("csgo");
FindGameDir();
PlaceConfigFile();

View File

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

View File

@ -24,7 +24,7 @@ namespace Artemis.Modules.Games.Dota2
Settings = SettingsProvider.Load<Dota2Settings>();
DataModel = new Dota2DataModel();
ProcessName = "dota2";
ProcessNames.Add("dota2");
FindGameDir();
PlaceConfigFile();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -38,7 +38,7 @@ namespace Artemis.Modules.Games.Overwatch
Settings = SettingsProvider.Load<OverwatchSettings>();
DataModel = new OverwatchDataModel();
ProcessName = "Overwatch";
ProcessNames.Add("Overwatch");
LoadOverwatchCharacters();
FindOverwatch();

View File

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

View File

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

View File

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

View File

@ -32,8 +32,6 @@ namespace Artemis.Modules.Games.RocketLeague
}
}
public RocketLeagueModel RocketLeagueModel { get; set; }
private void SetVersionText()
{
if (!SettingsProvider.Load<GeneralSettings>().EnablePointersUpdate)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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