From 2ffb8d922d45a8f31dccd1dddb62520eb2bc94d1 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Mon, 29 Apr 2019 21:10:51 +0300 Subject: [PATCH] (acf0cb343) Fixes to EnableWorkShopItem: - Don't allow enabling if the item is not compatible with the user's version of Barotrauma or if it's a core package that's missing some required files. - Don't allow enabling if the item external files referenced in the content package are not found (e.g. if a mod uses vanilla files but the vanilla files aren't found). --- .../Source/Characters/Animation/Ragdoll.cs | 26 +++++++++ .../Source/Networking/SteamManager.cs | 56 +++++++++++++++++-- .../Source/Screens/SteamWorkshopScreen.cs | 8 ++- .../BarotraumaShared/Source/ContentPackage.cs | 29 +++++++++- .../BarotraumaShared/Source/GameSettings.cs | 22 ++++---- 5 files changed, 121 insertions(+), 20 deletions(-) diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs index 8f9276859..bcf133b30 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/Animation/Ragdoll.cs @@ -152,6 +152,32 @@ namespace Barotrauma } + if (character.MemLocalState.Count > 120) character.MemLocalState.RemoveRange(0, character.MemLocalState.Count - 120); + character.MemState.Clear(); + } + } + + partial void ImpactProjSpecific(float impact, Body body) + { + float volume = MathHelper.Clamp(impact - 3.0f, 0.5f, 1.0f); + + if (body.UserData is Limb limb && character.Stun <= 0f) + { + if (impact > 3.0f) { PlayImpactSound(limb); } + } + else if (body.UserData is Limb || body == Collider.FarseerBody) + { + if (!character.IsRemotePlayer && impact > ImpactTolerance) + { + SoundPlayer.PlayDamageSound("LimbBlunt", strongestImpact, Collider); + } + } + if (Character.Controlled == character) + { + GameMain.GameScreen.Cam.Shake = Math.Min(Math.Max(strongestImpact, GameMain.GameScreen.Cam.Shake), 3.0f); + } + } + if (character.MemState.Count < 1) return; overrideTargetMovement = Vector2.Zero; diff --git a/Barotrauma/BarotraumaClient/Source/Networking/SteamManager.cs b/Barotrauma/BarotraumaClient/Source/Networking/SteamManager.cs index 94131a5b3..4d4f12241 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/SteamManager.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/SteamManager.cs @@ -583,6 +583,23 @@ namespace Barotrauma.Steam ContentPackage contentPackage = new ContentPackage(metaDataFilePath); string newContentPackagePath = GetWorkshopItemContentPackagePath(contentPackage); + if (!contentPackage.IsCompatible()) + { + errorMsg = TextManager.Get(contentPackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage") + .Replace("[packagename]", contentPackage.Name) + .Replace("[packageversion]", contentPackage.GameVersion.ToString()) + .Replace("[gameversion]", GameMain.Version.ToString()); + return false; + } + + if (contentPackage.CorePackage && !contentPackage.ContainsRequiredCorePackageFiles(out List missingContentTypes)) + { + errorMsg = TextManager.Get("ContentPackageMissingCoreFiles") + .Replace("[packagename]", contentPackage.Name) + .Replace("[missingfiletypes]", string.Join(", ", missingContentTypes)); + return false; + } + var allPackageFiles = Directory.GetFiles(item.Directory.FullName, "*", SearchOption.AllDirectories); List nonContentFiles = new List(); foreach (string file in allPackageFiles) @@ -599,8 +616,6 @@ namespace Barotrauma.Steam if (!allowFileOverwrite) { - // TODO: If you create a new mod via the workshop interface and enable it, it will show the error msg, but still allows you to enable the content. - if (File.Exists(newContentPackagePath) && !CheckFileEquality(newContentPackagePath, metaDataFilePath)) { errorMsg = TextManager.Get("WorkshopErrorOverwriteOnEnable") @@ -629,12 +644,41 @@ namespace Barotrauma.Steam foreach (ContentFile contentFile in contentPackage.Files) { string sourceFile = Path.Combine(item.Directory.FullName, contentFile.Path); - if (!File.Exists(sourceFile)) { continue; } + + //path not allowed -> the content file must be a reference to an external file (such as some vanilla file outside the Mods folder) if (!ContentPackage.IsModFilePathAllowed(contentFile)) { - DebugConsole.ThrowError(TextManager.Get("WorkshopErrorIllegalPathOnEnable").Replace("[filename]", contentFile.Path)); + //the content package is trying to copy a file to a prohibited path, which is not allowed + if (File.Exists(sourceFile)) + { + errorMsg = TextManager.Get("WorkshopErrorIllegalPathOnEnable").Replace("[filename]", contentFile.Path); + return false; + } + //not trying to copy anything, so this is a reference to an external file + //if the external file doesn't exist, we cannot enable the package + else if (!File.Exists(contentFile.Path)) + { + //TODO: add the error message to localization + errorMsg = TextManager.Get("WorkshopErrorEnableFailed").Replace("[itemname]", item.Title) + " {File \"" + contentFile.Path + "\" not found.}"; + return false; + } continue; } + else if (!File.Exists(sourceFile)) + { + if (File.Exists(contentFile.Path)) + { + //the file is already present in the game folder, all good + continue; + } + else + { + //file not present in either the mod or the game folder -> cannot enable the package + //TODO: add the error message to localization + errorMsg = TextManager.Get("WorkshopErrorEnableFailed").Replace("[itemname]", item.Title) + " {File \"" + contentFile.Path + "\" not found.}"; + return false; + } + } //make sure the destination directory exists Directory.CreateDirectory(Path.GetDirectoryName(contentFile.Path)); @@ -656,7 +700,7 @@ namespace Barotrauma.Steam } catch (Exception e) { - errorMsg = TextManager.Get("WorkshopErrorEnableFailed").Replace("[itemname]", item.Title) + " " + e.Message; + errorMsg = TextManager.Get("WorkshopErrorEnableFailed").Replace("[itemname]", item.Title) + " {" + e.Message + "}"; DebugConsole.NewMessage(errorMsg, Microsoft.Xna.Framework.Color.Red); return false; } @@ -827,7 +871,7 @@ namespace Barotrauma.Steam { foreach (ContentFile contentFile in contentPackage.Files) { - if (!File.Exists(contentFile.Path)) return false; + if (!File.Exists(contentFile.Path)) { return false; } } } diff --git a/Barotrauma/BarotraumaClient/Source/Screens/SteamWorkshopScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/SteamWorkshopScreen.cs index a2a112ec5..c2c825c7b 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/SteamWorkshopScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/SteamWorkshopScreen.cs @@ -383,6 +383,7 @@ namespace Barotrauma var titleText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.0f), rightColumn.RectTransform), EnsureUTF8(item.Title), textAlignment: Alignment.CenterLeft, wrap: true) { + UserData = "titletext", CanBeFocused = false }; @@ -575,8 +576,7 @@ namespace Barotrauma private bool ToggleItemEnabled(GUITickBox tickBox) { - Facepunch.Steamworks.Workshop.Item item = tickBox.UserData as Facepunch.Steamworks.Workshop.Item; - if (item == null) { return false; } + if (!(tickBox.UserData is Facepunch.Steamworks.Workshop.Item item)) { return false; } var updateButton = tickBox.Parent.FindChild("updatebutton"); @@ -585,7 +585,9 @@ namespace Barotrauma { if (!SteamManager.EnableWorkShopItem(item, false, out errorMsg)) { - tickBox.Enabled = false; + tickBox.Visible = false; + tickBox.Selected = false; + if (tickBox.Parent.GetChildByUserData("titletext") is GUITextBlock titleText) { titleText.TextColor = Color.Red; } } } else diff --git a/Barotrauma/BarotraumaShared/Source/ContentPackage.cs b/Barotrauma/BarotraumaShared/Source/ContentPackage.cs index fe9c213f3..e51a98e27 100644 --- a/Barotrauma/BarotraumaShared/Source/ContentPackage.cs +++ b/Barotrauma/BarotraumaShared/Source/ContentPackage.cs @@ -217,6 +217,7 @@ namespace Barotrauma { return corePackageRequiredFiles.All(fileType => Files.Any(file => file.Type == fileType)); } + public bool ContainsRequiredCorePackageFiles(out List missingContentTypes) { missingContentTypes = new List(); @@ -230,6 +231,25 @@ namespace Barotrauma return missingContentTypes.Count == 0; } + /// + /// Make sure all the files defined in the content package are present + /// + /// + public bool VerifyFiles(out List errorMessages) + { + errorMessages = new List(); + foreach (ContentFile file in Files) + { + if (!File.Exists(file.Path)) + { + errorMessages.Add("File \"" + file.Path + "\" not found."); + continue; + } + } + + return errorMessages.Count == 0; + } + public static ContentPackage CreatePackage(string name, string path, bool corePackage) { ContentPackage newPackage = new ContentPackage() @@ -398,6 +418,13 @@ namespace Barotrauma return path == "Mods"; } } + /// + /// Are mods allowed to install a file into the specified path. If a content package XML includes files + /// with a prohibited path, they are treated as references to external files. For example, a mod could include + /// some vanilla files in the XML, in which case the game will simply use the vanilla files present in the game folder. + /// + /// + /// public static bool IsModFilePathAllowed(string path) { while (true) @@ -426,7 +453,7 @@ namespace Barotrauma { return Files.Where(f => f.Type == type).Select(f => f.Path); } - + public static void LoadAll(string folder) { if (!Directory.Exists(folder)) diff --git a/Barotrauma/BarotraumaShared/Source/GameSettings.cs b/Barotrauma/BarotraumaShared/Source/GameSettings.cs index e85d877db..fc6b1cdc0 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSettings.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSettings.cs @@ -604,13 +604,14 @@ namespace Barotrauma } foreach (ContentPackage contentPackage in SelectedContentPackages) { + bool packageOk = contentPackage.VerifyFiles(out List errorMessages); + if (!packageOk) + { + DebugConsole.ThrowError("Error in content package \"" + contentPackage.Name + "\":\n" + string.Join("\n", errorMessages)); + continue; + } foreach (ContentFile file in contentPackage.Files) { - if (!System.IO.File.Exists(file.Path)) - { - DebugConsole.ThrowError("Error in content package \"" + contentPackage.Name + "\" - file \"" + file.Path + "\" not found."); - continue; - } ToolBox.IsProperFilenameCase(file.Path); } } @@ -970,13 +971,14 @@ namespace Barotrauma foreach (ContentPackage contentPackage in SelectedContentPackages) { + bool packageOk = contentPackage.VerifyFiles(out List errorMessages); + if (!packageOk) + { + DebugConsole.ThrowError("Error in content package \"" + contentPackage.Name + "\":\n" + string.Join("\n", errorMessages)); + continue; + } foreach (ContentFile file in contentPackage.Files) { - if (!System.IO.File.Exists(file.Path)) - { - DebugConsole.ThrowError("Error in content package \"" + contentPackage.Name + "\" - file \"" + file.Path + "\" not found."); - continue; - } ToolBox.IsProperFilenameCase(file.Path); } }