internal TranslationDescription(Leayal.Ini.IniFile rawdata) { this.inifile = rawdata; this.descripList = new List <Description>(); var sections = rawdata.Sections; if (sections.Count > 0) { foreach (string section in sections) { this.descripList.Add(new Description(section, rawdata.GetValue(section, "path", string.Empty), rawdata.GetValue(section, "path_a", string.Empty), rawdata.GetValue(section, "path_d", string.Empty), rawdata.GetValue(section, "format", string.Empty) )); } } }
private void BWorker_DoWork(object sender, DoWorkEventArgs e) { WorkerArguments args = e.Argument as WorkerArguments; if (args == null) { throw new InvalidOperationException("Something went wrong, this is out of design."); } var fileinfo = args.TranslationResource.GetCurrentLanguageFile(); string currentLanguage = args.TranslationResource.SelectedLanguage, currentRegion = args.TranslationResource.SelectedClientRegion, gamedata12 = Path.Combine(args.GameDirectory, "datas", "data12.v"), outputpath = args.OutputPath; // Directly read the game resource and make a copy of the .res file in the memory ??? if (!File.Exists(gamedata12)) { throw new FileNotFoundException("Can not find original data file.", gamedata12); } if (!fileinfo.Exists) { throw new TranslationFileNotFoundException("Can not find translation files.", fileinfo.FullName); } // Get the file password and make it as a pre-list TranslationDescription transDesc; System.Collections.Concurrent.ConcurrentDictionary <string, string> encryptions = new System.Collections.Concurrent.ConcurrentDictionary <string, string>(StringComparer.OrdinalIgnoreCase); // Read our derped translation files using (ZipFile translationzf = ZipFile.Read(fileinfo.FullName)) { // Password file using (Stream entryStream = translationzf["datas.ini"].OpenReader()) using (StreamReader sr = new StreamReader(entryStream)) { Leayal.Ini.IniFile afile = new Leayal.Ini.IniFile(sr); foreach (var keyValue in afile.GetAllValues("Zip Passwords")) { if (!keyValue.Value.IsComment) { encryptions.TryAdd(keyValue.Key, keyValue.Value.Value); } } afile.Close(); } // Translation Description file using (Stream entryStream = translationzf["TranslationPackData.ini"].OpenReader()) using (StreamReader sr = new StreamReader(entryStream)) { Leayal.Ini.IniFile afile = new Leayal.Ini.IniFile(sr); transDesc = new TranslationDescription(afile); afile.Close(); } using (FileStream fs = File.OpenRead(gamedata12)) // Wrap the FileStream in XorStream so we can use ZipFile class directly. using (XorStream xoredStream = new XorStream(fs, LionGameSecretByte)) using (ZipFile zf = ZipFile.Read(xoredStream)) { string[] splittedStr; DataFormatBuilder formatBuilder = new DataFormatBuilder(); zf.CompressionLevel = Ionic.Zlib.CompressionLevel.BestSpeed; if (encryptions.ContainsKey("data12")) { zf.Password = encryptions["data12"]; } System.Collections.Generic.Dictionary <string, Leayal.IO.RecyclableMemoryStream> somethingliawhglaihwg = new System.Collections.Generic.Dictionary <string, Leayal.IO.RecyclableMemoryStream>(StringComparer.OrdinalIgnoreCase); for (int i = 0; i < transDesc.Descriptions.Length; i++) { if (transDesc.Descriptions[i].TargetData.EndsWith("data12.v", StringComparison.OrdinalIgnoreCase)) // Build only for data12.v { formatBuilder.Clear(); if (this.bWorker.CancellationPending) { break; } this.OnBuildProgressChanged(new ProgressBarValueEventArgs(i + 1, transDesc.Descriptions.Length)); TranslationDescription.Description desc = transDesc.Descriptions[i]; this.OnBuildStepChanged(new StringEventArgs(Path.GetFileName(desc.PathTXT))); splittedStr = desc.ResourceFormat.Split(' '); formatBuilder.CountDataType = (DataType)Leayal.NumberHelper.Parse(splittedStr[1]); formatBuilder.IDIndex = Leayal.NumberHelper.Parse(splittedStr[0]); for (int splittedCount = 2; splittedCount < splittedStr.Length; splittedCount++) { if (!string.IsNullOrEmpty(splittedStr[splittedCount])) { formatBuilder.Append(splittedStr[splittedCount]); } } DataFormat readformat = formatBuilder.ToDataFormat(); TranslationDatabase translatedb; using (Stream transText = translationzf[desc.PathTXT].OpenReader()) using (StreamReader sr = new StreamReader(transText)) { translatedb = TranslationDatabase.From(sr, readformat); } // Read the source resource here. Ionic.Crc.CrcCalculatorStream dataStream; if (encryptions.ContainsKey("data12")) { dataStream = zf[desc.PathInsideArchieve].OpenReader(encryptions["data12"]); } else { dataStream = zf[desc.PathInsideArchieve].OpenReader(); } System.Collections.Generic.List <ResourceData[]> databuffer; using (dataStream) using (ResourceReader rr = new ResourceReader(dataStream, readformat, true)) databuffer = rr.ReadToEnd(); Leayal.IO.RecyclableMemoryStream memoryEntry = new Leayal.IO.RecyclableMemoryStream(desc.PathInsideArchieve); somethingliawhglaihwg.Add(Path.GetFileName(desc.PathInsideArchieve), memoryEntry); ResourceData[] currentnode; using (ResourceWriter sw = new ResourceWriter(memoryEntry, readformat, true)) for (int writeEntryCount = 0; writeEntryCount < databuffer.Count; writeEntryCount++) { currentnode = databuffer[writeEntryCount]; // Apply translation here currentnode = translatedb.ApplyTranslation(currentnode); sw.WriteEntry(currentnode); } zf.UpdateEntry(desc.PathInsideArchieve, new WriteDelegate((filename, writeStream) => { var memStream = somethingliawhglaihwg[Path.GetFileName(filename)]; writeStream.Write(memStream.GetBuffer(), 0, (int)memStream.Length); })); } } if (!this.bWorker.CancellationPending) { // Get client version (again) Leayal.Ini.IniFile inifile = new Leayal.Ini.IniFile(Path.Combine(args.GameDirectory, "ver.ini")); string clientVer = inifile.GetValue("Client", "ver", string.Empty); if (string.IsNullOrWhiteSpace(clientVer)) { clientVer = "Unknown"; } outputpath = Path.Combine(args.OutputPath, $"SoulWorker{args.TranslationResource.SelectedClientRegion.ToUpper()} {args.TranslationResource.SelectedLanguage} Patch for client v{clientVer}.zip"); inifile.Close(); Microsoft.VisualBasic.FileIO.FileSystem.CreateDirectory(args.OutputPath); File.Delete(outputpath); using (ZipFile outputzf = new ZipFile(outputpath, System.Text.Encoding.UTF8)) { outputzf.AddEntry($"{args.TranslationResource.SelectedLanguage}\\data12.v", new WriteDelegate((_entryName, _entryStream) => { using (XorStream writeout = new XorStream(_entryStream, LionGameSecretByte)) { zf.Save(writeout); } })); outputzf.AddFile(gamedata12, "original"); outputzf.AddEntry("version.txt", $"100% compatible with SoulWorker{args.TranslationResource.SelectedClientRegion.ToUpper()} client v{clientVer}", System.Text.Encoding.UTF8); outputzf.Save(); } } foreach (Leayal.IO.RecyclableMemoryStream memStream in somethingliawhglaihwg.Values) { memStream.Dispose(); } somethingliawhglaihwg.Clear(); } } if (this.bWorker.CancellationPending) { e.Cancel = true; } else { // Return the fullpath of output e.Result = new BuildResult(currentRegion, currentLanguage, "PatchVersion", outputpath); } }
private void BuildPatch_Click(object sender, RoutedEventArgs e) { string targetlocation = this.textBox_gamelocation.Text, verlocation = Leayal.IO.PathHelper.Combine(targetlocation, "Ver.ini"); if (!string.IsNullOrWhiteSpace(targetlocation) && System.IO.File.Exists(verlocation)) { Leayal.Ini.IniFile verIni = new Leayal.Ini.IniFile(verlocation); if (MessageBox.Show(this, $"Do you want to build Translation Patch for SoulWorker client v{verIni.GetValue("Client", "ver", "Unknown")}?\nIf the game client has any new updates, it is RECOMMENDED for you to build a new patch after the updates.", "Confirmation", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) { this.config.Save(System.Text.Encoding.UTF8); this._patchcontroller.OutputPatchFilename = this.textBox_outputfile.Text; this._patchcontroller.BuildPatchAsync(targetlocation); } verIni.Close(); } else { MessageBox.Show(this, $"Can not find the file 'Ver.ini' in '{targetlocation}'.", "FileNotFoundException", MessageBoxButton.OK, MessageBoxImage.Error); } }
protected override bool OnStartup(StartupEventArgs eventArgs) { this._wrapperform = new WrapperForm(); this.MainForm = this._wrapperform; try { config = new Leayal.Ini.IniFile(Path.Combine(this.Info.DirectoryPath, "BnSLaunchWrapper.ini")); if (config.IsEmpty) { config.SetValue("Wrapper", "bKeepRunning", "0"); config.SetValue("Wrapper", "bCheckNullParams", "1"); config.SetValue("Wrapper", "sExecutable", "RealClient.exe"); config.SetValue("Wrapper", "sAdditionParams", string.Empty); config.SetValue("UnrealEngineParams", "bUnattended", "1"); config.SetValue("UnrealEngineParams", "bNoTextureStreaming", "0"); config.SetValue("UnrealEngineParams", "bUseAllAvailableCores", "1"); config.SetValue("Mods", "Enable xml.dat swap", "0"); config.SetValue("Mods", "Optimize loading", "0"); config.SetValue("Mods", "Enable xml.dat auto-patching", "0"); config.SetValue("xml.dat swap", "ignore warning", "0"); config.SetValue("xml.dat swap", "original xml.dat", string.Empty); config.SetValue("xml.dat swap", "modded xml.dat", string.Empty); config.SetValue("xml.dat swap", "original sha256 hash", string.Empty); config.SetValue("xml.dat patching", "patcher path", string.Empty); config.SetValue("xml.dat patching", "patch info folder", string.Empty); config.SetValue("xml.dat patching", "working directory", string.Empty); config.SetValue("Optimize Loading", "GameFolder", string.Empty); config.SetValue("Optimize Loading", "BackupFolder", string.Empty); config.SetValue("Optimize Loading", "Files", "00009368.upk;Loading.pkg"); config.SetValue("DiscordApp", "Enable Rich Presence", "0"); config.SetValue("DiscordApp", "ClientID", string.Empty); } List <string> cmdlines = new List <string>(eventArgs.CommandLine); if (Path.IsPathRooted(cmdlines[0]) && cmdlines[0].EndsWith(Path.GetFileName(AppInfo.ProcessFullpath), StringComparison.OrdinalIgnoreCase) && Leayal.StringHelper.IsEqual(Path.GetFullPath(cmdlines[0]), AppInfo.ProcessFullpath, true)) { cmdlines.RemoveAt(0); } if (config.GetValue("Wrapper", "bCheckNullParams", "1") != "0") { if (cmdlines.Count == 0) { this.ExitProgram(1); } } string fullexepath = config.GetValue("Wrapper", "sExecutable", string.Empty); if (string.IsNullOrWhiteSpace(fullexepath)) { this.ExitProgram(2); } else { fullexepath = Path.GetFullPath(fullexepath); } if (File.Exists(fullexepath)) { if (config.GetValue("UnrealEngineParams", "bUnattended", "1") != "0") { if (!cmdlines.Contains("-UNATTENDED", StringComparer.OrdinalIgnoreCase)) { cmdlines.Add("-UNATTENDED"); } } if (config.GetValue("UnrealEngineParams", "bNoTextureStreaming", "0") != "0") { if (!cmdlines.Contains("-NOTEXTURESTREAMING", StringComparer.OrdinalIgnoreCase)) { cmdlines.Add("-NOTEXTURESTREAMING"); } } if (config.GetValue("UnrealEngineParams", "bUseAllAvailableCores", "1") != "0") { if (!cmdlines.Contains("-USEALLAVAILABLECORES", StringComparer.OrdinalIgnoreCase)) { cmdlines.Add("-USEALLAVAILABLECORES"); } } StringBuilder strBuilder = new StringBuilder(ProcessHelper.TableStringToArgs(cmdlines)); string configArgs = config.GetValue("Wrapper", "sAdditionParams", string.Empty); if (!string.IsNullOrWhiteSpace(configArgs)) { strBuilder.Append(" "); strBuilder.Append(configArgs); } this.gameProcess = new Process() { StartInfo = new ProcessStartInfo() { Arguments = strBuilder.ToString(), FileName = fullexepath, Verb = "runas" } }; keeprunning = (config.GetValue("Wrapper", "bKeepRunning", "0") != "0"); optimizeLoading = (config.GetValue("Mods", "Optimize loading", "0") != "0"); bool swap_ignorewarning = (config.GetValue("xml.dat swap", "ignore warning", "0") != "0"), autopatching = (config.GetValue("Mods", "Enable xml.dat auto-patching", "0") != "0"), discord_enableRP = (config.GetValue("DiscordApp", "Enable Rich Presence", "0") != "0"); optLoading_from = config.GetValue("Optimize Loading", "GameFolder", string.Empty); optLoading_to = config.GetValue("Optimize Loading", "BackupFolder", string.Empty); string xml_ori = config.GetValue("xml.dat swap", "original xml.dat", string.Empty), xml_modded = config.GetValue("xml.dat swap", "modded xml.dat", string.Empty), original_hash = config.GetValue("xml.dat swap", "original sha256 hash", string.Empty), optLoading_filelist = config.GetValue("Optimize Loading", "Files", string.Empty), patcher_path = config.GetValue("xml.dat patching", "patcher path", string.Empty), patcher_pathinfo = config.GetValue("xml.dat patching", "patch info folder", string.Empty), patcher_workingdir = config.GetValue("xml.dat patching", "working directory", string.Empty), discord_clientID = config.GetValue("DiscordApp", "ClientID", string.Empty); if (keeprunning) { if (config.GetValue("Mods", "enable xml.dat swap", "0") != "0") { if (!string.IsNullOrWhiteSpace(xml_ori) && File.Exists(xml_ori)) { if (!string.IsNullOrWhiteSpace(xml_modded)) { xml_ori = Path.GetFullPath(xml_ori); xml_modded = Path.GetFullPath(xml_modded); bool xml_modded_exist = File.Exists(xml_modded), patcher_path_exist = File.Exists(patcher_path), patcher_pathinfo_exist = Directory.Exists(patcher_pathinfo), patcher_pathinfo_empty = patcher_pathinfo_exist ? Leayal.IO.DirectoryHelper.IsFolderEmpty(patcher_pathinfo) : true, safetoswap = false; string currenthash = null; if (autopatching && !xml_modded_exist) { if (patcher_path_exist && patcher_pathinfo_exist && !patcher_pathinfo_empty) { if (MessageBox.Show(this.GetWrapperForm(), "The modded xml.dat has not been created yet. Do you want to create it?", "Question", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.Yes) { using (Process patchingProc = new Process()) { patchingProc.StartInfo.FileName = patcher_path; List <string> paramList = new List <string>(5); paramList.Add("/p"); paramList.Add(xml_ori); paramList.Add(patcher_pathinfo); paramList.Add("-o"); paramList.Add(xml_modded); if (!string.IsNullOrWhiteSpace(patcher_workingdir)) { Microsoft.VisualBasic.FileIO.FileSystem.CreateDirectory(patcher_workingdir); paramList.Add(patcher_workingdir); } patchingProc.StartInfo.Arguments = ProcessHelper.TableStringToArgs(paramList); patchingProc.Start(); patchingProc.WaitForExit(); if (patchingProc.ExitCode == 0) { if (string.IsNullOrEmpty(currenthash)) { currenthash = Leayal.Security.Cryptography.SHA256Wrapper.HashFromFile(xml_ori); } config.SetValue("xml.dat swap", "original sha256 hash", currenthash); safetoswap = true; xml_modded_exist = true; } } } } } if (xml_modded_exist) { if (swap_ignorewarning) { safetoswap = true; } else { if (string.IsNullOrEmpty(currenthash)) { currenthash = Leayal.Security.Cryptography.SHA256Wrapper.HashFromFile(xml_ori); } if (string.IsNullOrWhiteSpace(original_hash)) { config.SetValue("xml.dat swap", "original sha256 hash", currenthash); safetoswap = true; } else { if (currenthash.IsEqual(original_hash, true)) { safetoswap = true; } else { // Throw warning and exit. this._wrapperform.Show(); bool patchsuccess = false; if (autopatching && patcher_path_exist && patcher_pathinfo_exist && !patcher_pathinfo_empty) { if (MessageBox.Show(this.GetWrapperForm(), "The original xml.dat has been changed. Do you want to patch it?", "Question", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.Yes) { using (Process patchingProc = new Process()) { patchingProc.StartInfo.FileName = patcher_path; List <string> paramList = new List <string>(5); paramList.Add("-p"); paramList.Add(xml_ori); paramList.Add(xml_modded); paramList.Add(patcher_pathinfo); if (!string.IsNullOrWhiteSpace(patcher_workingdir)) { Microsoft.VisualBasic.FileIO.FileSystem.CreateDirectory(patcher_workingdir); paramList.Add(patcher_workingdir); } patchingProc.StartInfo.Arguments = ProcessHelper.TableStringToArgs(paramList); patchingProc.Start(); patchingProc.WaitForExit(); if (patchingProc.ExitCode == 0) { config.SetValue("xml.dat swap", "original sha256 hash", currenthash); safetoswap = true; patchsuccess = true; } } } } if (!patchsuccess) { if (MessageBox.Show(this.GetWrapperForm(), "The original xml.dat has been changed. You should rebuild/update your modded xml.dat file, otherwise unexpected results may happen.\nIgnore hash check for current version and continue?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.Yes) { config.SetValue("xml.dat swap", "original sha256 hash", currenthash); safetoswap = true; } else { this.ExitProgram(1); } } } } } if (safetoswap) { swapFileResult = SwapFile(xml_ori, xml_modded, Path.ChangeExtension(xml_ori, ".original")); if (swapFileResult.Error == null) { swapfile_swapped = true; } else { this._wrapperform.Show(); if (MessageBox.Show(this.GetWrapperForm(), "An error has been occured. Start game anyway???\nError detail: " + swapFileResult.Error.ToString(), "Error while swapping file.", MessageBoxButtons.YesNo, MessageBoxIcon.Error) != DialogResult.Yes) { this.ExitProgram(2); } } } } } } } if (optimizeLoading) { if (!string.IsNullOrWhiteSpace(optLoading_from) && !string.IsNullOrWhiteSpace(optLoading_to) && !string.IsNullOrWhiteSpace(optLoading_filelist)) { optLoading_from = Path.GetFullPath(optLoading_from); optLoading_to = Path.GetFullPath(optLoading_to); if (Directory.Exists(optLoading_from)) { string[] files; if (optLoading_filelist.IndexOf(';') > -1) { files = optLoading_filelist.Split(';'); } else { files = new string[] { optLoading_filelist } }; Microsoft.VisualBasic.FileIO.FileSystem.CreateDirectory(optLoading_to); if (files.Length > 0) { filelist = new List <string>(files.Length); string tmpstrFrom, tmpstrTo; for (int i = 0; i < files.Length; i++) { tmpstrFrom = Path.Combine(optLoading_from, files[i]); tmpstrTo = Path.Combine(optLoading_to, files[i] + ".bak"); if (File.Exists(tmpstrFrom)) { if (File.Exists(tmpstrTo)) { File.Delete(tmpstrTo); } File.Move(tmpstrFrom, tmpstrTo); filelist.Add(files[i]); } } } } } } } this._wrapperform.Hide(); if (keeprunning) { if (discord_enableRP && File.Exists("discord-rpc-x86.dll")) { if (!string.IsNullOrWhiteSpace(discord_clientID)) { this.handlers = new DiscordRPC.EventHandlers(); this.handlers.readyCallback = Discord_ReadyCallback; this.handlers.disconnectedCallback = Discord_DisconnectedCallback; this.handlers.errorCallback = Discord_ErrorCallback; enableDiscordRP = true; this.cacheRP = new DiscordRPC.RichPresence(); this.cacheRP.startTimestamp = DateTimeToTimestamp(DateTime.Now); DiscordRPC.Initialize(discord_clientID, ref this.handlers, true, null); DiscordRPC.RunCallbacks(); ThreadPool.QueueUserWorkItem(new WaitCallback(delegate { Thread.Sleep(1500); this.UpdateRichPresence(); DiscordRPC.RunCallbacks(); })); } } gameProcess.EnableRaisingEvents = true; gameProcess.Exited += this.Proc_Exited; gameProcess.Start(); return(true); } else { gameProcess.Start(); this.ExitProgram(0); } } else { this.ExitProgram(-1); } } catch (Exception ex) { this._wrapperform.Show(); MessageBox.Show(this.GetWrapperForm(), ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); this.ExitProgram(-2); } return(false); }
private void UpdateRichPresence(bool force) { var rpData = new Leayal.Ini.IniFile(Path.Combine(AppInfo.EntryAssemblyInfo.DirectoryPath, "Discord-RPC-Payload.ini")); if (rpData.IsEmpty) { rpData.SetValue("DiscordRichPresence", "State", "Playing Solo"); rpData.SetValue("DiscordRichPresence", "Details", "Leveling up class"); rpData.SetValue("DiscordRichPresence", "LargeImageKey", "Map-Name-Key"); rpData.SetValue("DiscordRichPresence", "LargeImageText", "Map's name"); rpData.SetValue("DiscordRichPresence", "SmallImageKey", "char-icon-key"); rpData.SetValue("DiscordRichPresence", "SmallImageText", "CharacterName"); rpData.SetValue("DiscordRichPresence", "PartySizeMax", "0"); rpData.SetValue("DiscordRichPresence", "PartySizeCurrent", "0"); rpData.Save(Encoding.UTF8); } if (!enableDiscordRP) { rpData.Close(); return; } this.cacheRP.state = rpData.GetValue("DiscordRichPresence", "State", "Playing Solo"); this.cacheRP.details = rpData.GetValue("DiscordRichPresence", "Details", "Leveling up class"); this.cacheRP.largeImageKey = rpData.GetValue("DiscordRichPresence", "LargeImageKey", "Map-Name-Key"); this.cacheRP.largeImageText = rpData.GetValue("DiscordRichPresence", "LargeImageText", "Map's name"); this.cacheRP.smallImageKey = rpData.GetValue("DiscordRichPresence", "SmallImageKey", "char-icon-key"); this.cacheRP.smallImageText = rpData.GetValue("DiscordRichPresence", "SmallImageText", "CharacterName"); string inString = rpData.GetValue("DiscordRichPresence", "PartySizeMax", "4"); int outNumber; if (int.TryParse(inString, out outNumber)) { this.cacheRP.partyMax = outNumber; } else { this.cacheRP.partyMax = 0; } inString = rpData.GetValue("DiscordRichPresence", "PartySizeCurrent", "1"); if (int.TryParse(inString, out outNumber)) { this.cacheRP.partySize = outNumber; } else { this.cacheRP.partySize = 0; } rpData.Close(); DiscordRPC.UpdatePresence(ref this.cacheRP); this.GetWrapperForm(); if (!force) { this.MainForm.Hide(); } }