private byte[] CalculateFileHash(ContentFile file, ref MD5 md5) { using (var stream = File.OpenRead(file.path)) { return(md5.ComputeHash(stream)); } }
private void LoadConfig(ContentFile config) { try { XDocument doc = XMLExtensions.TryLoadXml(config.Path); if (doc == null) { return; } var mainElement = doc.Root; if (mainElement.IsOverride()) { mainElement = doc.Root.FirstElement(); prefabs.Clear(); DebugConsole.NewMessage($"Overriding all background creatures with '{config.Path}'", Color.Yellow); } else if (prefabs.Any()) { DebugConsole.NewMessage($"Loading additional background creatures from file '{config.Path}'"); } foreach (XElement element in mainElement.Elements()) { prefabs.Add(new BackgroundCreaturePrefab(element)); } ; } catch (Exception e) { DebugConsole.ThrowError(String.Format("Failed to load BackgroundCreatures from {0}", config.Path), e); } }
public DecalPrefab(XElement element, ContentFile file) { Name = element.Name.ToString(); Identifier = Name.ToLowerInvariant(); FilePath = file.Path; ContentPackage = file.ContentPackage; Sprites = new List <Sprite>(); foreach (XElement subElement in element.Elements()) { if (subElement.Name.ToString().Equals("sprite", StringComparison.OrdinalIgnoreCase)) { Sprites.Add(new Sprite(subElement)); } } Color = element.GetAttributeColor("color", Color.White); LifeTime = element.GetAttributeFloat("lifetime", 10.0f); FadeOutTime = Math.Min(LifeTime, element.GetAttributeFloat("fadeouttime", 1.0f)); FadeInTime = Math.Min(LifeTime - FadeOutTime, element.GetAttributeFloat("fadeintime", 0.0f)); }
private byte[] CalculateFileHash(ContentFile file) { using (MD5 md5 = MD5.Create()) { List <string> filePaths = new List <string> { file.Path }; List <byte> data = new List <byte>(); switch (file.Type) { case ContentType.Character: XDocument doc = XMLExtensions.TryLoadXml(file.Path); var rootElement = doc.Root; var element = rootElement.IsOverride() ? rootElement.FirstElement() : rootElement; var ragdollFolder = RagdollParams.GetFolder(doc, file.Path).CleanUpPathCrossPlatform(true); if (Directory.Exists(ragdollFolder)) { Directory.GetFiles(ragdollFolder, "*.xml").ForEach(f => filePaths.Add(f)); } var animationFolder = AnimationParams.GetFolder(doc, file.Path).CleanUpPathCrossPlatform(true); if (Directory.Exists(animationFolder)) { Directory.GetFiles(animationFolder, "*.xml").ForEach(f => filePaths.Add(f)); } break; } if (filePaths.Count > 1) { using (MD5 tempMd5 = MD5.Create()) { filePaths = filePaths.OrderBy(f => ToolBox.StringToUInt32Hash(f.CleanUpPathCrossPlatform(true).ToLowerInvariant(), tempMd5)).ToList(); } } foreach (string filePath in filePaths) { if (!File.Exists(filePath)) { continue; } using (var stream = File.OpenRead(filePath)) { byte[] fileData = new byte[stream.Length]; stream.Read(fileData, 0, (int)stream.Length); if (filePath.EndsWith(".xml", true, System.Globalization.CultureInfo.InvariantCulture)) { string text = System.Text.Encoding.UTF8.GetString(fileData); text = text.Replace("\n", "").Replace("\r", "").Replace("\\", "/"); fileData = System.Text.Encoding.UTF8.GetBytes(text); } data.AddRange(fileData); } } return(md5.ComputeHash(data.ToArray())); } }
public void RemoveFile(ContentFile file) { if (filesToAdd.Contains(file)) { filesToAdd.Remove(file); } if (files.Contains(file) && !filesToRemove.Contains(file)) { filesToRemove.Add(file); } }
public ContentFile AddFile(string path, ContentType type) { if (Files.Find(file => file.Path == path && file.Type == type) != null) { return(null); } ContentFile cf = new ContentFile(path, type); Files.Add(cf); return(cf); }
public void AddFile(ContentFile file) { if (filesToRemove.Contains(file)) { filesToRemove.Remove(file); } if (Files.Concat(FilesToAdd).Any(f => f.Path == file.Path && f.Type == file.Type)) { return; } filesToAdd.Add(file); }
private byte[] CalculateFileHash(ContentFile file) { var md5 = MD5.Create(); List <string> filePaths = new List <string> { file.Path }; List <byte> data = new List <byte>(); switch (file.Type) { case ContentType.Character: XDocument doc = XMLExtensions.TryLoadXml(file.Path); var rootElement = doc.Root; var element = rootElement.IsOverride() ? rootElement.FirstElement() : rootElement; var speciesName = element.GetAttributeString("speciesname", element.GetAttributeString("name", "")); var ragdollFolder = RagdollParams.GetFolder(speciesName); if (Directory.Exists(ragdollFolder)) { Directory.GetFiles(ragdollFolder, "*.xml").ForEach(f => filePaths.Add(f)); } var animationFolder = AnimationParams.GetFolder(speciesName); if (Directory.Exists(animationFolder)) { Directory.GetFiles(animationFolder, "*.xml").ForEach(f => filePaths.Add(f)); } break; } foreach (string filePath in filePaths) { if (!File.Exists(filePath)) { continue; } using (var stream = File.OpenRead(filePath)) { byte[] fileData = new byte[stream.Length]; stream.Read(fileData, 0, (int)stream.Length); if (filePath.EndsWith(".xml", true, System.Globalization.CultureInfo.InvariantCulture)) { string text = System.Text.Encoding.UTF8.GetString(fileData); text = text.Replace("\n", "").Replace("\r", ""); fileData = System.Text.Encoding.UTF8.GetBytes(text); } data.AddRange(fileData); } } return(md5.ComputeHash(data.ToArray())); }
public ContentFile AddFile(string path, ContentType type) { if (Files.Concat(FilesToAdd).Any(file => file.Path == path && file.Type == type)) { return(null); } ContentFile cf = new ContentFile(path, type) { ContentPackage = this }; filesToAdd.Add(cf); return(cf); }
public static void LoadFromFile(ContentFile file) { DebugConsole.Log("Loading talent prefab: " + file.Path); RemoveByFile(file.Path); XDocument doc = XMLExtensions.TryLoadXml(file.Path); if (doc == null) { return; } var rootElement = doc.Root; switch (rootElement.Name.ToString().ToLowerInvariant()) { case "talent": TalentPrefabs.Add(new TalentPrefab(rootElement, file.Path), false); break; case "talents": foreach (var element in rootElement.Elements()) { if (element.IsOverride()) { var itemElement = element.GetChildElement("talent"); if (itemElement != null) { TalentPrefabs.Add(new TalentPrefab(rootElement, file.Path), true); } else { DebugConsole.ThrowError($"Cannot find a talent element from the children of the override element defined in {file.Path}"); } } else { TalentPrefabs.Add(new TalentPrefab(element, file.Path), false); } } break; default: DebugConsole.ThrowError($"Invalid XML root element: '{rootElement.Name.ToString()}' in {file.Path}"); break; } }
private byte[] CalculateFileHash(ContentFile file) { var md5 = MD5.Create(); List <string> filePaths = new List <string> { file.Path }; List <byte> data = new List <byte>(); switch (file.Type) { case ContentType.Character: XDocument doc = XMLExtensions.TryLoadXml(file.Path); string speciesName = doc.Root.GetAttributeString("name", ""); //TODO: check non-default paths if defined filePaths.Add(RagdollParams.GetDefaultFile(speciesName, this)); foreach (AnimationType animationType in Enum.GetValues(typeof(AnimationType))) { filePaths.Add(AnimationParams.GetDefaultFile(speciesName, animationType, this)); } break; } foreach (string filePath in filePaths) { if (!File.Exists(filePath)) { continue; } using (var stream = File.OpenRead(filePath)) { byte[] fileData = new byte[stream.Length]; stream.Read(fileData, 0, (int)stream.Length); if (filePath.EndsWith(".xml", true, System.Globalization.CultureInfo.InvariantCulture)) { string text = System.Text.Encoding.UTF8.GetString(fileData); text = text.Replace("\n", "").Replace("\r", ""); fileData = System.Text.Encoding.UTF8.GetBytes(text); } data.AddRange(fileData); } } return(md5.ComputeHash(data.ToArray())); }
private byte[] CalculateXmlHash(ContentFile file, ref MD5 md5) //todo: Change ref to in (in C# 7.2) { var doc = XMLExtensions.TryLoadXml(file.path); if (doc == null) { throw new Exception($"file {file.path} could not be opened as XML document"); } using (var memoryStream = new MemoryStream()) { using (var writer = new StreamWriter(memoryStream)) { writer.Write(doc.ToString()); writer.Flush(); memoryStream.Position = 0; return(md5.ComputeHash(memoryStream)); } } }
public static void LoadFromFile(ContentFile file) { XDocument doc = XMLExtensions.TryLoadXml(file.Path); if (doc == null) { return; } var mainElement = doc.Root.IsOverride() ? doc.Root.FirstElement() : doc.Root; if (doc.Root.IsOverride()) { DebugConsole.ThrowError($"Error in '{file.Path}': Cannot override all job prefabs, because many of them are required by the main game! Please try overriding jobs one by one."); } foreach (XElement element in mainElement.Elements()) { if (element.Name.ToString().Equals("nojob", StringComparison.OrdinalIgnoreCase)) { continue; } if (element.IsOverride()) { var job = new JobPrefab(element.FirstElement(), file.Path) { ContentPackage = file.ContentPackage }; Prefabs.Add(job, true); } else { var job = new JobPrefab(element, file.Path) { ContentPackage = file.ContentPackage }; Prefabs.Add(job, false); } } NoJobElement = NoJobElement ?? mainElement.Element("NoJob"); NoJobElement = NoJobElement ?? mainElement.Element("nojob"); }
public static bool IsModFilePathAllowed(ContentFile contentFile) { string path = contentFile.Path; while (true) { string temp = System.IO.Path.GetDirectoryName(path); if (string.IsNullOrEmpty(temp)) { break; } path = temp; } switch (contentFile.Type) { case ContentType.Submarine: return(path == "Submarines" || path == "Mods"); default: return(path == "Mods"); } }
private static void Load(ContentFile file) { XDocument doc = XMLExtensions.TryLoadXml(file.Path); if (doc == null) { return; } var mainElement = doc.Root; bool allowOverriding = false; if (doc.Root.IsOverride()) { mainElement = doc.Root.FirstElement(); allowOverriding = true; } foreach (XElement subElement in mainElement.Elements()) { var element = subElement.IsOverride() ? subElement.FirstElement() : subElement; string identifier = element.Name.ToString(); var duplicate = List.FirstOrDefault(e => e.Identifier.ToString().Equals(identifier, StringComparison.OrdinalIgnoreCase)); if (duplicate != null) { if (allowOverriding || subElement.IsOverride()) { DebugConsole.NewMessage($"Overriding the existing preset '{identifier}' in the event manager settings using the file '{file.Path}'", Color.Yellow); List.Remove(duplicate); } else { DebugConsole.ThrowError($"Error in '{file.Path}': Another element with the name '{identifier}' found! Each element must have a unique name. Use <override></override> tags if you want to override an existing preset."); continue; } } List.Add(new EventManagerSettings(element)); } List.Sort((x, y) => { return(Math.Sign((x.MinLevelDifficulty + x.MaxLevelDifficulty) / 2.0f - (y.MinLevelDifficulty + y.MaxLevelDifficulty) / 2.0f)); }); }
public static void LoadFromFile(ContentFile file) { XDocument doc = XMLExtensions.TryLoadXml(file.Path); if (doc == null) { return; } var rootElement = doc.Root; if (rootElement.IsOverride()) { foreach (var element in rootElement.Elements()) { foreach (var childElement in element.Elements()) { Load(childElement, true, file); } } } else { foreach (var element in rootElement.Elements()) { if (element.IsOverride()) { foreach (var childElement in element.Elements()) { Load(childElement, true, file); } } else { Load(element, false, file); } } } }
public static void LoadFromFile(ContentFile file) { XDocument doc = XMLExtensions.TryLoadXml(file.Path); if (doc == null) { return; } string language = doc.Root.GetAttributeString("Language", "English"); string identifier = doc.Root.GetAttributeString("identifier", null); if (string.IsNullOrWhiteSpace(identifier)) { DebugConsole.ThrowError($"Conversations file '{file.Path}' has no identifier!"); return; } foreach (XElement subElement in doc.Root.Elements()) { switch (subElement.Name.ToString().ToLowerInvariant()) { case "conversation": if (!allConversations.ContainsKey(identifier)) { allConversations.Add(identifier, new ConversationCollection(identifier)); } allConversations[identifier].Add(language, file.Path, subElement); break; case "personalitytrait": new NPCPersonalityTrait(subElement, file.Path); break; } } }
public static void LoadFromFile(ContentFile file) { XDocument doc = XMLExtensions.TryLoadXml(file.Path); var rootElement = doc?.Root; if (rootElement == null) { return; } switch (rootElement.Name.ToString().ToLowerInvariant()) { case "ballastflorabehavior": { new BallastFloraPrefab(rootElement, file.Path, false) { ContentPackage = file.ContentPackage }; break; } case "ballastflorabehaviors": { foreach (var element in rootElement.Elements()) { if (element.IsOverride()) { XElement upgradeElement = element.GetChildElement("mapcreature"); if (upgradeElement != null) { new BallastFloraPrefab(upgradeElement, file.Path, true) { ContentPackage = file.ContentPackage }; } else { DebugConsole.ThrowError($"Cannot find a map creature element from the children of the override element defined in {file.Path}"); } } else { if (element.Name.ToString().Equals("mapcreature", StringComparison.OrdinalIgnoreCase)) { new BallastFloraPrefab(element, file.Path, false) { ContentPackage = file.ContentPackage }; } } } break; } case "override": { XElement mapCreatures = rootElement.GetChildElement("ballastflorabehaviors"); if (mapCreatures != null) { foreach (XElement element in mapCreatures.Elements()) { new BallastFloraPrefab(element, file.Path, true) { ContentPackage = file.ContentPackage }; } } foreach (XElement element in rootElement.GetChildElements("ballastflorabehavior")) { new BallastFloraPrefab(element, file.Path, true) { ContentPackage = file.ContentPackage }; } break; } default: { DebugConsole.ThrowError($"Invalid XML root element: '{rootElement.Name}' in {file.Path}\n " + "Valid elements are: \"MapCreature\", \"MapCreatures\" and \"Override\"."); break; } } }
private static void LoadFromFile(ContentFile file) { XDocument doc = XMLExtensions.TryLoadXml(file.Path); var rootElement = doc?.Root; if (rootElement == null) { return; } switch (rootElement.Name.ToString().ToLowerInvariant()) { case "upgrademodule": { new UpgradePrefab(rootElement, file.Path, false) { ContentPackage = file.ContentPackage }; break; } case "upgradecategory": { new UpgradeCategory(rootElement); break; } case "upgrademodules": { foreach (var element in rootElement.Elements()) { if (element.IsOverride()) { var upgradeElement = element.GetChildElement("upgradeprefab"); if (upgradeElement != null) { new UpgradePrefab(upgradeElement, file.Path, true) { ContentPackage = file.ContentPackage }; } else { DebugConsole.ThrowError($"Cannot find an upgrade element from the children of the override element defined in {file.Path}"); } } else { switch (element.Name.ToString().ToLowerInvariant()) { case "upgrademodule": { new UpgradePrefab(element, file.Path, false) { ContentPackage = file.ContentPackage }; break; } case "upgradecategory": { new UpgradeCategory(element); break; } } } } break; } case "override": { var upgrades = rootElement.GetChildElement("upgrademodules"); if (upgrades != null) { foreach (var element in upgrades.Elements()) { new UpgradePrefab(element, file.Path, true) { ContentPackage = file.ContentPackage }; } } foreach (var element in rootElement.GetChildElements("upgrademodule")) { new UpgradePrefab(element, file.Path, true) { ContentPackage = file.ContentPackage }; } break; } default: DebugConsole.ThrowError($"Invalid XML root element: '{rootElement.Name}' in {file.Path}\n " + "Valid elements are: \"UpgradeModule\", \"UpgradeModules\" and \"Override\"."); break; } }
private byte[] CalculateFileHash(ContentFile file) { using (MD5 md5 = MD5.Create()) { List <string> filePaths = new List <string> { file.Path }; List <byte> data = new List <byte>(); switch (file.Type) { case ContentType.Character: XDocument doc = XMLExtensions.TryLoadXml(file.Path); var rootElement = doc.Root; var element = rootElement.IsOverride() ? rootElement.FirstElement() : rootElement; var ragdollFolder = RagdollParams.GetFolder(doc, file.Path).CleanUpPathCrossPlatform(true); if (Directory.Exists(ragdollFolder)) { Directory.GetFiles(ragdollFolder, "*.xml").ForEach(f => filePaths.Add(f)); } var animationFolder = AnimationParams.GetFolder(doc, file.Path).CleanUpPathCrossPlatform(true); if (Directory.Exists(animationFolder)) { Directory.GetFiles(animationFolder, "*.xml").ForEach(f => filePaths.Add(f)); } break; } if (filePaths.Count > 1) { using (MD5 tempMd5 = MD5.Create()) { // TODO: ToLower() fixes discrepencies between windows folder name capitalization for server/client interactions. // The proper fix would probably be to save both a case-sensitive and non-casesensitive hash on the server, // and only compare case-sensitive clients with the case-sensitive hash, and case-insensitive clients with the // case insensitive hash. // Though ultimately, the only case where this will cause issues is if someone made a mod with identical folder names in the same path. // Windows... 😩 filePaths = filePaths.OrderBy(f => ToolBox.StringToUInt32Hash(f.CleanUpPathCrossPlatform(true).ToLower(), tempMd5)).ToList(); } } foreach (string filePath in filePaths) { if (!File.Exists(filePath)) { continue; } using (var stream = File.OpenRead(filePath)) { byte[] fileData = new byte[stream.Length]; stream.Read(fileData, 0, (int)stream.Length); if (filePath.EndsWith(".xml", true, System.Globalization.CultureInfo.InvariantCulture)) { string text = System.Text.Encoding.UTF8.GetString(fileData); text = text.Replace("\n", "").Replace("\r", "").Replace("\\", "/"); fileData = System.Text.Encoding.UTF8.GetBytes(text); } data.AddRange(fileData); } } return(md5.ComputeHash(data.ToArray())); } }
public static bool IsModFilePathAllowed(ContentFile contentFile) { string path = contentFile.Path; return(IsModFilePathAllowed(path)); }
public static void LoadFromFile(ContentFile file) { XDocument doc = XMLExtensions.TryLoadXml(file.Path); if (doc == null) { return; } var mainElement = doc.Root.IsOverride() ? doc.Root.FirstElement() : doc.Root; if (doc.Root.IsOverride()) { DebugConsole.ThrowError("Cannot override all afflictions, because many of them are required by the main game! Please try overriding them one by one."); } foreach (XElement element in mainElement.Elements()) { bool isOverride = element.IsOverride(); XElement sourceElement = isOverride ? element.FirstElement() : element; string elementName = sourceElement.Name.ToString().ToLowerInvariant(); string identifier = sourceElement.GetAttributeString("identifier", null); if (!elementName.Equals("cprsettings", StringComparison.OrdinalIgnoreCase) && !elementName.Equals("damageoverlay", StringComparison.OrdinalIgnoreCase)) { if (string.IsNullOrWhiteSpace(identifier)) { DebugConsole.ThrowError($"No identifier defined for the affliction '{elementName}' in file '{file.Path}'"); continue; } if (Prefabs.ContainsKey(identifier)) { if (isOverride) { DebugConsole.NewMessage($"Overriding an affliction or a buff with the identifier '{identifier}' using the file '{file.Path}'", Color.Yellow); } else { DebugConsole.ThrowError($"Duplicate affliction: '{identifier}' defined in {elementName} of '{file.Path}'"); continue; } } } string type = sourceElement.GetAttributeString("type", ""); switch (sourceElement.Name.ToString().ToLowerInvariant()) { case "cprsettings": type = "cprsettings"; break; case "damageoverlay": type = "damageoverlay"; break; } AfflictionPrefab prefab = null; switch (type) { case "damageoverlay": #if CLIENT if (CharacterHealth.DamageOverlay != null) { if (isOverride) { DebugConsole.NewMessage($"Overriding damage overlay with '{file.Path}'", Color.Yellow); } else { DebugConsole.ThrowError($"Error in '{file.Path}': damage overlay already loaded. Add <override></override> tags as the parent of the custom damage overlay sprite to allow overriding the vanilla one."); break; } } CharacterHealth.DamageOverlay?.Remove(); CharacterHealth.DamageOverlay = new Sprite(element); CharacterHealth.DamageOverlayFile = file.Path; #endif break; case "bleeding": prefab = new AfflictionPrefab(sourceElement, file.Path, typeof(AfflictionBleeding)); break; case "huskinfection": prefab = new AfflictionPrefabHusk(sourceElement, file.Path, typeof(AfflictionHusk)); break; case "cprsettings": if (CPRSettings.IsLoaded) { if (isOverride) { DebugConsole.NewMessage($"Overriding the CPR settings with '{file.Path}'", Color.Yellow); } else { DebugConsole.ThrowError($"Error in '{file.Path}': CPR settings already loaded. Add <override></override> tags as the parent of the custom CPRSettings to allow overriding the vanilla values."); break; } } CPRSettings.Load(sourceElement, file.Path); break; case "damage": case "burn": case "oxygenlow": case "bloodloss": case "stun": case "pressure": case "internaldamage": prefab = new AfflictionPrefab(sourceElement, file.Path, typeof(Affliction)) { ContentPackage = file.ContentPackage }; break; default: prefab = new AfflictionPrefab(sourceElement, file.Path) { ContentPackage = file.ContentPackage }; break; } switch (identifier) { case "internaldamage": InternalDamage = prefab; break; case "bleeding": Bleeding = prefab; break; case "burn": Burn = prefab; break; case "oxygenlow": OxygenLow = prefab; break; case "bloodloss": Bloodloss = prefab; break; case "pressure": Pressure = prefab; break; case "stun": Stun = prefab; break; } if (prefab != null) { Prefabs.Add(prefab, isOverride); } } using MD5 md5 = MD5.Create(); foreach (AfflictionPrefab prefab in Prefabs) { prefab.UIntIdentifier = ToolBox.StringToUInt32Hash(prefab.Identifier, md5); //it's theoretically possible for two different values to generate the same hash, but the probability is astronomically small var collision = Prefabs.Find(p => p != prefab && p.UIntIdentifier == prefab.UIntIdentifier); if (collision != null) { DebugConsole.ThrowError("Hashing collision when generating uint identifiers for Afflictions: " + prefab.Identifier + " has the same identifier as " + collision.Identifier + " (" + prefab.UIntIdentifier + ")"); collision.UIntIdentifier++; } } }
public static void LoadFromFile(ContentFile file) { XDocument doc = XMLExtensions.TryLoadXml(file.Path); if (doc == null) { return; } var mainElement = doc.Root.IsOverride() ? doc.Root.FirstElement() : doc.Root; if (doc.Root.IsOverride()) { DebugConsole.ThrowError("Cannot override all afflictions, because many of them are required by the main game! Please try overriding them one by one."); } List <(AfflictionPrefab prefab, XElement element)> loadedAfflictions = new List <(AfflictionPrefab prefab, XElement element)>(); foreach (XElement element in mainElement.Elements()) { bool isOverride = element.IsOverride(); XElement sourceElement = isOverride ? element.FirstElement() : element; string elementName = sourceElement.Name.ToString().ToLowerInvariant(); string identifier = sourceElement.GetAttributeString("identifier", null); if (!elementName.Equals("cprsettings", StringComparison.OrdinalIgnoreCase) && !elementName.Equals("damageoverlay", StringComparison.OrdinalIgnoreCase)) { if (string.IsNullOrWhiteSpace(identifier)) { DebugConsole.ThrowError($"No identifier defined for the affliction '{elementName}' in file '{file.Path}'"); continue; } if (Prefabs.ContainsKey(identifier)) { if (isOverride) { DebugConsole.NewMessage($"Overriding an affliction or a buff with the identifier '{identifier}' using the file '{file.Path}'", Color.Yellow); } else { DebugConsole.ThrowError($"Duplicate affliction: '{identifier}' defined in {elementName} of '{file.Path}'"); continue; } } } string type = sourceElement.GetAttributeString("type", ""); switch (sourceElement.Name.ToString().ToLowerInvariant()) { case "cprsettings": type = "cprsettings"; break; case "damageoverlay": type = "damageoverlay"; break; } AfflictionPrefab prefab = null; switch (type) { case "damageoverlay": #if CLIENT if (CharacterHealth.DamageOverlay != null) { if (isOverride) { DebugConsole.NewMessage($"Overriding damage overlay with '{file.Path}'", Color.Yellow); } else { DebugConsole.ThrowError($"Error in '{file.Path}': damage overlay already loaded. Add <override></override> tags as the parent of the custom damage overlay sprite to allow overriding the vanilla one."); break; } } CharacterHealth.DamageOverlay?.Remove(); CharacterHealth.DamageOverlay = new Sprite(element); CharacterHealth.DamageOverlayFile = file.Path; #endif break; case "bleeding": prefab = new AfflictionPrefab(sourceElement, file.Path, typeof(AfflictionBleeding)); break; case "huskinfection": case "alieninfection": prefab = new AfflictionPrefabHusk(sourceElement, file.Path, typeof(AfflictionHusk)); break; case "cprsettings": if (CPRSettings.IsLoaded) { if (isOverride) { DebugConsole.NewMessage($"Overriding the CPR settings with '{file.Path}'", Color.Yellow); } else { DebugConsole.ThrowError($"Error in '{file.Path}': CPR settings already loaded. Add <override></override> tags as the parent of the custom CPRSettings to allow overriding the vanilla values."); break; } } CPRSettings.Load(sourceElement, file.Path); break; case "damage": case "burn": case "oxygenlow": case "bloodloss": case "stun": case "pressure": case "internaldamage": prefab = new AfflictionPrefab(sourceElement, file.Path, typeof(Affliction)) { ContentPackage = file.ContentPackage }; break; default: prefab = new AfflictionPrefab(sourceElement, file.Path) { ContentPackage = file.ContentPackage }; break; } switch (identifier) { case "internaldamage": InternalDamage = prefab; break; case "blunttrauma": ImpactDamage = prefab; break; case "bleeding": Bleeding = prefab; break; case "burn": Burn = prefab; break; case "oxygenlow": OxygenLow = prefab; break; case "bloodloss": Bloodloss = prefab; break; case "pressure": Pressure = prefab; break; case "stun": Stun = prefab; break; case "radiationsickness": RadiationSickness = prefab; break; } if (ImpactDamage == null) { ImpactDamage = InternalDamage; } if (prefab != null) { loadedAfflictions.Add((prefab, sourceElement)); Prefabs.Add(prefab, isOverride); prefab.CalculatePrefabUIntIdentifier(Prefabs); } } //load the effects after all the afflictions in the file have been instantiated //otherwise afflictions can't inflict other afflictions that are defined at a later point in the file foreach ((AfflictionPrefab prefab, XElement element) in loadedAfflictions) { prefab.LoadEffects(element); } }
public void RemoveFile(ContentFile file) { Files.Remove(file); }
public static void LoadFromFile(ContentFile file) { XDocument doc = XMLExtensions.TryLoadXml(file.Path); if (doc == null) { return; } var mainElement = doc.Root.IsOverride() ? doc.Root.FirstElement() : doc.Root; if (doc.Root.IsOverride()) { DebugConsole.ThrowError($"Error in '{file.Path}': Cannot override all job prefabs, because many of them are required by the main game! Please try overriding jobs one by one."); } foreach (XElement element in mainElement.Elements()) { if (element.IsOverride()) { var job = new JobPrefab(element.FirstElement(), file.Path) { ContentPackage = file.ContentPackage }; Prefabs.Add(job, true); } else { if (!element.Name.ToString().Equals("job", StringComparison.OrdinalIgnoreCase)) { continue; } var job = new JobPrefab(element, file.Path) { ContentPackage = file.ContentPackage }; Prefabs.Add(job, false); } } NoJobElement ??= mainElement.GetChildElement("nojob"); var itemRepairPrioritiesElement = mainElement.GetChildElement("ItemRepairPriorities"); if (itemRepairPrioritiesElement != null) { foreach (var subElement in itemRepairPrioritiesElement.Elements()) { string tag = subElement.GetAttributeString("tag", null); if (tag != null) { float priority = subElement.GetAttributeFloat("priority", -1f); if (priority >= 0) { _itemRepairPriorities.TryAdd(tag, priority); } else { DebugConsole.AddWarning($"The 'priority' attribute is missing from the the item repair priorities definition in {subElement} of {file.Path}."); } } else { DebugConsole.AddWarning($"The 'tag' attribute is missing from the the item repair priorities definition in {subElement} of {file.Path}."); } } } }
public void LoadFromFile(ContentFile configFile) { XDocument doc = XMLExtensions.TryLoadXml(configFile.Path); if (doc == null) { return; } if (grimeSpritesByFile.ContainsKey(configFile.Path)) { foreach (Sprite sprite in grimeSpritesByFile[configFile.Path]) { sprite.Remove(); GrimeSprites.Remove(sprite); } grimeSpritesByFile.Remove(configFile.Path); } bool allowOverriding = false; var mainElement = doc.Root; if (doc.Root.IsOverride()) { mainElement = doc.Root.FirstElement(); allowOverriding = true; } foreach (XElement sourceElement in mainElement.Elements()) { var element = sourceElement.IsOverride() ? sourceElement.FirstElement() : sourceElement; string name = element.Name.ToString().ToLowerInvariant(); switch (name) { case "grime": if (!grimeSpritesByFile.ContainsKey(configFile.Path)) { grimeSpritesByFile.Add(configFile.Path, new List <Sprite>()); } var grimeSprite = new Sprite(element); GrimeSprites.Add(grimeSprite); grimeSpritesByFile[configFile.Path].Add(grimeSprite); break; default: if (Prefabs.ContainsKey(name)) { if (allowOverriding || sourceElement.IsOverride()) { DebugConsole.NewMessage($"Overriding the existing decal prefab '{name}' using the file '{configFile.Path}'", Color.Yellow); } else { DebugConsole.ThrowError($"Error in '{configFile.Path}': Duplicate decal prefab '{name}' found in '{configFile.Path}'! Each decal prefab must have a unique name. " + "Use <override></override> tags to override prefabs."); continue; } } Prefabs.Add(new DecalPrefab(element, configFile), allowOverriding || sourceElement.IsOverride()); break; } } using MD5 md5 = MD5.Create(); foreach (DecalPrefab prefab in Prefabs) { prefab.UIntIdentifier = ToolBox.StringToUInt32Hash(prefab.Identifier, md5); //it's theoretically possible for two different values to generate the same hash, but the probability is astronomically small var collision = Prefabs.Find(p => p != prefab && p.UIntIdentifier == prefab.UIntIdentifier); if (collision != null) { DebugConsole.ThrowError("Hashing collision when generating uint identifiers for Decals: " + prefab.Identifier + " has the same identifier as " + collision.Identifier + " (" + prefab.UIntIdentifier + ")"); collision.UIntIdentifier++; } } }
private static StructurePrefab Load(XElement element, bool allowOverride, ContentFile file) { StructurePrefab sp = new StructurePrefab { originalName = element.GetAttributeString("name", ""), FilePath = file.Path, ContentPackage = file.ContentPackage }; sp.name = sp.originalName; sp.ConfigElement = element; sp.identifier = element.GetAttributeString("identifier", ""); var parentType = element.Parent?.GetAttributeString("prefabtype", "") ?? string.Empty; string nameIdentifier = element.GetAttributeString("nameidentifier", ""); string descriptionIdentifier = element.GetAttributeString("descriptionidentifier", ""); if (string.IsNullOrEmpty(sp.originalName)) { if (string.IsNullOrEmpty(nameIdentifier)) { sp.name = TextManager.Get("EntityName." + sp.identifier, true) ?? string.Empty; } else { sp.name = TextManager.Get("EntityName." + nameIdentifier, true) ?? string.Empty; } } if (string.IsNullOrEmpty(sp.name)) { sp.name = TextManager.Get("EntityName." + sp.identifier, returnNull: true) ?? $"Not defined ({sp.identifier})"; } sp.Tags = new HashSet <string>(); string joinedTags = element.GetAttributeString("tags", ""); if (string.IsNullOrEmpty(joinedTags)) { joinedTags = element.GetAttributeString("Tags", ""); } foreach (string tag in joinedTags.Split(',')) { sp.Tags.Add(tag.Trim().ToLowerInvariant()); } if (element.Attribute("ishorizontal") != null) { sp.IsHorizontal = element.GetAttributeBool("ishorizontal", false); } foreach (XElement subElement in element.Elements()) { switch (subElement.Name.ToString()) { case "sprite": sp.sprite = new Sprite(subElement, lazyLoad: true); if (subElement.Attribute("sourcerect") == null) { DebugConsole.ThrowError("Warning - sprite sourcerect not configured for structure \"" + sp.name + "\"!"); } #if CLIENT if (subElement.GetAttributeBool("fliphorizontal", false)) { sp.sprite.effects = SpriteEffects.FlipHorizontally; } if (subElement.GetAttributeBool("flipvertical", false)) { sp.sprite.effects = SpriteEffects.FlipVertically; } #endif sp.canSpriteFlipX = subElement.GetAttributeBool("canflipx", true); sp.canSpriteFlipY = subElement.GetAttributeBool("canflipy", true); if (subElement.Attribute("name") == null && !string.IsNullOrWhiteSpace(sp.Name)) { sp.sprite.Name = sp.Name; } sp.sprite.EntityID = sp.identifier; break; case "backgroundsprite": sp.BackgroundSprite = new Sprite(subElement, lazyLoad: true); if (subElement.Attribute("sourcerect") == null && sp.sprite != null) { sp.BackgroundSprite.SourceRect = sp.sprite.SourceRect; sp.BackgroundSprite.size = sp.sprite.size; sp.BackgroundSprite.size.X *= sp.sprite.SourceRect.Width; sp.BackgroundSprite.size.Y *= sp.sprite.SourceRect.Height; sp.BackgroundSprite.RelativeOrigin = subElement.GetAttributeVector2("origin", new Vector2(0.5f, 0.5f)); } #if CLIENT if (subElement.GetAttributeBool("fliphorizontal", false)) { sp.BackgroundSprite.effects = SpriteEffects.FlipHorizontally; } if (subElement.GetAttributeBool("flipvertical", false)) { sp.BackgroundSprite.effects = SpriteEffects.FlipVertically; } sp.BackgroundSpriteColor = subElement.GetAttributeColor("color", Color.White); #endif break; case "decorativesprite": #if CLIENT string decorativeSpriteFolder = ""; if (!subElement.GetAttributeString("texture", "").Contains("/")) { decorativeSpriteFolder = Path.GetDirectoryName(file.Path); } int groupID = 0; DecorativeSprite decorativeSprite = null; if (subElement.Attribute("texture") == null) { groupID = subElement.GetAttributeInt("randomgroupid", 0); } else { decorativeSprite = new DecorativeSprite(subElement, decorativeSpriteFolder, lazyLoad: true); sp.DecorativeSprites.Add(decorativeSprite); groupID = decorativeSprite.RandomGroupID; } if (!sp.DecorativeSpriteGroups.ContainsKey(groupID)) { sp.DecorativeSpriteGroups.Add(groupID, new List <DecorativeSprite>()); } sp.DecorativeSpriteGroups[groupID].Add(decorativeSprite); #endif break; } } if (string.Equals(parentType, "wrecked", StringComparison.OrdinalIgnoreCase)) { if (!string.IsNullOrEmpty(sp.Name)) { sp.name = TextManager.GetWithVariable("wreckeditemformat", "[name]", sp.name); } } string categoryStr = element.GetAttributeString("category", "Structure"); if (!Enum.TryParse(categoryStr, true, out MapEntityCategory category)) { category = MapEntityCategory.Structure; } sp.Category = category; if (category.HasFlag(MapEntityCategory.Legacy)) { if (string.IsNullOrWhiteSpace(sp.identifier)) { sp.identifier = "legacystructure_" + sp.name.ToLowerInvariant().Replace(" ", ""); } } sp.Aliases = (element.GetAttributeStringArray("aliases", null) ?? element.GetAttributeStringArray("Aliases", new string[0])).ToHashSet(); string nonTranslatedName = element.GetAttributeString("name", null) ?? element.Name.ToString(); sp.Aliases.Add(nonTranslatedName.ToLowerInvariant()); SerializableProperty.DeserializeProperties(sp, element); if (sp.Body) { sp.Tags.Add("wall"); } if (string.IsNullOrEmpty(sp.Description)) { if (!string.IsNullOrEmpty(descriptionIdentifier)) { sp.Description = TextManager.Get("EntityDescription." + descriptionIdentifier, returnNull: true) ?? string.Empty; } else if (string.IsNullOrEmpty(nameIdentifier)) { sp.Description = TextManager.Get("EntityDescription." + sp.identifier, returnNull: true) ?? string.Empty; } else { sp.Description = TextManager.Get("EntityDescription." + nameIdentifier, true) ?? string.Empty; } } //backwards compatibility if (element.Attribute("size") == null) { sp.size = Vector2.Zero; if (element.Attribute("width") == null && element.Attribute("height") == null) { sp.size.X = sp.sprite.SourceRect.Width; sp.size.Y = sp.sprite.SourceRect.Height; } else { sp.size.X = element.GetAttributeFloat("width", 0.0f); sp.size.Y = element.GetAttributeFloat("height", 0.0f); } } //backwards compatibility if (categoryStr.Equals("Thalamus", StringComparison.OrdinalIgnoreCase)) { sp.Category = MapEntityCategory.Wrecked; sp.Subcategory = "Thalamus"; } if (string.IsNullOrEmpty(sp.identifier)) { DebugConsole.ThrowError( "Structure prefab \"" + sp.name + "\" has no identifier. All structure prefabs have a unique identifier string that's used to differentiate between items during saving and loading."); } Prefabs.Add(sp, allowOverride); return(sp); }
public static bool LoadFromFile(ContentFile file, bool forceOverride = false) { return(LoadFromFile(file.Path, file.ContentPackage, forceOverride)); }
public static void LoadFromFile(ContentFile file) { DebugConsole.Log("*** " + file.Path + " ***"); RemoveByFile(file.Path); XDocument doc = XMLExtensions.TryLoadXml(file.Path); if (doc == null) { return; } var rootElement = doc.Root; switch (rootElement.Name.ToString().ToLowerInvariant()) { case "item": new ItemPrefab(rootElement, file.Path, false) { ContentPackage = file.ContentPackage }; break; case "items": foreach (var element in rootElement.Elements()) { if (element.IsOverride()) { var itemElement = element.GetChildElement("item"); if (itemElement != null) { new ItemPrefab(itemElement, file.Path, true) { ContentPackage = file.ContentPackage, IsOverride = true }; } else { DebugConsole.ThrowError($"Cannot find an item element from the children of the override element defined in {file.Path}"); } } else { new ItemPrefab(element, file.Path, false) { ContentPackage = file.ContentPackage }; } } break; case "override": var items = rootElement.GetChildElement("items"); if (items != null) { foreach (var element in items.Elements()) { new ItemPrefab(element, file.Path, true) { ContentPackage = file.ContentPackage, IsOverride = true }; } } foreach (var element in rootElement.GetChildElements("item")) { new ItemPrefab(element, file.Path, true) { ContentPackage = file.ContentPackage }; } break; default: DebugConsole.ThrowError($"Invalid XML root element: '{rootElement.Name.ToString()}' in {file.Path}"); break; } }