Skip to content

Commit 9ba47e4

Browse files
committed
* Mod Framework button programmed.
* All .package downloads will now check for SimTools custom Mod Framework.
1 parent 98c25ea commit 9ba47e4

6 files changed

Lines changed: 330 additions & 110 deletions

File tree

Pages/GameplayFixViewModels.cs

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Collections.ObjectModel;
4+
using System.ComponentModel;
5+
using System.Linq;
6+
using System.Runtime.CompilerServices;
7+
using System.Windows.Input;
8+
9+
namespace SimTools;
10+
11+
// ══════════════════════════════════════════════════════════════════════════════
12+
// Data record — in its own file so the XAML compiler can resolve the types
13+
// referenced via {x:Type local:GameplayFixViewModel} / GameplaySectionViewModel
14+
// ══════════════════════════════════════════════════════════════════════════════
15+
16+
public sealed record GameplayFixItem(
17+
string DisplayName,
18+
string FileName,
19+
string Url,
20+
string OnCheckedMessage = "");
21+
22+
// ══════════════════════════════════════════════════════════════════════════════
23+
// Item ViewModel
24+
// ══════════════════════════════════════════════════════════════════════════════
25+
public sealed class GameplayFixViewModel : INotifyPropertyChanged
26+
{
27+
public string DisplayName { get; }
28+
public string FileName { get; }
29+
public string Url { get; }
30+
public string OnCheckedMessage { get; }
31+
32+
/// <summary>True for real items; false for TBD placeholders (empty FileName).</summary>
33+
public bool IsActive => !string.IsNullOrEmpty(FileName);
34+
35+
private bool _isChecked;
36+
public bool IsChecked
37+
{
38+
get => _isChecked;
39+
set
40+
{
41+
if (_isChecked == value) return;
42+
_isChecked = value;
43+
OnPropertyChanged();
44+
45+
if (value && !string.IsNullOrEmpty(OnCheckedMessage))
46+
CheckedMessageRequested?.Invoke(this, OnCheckedMessage);
47+
}
48+
}
49+
50+
public event EventHandler<string>? CheckedMessageRequested;
51+
52+
public GameplayFixViewModel(GameplayFixItem item)
53+
{
54+
DisplayName = item.DisplayName;
55+
FileName = item.FileName;
56+
Url = item.Url;
57+
OnCheckedMessage = item.OnCheckedMessage;
58+
}
59+
60+
public event PropertyChangedEventHandler? PropertyChanged;
61+
private void OnPropertyChanged([CallerMemberName] string? n = null)
62+
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(n));
63+
}
64+
65+
// ══════════════════════════════════════════════════════════════════════════════
66+
// Section ViewModel
67+
// ══════════════════════════════════════════════════════════════════════════════
68+
public sealed class GameplaySectionViewModel : INotifyPropertyChanged
69+
{
70+
public string Header { get; }
71+
public ObservableCollection<GameplayFixViewModel> Items { get; }
72+
public ICommand ToggleAllCommand { get; }
73+
74+
/// <summary>
75+
/// Drives the section-header three-state checkbox (OneWay binding).
76+
/// Considers only active (non-TBD) items.
77+
/// </summary>
78+
public bool? IsAllSelected
79+
{
80+
get
81+
{
82+
var active = Items.Where(i => i.IsActive).ToList();
83+
if (active.Count == 0) return false;
84+
bool any = active.Any(i => i.IsChecked);
85+
bool all = active.All(i => i.IsChecked);
86+
return all ? true : any ? null : false;
87+
}
88+
}
89+
90+
public GameplaySectionViewModel(string header, IEnumerable<GameplayFixViewModel> items)
91+
{
92+
Header = header;
93+
Items = new ObservableCollection<GameplayFixViewModel>(items);
94+
95+
ToggleAllCommand = new RelayCommand(_ =>
96+
{
97+
var active = Items.Where(i => i.IsActive).ToList();
98+
bool check = active.Any(i => !i.IsChecked);
99+
foreach (var item in active)
100+
item.IsChecked = check;
101+
});
102+
103+
foreach (var item in Items)
104+
item.PropertyChanged += (_, args) =>
105+
{
106+
if (args.PropertyName == nameof(GameplayFixViewModel.IsChecked))
107+
OnPropertyChanged(nameof(IsAllSelected));
108+
};
109+
}
110+
111+
public event PropertyChangedEventHandler? PropertyChanged;
112+
private void OnPropertyChanged([CallerMemberName] string? n = null)
113+
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(n));
114+
}

Pages/GameplayFixesWindow.xaml.cs

