wow-game-launcher/MainWindow.xaml.cs
2025-05-15 19:29:39 -05:00

1175 lines
41 KiB
C#

using System;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
using System.Threading.Tasks;
using System.Windows.Media.Effects;
using System.Text.Json;
using System.Xml.Linq;
namespace MultiWoWLauncher
{
public partial class MainWindow : Window
{
// Config file key for WoW path
private const string WowPathKey = "WowExecutablePath";
private const string ClearCacheKey = "ClearCache";
// AppData config constants
private const string AppName = "MultiWoWLauncher";
private const string ConfigFileName = "config.xml";
private string ConfigFilePath => Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
AppName,
ConfigFileName);
// Class level variables
private DispatcherTimer _contentRefreshTimer; // Combined refresh timer
private HttpClient _httpClient;
private string _playerCountUrl = "http://127.0.0.1/count.php";
private bool _isStatusUpdating = false;
private string _newsUrl = "http://127.0.0.1/news.php"; // Change to your news endpoint
private DateTime _lastNewsUpdate = DateTime.MinValue;
public MainWindow()
{
InitializeComponent();
// Initialize HTTP client
_httpClient = new HttpClient();
_httpClient.Timeout = TimeSpan.FromSeconds(10); // Set a reasonable timeout
// Load settings from config
LoadSettingsFromConfig();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// Load the embedded video resource
LoadEmbeddedVideo();
// Initial load of content
_ = UpdatePlayerCount(); // Initial player count update
LoadNews(); // Initial news load
// Initialize the unified content refresh
InitializeContentRefresh();
}
private void Window_Closed(object sender, EventArgs e)
{
// Clean up resources
if (_contentRefreshTimer != null)
{
_contentRefreshTimer.Stop();
}
if (_httpClient != null)
{
_httpClient.Dispose();
}
}
// Load settings from config file
private void LoadSettingsFromConfig()
{
try
{
// Load Clear Cache setting
string clearCacheSetting = GetSettingFromConfig(ClearCacheKey, "False");
ClearCacheCheckBox.IsChecked = Convert.ToBoolean(clearCacheSetting);
}
catch (Exception ex)
{
Console.WriteLine($"Error loading settings: {ex.Message}");
}
}
// Save setting to config file
private void SaveSettingToConfig(string key, string value)
{
try
{
// Create the config directory if it doesn't exist
string configDir = Path.GetDirectoryName(ConfigFilePath);
if (!Directory.Exists(configDir))
{
Directory.CreateDirectory(configDir);
}
// Load or create the XML configuration file
XDocument doc;
if (File.Exists(ConfigFilePath))
{
// Load existing config
doc = XDocument.Load(ConfigFilePath);
}
else
{
// Create new config file
doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("configuration",
new XElement("appSettings")
)
);
}
// Get or create the appSettings element
XElement appSettings = doc.Root.Element("appSettings");
if (appSettings == null)
{
appSettings = new XElement("appSettings");
doc.Root.Add(appSettings);
}
// Find existing setting
XElement setting = appSettings.Elements("add")
.FirstOrDefault(e => (string)e.Attribute("key") == key);
if (setting != null)
{
// Update existing setting
setting.Attribute("value").Value = value;
}
else
{
// Add new setting
appSettings.Add(new XElement("add",
new XAttribute("key", key),
new XAttribute("value", value)
));
}
// Save the configuration
doc.Save(ConfigFilePath);
}
catch (Exception ex)
{
MessageBox.Show($"Error saving setting to configuration: {ex.Message}",
"Configuration Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
// Get setting from config file
private string GetSettingFromConfig(string key, string defaultValue = "")
{
try
{
if (File.Exists(ConfigFilePath))
{
XDocument doc = XDocument.Load(ConfigFilePath);
XElement appSettings = doc.Root.Element("appSettings");
if (appSettings != null)
{
XElement setting = appSettings.Elements("add")
.FirstOrDefault(e => (string)e.Attribute("key") == key);
if (setting != null)
{
return (string)setting.Attribute("value");
}
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error loading setting from configuration: {ex.Message}");
}
return defaultValue;
}
// Initialize the unified content refresh
private void InitializeContentRefresh()
{
// Create and configure the timer for all content
_contentRefreshTimer = new DispatcherTimer
{
Interval = TimeSpan.FromSeconds(10) // Refresh every 10 seconds
};
// Set up the timer event
_contentRefreshTimer.Tick += async (sender, e) =>
{
await RefreshAllContent();
};
// Start the timer
_contentRefreshTimer.Start();
// Update the last updated text immediately
UpdateLastUpdatedText();
}
// Method to refresh all content
private async Task RefreshAllContent()
{
try
{
// Start both refresh tasks concurrently for efficiency
Task<string> newsTask = FetchNewsContent();
Task playerCountTask = UpdatePlayerCount();
// Wait for news content to be retrieved
string newsContent = await newsTask;
// Update the news panel
UpdateNewsPanel(newsContent);
// Update last refresh time for news
_lastNewsUpdate = DateTime.Now;
// Update the last updated text
UpdateLastUpdatedText();
// Add a subtle visual indicator of refresh
FlashNewsRefreshIndicator();
FlashPlayerCountIndicator();
// Wait for player count task to complete (should already be done)
await playerCountTask;
Console.WriteLine("All content refreshed at: " + DateTime.Now.ToString("HH:mm:ss"));
}
catch (Exception ex)
{
Console.WriteLine($"Error in content refresh: {ex.Message}");
}
}
// Update the last updated text
private void UpdateLastUpdatedText()
{
try
{
// Get the LastUpdatedText element
TextBlock lastUpdatedText = FindName("LastUpdatedText") as TextBlock;
if (lastUpdatedText != null)
{
// Update it with the current time
lastUpdatedText.Text = $"Updated: {DateTime.Now.ToString("HH:mm:ss")}";
}
else
{
Console.WriteLine("LastUpdatedText not found in XAML");
}
}
catch (Exception ex)
{
Console.WriteLine($"Error updating last updated text: {ex.Message}");
}
}
private async Task UpdatePlayerCount()
{
// Prevent multiple simultaneous updates
if (_isStatusUpdating)
return;
_isStatusUpdating = true;
try
{
// Fetch player count from your local endpoint
string response = await _httpClient.GetStringAsync(_playerCountUrl);
// Try to parse the response as an integer
if (int.TryParse(response.Trim(), out int playerCount))
{
// Update the UI with the player count
OnlinePlayersText.Text = $"{playerCount:N0} Players Online";
// Update the status indicator color based on player count
UpdateStatusIndicator(playerCount);
}
else
{
// If we couldn't parse the response as a number
OnlinePlayersText.Text = "Server Status Unknown";
SetStatusIndicatorColor(Colors.Gray);
}
}
catch (Exception ex)
{
// Handle any errors in fetching or parsing the data
Console.WriteLine($"Error updating player count: {ex.Message}");
OnlinePlayersText.Text = "Server Offline";
SetStatusIndicatorColor(Colors.Red);
}
finally
{
_isStatusUpdating = false;
}
}
private void UpdateStatusIndicator(int playerCount)
{
// Change color based on population
if (playerCount > 500)
{
// High population - green
SetStatusIndicatorColor(Colors.LimeGreen);
}
else if (playerCount > 100)
{
// Medium population - yellow
SetStatusIndicatorColor(Colors.Yellow);
}
else if (playerCount > 0)
{
// Low population - orange
SetStatusIndicatorColor(Colors.Orange);
}
else
{
// No players - red
SetStatusIndicatorColor(Colors.Red);
}
}
private void SetStatusIndicatorColor(Color color)
{
// Update the status indicator color
StatusIndicator.Fill = new SolidColorBrush(color);
// Update the glow effect
if (StatusIndicator.Effect is DropShadowEffect effect)
{
effect.Color = color;
}
}
private void FlashPlayerCountIndicator()
{
// Find the player count border
var playerCountBorder = GetPlayerCountBorder();
if (playerCountBorder == null) return;
// Store the original background
Brush originalBackground = playerCountBorder.Background;
// Create a subtle animation
DispatcherTimer flashTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(100) };
int flashCount = 0;
flashTimer.Tick += (s, e) =>
{
flashCount++;
if (flashCount == 1)
{
// Flash to a slightly lighter color
playerCountBorder.Background = new SolidColorBrush(Color.FromArgb(80, 0, 0, 0));
}
else
{
// Restore original background
playerCountBorder.Background = originalBackground;
flashTimer.Stop();
}
};
flashTimer.Start();
}
private Border GetPlayerCountBorder()
{
// Find the player count text block
var playerCountText = FindName("OnlinePlayersText") as TextBlock;
if (playerCountText == null) return null;
// Walk up the visual tree to find the parent Border
DependencyObject current = playerCountText;
while (current != null)
{
if (current is Border border)
{
return border;
}
current = VisualTreeHelper.GetParent(current);
}
return null;
}
private void FlashNewsRefreshIndicator()
{
// Find the news header border
var newsHeader = FindNewsHeaderBorder();
if (newsHeader == null) return;
// Store the original background
Brush originalBackground = newsHeader.Background;
// Create a subtle animation
DispatcherTimer flashTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(100) };
int flashCount = 0;
flashTimer.Tick += (s, e) =>
{
flashCount++;
if (flashCount == 1)
{
// Flash to a slightly lighter color
newsHeader.Background = new SolidColorBrush(Color.FromRgb(50, 50, 50));
}
else
{
// Restore original background
newsHeader.Background = originalBackground;
flashTimer.Stop();
}
};
flashTimer.Start();
}
private Border FindNewsHeaderBorder()
{
// Find the news panel first
var newsPanel = FindName("NewsPanel") as StackPanel;
if (newsPanel == null) return null;
// Walk up the visual tree to find the parent Border in Row 0
DependencyObject current = newsPanel;
// Look for parent elements until we find what might be the header border
while (current != null)
{
// Check if this is a Grid
if (current is Grid grid)
{
// Check for a Border in Row 0
foreach (UIElement child in grid.Children)
{
if (child is Border border && Grid.GetRow(child) == 0)
{
return border;
}
}
}
current = VisualTreeHelper.GetParent(current);
}
return null;
}
// Method to load news
private async void LoadNews()
{
try
{
// Only update news if it hasn't been updated in the last hour
if (DateTime.Now - _lastNewsUpdate > TimeSpan.FromHours(1))
{
string newsContent = await FetchNewsContent();
UpdateNewsPanel(newsContent);
_lastNewsUpdate = DateTime.Now;
// Update the last updated text after initial load
UpdateLastUpdatedText();
}
}
catch (Exception ex)
{
Console.WriteLine($"Error loading news: {ex.Message}");
// Show error in news panel
var newsPanel = FindName("NewsPanel") as StackPanel;
if (newsPanel != null)
{
newsPanel.Children.Clear();
newsPanel.Children.Add(CreateNewsErrorItem("Unable to load news updates. Please check your connection."));
}
}
}
// Method to fetch news content
private async Task<string> FetchNewsContent()
{
try
{
// Use the existing HttpClient instead of creating a new one
string content = await _httpClient.GetStringAsync(_newsUrl);
return content;
}
catch (Exception ex)
{
Console.WriteLine($"Error fetching news: {ex.Message}");
// Fallback to default news if server is unavailable
return GetDefaultNews();
}
}
// Method to parse and update the news panel
private void UpdateNewsPanel(string newsContent)
{
var newsPanel = FindName("NewsPanel") as StackPanel;
if (newsPanel == null) return;
// Clear existing items
newsPanel.Children.Clear();
try
{
// Parse the JSON content as an array
JsonDocument doc = JsonDocument.Parse(newsContent);
// The root element should be an array
if (doc.RootElement.ValueKind == JsonValueKind.Array)
{
bool hasNews = false;
// Process each news item in the array
foreach (JsonElement element in doc.RootElement.EnumerateArray())
{
// Create a NewsItem object from the JSON element
NewsItem item = new NewsItem
{
Title = GetJsonPropertyString(element, "title", "Untitled"),
Content = GetJsonPropertyString(element, "content", "No content"),
Date = GetJsonPropertyString(element, "date", DateTime.Now.ToString("yyyy-MM-dd")),
Type = GetJsonPropertyString(element, "type", "update")
};
// Add the news item to the panel
newsPanel.Children.Add(CreateNewsItem(item));
hasNews = true;
}
// If no news items were found
if (!hasNews)
{
newsPanel.Children.Add(CreateDefaultNewsItem("No news updates available."));
}
}
else
{
// If the root element is not an array
newsPanel.Children.Add(CreateNewsErrorItem("Invalid news format: Expected an array of news items."));
}
}
catch (JsonException ex)
{
Console.WriteLine($"Error parsing news JSON: {ex.Message}");
newsPanel.Children.Add(CreateNewsErrorItem($"Error parsing news data: {ex.Message}"));
}
catch (Exception ex)
{
Console.WriteLine($"Error processing news: {ex.Message}");
newsPanel.Children.Add(CreateNewsErrorItem($"Error loading news content: {ex.Message}"));
}
}
// Helper method to safely get string property from JSON
private string GetJsonPropertyString(JsonElement element, string propertyName, string defaultValue)
{
if (element.TryGetProperty(propertyName, out JsonElement property) &&
property.ValueKind == JsonValueKind.String)
{
return property.GetString() ?? defaultValue;
}
return defaultValue;
}
// Class to represent a news item
private class NewsItem
{
public string Title { get; set; }
public string Content { get; set; }
public string Date { get; set; }
public string Type { get; set; } // e.g., "update", "maintenance", "event"
}
// Create a UI element for a news item
private UIElement CreateNewsItem(NewsItem item)
{
// Container for the entire news item
Border container = new Border
{
Margin = new Thickness(0, 0, 0, 15),
BorderThickness = new Thickness(0, 0, 0, 1),
BorderBrush = new SolidColorBrush(Color.FromArgb(50, 255, 255, 255)),
Padding = new Thickness(0, 0, 0, 10)
};
// Content inside the news item
StackPanel content = new StackPanel();
// News title
TextBlock titleBlock = new TextBlock
{
Text = item.Title,
FontWeight = FontWeights.Bold,
FontSize = 14,
Foreground = new SolidColorBrush(Colors.White),
TextWrapping = TextWrapping.Wrap,
Margin = new Thickness(0, 0, 0, 5)
};
// News content
TextBlock contentBlock = new TextBlock
{
Text = item.Content,
Foreground = new SolidColorBrush(Color.FromRgb(204, 204, 204)),
TextWrapping = TextWrapping.Wrap,
Margin = new Thickness(0, 0, 0, 5)
};
// News date
TextBlock dateBlock = new TextBlock
{
Text = item.Date,
FontStyle = FontStyles.Italic,
FontSize = 11,
Foreground = new SolidColorBrush(Color.FromRgb(153, 153, 153)),
HorizontalAlignment = HorizontalAlignment.Right
};
// Add color indicator based on news type
Border typeIndicator = new Border
{
Width = 3,
HorizontalAlignment = HorizontalAlignment.Left,
Margin = new Thickness(-10, 0, 0, 0)
};
// Set color based on news type
if (item.Type?.ToLower() == "maintenance")
{
typeIndicator.Background = new SolidColorBrush(Color.FromRgb(255, 165, 0)); // Orange
}
else if (item.Type?.ToLower() == "update")
{
typeIndicator.Background = new SolidColorBrush(Color.FromRgb(0, 174, 255)); // Blue
}
else if (item.Type?.ToLower() == "event")
{
typeIndicator.Background = new SolidColorBrush(Color.FromRgb(124, 252, 0)); // Green
}
else
{
typeIndicator.Background = new SolidColorBrush(Color.FromRgb(200, 200, 200)); // Grey
}
// Assemble the news item
content.Children.Add(titleBlock);
content.Children.Add(contentBlock);
content.Children.Add(dateBlock);
Grid newsGrid = new Grid();
newsGrid.Children.Add(typeIndicator);
newsGrid.Children.Add(content);
container.Child = newsGrid;
return container;
}
// Create a simple news item from plain text
private UIElement CreateSimpleNewsItem(string content)
{
TextBlock textBlock = new TextBlock
{
Text = content,
Foreground = new SolidColorBrush(Colors.White),
TextWrapping = TextWrapping.Wrap
};
return textBlock;
}
// Create a default news item
private UIElement CreateDefaultNewsItem(string message)
{
TextBlock textBlock = new TextBlock
{
Text = message,
Foreground = new SolidColorBrush(Color.FromRgb(180, 180, 180)),
FontStyle = FontStyles.Italic,
TextWrapping = TextWrapping.Wrap
};
return textBlock;
}
// Create an error news item
private UIElement CreateNewsErrorItem(string errorMessage)
{
TextBlock textBlock = new TextBlock
{
Text = errorMessage,
Foreground = new SolidColorBrush(Color.FromRgb(255, 100, 100)),
FontStyle = FontStyles.Italic,
TextWrapping = TextWrapping.Wrap
};
return textBlock;
}
// Get default news content if server is unavailable
private string GetDefaultNews()
{
// Create a sample JSON news array
var defaultNews = new List<NewsItem>
{
new NewsItem
{
Title = "Welcome to the Multi WoW Launcher!",
Content = "This launcher is currently in alpha testing. Please report any bugs or issues you encounter.",
Date = DateTime.Now.ToString("yyyy-MM-dd"),
Type = "update"
},
new NewsItem
{
Title = "Upcoming Maintenance",
Content = "Server maintenance is scheduled for next Tuesday from 2 AM to 6 AM server time.",
Date = DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd"),
Type = "maintenance"
},
new NewsItem
{
Title = "Weekend Event: Double XP",
Content = "Enjoy double XP gains this weekend! Perfect time to level up your alts.",
Date = DateTime.Now.AddDays(-3).ToString("yyyy-MM-dd"),
Type = "event"
}
};
return System.Text.Json.JsonSerializer.Serialize(defaultNews);
}
private void LoadEmbeddedVideo()
{
try
{
// Get the assembly that contains the embedded resource
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
// Build the resource name - it includes the namespace
// Format: YourNamespace.FolderName.FileName.Extension
string resourceName = "MultiWoWLauncher.Assets.bg.mp4";
// Get a stream of the embedded resource
using (Stream resourceStream = assembly.GetManifestResourceStream(resourceName))
{
if (resourceStream != null)
{
// Create a temporary file to hold the video
string tempFile = Path.Combine(Path.GetTempPath(), $"wow_bg_{Guid.NewGuid()}.mp4");
// Copy the embedded resource to the temporary file
using (FileStream fileStream = new FileStream(tempFile, FileMode.Create))
{
resourceStream.CopyTo(fileStream);
}
// Set the MediaElement source to the temporary file
BackgroundVideo.Source = new Uri(tempFile);
// Register for application exit to clean up the temp file
Application.Current.Exit += (s, e) =>
{
try
{
if (File.Exists(tempFile))
{
File.Delete(tempFile);
}
}
catch
{
// Ignore errors on cleanup
}
};
// Start playing the video
BackgroundVideo.Play();
}
else
{
// Resource not found, show fallback background
ShowFallbackBackground();
Console.WriteLine("Video resource not found: " + resourceName);
// To debug, list all available resources:
string[] resources = assembly.GetManifestResourceNames();
Console.WriteLine("Available resources:");
foreach (string res in resources)
{
Console.WriteLine(" " + res);
}
}
}
}
catch (Exception ex)
{
ShowFallbackBackground();
Console.WriteLine($"Error loading embedded video: {ex.Message}");
}
}
private void ShowFallbackBackground()
{
// Hide video element and show fallback
BackgroundVideo.Visibility = Visibility.Collapsed;
// If you have a fallback background element:
if (FallbackBackground != null)
{
FallbackBackground.Visibility = Visibility.Visible;
}
// Otherwise, set a fallback on the parent Grid:
else
{
var parent = BackgroundVideo.Parent as Panel;
if (parent != null)
{
parent.Background = new LinearGradientBrush
{
StartPoint = new Point(0, 0),
EndPoint = new Point(1, 1),
GradientStops = new GradientStopCollection
{
new GradientStop(Color.FromRgb(10, 16, 33), 0),
new GradientStop(Color.FromRgb(21, 40, 66), 1)
}
};
}
}
}
private void LoadEmbeddedVideoInMemory()
{
try
{
// Get the assembly that contains the embedded resource
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
// Build the resource name with your namespace
string resourceName = "MultiWoWLauncher.Assets.bg.mp4";
// Get a stream of the embedded resource
using (Stream resourceStream = assembly.GetManifestResourceStream(resourceName))
{
if (resourceStream != null)
{
// Create a MemoryStream to hold the video data
MemoryStream memoryStream = new MemoryStream();
// Copy the resource data to the memory stream
resourceStream.CopyTo(memoryStream);
memoryStream.Position = 0;
// Create a BitmapSource from the memory stream
var uri = new Uri("pack://application:,,,/" + resourceName);
var streamResourceInfo = Application.GetResourceStream(uri);
if (streamResourceInfo != null)
{
BackgroundVideo.Source = uri;
BackgroundVideo.Play();
}
else
{
// If direct URI approach fails, try MediaStreamSource (more complex)
ShowFallbackBackground();
Console.WriteLine("Could not get resource stream for: " + resourceName);
}
}
else
{
ShowFallbackBackground();
Console.WriteLine("Video resource not found: " + resourceName);
// Debug info - list all resources
string[] resources = assembly.GetManifestResourceNames();
Console.WriteLine("Available resources:");
foreach (string res in resources)
{
Console.WriteLine(" " + res);
}
}
}
}
catch (Exception ex)
{
ShowFallbackBackground();
Console.WriteLine($"Error loading embedded video: {ex.Message}");
}
}
private void BackgroundVideo_MediaOpened(object sender, RoutedEventArgs e)
{
// When media is successfully opened, play it
BackgroundVideo.Play();
}
private void BackgroundVideo_MediaEnded(object sender, RoutedEventArgs e)
{
// Loop the video
BackgroundVideo.Position = TimeSpan.Zero;
BackgroundVideo.Play();
}
private void BackgroundVideo_MediaFailed(object sender, ExceptionRoutedEventArgs e)
{
// If video fails to load, show the fallback background
ShowFallbackBackground();
Console.WriteLine($"Media failed to load: {e.ErrorException.Message}");
}
private void LaunchWoW_Click(object sender, RoutedEventArgs e)
{
try
{
// Try to get WoW path from config
string wowPath = GetSettingFromConfig(WowPathKey);
// Check if path is defined and valid
if (string.IsNullOrEmpty(wowPath) || !File.Exists(wowPath))
{
// Prompt user to select WoW directory
if (!PromptForWowPath())
{
// User cancelled the selection
return;
}
// Get the path that was just saved
wowPath = GetSettingFromConfig(WowPathKey);
}
// Check if user wants to clear cache
bool clearCache = ClearCacheCheckBox.IsChecked ?? false;
if (clearCache)
{
ClearWowCache(wowPath);
}
// Launch WoW and store the process
Process wowProcess = Process.Start(wowPath);
if (wowProcess != null)
{
// Give WoW a moment to start
System.Threading.Thread.Sleep(1500);
// Close the launcher
this.Close();
}
}
catch (Exception ex)
{
MessageBox.Show($"Error launching World of Warcraft: {ex.Message}",
"Launch Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private bool PromptForWowPath()
{
MessageBox.Show("World of Warcraft executable path is not set. Please select your WoW.exe file.",
"Setup Required", MessageBoxButton.OK, MessageBoxImage.Information);
var dialog = new Microsoft.Win32.OpenFileDialog
{
DefaultExt = ".exe",
Filter = "World of Warcraft|Wow.exe|All Executable Files (*.exe)|*.exe",
Title = "Select World of Warcraft Executable",
CheckFileExists = true
};
// Try to set initial directory to common WoW installation paths
string[] commonPaths = new[]
{
@"C:\Program Files (x86)\World of Warcraft\_retail_",
@"C:\Program Files\World of Warcraft\_retail_",
@"D:\World of Warcraft\_retail_",
@"C:\Games\World of Warcraft\_retail_"
};
foreach (string path in commonPaths)
{
if (Directory.Exists(path))
{
dialog.InitialDirectory = path;
break;
}
}
if (dialog.ShowDialog() == true)
{
// User selected a file, save to config
SaveWowPathToConfig(dialog.FileName);
return true;
}
return false;
}
private void ClearCacheCheckBox_CheckedChanged(object sender, RoutedEventArgs e)
{
// Save the current state of the checkbox to config
try
{
bool isChecked = ClearCacheCheckBox.IsChecked ?? false;
SaveSettingToConfig(ClearCacheKey, isChecked.ToString());
}
catch (Exception ex)
{
MessageBox.Show($"Error saving Clear Cache setting: {ex.Message}");
}
}
private void ClearWowCache(string wowPath)
{
try
{
// Get the WoW directory from the executable path
string wowDirectory = Path.GetDirectoryName(wowPath);
// Navigate up one level from _retail_ folder if needed
if (Path.GetFileName(wowDirectory).Equals("_retail_", StringComparison.OrdinalIgnoreCase))
{
wowDirectory = Directory.GetParent(wowDirectory).FullName;
}
// Common cache folder paths for WoW
string[] cachePaths = new string[]
{
Path.Combine(wowDirectory, "_retail_", "Cache"),
Path.Combine(wowDirectory, "Cache"),
Path.Combine(wowDirectory, "_retail_", "WTF", "Cache")
};
foreach (string cachePath in cachePaths)
{
if (Directory.Exists(cachePath))
{
try
{
// Delete all files in the cache directory
foreach (string file in Directory.GetFiles(cachePath, "*", SearchOption.AllDirectories))
{
File.Delete(file);
}
// Delete all subdirectories
foreach (string dir in Directory.GetDirectories(cachePath))
{
Directory.Delete(dir, true);
}
}
catch (Exception ex)
{
// continue
}
}
}
}
catch (Exception ex)
{
// continue
}
}
// Save WoW path to config
private void SaveWowPathToConfig(string wowExecutablePath)
{
try
{
SaveSettingToConfig(WowPathKey, wowExecutablePath);
MessageBox.Show($"World of Warcraft path set successfully to:\n{wowExecutablePath}",
"Path Saved", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (Exception ex)
{
MessageBox.Show($"Error saving WoW path to configuration: {ex.Message}",
"Configuration Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void TitleBar_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
this.DragMove();
}
}
private void CloseButton_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
// Method for manual refresh
public async void ManuallyRefreshContent()
{
await RefreshAllContent();
}
// Optional: Add this method for a refresh button
private async void RefreshButton_Click(object sender, RoutedEventArgs e)
{
var button = sender as Button;
if (button != null)
{
button.IsEnabled = false;
}
try
{
await RefreshAllContent();
}
finally
{
if (button != null)
{
button.IsEnabled = true;
}
}
}
// Helper method to find a TextBlock by its Text property
private TextBlock FindTextBlockByText(string text)
{
return FindVisualChild<TextBlock>(this, tb => tb.Text == text);
}
// Generic method to find visual children
private T FindVisualChild<T>(DependencyObject parent, Func<T, bool> condition) where T : DependencyObject
{
int childCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childCount; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(parent, i);
if (child is T typedChild && condition(typedChild))
{
return typedChild;
}
T result = FindVisualChild<T>(child, condition);
if (result != null)
{
return result;
}
}
return null;
}
}
}