// Import individual XML mod private static void ImportMod(string path) { FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read); XmlDocument xmldoc = new XmlDocument(); XmlNodeList xmlnode; XmlNode mod; string name, tyversion, version, authors, description; TyVersion tyversionRange; xmldoc.Load(fs); xmlnode = xmldoc.GetElementsByTagName("tymod"); for (int i = 0; i < xmlnode.Count; i++) { name = null; tyversion = null; version = null; tyversionRange = null; authors = null; description = null; mod = xmlnode[i]; try { name = mod.Attributes.GetNamedItem("name").Value; } catch (Exception e) { Program.Log(path, "Invalid name attribute for tymod \"" + mod.OuterXml + "\"", e); continue; } try { version = mod.Attributes.GetNamedItem("version").Value; } catch { } try { authors = mod.Attributes.GetNamedItem("authors").Value; } catch { } try { description = mod.Attributes.GetNamedItem("description").Value; } catch { } try { tyversion = mod.Attributes.GetNamedItem("tyversion").Value; tyversionRange = new TyVersion(tyversion, name + " (" + (version ?? String.Empty) + ";" + (authors ?? String.Empty) + ")"); } catch { } if (name != null && name != String.Empty) { TyMod tymod = new TyMod(name, tyversionRange, version, authors, description); // Check if tymod already exists if (Mods.Any(x => x.ToString() == tymod.ToString() && x.TyVersion.OverlapsVersion(tymod.TyVersion))) { Log(path, "TyMod with same name, version, authors, and dependency already exists (\"" + tymod.ToString() + "\")"); continue; } // Add Elements from node tymod.AddFromNode(mod); // Add to list Mods.Add(tymod); } } fs.Close(); }
private static void ApplyMods_Level(List <TyLevel> levels, ref Dictionary <string, TyTranslation> translations) { List <string> customLevels = new List <string>(); string z1LV2, levelID; string[] englishTranslations = null; uint levelStart = 0; TyLevel level; if (levels == null || levels.Count == 0) { return; } // Sort least to greatest by IndexOffset levels.Sort((a, b) => a.IndexOffset.CompareTo(b.IndexOffset)); // Load the potentially altered z1.lv2 z1LV2 = File.ReadAllText(Path.Combine(Program.OutDirectory, "z1.lv2"), Encoding.GetEncoding("iso-8859-1")); // Offset levelIndex by index of "TEXT_LEVEL_Z1" translation entry englishTranslations = translations["english"].Translations.Keys.ToArray(); while (englishTranslations[levelStart] != "TEXT_LEVEL_Z1") { levelStart++; } levelStart = (uint)translations["english"].Translations.Count - levelStart; while (levelStart < CustomMapStartIndex) { string key = "TEXT_LEVEL_NULL_" + levelStart.ToString(); translations["english"].Translations.Add(key, String.Empty); translations["german"].Translations.Add(key, String.Empty); translations["spanish"].Translations.Add(key, String.Empty); translations["french"].Translations.Add(key, String.Empty); translations["italian"].Translations.Add(key, String.Empty); levelStart++; } // Apply level for (int x = 0; x <= levels.Max(l => l.IndexOffset); x++) { levelID = "f" + x.ToString(); level = levels.Where(l => l.IndexOffset == x).FirstOrDefault(); // Try to add level names to translations try { translations["english"].Translations.Add("TEXT_LEVEL_" + levelID, level.LanguageNames["english"]); } catch (Exception e) { if (level != null) { Log(level.ToString(), "Unable to get english translation", e); } translations["english"].Translations.Add("TEXT_LEVEL_" + levelID, String.Empty); } try { translations["german"].Translations.Add("TEXT_LEVEL_" + levelID, level.LanguageNames["german"]); } catch (Exception e) { if (level != null) { Log(level.ToString(), "Unable to get german translation", e); } translations["german"].Translations.Add("TEXT_LEVEL_" + levelID, String.Empty); } try { translations["spanish"].Translations.Add("TEXT_LEVEL_" + levelID, level.LanguageNames["spanish"]); } catch (Exception e) { if (level != null) { Log(level.ToString(), "Unable to get spanish translation", e); } translations["spanish"].Translations.Add("TEXT_LEVEL_" + levelID, String.Empty); } try { translations["french"].Translations.Add("TEXT_LEVEL_" + levelID, level.LanguageNames["french"]); } catch (Exception e) { if (level != null) { Log(level.ToString(), "Unable to get french translation", e); } translations["french"].Translations.Add("TEXT_LEVEL_" + levelID, String.Empty); } try { translations["italian"].Translations.Add("TEXT_LEVEL_" + levelID, level.LanguageNames["italian"]); } catch (Exception e) { if (level != null) { Log(level.ToString(), "Unable to get italian translation", e); } translations["italian"].Translations.Add("TEXT_LEVEL_" + levelID, String.Empty); } // Apply level if (level != null) { // Find portal entries in z1.lv2 Match portal = Regex.Match(z1LV2, @"^name\s*PORTAL\s*$", RegexOptions.Multiline); if (!portal.Success) { Program.Log("z1.lv2", "Unable to find portal entries", null, true); return; } // Add level files to output directory TyMod.ApplyLevel(levelID, level); // Add portal for level z1LV2 = z1LV2.Insert(z1LV2.IndexOf("\r\n", portal.Index) + 2, "\r\n" + Program.PortalEntry .Replace("%l", levelID) .Replace("%i", (x + levelStart).ToString()) .Replace("%x", level.X.ToString("F")) .Replace("%y", level.Y.ToString("F")) .Replace("%z", level.Z.ToString("F")) .Replace("%a", level.Authors) ); // Add to list of custom levels (to be used by the OpenAL32 proxy) customLevels.Add((x + levelStart).ToString() + " " + levelID + " " + Path.Combine("Mods", level.InputPath)); } } // Write potentially edited zl.lv2 File.WriteAllText(Path.Combine(Program.OutDirectory, "z1.lv2"), z1LV2, Encoding.GetEncoding("iso-8859-1")); // Write list of custom maps to cmaps.ini for the proxy dll to parse File.WriteAllText(Path.Combine(Program.OutDirectory, "cmaps.ini"), String.Join("\n", customLevels)); }
// Apply list of mods public static bool ApplyMods(List <TyMod> mods) { Dictionary <string, TyGlobal> globals = new Dictionary <string, TyGlobal>(); Dictionary <string, TyTranslation> translations = new Dictionary <string, TyTranslation>(); List <TyLevel> levels = new List <TyLevel>(); // Save level order ApplyMods_LevelOrder(); // Delete existing directory if (Directory.Exists(Program.OutDirectory)) { Directory.Delete(Program.OutDirectory, true); } // Wait until directory is deleted while (Directory.Exists(Program.OutDirectory)) { System.Threading.Thread.Sleep(10); } // Create new PC_External directory Directory.CreateDirectory(Program.OutDirectory); // Import all translation files translations.Add("english", new TyTranslation("Translations.English.txt", DataPC.ExtractText(DataPC.FileEntries.Where(f => f.FileName == "Translations.English.txt").FirstOrDefault()))); translations.Add("german", new TyTranslation("Translations.German.txt", DataPC.ExtractText(DataPC.FileEntries.Where(f => f.FileName == "Translations.German.txt").FirstOrDefault()))); translations.Add("spanish", new TyTranslation("Translations.Spanish.txt", DataPC.ExtractText(DataPC.FileEntries.Where(f => f.FileName == "Translations.Spanish.txt").FirstOrDefault()))); translations.Add("french", new TyTranslation("Translations.French.txt", DataPC.ExtractText(DataPC.FileEntries.Where(f => f.FileName == "Translations.French.txt").FirstOrDefault()))); translations.Add("italian", new TyTranslation("Translations.Italian.txt", DataPC.ExtractText(DataPC.FileEntries.Where(f => f.FileName == "Translations.Italian.txt").FirstOrDefault()))); // Import z1.lv2 // We do this to later add portals for any added custom maps // If we load this file from the OutDirectory instead from the RKV AND we load user imports before user levels... // We can support any direct user modification to the z1.lv2 File.WriteAllText(Path.Combine(Program.OutDirectory, "z1.lv2"), DataPC.ExtractText(DataPC.FileEntries.Where(f => f.FileName == "z1.lv2").FirstOrDefault()), Encoding.GetEncoding("iso-8859-1")); // Apply all imports first foreach (TyMod mod in mods) { if (mod.Enabled && mod.Valid && (mod.TyVersion == null || mod.TyVersion.ContainsVersion(Program.RVersion))) { foreach (TyModImport import in mod.Imports) { TyMod.ApplyImport(mod, import); } } } // Apply everything else foreach (TyMod mod in mods) { if (mod.Enabled && mod.Valid && (mod.TyVersion == null || mod.TyVersion.ContainsVersion(Program.RVersion))) { // Apply global edit foreach (TyModEdit edit in mod.Edits) { if (!globals.ContainsKey(edit.Source)) { TyRKV.FileEntry file = DataPC.FileEntries.Where(f => f.FileName == edit.Source || f.FullPath == edit.Source).FirstOrDefault(); if (file.FileName == null) { Program.Log(mod.ToString(), "Unable to find global source file \"" + edit.Source + "\""); continue; } globals.Add(edit.Source, new TyGlobal(edit.Source, DataPC.ExtractText(file))); } TyMod.ApplyGlobal(globals[edit.Source], edit); } // Add level foreach (TyLevel level in mod.Levels) { levels.Add(level); } foreach (TyModTranslate translation in mod.Translations) { TyMod.ApplyTranslate(translations, translation); } } } // Apply levels ApplyMods_Level(levels, ref translations); // Write all edited global files foreach (string key in globals.Keys) { FileInfo file = new FileInfo(Path.Combine(Program.OutDirectory, key)); if (!file.Directory.Exists) { Directory.CreateDirectory(file.Directory.FullName); } File.WriteAllText(file.FullName, globals[key].ToString(), Encoding.GetEncoding("iso-8859-1")); } // Write all edited translation files foreach (string key in translations.Keys) { FileInfo file = new FileInfo(Path.Combine(Program.OutDirectory, "Translations." + (char.ToUpper(key[0]) + key.Substring(1)) + ".txt")); if (!file.Directory.Exists) { Directory.CreateDirectory(file.Directory.FullName); } File.WriteAllText(file.FullName, translations[key].ToString(), Encoding.GetEncoding("iso-8859-1")); } return(true); }