Lines changed: 25 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,121 +1,14 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.Collections.ObjectModel;
4-
using System.ComponentModel;
53
using System.IO;
64
using System.Linq;
75
using System.Net.Http;
8-
using System.Runtime.CompilerServices;
96
using System.Windows;
10-
using System.Windows.Input;
117

128
using WpfMessageBox = System.Windows.MessageBox;
139

1410
namespace SimTools;
1511

16-
// ══════════════════════════════════════════════════════════════════════════════
17-
// Data record — top-level so all ViewModels can reference it
18-
// ══════════════════════════════════════════════════════════════════════════════
19-
public sealed record GameplayFixItem(
20-
string DisplayName,
21-
string FileName,
22-
string Url,
23-
string OnCheckedMessage = "");
24-
25-
// ══════════════════════════════════════════════════════════════════════════════
26-
// Item ViewModel
27-
// ══════════════════════════════════════════════════════════════════════════════
28-
public sealed class GameplayFixViewModel : INotifyPropertyChanged
29-
{
30-
public string DisplayName { get; }
31-
public string FileName { get; }
32-
public string Url { get; }
33-
public string OnCheckedMessage { get; }
34-
35-
/// <summary>True for real items; false for TBD placeholders (empty FileName).</summary>
36-
public bool IsActive => !string.IsNullOrEmpty(FileName);
37-
38-
private bool _isChecked;
39-
public bool IsChecked
40-
{
41-
get => _isChecked;
42-
set
43-
{
44-
if (_isChecked == value) return;
45-
_isChecked = value;
46-
OnPropertyChanged();
47-
48-
if (value && !string.IsNullOrEmpty(OnCheckedMessage))
49-
CheckedMessageRequested?.Invoke(this, OnCheckedMessage);
50-
}
51-
}
52-
53-
public event EventHandler<string>? CheckedMessageRequested;
54-
55-
public GameplayFixViewModel(GameplayFixItem item)
56-
{
57-
DisplayName = item.DisplayName;
58-
FileName = item.FileName;
59-
Url = item.Url;
60-
OnCheckedMessage = item.OnCheckedMessage;
61-
}
62-
63-
public event PropertyChangedEventHandler? PropertyChanged;
64-
private void OnPropertyChanged([CallerMemberName] string? n = null)
65-
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(n));
66-
}
67-
68-
// ══════════════════════════════════════════════════════════════════════════════
69-
// Section ViewModel
70-
// ══════════════════════════════════════════════════════════════════════════════
71-
public sealed class GameplaySectionViewModel : INotifyPropertyChanged
72-
{
73-
public string Header { get; }
74-
public ObservableCollection<GameplayFixViewModel> Items { get; }
75-
public ICommand ToggleAllCommand { get; }
76-
77-
/// <summary>
78-
/// Drives the section-header three-state checkbox (OneWay binding).
79-
/// Considers only active (non-TBD) items.
80-
/// </summary>
81-
public bool? IsAllSelected
82-
{
83-
get
84-
{
85-
var active = Items.Where(i => i.IsActive).ToList();
86-
if (active.Count == 0) return false;
87-
bool any = active.Any(i => i.IsChecked);
88-
bool all = active.All(i => i.IsChecked);
89-
return all ? true : any ? null : false;
90-
}
91-
}
92-
93-
public GameplaySectionViewModel(string header, IEnumerable<GameplayFixViewModel> items)
94-
{
95-
Header = header;
96-
Items = new ObservableCollection<GameplayFixViewModel>(items);
97-
98-
ToggleAllCommand = new RelayCommand(_ =>
99-
{
100-
var active = Items.Where(i => i.IsActive).ToList();
101-
bool check = active.Any(i => !i.IsChecked);
102-
foreach (var item in active)
103-
item.IsChecked = check;
104-
});
105-
106-
foreach (var item in Items)
107-
item.PropertyChanged += (_, args) =>
108-
{
109-
if (args.PropertyName == nameof(GameplayFixViewModel.IsChecked))
110-
OnPropertyChanged(nameof(IsAllSelected));
111-
};
112-
}
113-
114-
public event PropertyChangedEventHandler? PropertyChanged;
115-
private void OnPropertyChanged([CallerMemberName] string? n = null)
116-
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(n));
117-
}
118-
11912
// ══════════════════════════════════════════════════════════════════════════════
12013
// Window code-behind
12114
// ══════════════════════════════════════════════════════════════════════════════
@@ -162,6 +55,29 @@ private IEnumerable<GameplayFixViewModel> AllActiveItems()
16255
private void GlobalSelectAll_Click(object sender, RoutedEventArgs e)
16356
{
16457
bool check = GlobalSelectAll.IsChecked == true;
58+
59+
if (check)
60+
{
61+
var result = WpfMessageBox.Show(
62+
"You are about to select every available fix.\n\n" +
63+
"SimTools is designed to make games run better — but installing " +
64+
"every package will increase load times and may bog down the engine. " +
65+
"It is strongly recommended to only install fixes for features and " +
66+
"objects you actively use.\n\n" +
67+
"Additionally, installing fixes for Expansion Packs or Stuff Packs " +
68+
"that are not installed on your system can result in crashes or " +
69+
"unexpected behaviour.\n\n" +
70+
"Do you still want to select all fixes?",
71+
"SimTools — Select All Warning",
72+
MessageBoxButton.YesNo, MessageBoxImage.Warning);
73+
74+
if (result != MessageBoxResult.Yes)
75+
{
76+
GlobalSelectAll.IsChecked = false;
77+
return;
78+
}
79+
}
80+
16581
foreach (var item in AllActiveItems())
16682
item.IsChecked = check;
16783
}
@@ -182,6 +98,8 @@ private async void DownloadSelected_Click(object sender, RoutedEventArgs e)
18298
return;
18399
}
184100

