Skip to content

Commit 79c69be

Browse files
authored
Pinvoke x11 xrandr for linux resolutions (#107)
* Pinvoke x11 xrandr for linux resolutions * Replace events with reactive * Replace autofac with microsoft DI * Enable warnings as errors
1 parent 17ba56f commit 79c69be

40 files changed

Lines changed: 518 additions & 451 deletions

README.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,6 @@ This program patches **The Sims 1** to a custom resolution.
99
* NoCD/Cracked Sims Executable
1010
* This exe cannot be previously patched to a custom resolution. For example, if you downloaded a crack that was patched to 1080p, this program will not work.
1111

12-
**Linux**
13-
14-
* xrandr
15-
* Ubuntu ```sudo apt install xrandr```
16-
* Fedora ```sudo dnf install xrandr```
17-
1812
### OS Version Compatability
1913

2014
| Windows |

Sims1WidescreenPatcher.Core/Models/AspectRatio.cs

Lines changed: 21 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -2,83 +2,41 @@
22

33
namespace Sims1WidescreenPatcher.Core.Models;
44

5-
public class AspectRatio : IEqualityComparer<AspectRatio>, IComparable<AspectRatio>
5+
public record AspectRatio : IComparable<AspectRatio>
66
{
7-
protected bool Equals(AspectRatio other)
8-
{
9-
return Numerator == other.Numerator && Denominator == other.Denominator;
10-
}
7+
private readonly BigInteger _gcd;
118

12-
public override bool Equals(object? obj)
9+
public AspectRatio(int Width, int Height)
1310
{
14-
if (ReferenceEquals(null, obj)) return false;
15-
if (ReferenceEquals(this, obj)) return true;
16-
if (obj.GetType() != this.GetType()) return false;
17-
return Equals((AspectRatio) obj);
11+
this.Width = Width;
12+
this.Height = Height;
13+
_gcd = BigInteger.GreatestCommonDivisor(Width, Height);
1814
}
1915

20-
public override int GetHashCode()
21-
{
22-
unchecked
23-
{
24-
return (Numerator * 397) ^ Denominator;
25-
}
26-
}
16+
public int Numerator => Width / (int)_gcd;
17+
public int Denominator => Height / (int)_gcd;
18+
public int Width { get; init; }
19+
public int Height { get; init; }
2720

28-
public int Numerator;
29-
public int Denominator;
30-
31-
public AspectRatio(int width, int height)
32-
{
33-
CalculateAspectRatio(width, height);
34-
}
21+
public override string ToString() => $"{Numerator}:{Denominator}";
3522

36-
public override string ToString()
37-
{
38-
return $"{Numerator}:{Denominator}";
39-
}
40-
41-
public static bool operator ==(AspectRatio obj1, AspectRatio obj2)
42-
{
43-
return (obj1.Numerator == obj2.Numerator
44-
&& obj1.Denominator == obj2.Denominator);
45-
}
23+
public virtual bool Equals(AspectRatio? other) =>
24+
other is not null && Numerator == other.Numerator && Denominator == other.Denominator;
4625

47-
public static bool operator !=(AspectRatio obj1, AspectRatio obj2)
48-
{
49-
return !(obj1 == obj2);
50-
}
51-
52-
private void CalculateAspectRatio(int width, int height)
53-
{
54-
var gcd = BigInteger.GreatestCommonDivisor(width, height);
55-
Numerator = width / (int)gcd;
56-
Denominator = height / (int)gcd;
57-
}
58-
59-
public bool Equals(AspectRatio x, AspectRatio y)
60-
{
61-
if (ReferenceEquals(x, y)) return true;
62-
if (ReferenceEquals(x, null)) return false;
63-
if (ReferenceEquals(y, null)) return false;
64-
if (x.GetType() != y.GetType()) return false;
65-
return x.Numerator == y.Numerator && x.Denominator == y.Denominator;
66-
}
67-
68-
public int GetHashCode(AspectRatio obj)
69-
{
70-
unchecked
71-
{
72-
return (obj.Numerator * 397) ^ obj.Denominator;
73-
}
74-
}
26+
public override int GetHashCode() => HashCode.Combine(Numerator, Denominator);
7527

7628
public int CompareTo(AspectRatio? other)
7729
{
7830
if (ReferenceEquals(this, other)) return 0;
79-
if (ReferenceEquals(null, other)) return 1;
31+
if (other is null) return 1;
8032
var numeratorComparison = Numerator.CompareTo(other.Numerator);
8133
if (numeratorComparison != 0) return numeratorComparison;
8234
return Denominator.CompareTo(other.Denominator);
8335
}
36+
37+
public void Deconstruct(out int Width, out int Height)
38+
{
39+
Width = this.Width;
40+
Height = this.Height;
41+
}
8442
}

Sims1WidescreenPatcher.Core/Models/CheckboxSelectionSnapshot.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
using Sims1WidescreenPatcher.Core.ViewModels;
2-
3-
namespace Sims1WidescreenPatcher.Core.Models;
1+
namespace Sims1WidescreenPatcher.Core.Models;
42

53
public class CheckboxSelectionSnapshot : IEquatable<CheckboxSelectionSnapshot>
64
{

Sims1WidescreenPatcher.Core/Models/CompositeImageJob.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public override void Run()
1919
}
2020

2121
using var image = new MagickImage(ImageBytes!);
22-
using var background = new MagickImage(new MagickColor(Color), Width, Height);
22+
using var background = new MagickImage(new MagickColor(Color), (uint)Width, (uint)Height);
2323
background.Composite(image, Gravity.Center);
2424
SetCommonBmpSettings(background);
2525
background.Write(Output!);
Lines changed: 21 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,38 @@
1-
using System.Numerics;
1+
namespace Sims1WidescreenPatcher.Core.Models;
22

3-
namespace Sims1WidescreenPatcher.Core.Models;
4-
5-
public class Resolution : IComparable<Resolution>
3+
public record Resolution : IComparable<Resolution>
64
{
7-
private sealed class WidthHeightEqualityComparer : IEqualityComparer<Resolution>
5+
public readonly AspectRatio AspectRatio;
6+
7+
public Resolution(int Width, int Height)
88
{
9-
public bool Equals(Resolution x, Resolution y)
10-
{
11-
if (ReferenceEquals(x, y)) return true;
12-
if (ReferenceEquals(x, null)) return false;
13-
if (ReferenceEquals(y, null)) return false;
14-
if (x.GetType() != y.GetType()) return false;
15-
return x.Width == y.Width && x.Height == y.Height;
16-
}
17-
18-
public int GetHashCode(Resolution obj)
19-
{
20-
unchecked
21-
{
22-
return (obj.Width * 397) ^ obj.Height;
23-
}
24-
}
9+
this.Width = Width;
10+
this.Height = Height;
11+
AspectRatio = new AspectRatio(Width, Height);
2512
}
2613

27-
public static IEqualityComparer<Resolution>? WidthHeightComparer { get; } = new WidthHeightEqualityComparer();
14+
public int Width { get; init; }
15+
public int Height { get; init; }
2816

29-
public int Width { get; }
30-
public int Height { get; }
31-
public AspectRatio AspectRatio { get; }
17+
public override string ToString() => $"{Width}x{Height} ({AspectRatio})";
3218

33-
public Resolution(int width, int height)
34-
{
35-
Width = width;
36-
Height = height;
37-
AspectRatio = new AspectRatio(width, height);
38-
}
19+
public virtual bool Equals(Resolution? other) => other is not null && Width == other.Width &&
20+
Height == other.Height && AspectRatio.Equals(other.AspectRatio);
3921

40-
public override string ToString()
41-
{
42-
return $"{Width}x{Height} ({AspectRatio})";
43-
}
22+
public override int GetHashCode() => HashCode.Combine(AspectRatio, Width, Height);
4423

4524
public int CompareTo(Resolution? other)
4625
{
4726
if (ReferenceEquals(this, other)) return 0;
48-
if (ReferenceEquals(null, other)) return 1;
27+
if (other is null) return 1;
4928
var widthComparison = Width.CompareTo(other.Width);
5029
if (widthComparison != 0) return widthComparison;
5130
return Height.CompareTo(other.Height);
5231
}
32+
33+
public void Deconstruct(out int Width, out int Height)
34+
{
35+
Width = this.Width;
36+
Height = this.Height;
37+
}
5338
}

Sims1WidescreenPatcher.Core/Models/ScalePanelBackJob.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ public override void Run()
1010

1111
using var image = new MagickImage(ImageBytes!);
1212
var left = image.Clone(0, 0, 286, 100);
13-
var middle = image.Clone(left.Width, 0, 500, 100);
14-
var right = image.Clone(left.Width + middle.Width, 0, 18, 100);
15-
middle.Resize(new MagickGeometry(Width - left.Width - right.Width, Height) { IgnoreAspectRatio = true });
13+
var middle = image.Clone((int)left.Width, 0, 500, 100);
14+
var right = image.Clone((int)left.Width + (int)middle.Width, 0, 18, 100);
15+
middle.Resize(new MagickGeometry((uint)Width - left.Width - right.Width, (uint)Height) { IgnoreAspectRatio = true });
1616
left.Page = new MagickGeometry("+0+0");
1717
middle.Page = new MagickGeometry($"+{left.Width}+0");
1818
right.Page = new MagickGeometry($"+{left.Width + middle.Width}+0");

Sims1WidescreenPatcher.Core/Models/ScaleTallSubPanelJob.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ public override void Run()
99
base.Run();
1010

1111
using var image = new MagickImage(ImageBytes!, MagickFormat.Tga);
12-
image.Resize(new MagickGeometry(Width, Height) { IgnoreAspectRatio = true });
12+
image.Resize(new MagickGeometry((uint)Width, (uint)Height) { IgnoreAspectRatio = true });
1313
image.Depth = 32;
1414
image.Settings.Compression = CompressionMethod.RLE;
1515
image.Settings.Format = MagickFormat.Tga;

Sims1WidescreenPatcher.Core/Services/CheatsService.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ namespace Sims1WidescreenPatcher.Core.Services;
55

66
public class CheatsService : ICheatsService
77
{
8-
private const string DisableCheatsPattern = "00 56 90 90";
9-
private const string EnableCheatsPattern = "00 56 75 04";
108
private readonly IAppState _appState;
119
private readonly IPatchFileService _patchFileService;
1210

@@ -16,8 +14,15 @@ public CheatsService(IAppState appState, IPatchFileService patchFileService)
1614
_patchFileService = patchFileService;
1715
}
1816

17+
private const string DisableCheatsPattern = "00 56 90 90";
18+
private const string EnableCheatsPattern = "00 56 75 04";
19+
1920
public bool CheatsEnabled()
2021
{
22+
if (string.IsNullOrWhiteSpace(_appState.SimsExePath))
23+
{
24+
return false;
25+
}
2126
var (found, _, _) = _patchFileService.FindPattern(_appState.SimsExePath, DisableCheatsPattern);
2227
return found;
2328
}
@@ -28,6 +33,10 @@ public bool CheatsEnabled()
2833
/// <returns></returns>
2934
public bool CanEnableCheats()
3035
{
36+
if (string.IsNullOrWhiteSpace(_appState.SimsExePath))
37+
{
38+
return false;
39+
}
3140
var (disablePatternFound, _, _) = _patchFileService.FindPattern(_appState.SimsExePath, DisableCheatsPattern);
3241
var (enablePatternFound, _, _) = _patchFileService.FindPattern(_appState.SimsExePath,EnableCheatsPattern);
3342
return disablePatternFound || enablePatternFound;
@@ -45,6 +54,10 @@ public void DisableCheats()
4554

4655
private void EditSimsExe(string pattern, Tuple<byte, byte> replacementBytes)
4756
{
57+
if (string.IsNullOrWhiteSpace(_appState.SimsExePath))
58+
{
59+
return;
60+
}
4861
var (found, offset, bytes) = _patchFileService.FindPattern(_appState.SimsExePath, pattern);
4962
if (!found)
5063
{

Sims1WidescreenPatcher.Core/Services/ImagesService.cs

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@ namespace Sims1WidescreenPatcher.Core.Services;
77
public class ImagesService : IImagesService
88
{
99
private string? _uiGraphicsPath;
10-
private readonly IAppState _appState;
11-
private readonly IProgressService _progressService;
12-
private readonly IFar _far;
1310

1411
private readonly string[] _blackBackground =
1512
{
@@ -35,9 +32,9 @@ public class ImagesService : IImagesService
3532
@"Studiotown\dlgframe_1024x768.bmp",
3633
};
3734

38-
private const string TallSubPanel = @"cpanel\Backgrounds\TallSubPanel.TGA";
39-
40-
private const string PanelBack = @"cpanel\Backgrounds\PanelBack.bmp";
35+
private readonly IAppState _appState;
36+
private readonly IProgressService _progressService;
37+
private readonly IFar _far;
4138

4239
public ImagesService(IAppState appState, IProgressService progressService, IFar far)
4340
{
@@ -46,6 +43,10 @@ public ImagesService(IAppState appState, IProgressService progressService, IFar
4643
_far = far;
4744
}
4845

46+
private const string TallSubPanel = @"cpanel\Backgrounds\TallSubPanel.TGA";
47+
48+
private const string PanelBack = @"cpanel\Backgrounds\PanelBack.bmp";
49+
4950
public void Install()
5051
{
5152
_uiGraphicsPath = GetUiGraphicsFolder();
@@ -74,7 +75,7 @@ public void Uninstall()
7475

7576
foreach (var i in _blackBackground
7677
.Concat(_blueBackground)
77-
.Concat(new[] { TallSubPanel, PanelBack }))
78+
.Concat(new List<string> { TallSubPanel, PanelBack }.AsReadOnly()))
7879
{
7980
DeleteUiGraphicsFile(i);
8081
}
@@ -85,6 +86,11 @@ private List<BaseImageProcessingJob> GetJobs()
8586
_far.ParseFar();
8687
var jobs = new List<BaseImageProcessingJob>();
8788

89+
if (_appState.Resolution is null)
90+
{
91+
return jobs;
92+
}
93+
8894
if (_far.TryGetBytes(PanelBack, out var bytes))
8995
{
9096
jobs.Add(new ScalePanelBackJob
@@ -116,6 +122,10 @@ private List<BaseImageProcessingJob> GetJobs()
116122

117123
private IEnumerable<BaseImageProcessingJob> GetCompositeJobs(IEnumerable<string> images, string color)
118124
{
125+
if (_appState.Resolution is null)
126+
{
127+
throw new Exception("Resolution is null");
128+
}
119129
foreach (var i in images)
120130
{
121131
if (_far.TryGetBytes(i, out var bytes))
@@ -134,7 +144,15 @@ private IEnumerable<BaseImageProcessingJob> GetCompositeJobs(IEnumerable<string>
134144

135145
private string GetUiGraphicsFolder()
136146
{
137-
var simsInstallDir = Directory.GetParent(_appState.SimsExePath).ToString();
147+
if (string.IsNullOrWhiteSpace(_appState.SimsExePath))
148+
{
149+
throw new Exception("SimsExePath is null or empty");
150+
}
151+
var simsInstallDir = Directory.GetParent(_appState.SimsExePath)?.ToString();
152+
if (string.IsNullOrWhiteSpace(simsInstallDir))
153+
{
154+
throw new Exception("SimsExePath is null or empty");
155+
}
138156
return Path.Combine(simsInstallDir, "UIGraphics");
139157
}
140158

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
1-
using Sims1WidescreenPatcher.Core.Events;
2-
using Sims1WidescreenPatcher.Core.Models;
1+
using System.Reactive;
2+
using Sims1WidescreenPatcher.Core.Events;
33

44
namespace Sims1WidescreenPatcher.Core.Services.Interfaces
55
{
66
public interface IProgressService
77
{
8-
event EventHandler<NewProgressEventArgs>? NewProgressEventHandler;
9-
108
void UpdateProgress(double pct);
119
void UpdateProgress(double pct, string status, string status2);
12-
event EventHandler<NewUninstallEventArgs>? NewUninstallEventHandler;
1310
void UpdateUninstall();
11+
IObservable<Unit> Uninstall { get; }
12+
IObservable<NewProgressEventArgs> NewProgressObservable { get; }
1413
}
1514
}

0 commit comments

Comments
 (0)