/// <summary> /// Gets all the mods and patches them. /// </summary> private void worker_DoWork(object sender, DoWorkEventArgs e) { _errorLevel = ErrorLevel.NoError; //Gets the list of mods ItemCollection modCollection = null; string lolLocation = null; //Get the data from the UI thread Dispatcher.Invoke(DispatcherPriority.Input, new ThreadStart(() => { modCollection = ModsListBox.Items; lolLocation = LocationTextbox.Text; })); SetStatusLabelAsync("Gathering mods..."); //Gets the list of mods that have been checked. List <LessMod> modsToPatch = new List <LessMod>(); foreach (var x in modCollection) { CheckBox box = (CheckBox)x; bool isBoxChecked = false; Dispatcher.Invoke(DispatcherPriority.Input, new ThreadStart(() => { isBoxChecked = box.IsChecked ?? false; })); if (isBoxChecked) { modsToPatch.Add(_lessMods[box]); } } //Create a new dictionary to hold the SWF definitions in. This stops opening and closing the same SWF file if it's going to be modified more than once. Dictionary <string, SwfFile> swfs = new Dictionary <string, SwfFile>(); //Start the stopwatch to see how long it took to patch (aiming for ~5 sec or less on test machine) timer = Stopwatch.StartNew(); //Go through each modification foreach (var lessMod in modsToPatch) { SetStatusLabelAsync("Patching mod: " + lessMod.Name); //Go through each patch within the mod foreach (var patch in lessMod.Patches) { //If the swf hasn't been loaded, load it into the dictionary. if (!swfs.ContainsKey(patch.Swf)) { string fullPath = Path.Combine(lolLocation, patch.Swf); //Backup the SWF string CurrentLocation = ""; string[] FileLocation = patch.Swf.Split('/', '\\'); foreach (string s in FileLocation.Take(FileLocation.Length - 1)) { CurrentLocation = Path.Combine(CurrentLocation, s); if (!Directory.Exists(Path.Combine(lolLocation, "LESsBackup", BackupVersion, CurrentLocation))) { Directory.CreateDirectory(Path.Combine(lolLocation, "LESsBackup", BackupVersion, CurrentLocation)); } } if (!File.Exists(Path.Combine(lolLocation, "LESsBackup", BackupVersion, patch.Swf))) { File.Copy(Path.Combine(lolLocation, patch.Swf), Path.Combine(lolLocation, "LESsBackup", BackupVersion, patch.Swf)); } swfs.Add(patch.Swf, SwfFile.ReadFile(fullPath)); } //Get the SWF file that is being modified SwfFile swf = swfs[patch.Swf]; if (patch.Action == "replace_swf_character")// replace an swf-character (buttons, sprites, fonts etc.) { ushort charId; if (ushort.TryParse(patch.Class, out charId) && swf.CharacterTags.ContainsKey(charId)) { swf.CharacterTags[charId].SetData(File.ReadAllBytes(Path.Combine(lessMod.Directory, patch.Code))); } else { _errorLevel = ErrorLevel.UnableToPatch; throw new TraitNotFoundException($"<{patch.Class}> is not a valid Character ID."); } } else { //Get the ABC tags (containing the code) from the swf file. List <DoAbcTag> tags = swf.GetDoAbcTags(); bool classFound = false; foreach (var tag in tags) { //check if this tag contains our script ScriptInfo si = tag.GetScriptByClassName(patch.Class); //check next tag if it doesn't if (si == null) { continue; } ClassInfo cls = si.FindClass(patch.Class); classFound = true; Assembler asm; //Perform the action based on what the patch defines switch (patch.Action) { case "replace_trait": //replace trait (method) //Load the code from the patch and assemble it to be inserted into the code asm = new Assembler(File.ReadAllText(Path.Combine(lessMod.Directory, patch.Code))); TraitInfo newTrait = asm.Assemble() as TraitInfo; int traitIndex = cls.GetTraitIndexByTypeAndName(newTrait.Type, newTrait.Name.Name, Scope.Instance); bool classTrait = false; if (traitIndex < 0) { traitIndex = cls.GetTraitIndexByTypeAndName(newTrait.Type, newTrait.Name.Name, Scope.Class); classTrait = true; } if (traitIndex < 0) { throw new TraitNotFoundException(String.Format("Can't find trait \"{0}\" in class \"{1}\"", newTrait.Name.Name, patch.Class)); } //Modified the found trait if (classTrait) { cls.ClassTraits[traitIndex] = newTrait; } else { cls.InstanceTraits[traitIndex] = newTrait; } break; case "replace_cinit": //replace class constructor //Load the code from the patch and assemble it to be inserted into the code asm = new Assembler(File.ReadAllText(Path.Combine(lessMod.Directory, patch.Code))); cls.ClassInit = asm.Assemble() as MethodInfo; break; case "replace_iinit": //replace instance constructor //Load the code from the patch and assemble it to be inserted into the code asm = new Assembler(File.ReadAllText(Path.Combine(lessMod.Directory, patch.Code))); cls.InstanceInit = asm.Assemble() as MethodInfo; break; case "add_class_trait": //add new class trait (method) //Load the code from the patch and assemble it to be inserted into the code asm = new Assembler(File.ReadAllText(Path.Combine(lessMod.Directory, patch.Code))); newTrait = asm.Assemble() as TraitInfo; traitIndex = cls.GetTraitIndexByTypeAndName(newTrait.Type, newTrait.Name.Name, Scope.Class); if (traitIndex < 0) { cls.ClassTraits.Add(newTrait); } else { cls.ClassTraits[traitIndex] = newTrait; } break; case "add_instance_trait": //add new instance trait (method) //Load the code from the patch and assemble it to be inserted into the code asm = new Assembler(File.ReadAllText(Path.Combine(lessMod.Directory, patch.Code))); newTrait = asm.Assemble() as TraitInfo; traitIndex = cls.GetTraitIndexByTypeAndName(newTrait.Type, newTrait.Name.Name, Scope.Instance); if (traitIndex < 0) { cls.InstanceTraits.Add(newTrait); } else { cls.InstanceTraits[traitIndex] = newTrait; } break; case "remove_class_trait": throw new NotImplementedException(); case "remove_instance_trait": throw new NotImplementedException(); default: throw new NotSupportedException($"Unknown Action \"{patch.Action}\" in mod {lessMod.Name}"); } } if (!classFound) { _errorLevel = ErrorLevel.UnableToPatch; throw new ClassNotFoundException($"Class {patch.Class} not found in file {patch.Swf}"); } } } } //Save the modified SWFS to their original location foreach (var patchedSwf in swfs) { try { SetStatusLabelAsync("Applying mods: " + patchedSwf.Key); string swfLoc = Path.Combine(lolLocation, patchedSwf.Key); SwfFile.WriteFile(patchedSwf.Value, swfLoc); } catch { _errorLevel = ErrorLevel.GoodJobYourInstallationIsProbablyCorruptedNow; if (Debugger.IsAttached) { throw; } } } timer.Stop(); }