101+
if (!ModFrameworkHelper.EnsureInstalled(_sims3Mods)) return;
102+
185103
var toDownload = _sections
186104
.SelectMany(s => s.Items)
187105
.Where(i => i.IsChecked && !string.IsNullOrEmpty(i.FileName))

Pages/MainWindow.xaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383
</Style>
8484
</Button.Style>
8585
</Button>
86-
<Button x:Name="TweakButton" Content="Game Tweaks &gt;" HorizontalAlignment="Left" Margin="8,256,0,0" VerticalAlignment="Top" Width="162" Height="34" FontFamily="Tahoma" FontWeight="Bold" Click="TweakButton_Click" FontSize="11" ContextMenuOpening="TweakButton_Context" BorderBrush="{x:Null}">
86+
<Button x:Name="TweakButton" Content="Game Tweaks &gt;" HorizontalAlignment="Left" Margin="8,256,0,0" VerticalAlignment="Top" Width="162" Height="34" FontFamily="Tahoma" FontWeight="Bold" Click="TweakButton_Click" FontSize="11" BorderBrush="{x:Null}">
8787
<Button.Background>
8888
<ImageBrush ImageSource="/Images/button_normal.png"/>
8989
</Button.Background>
@@ -148,7 +148,7 @@
148148
<TextBlock x:Name="BuyTS3Text" HorizontalAlignment="Left" Margin="184,457,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="401" Height="36" FontFamily="SimSun" Foreground="White" FontSize="11" Text="Here you can find links for buying The Sims 3 and it's various expansion and stuff packs. I earn commission per sale if you elect to purchase through SimTools."/>
149149
<TextBlock x:Name="ModToolsText" HorizontalAlignment="Left" Margin="184,496,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="401" Height="36" FontFamily="SimSun" Foreground="White" FontSize="11"><Run Text="A collection of tools to help you create worlds, objects, skins, clothing, scripts, packages, etc. Use with care. Various tutorials can be found on YouTube."/><LineBreak/><Run/></TextBlock>
150150
<TextBlock x:Name="GenKeysText" HorizontalAlignment="Left" Margin="184,536,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="401" Height="36" FontFamily="SimSun" Foreground="White" FontSize="11" Text="Lost your game case? Bought a game second-hand with no case at all? This menu will display generic keys that can be used to install from Retail discs."/>
151-
<Button x:Name="ModFrameworkButton" Content="Mod Framework" HorizontalAlignment="Left" Margin="184,600,0,0" VerticalAlignment="Top" Width="122" Height="34" FontFamily="Tahoma" FontWeight="Bold" Click="TweakButton_Click" FontSize="11" ContextMenuOpening="TweakButton_Context" BorderBrush="{x:Null}">
151+
<Button x:Name="ModFrameworkButton" Content="Mod Framework" HorizontalAlignment="Left" Margin="184,600,0,0" VerticalAlignment="Top" Width="122" Height="34" FontFamily="Tahoma" FontWeight="Bold" Click="ModFrameworkButton_Click" FontSize="11" BorderBrush="{x:Null}">
152152
<Button.Background>
153153
<ImageBrush ImageSource="/Images/button_normal.png"/>
154154
</Button.Background>

0 commit comments

Comments
 (0)