diff --git a/stellaris_mod_lang_patcher/MainWindow.xaml b/stellaris_mod_lang_patcher/MainWindow.xaml index 0647c0e..a4da55a 100644 --- a/stellaris_mod_lang_patcher/MainWindow.xaml +++ b/stellaris_mod_lang_patcher/MainWindow.xaml @@ -5,39 +5,41 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:stellaris_mod_lang_patcher" mc:Ignorable="d" - Title="Stellaris Mod Language Patcher" Height="850" Width="600"> + Title="Stellaris Mod Language Patcher" Height="600" Width="800"> - - - - C:\Program Files (x86)\Steam\steamapps\workshop\content\281990 - - - - - - - - - english - - korean - - - - - - - - - - - - - - - - - + + + + + + + + C:\Program Files (x86)\Steam\steamapps\workshop\content\281990 + + + + + + + + + english + + korean + + + + + + + + + + + + + + + diff --git a/stellaris_mod_lang_patcher/MainWindow.xaml.cs b/stellaris_mod_lang_patcher/MainWindow.xaml.cs index 11fdf07..b9c18e0 100644 --- a/stellaris_mod_lang_patcher/MainWindow.xaml.cs +++ b/stellaris_mod_lang_patcher/MainWindow.xaml.cs @@ -21,10 +21,86 @@ public partial class MainWindow : Window { string mod_folder_path = @"C:\Program Files (x86)\Steam\steamapps\workshop\content\281990"; List mods = null; + private enum ProgramState { INVALID, IDLE, RUNNING, ERROR } + ProgramState current_state = ProgramState.IDLE; + object state_lock = new object(); + + Dictionary> force_patch_dict = new Dictionary> { + { "korean", new List { + "2703186360", // MKC Addon: AlphaMod + "2524944243", // MKC Addon: Gigastructural Engineering & More + "2420144001", // MKC Addon : Planetary Diversity Korean Translation + "2524947989", // MKC Addon: NSC2 Season 6 + "2533584571", // MKC Addon: Ethics and Civics Alternative - Redux + "2789326040", // MKC Addon: Real Space - New Frontiers + "2547749868", // MKC Addon: Ethics and Civics Classic 3.0 + "2703189043", // MKC Addon: EUTAB - Ethos Unique Techs and Buildings + "2506141839", // Mod Korean Collection: 모드 한국어 모음 + "2747894657", // Korean Language(Korean name) + } } + }; + + Dictionary file_name_typo_dict = new Dictionary + { + { "l_koean", "l_korean" } + }; + + private bool ChangeState(ProgramState next_state, ProgramState condition = ProgramState.INVALID) + { + lock (state_lock) + { + if (condition != ProgramState.INVALID && condition != current_state) + { + return false; + } + + current_state = next_state; + + + Dispatcher.Invoke(() => + { + switch (current_state) + { + case ProgramState.IDLE: + Title = "Stellaris Mod Language Patcher - Idle"; + Button_LoadModList.IsEnabled = true; + Button_Patch.IsEnabled = mods != null; + TextBox_From.IsEnabled = true; + TextBox_To.IsEnabled = true; + TextBox_Mod_Folder.IsEnabled = true; + break; + case ProgramState.RUNNING: + Title = "Stellaris Mod Language Patcher - Running"; + Button_LoadModList.IsEnabled = false; + Button_Patch.IsEnabled = false; + TextBox_From.IsEnabled = false; + TextBox_To.IsEnabled = false; + TextBox_Mod_Folder.IsEnabled = false; + break; + case ProgramState.ERROR: + Title = "Stellaris Mod Language Patcher - Error"; + Button_LoadModList.IsEnabled = false; + Button_Patch.IsEnabled = false; + TextBox_From.IsEnabled = false; + TextBox_To.IsEnabled = false; + TextBox_Mod_Folder.IsEnabled = false; + break; + } + }); + + return true; + } + } + public MainWindow() { InitializeComponent(); + ChangeState(ProgramState.RUNNING); TextBox_Mod_Folder.Text = mod_folder_path; + + DataGridTextColumn_From.Header = "Support " + TextBox_From.Text; + DataGridTextColumn_To.Header = "Support " + TextBox_To.Text; + ChangeState(ProgramState.IDLE); } public List LoadModList(string path, string from, string to) @@ -51,19 +127,20 @@ public List LoadModList(string path, string from, string to) string[]? splited = line?.Split("="); if (splited?.Length >= 2 && splited[0].Trim() == "name") { - mod.Name = "(" + mod.Code + ")\t" + splited[1].Trim().Trim('"'); + mod.Name = splited[1].Trim().Trim('"'); } } } var localisation_folder = new DirectoryInfo(System.IO.Path.Join(mod_folder.FullName, "localisation")); - if (!localisation_folder.Exists) + var localisation_synced_folder = new DirectoryInfo(System.IO.Path.Join(mod_folder.FullName, "localisation_synced")); + if (!localisation_folder.Exists && !localisation_synced_folder.Exists) { continue; } var from_folder = new DirectoryInfo(System.IO.Path.Join(localisation_folder.FullName, from)); mod.HasFrom = from_folder.Exists; - + var to_folder = new DirectoryInfo(System.IO.Path.Join(localisation_folder.FullName, to)); mod.HasTo = to_folder.Exists; @@ -93,27 +170,40 @@ public List LoadModList(string path, string from, string to) continue; } - if (mod.HasFrom && !mod.HasTo) - { - mod_list.Add(mod); - } + mod_list.Add(mod); } return mod_list; } - private void Button_LoadModList_Click(object sender, RoutedEventArgs e) + private async void Button_LoadModList_Click(object sender, RoutedEventArgs e) + { + if (!ChangeState(ProgramState.RUNNING, ProgramState.IDLE)) + { + return; + } + await UpdateModList(); + ChangeState(ProgramState.IDLE); + } + + private async Task UpdateModList() { try { mod_folder_path = TextBox_Mod_Folder.Text; + string from = TextBox_From.Text; string to = TextBox_To.Text; - var mod_list = LoadModList(mod_folder_path, from, to); + var mod_list = await Task.Run(() => + { + return LoadModList(mod_folder_path, from, to); + }); - DataContext = mod_list; + DataGridTextColumn_From.Header = "Support " + TextBox_From.Text; + DataGridTextColumn_To.Header = "Support " + TextBox_To.Text; + Mod_List.DataContext = mod_list; mods = mod_list; } catch (Exception ex) @@ -121,6 +211,7 @@ private void Button_LoadModList_Click(object sender, RoutedEventArgs e) MessageBox.Show(ex.Message); } } + private void CopyFolder(string src, string dist) { foreach (string dirPath in Directory.GetDirectories(src, "*", SearchOption.AllDirectories)) @@ -129,12 +220,17 @@ private void CopyFolder(string src, string dist) } foreach (string newPath in Directory.GetFiles(src, "*.*", SearchOption.AllDirectories)) { - File.Copy(newPath, newPath.Replace(src, dist), true); + File.Copy(newPath, newPath.Replace(src, dist), false); } } - private void Button_Patch_Click(object sender, RoutedEventArgs e) + private async void Button_Patch_Click(object sender, RoutedEventArgs e) { + if (!ChangeState(ProgramState.RUNNING, ProgramState.IDLE)) + { + return; + } + try { if (mods == null) @@ -142,22 +238,79 @@ private void Button_Patch_Click(object sender, RoutedEventArgs e) return; } - string from = TextBox_From.Text; - string to = TextBox_To.Text; + await PatchMods(mods); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + ChangeState(ProgramState.ERROR); + return; + } - string l_from = "l_" + from; - string l_to = "l_" + to; + await UpdateModList(); + ChangeState(ProgramState.IDLE); + MessageBox.Show("Done"); + } - foreach (var mod in mods) + public async Task PatchMods(List mods) + { + string from = TextBox_From.Text; + string to = TextBox_To.Text; + + string l_from = "l_" + from; + string l_to = "l_" + to; + + await Parallel.ForEachAsync(mods, async (mod, token) => + { + await Task.Run(() => { - // from 폴더를 to 폴더로 복사 + // 파일명에 오타 있는 경우 수정 + { + Queue q = new Queue(); + if (mod.Folder == null) + { + return; + } + + q.Enqueue(mod.Folder); + while (q.Count > 0) + { + var root = q.Dequeue(); + + foreach (var file in root.GetFiles()) + { + foreach (var typo in file_name_typo_dict.Keys) + { + if (file.Name.Contains(typo)) + { + string new_file_path = System.IO.Path.Join(root.FullName, file.Name.Replace(typo, file_name_typo_dict[typo])); + var new_file = new FileInfo(new_file_path); + + if (new_file.Exists) + { + continue; + } + + File.Move(file.FullName, new_file.FullName); + } + } + } + + foreach (var dir in root.GetDirectories()) + { + q.Enqueue(dir); + } + } + } + + // from 폴더에 있는 파일들을 to 폴더로 복사 List from_folders = new List(); List to_folders = new List(); { Queue q = new Queue(); if (mod.Folder == null) { - continue; + return; } q.Enqueue(mod.Folder); @@ -195,7 +348,7 @@ private void Button_Patch_Click(object sender, RoutedEventArgs e) Queue q = new Queue(); if (mod.Folder == null) { - continue; + return; } q.Enqueue(mod.Folder); @@ -213,7 +366,7 @@ private void Button_Patch_Click(object sender, RoutedEventArgs e) if (file.Name.Contains(l_from)) { string new_file_path = System.IO.Path.Join(root.FullName, file.Name.Replace(from, to)); - var new_file = new DirectoryInfo(new_file_path); + var new_file = new FileInfo(new_file_path); if (new_file.Exists) { continue; @@ -244,7 +397,7 @@ private void Button_Patch_Click(object sender, RoutedEventArgs e) if (file.Name.Contains(l_from)) { string new_file_path = System.IO.Path.Join(to_folder.FullName, file.Name.Replace(from, to)); - var new_file = new DirectoryInfo(new_file_path); + var new_file = new FileInfo(new_file_path); if (new_file.Exists) { continue; @@ -260,12 +413,132 @@ private void Button_Patch_Click(object sender, RoutedEventArgs e) } } } + }); + }); + + // 기존 번역 모드들을 수정함 + { + UpdateRegacyTranslationMods(mod_folder_path, from, to); + } + + // 한글 이름 모드를 수정함 + { + foreach (var mod in mods) + { + if (mod.Code == "2747894657") + { + string localisation_synced_path = System.IO.Path.Join(mod.Folder.FullName, "localisation_synced"); + var localisation_synced = new DirectoryInfo(localisation_synced_path); + foreach (var file in localisation_synced.GetFiles()) + { + bool is_first = true; + string file_text = File.ReadAllText(file.FullName); + StringReader reader = new StringReader(file_text); + string result = ""; + while (true) + { + string? line = reader.ReadLine(); + if (line == null) + { + break; + } + + if (line.Contains(":") && is_first) + { + result += line + "\n"; + is_first = false; + continue; + } + + result += line.Replace(": ", ":0 ") + "\n"; + } + + File.WriteAllText(file.FullName, result, new UTF8Encoding(true)); + } + } } - MessageBox.Show("Done"); + } - catch (Exception ex) + } + + public void UpdateRegacyTranslationMods(string path, string from, string to) + { + DirectoryInfo di = new DirectoryInfo(path); + + var mod_folders = di.GetDirectories(); + + string l_from = "l_" + from; + string l_to = "l_" + to; + foreach (var mod_folder in mod_folders) { - MessageBox.Show(ex.Message); + bool is_regacy = force_patch_dict.ContainsKey(to) && force_patch_dict[to].Contains(mod_folder.Name); + if (!is_regacy) + { + continue; + } + + try + { + Queue q = new Queue(); + q.Enqueue(mod_folder); + while (q.Count > 0) + { + var root = q.Dequeue(); + + foreach (var file in root.GetFiles()) + { + if (file.Name.Contains(l_to)) + { + string t = File.ReadAllText(file.FullName); + t = t.Replace(l_from, l_to); + File.WriteAllText(file.FullName, t, new UTF8Encoding(true)); + } + } + + foreach (var dir in root.GetDirectories()) + { + q.Enqueue(dir); + } + } + } + catch (Exception) + { + continue; + } + + try + { + var localisation_folder = new DirectoryInfo(System.IO.Path.Join(mod_folder.FullName, "localisation")); + if (!localisation_folder.Exists) + { + continue; + } + + var korean_folder = new DirectoryInfo(System.IO.Path.Join(localisation_folder.FullName, "korean")); + if (!korean_folder.Exists) + { + korean_folder.Create(); + } + + foreach (var file in localisation_folder.GetFiles()) + { + if (file.Name.Contains(l_to)) + { + var new_file_path = System.IO.Path.Join(korean_folder.FullName, file.Name); + var new_file = new FileInfo(new_file_path); + if (new_file.Exists) + { + continue; + } + + File.Copy(file.FullName, new_file.FullName); + } + } + } + catch (Exception) + { + continue; + } } } } diff --git a/stellaris_mod_lang_patcher/stellaris_mod_lang_patcher.csproj b/stellaris_mod_lang_patcher/stellaris_mod_lang_patcher.csproj index 4106cb0..b1fa445 100644 --- a/stellaris_mod_lang_patcher/stellaris_mod_lang_patcher.csproj +++ b/stellaris_mod_lang_patcher/stellaris_mod_lang_patcher.csproj @@ -5,6 +5,10 @@ net6.0-windows enable true + stellaris_mod_lang_patcher.App + 1.1.0.0 + 1.1.0.0 + 1.1.0