From c0daa300bfaaa9b2f0f69716d6cf53677c35dc84 Mon Sep 17 00:00:00 2001 From: aomizu Date: Sat, 14 Jun 2025 14:28:50 +0900 Subject: [PATCH] added a apply recommended graphics settings button to options --- FyneApp.toml | 2 +- README.md | 1 + pkg/launcher/recommended.go | 135 ++++++++++++++++++++++++++++++++++++ pkg/ui/components.go | 112 ++++++++++++++++++++++++++++++ pkg/ui/popup.go | 5 ++ pkg/ui/status.go | 5 ++ pkg/ui/variables.go | 4 ++ 7 files changed, 263 insertions(+), 1 deletion(-) create mode 100644 pkg/launcher/recommended.go diff --git a/FyneApp.toml b/FyneApp.toml index c9c4f06..e2d03c8 100644 --- a/FyneApp.toml +++ b/FyneApp.toml @@ -3,4 +3,4 @@ Name = "TurtleSilicon" ID = "com.tairasu.turtlesilicon" Version = "1.2.2" - Build = 52 + Build = 57 diff --git a/README.md b/README.md index 4602e79..63d40a9 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ If you prefer to run the application directly from source code: 1. Set "Terrain distance" as low as possible. This reduces the overhead stress on the CPU 2. Turn Vertex Animation Shaders on. Otherwise you get graphic glitches on custom models. 3. Set Multisampling to 24-bit color 24-bit depth **2x** to make portraits load +4. Add `SET shadowLOD "0"` to your Config.wtf inside the WTF directory ## Build Instructions diff --git a/pkg/launcher/recommended.go b/pkg/launcher/recommended.go new file mode 100644 index 0000000..728075e --- /dev/null +++ b/pkg/launcher/recommended.go @@ -0,0 +1,135 @@ +package launcher + +import ( + "fmt" + "os" + "path/filepath" + "regexp" + "strings" + + "turtlesilicon/pkg/debug" + "turtlesilicon/pkg/paths" +) + +// RecommendedSettings contains the recommended graphics settings for optimal performance +var RecommendedSettings = map[string]string{ + "farclip": "177", + "M2UseShaders": "1", + "gxColorBits": "24", + "gxDepthBits": "24", + "gxMultisampleQuality": "0.000000", + "gxMultisample": "2", + "shadowLOD": "0", +} + +// CheckRecommendedSettings reads the Config.wtf file and checks if all recommended settings are applied +// Returns true if all settings are correctly applied, false otherwise +func CheckRecommendedSettings() bool { + if paths.TurtlewowPath == "" { + debug.Printf("TurtleWoW path not set, cannot check Config.wtf") + return false + } + + configPath := filepath.Join(paths.TurtlewowPath, "WTF", "Config.wtf") + + if _, err := os.Stat(configPath); os.IsNotExist(err) { + debug.Printf("Config.wtf not found at %s", configPath) + return false + } + + content, err := os.ReadFile(configPath) + if err != nil { + debug.Printf("Failed to read Config.wtf: %v", err) + return false + } + + configText := string(content) + + // Check each recommended setting + for setting, expectedValue := range RecommendedSettings { + if !isSettingCorrect(configText, setting, expectedValue) { + debug.Printf("Setting %s not found or incorrect in Config.wtf", setting) + return false + } + } + + debug.Printf("All recommended settings are correctly applied") + return true +} + +// isSettingCorrect checks if a specific setting has the correct value in the config text +func isSettingCorrect(configText, setting, expectedValue string) bool { + // Create regex pattern to match the setting + pattern := fmt.Sprintf(`SET\s+%s\s+"([^"]*)"`, regexp.QuoteMeta(setting)) + re := regexp.MustCompile(pattern) + + matches := re.FindStringSubmatch(configText) + if len(matches) < 2 { + return false + } + + currentValue := matches[1] + return currentValue == expectedValue +} + +// ApplyRecommendedSettings applies all recommended graphics settings to Config.wtf +func ApplyRecommendedSettings() error { + if paths.TurtlewowPath == "" { + return fmt.Errorf("TurtleWoW path not set") + } + + configPath := filepath.Join(paths.TurtlewowPath, "WTF", "Config.wtf") + + // Create WTF directory if it doesn't exist + wtfDir := filepath.Dir(configPath) + if err := os.MkdirAll(wtfDir, 0755); err != nil { + return fmt.Errorf("failed to create WTF directory: %v", err) + } + + var configText string + + // Read existing config if it exists + if content, err := os.ReadFile(configPath); err == nil { + configText = string(content) + } else { + debug.Printf("Config.wtf not found, creating new file") + configText = "" + } + + // Apply each recommended setting + for setting, value := range RecommendedSettings { + configText = updateOrAddSetting(configText, setting, value) + } + + // Write the updated config back to file + if err := os.WriteFile(configPath, []byte(configText), 0644); err != nil { + return fmt.Errorf("failed to write Config.wtf: %v", err) + } + + debug.Printf("Successfully applied recommended settings to Config.wtf") + return nil +} + +// updateOrAddSetting updates an existing setting or adds a new one if it doesn't exist +func updateOrAddSetting(configText, setting, value string) string { + // Create regex pattern to match the setting + pattern := fmt.Sprintf(`SET\s+%s\s+"[^"]*"`, regexp.QuoteMeta(setting)) + re := regexp.MustCompile(pattern) + + newSetting := fmt.Sprintf(`SET %s "%s"`, setting, value) + + if re.MatchString(configText) { + // Replace existing setting + configText = re.ReplaceAllString(configText, newSetting) + debug.Printf("Updated setting %s to %s", setting, value) + } else { + // Add new setting + if configText != "" && !strings.HasSuffix(configText, "\n") { + configText += "\n" + } + configText += newSetting + "\n" + debug.Printf("Added new setting %s with value %s", setting, value) + } + + return configText +} diff --git a/pkg/ui/components.go b/pkg/ui/components.go index 3608a9e..6862fac 100644 --- a/pkg/ui/components.go +++ b/pkg/ui/components.go @@ -1,6 +1,7 @@ package ui import ( + "fmt" "net/url" "strings" "time" @@ -13,6 +14,7 @@ import ( "fyne.io/fyne/v2" "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/dialog" "fyne.io/fyne/v2/widget" ) @@ -47,6 +49,35 @@ func createOptionsComponents() { vanillaTweaksCheckbox.SetChecked(prefs.EnableVanillaTweaks) launcher.EnableVanillaTweaks = prefs.EnableVanillaTweaks + // Create recommended settings button with help icon + applyRecommendedSettingsButton = widget.NewButton("Apply recommended settings", func() { + err := launcher.ApplyRecommendedSettings() + if err != nil { + debug.Printf("Failed to apply recommended settings: %v", err) + // Show error dialog if we have a window reference + if currentWindow != nil { + dialog.ShowError(fmt.Errorf("failed to apply recommended settings: %v", err), currentWindow) + } + } else { + debug.Printf("Successfully applied recommended settings") + // Show success dialog if we have a window reference + if currentWindow != nil { + dialog.ShowInformation("Success", "Recommended graphics settings have been applied to Config.wtf", currentWindow) + } + // Update button state + updateRecommendedSettingsButton() + } + }) + applyRecommendedSettingsButton.Importance = widget.MediumImportance + + // Create help button for recommended settings + recommendedSettingsHelpButton = widget.NewButton("?", func() { + showRecommendedSettingsHelpPopup() + }) + recommendedSettingsHelpButton.Importance = widget.MediumImportance + // Initialize button state + updateRecommendedSettingsButton() + // Create Wine registry Option-as-Alt buttons and status createWineRegistryComponents() @@ -350,3 +381,84 @@ func stopPulsingEffect() { pulsingTicker = nil } } + +// updateRecommendedSettingsButton updates the state of the recommended settings button +func updateRecommendedSettingsButton() { + if applyRecommendedSettingsButton == nil { + return + } + + // Check if all recommended settings are already applied + if launcher.CheckRecommendedSettings() { + applyRecommendedSettingsButton.Disable() + applyRecommendedSettingsButton.SetText("Settings applied") + } else { + applyRecommendedSettingsButton.Enable() + applyRecommendedSettingsButton.SetText("Apply recommended settings") + } + + // Help button should always be enabled + if recommendedSettingsHelpButton != nil { + recommendedSettingsHelpButton.Enable() + } +} + +// showRecommendedSettingsHelpPopup shows a popup explaining the recommended graphics settings +func showRecommendedSettingsHelpPopup() { + if currentWindow == nil { + return + } + + // Create help content + helpTitle := widget.NewRichTextFromMarkdown("# 📋 Recommended Graphics Settings") + + // Create individual setting labels for better formatting + settingsTitle := widget.NewLabel("The following settings will be applied to your Config.wtf file:") + settingsTitle.TextStyle = fyne.TextStyle{Bold: true} + + setting1 := widget.NewLabel("• Terrain Distance (farclip): 177 - Reduces CPU overhead - more fps") + setting2 := widget.NewLabel("• Vertex Animation Shaders (M2UseShaders): Enabled - Prevents graphic glitches") + setting3 := widget.NewLabel("• Multisampling (gxMultisample): 2x - Makes portraits load properly") + setting4 := widget.NewLabel("• Shadow LOD (shadowLOD): 0 - 10% fps increase") + + settingsContainer := container.NewVBox( + settingsTitle, + widget.NewSeparator(), + setting1, + setting2, + setting3, + setting4, + widget.NewSeparator(), + ) + + // Create OK button + okButton := widget.NewButton("OK", func() { + // This will be set when the popup is created + }) + okButton.Importance = widget.MediumImportance + + // Create help content container + helpContentContainer := container.NewVBox( + container.NewCenter(helpTitle), + widget.NewSeparator(), + settingsContainer, + widget.NewSeparator(), + container.NewCenter(okButton), + ) + + // Calculate popup size + windowSize := currentWindow.Content().Size() + popupWidth := windowSize.Width * 3 / 4 + popupHeight := windowSize.Height * 3 / 4 + + // Create the help popup + helpPopup := widget.NewModalPopUp(container.NewPadded(helpContentContainer), currentWindow.Canvas()) + helpPopup.Resize(fyne.NewSize(popupWidth, popupHeight)) + + // Set the OK button action to hide the help popup + okButton.OnTapped = func() { + helpPopup.Hide() + } + + helpPopup.Show() +} diff --git a/pkg/ui/popup.go b/pkg/ui/popup.go index 3e0ba17..59bac47 100644 --- a/pkg/ui/popup.go +++ b/pkg/ui/popup.go @@ -15,6 +15,9 @@ func showOptionsPopup() { // Create options content with better organization and smaller titles optionsTitle := widget.NewLabel("Options") optionsTitle.TextStyle = fyne.TextStyle{Bold: true} + // Create label for recommended settings + recommendedSettingsLabel := widget.NewLabel("Graphics settings:") + gameOptionsContainer := container.NewVBox( optionsTitle, widget.NewSeparator(), @@ -22,6 +25,8 @@ func showOptionsPopup() { showTerminalCheckbox, vanillaTweaksCheckbox, widget.NewSeparator(), + container.NewBorder(nil, nil, recommendedSettingsLabel, container.NewHBox(applyRecommendedSettingsButton, recommendedSettingsHelpButton), nil), + widget.NewSeparator(), container.NewBorder(nil, nil, nil, container.NewHBox(enableOptionAsAltButton, disableOptionAsAltButton), optionAsAltStatusLabel), ) diff --git a/pkg/ui/status.go b/pkg/ui/status.go index 37b37b1..91cf6ae 100644 --- a/pkg/ui/status.go +++ b/pkg/ui/status.go @@ -30,6 +30,11 @@ func UpdateAllStatuses() { if optionAsAltStatusLabel != nil { updateWineRegistryStatus() } + + // Update recommended settings button if component is initialized + if applyRecommendedSettingsButton != nil { + updateRecommendedSettingsButton() + } } // updateCrossoverStatus updates CrossOver path and patch status diff --git a/pkg/ui/variables.go b/pkg/ui/variables.go index 817a0e1..164c85e 100644 --- a/pkg/ui/variables.go +++ b/pkg/ui/variables.go @@ -32,6 +32,10 @@ var ( showTerminalCheckbox *widget.Check vanillaTweaksCheckbox *widget.Check + // Recommended settings button + applyRecommendedSettingsButton *widget.Button + recommendedSettingsHelpButton *widget.Button + // Wine registry buttons and status enableOptionAsAltButton *widget.Button disableOptionAsAltButton *widget.Button