Unstable 1.8.4.0
This commit is contained in:
+5
-6
@@ -1,11 +1,9 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -55,18 +53,19 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
if (AfflictionPrefab.Prefabs.ContainsKey(identifier))
|
||||
if (AfflictionPrefab.Prefabs.TryGet(identifier, out var existingAffliction))
|
||||
{
|
||||
if (overriding)
|
||||
{
|
||||
DebugConsole.NewMessage(
|
||||
$"Overriding an affliction or a buff with the identifier '{identifier}' using the file '{Path}'",
|
||||
$"Overriding an affliction or a buff with the identifier '{identifier}' using the version in '{element.ContentPackage.Name}'",
|
||||
Color.MediumPurple);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError(
|
||||
$"Duplicate affliction: '{identifier}' defined in {elementName} of '{Path}'",
|
||||
$"Duplicate affliction: '{identifier}' defined in {element.ContentPackage.Name} is already defined in the previously loaded content package {existingAffliction.ContentPackage.Name}."+
|
||||
$" You may need to adjust the mod load order to make sure {element.ContentPackage.Name} is loaded first.",
|
||||
contentPackage: element?.ContentPackage);
|
||||
return;
|
||||
}
|
||||
|
||||
+22
-3
@@ -1,9 +1,28 @@
|
||||
namespace Barotrauma
|
||||
namespace Barotrauma
|
||||
{
|
||||
sealed class BackgroundCreaturePrefabsFile : OtherFile
|
||||
#if CLIENT
|
||||
[NotSyncedInMultiplayer]
|
||||
sealed class BackgroundCreaturePrefabsFile : GenericPrefabFile<BackgroundCreaturePrefab>
|
||||
{
|
||||
public BackgroundCreaturePrefabsFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
|
||||
|
||||
//this content type only comes into play when a level is generated, so LoadFile and UnloadFile don't have anything to do
|
||||
protected override bool MatchesSingular(Identifier identifier) => !MatchesPlural(identifier);
|
||||
protected override bool MatchesPlural(Identifier identifier) => identifier == "backgroundcreatures";
|
||||
protected override PrefabCollection<BackgroundCreaturePrefab> Prefabs => BackgroundCreaturePrefab.Prefabs;
|
||||
protected override BackgroundCreaturePrefab CreatePrefab(ContentXElement element)
|
||||
{
|
||||
return new BackgroundCreaturePrefab(element, this);
|
||||
}
|
||||
|
||||
public sealed override Md5Hash CalculateHash() => Md5Hash.Blank;
|
||||
}
|
||||
#else
|
||||
[NotSyncedInMultiplayer]
|
||||
sealed class BackgroundCreaturePrefabsFile : OtherFile
|
||||
{
|
||||
public BackgroundCreaturePrefabsFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path)
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
+15
-11
@@ -1,4 +1,4 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -86,23 +86,27 @@ namespace Barotrauma
|
||||
|
||||
if (ragdollParams != null)
|
||||
{
|
||||
HashSet<string> texturePaths = new HashSet<string>
|
||||
{
|
||||
ContentPath.FromRaw(CharacterPrefab.Prefabs[speciesName].ContentPackage, ragdollParams.Texture).Value
|
||||
};
|
||||
HashSet<ContentPath> texturePaths = new HashSet<ContentPath>();
|
||||
AddTexturePath(ragdollParams.Texture);
|
||||
foreach (RagdollParams.LimbParams limb in ragdollParams.Limbs)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(limb.normalSpriteParams?.Texture)) { texturePaths.Add(limb.normalSpriteParams.Texture); }
|
||||
if (!string.IsNullOrEmpty(limb.deformSpriteParams?.Texture)) { texturePaths.Add(limb.deformSpriteParams.Texture); }
|
||||
if (!string.IsNullOrEmpty(limb.damagedSpriteParams?.Texture)) { texturePaths.Add(limb.damagedSpriteParams.Texture); }
|
||||
AddTexturePath(limb.normalSpriteParams?.Texture);
|
||||
AddTexturePath(limb.deformSpriteParams?.Texture);
|
||||
AddTexturePath(limb.damagedSpriteParams?.Texture);
|
||||
foreach (var decorativeSprite in limb.decorativeSpriteParams)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(decorativeSprite.Texture)) { texturePaths.Add(decorativeSprite.Texture); }
|
||||
AddTexturePath(decorativeSprite.Texture);
|
||||
}
|
||||
}
|
||||
foreach (string texturePath in texturePaths)
|
||||
foreach (ContentPath texturePath in texturePaths)
|
||||
{
|
||||
addPreloadedSprite(new Sprite(texturePath, Vector2.Zero));
|
||||
addPreloadedSprite(new Sprite(texturePath.Value, Vector2.Zero));
|
||||
}
|
||||
|
||||
void AddTexturePath(string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path)) { return; }
|
||||
texturePaths.Add(ContentPath.FromRaw(characterPrefab.ContentPackage, ragdollParams.Texture));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
internal sealed class DisembarkPerkFile : GenericPrefabFile<DisembarkPerkPrefab>
|
||||
{
|
||||
public DisembarkPerkFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
|
||||
|
||||
protected override bool MatchesSingular(Identifier identifier) => identifier == "disembarkperk";
|
||||
protected override bool MatchesPlural(Identifier identifier) => identifier == "disembarkperks";
|
||||
protected override PrefabCollection<DisembarkPerkPrefab> Prefabs => DisembarkPerkPrefab.Prefabs;
|
||||
protected override DisembarkPerkPrefab CreatePrefab(ContentXElement element)
|
||||
{
|
||||
return new DisembarkPerkPrefab(element, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-1
@@ -1,4 +1,4 @@
|
||||
using System.Xml.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -77,12 +77,15 @@ namespace Barotrauma
|
||||
|
||||
var rootElement = doc.Root.FromPackage(ContentPackage);
|
||||
LoadFromXElement(rootElement, false);
|
||||
|
||||
EventSet.RefreshAllEventPrefabs();
|
||||
}
|
||||
|
||||
public override void UnloadFile()
|
||||
{
|
||||
EventPrefab.Prefabs.RemoveByFile(this);
|
||||
EventSet.Prefabs.RemoveByFile(this);
|
||||
EventSet.RefreshAllEventPrefabs();
|
||||
#if CLIENT
|
||||
EventSprite.Prefabs.RemoveByFile(this);
|
||||
#endif
|
||||
@@ -92,6 +95,9 @@ namespace Barotrauma
|
||||
{
|
||||
EventPrefab.Prefabs.SortAll();
|
||||
EventSet.Prefabs.SortAll();
|
||||
//need to referesh, because the order of the prefabs may affect which content package overrides some event
|
||||
EventSet.RefreshAllEventPrefabs();
|
||||
|
||||
#if CLIENT
|
||||
EventSprite.Prefabs.SortAll();
|
||||
#endif
|
||||
|
||||
+163
-6
@@ -1,4 +1,4 @@
|
||||
#nullable enable
|
||||
#nullable enable
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Steam;
|
||||
using System;
|
||||
@@ -9,6 +9,9 @@ using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml;
|
||||
using Barotrauma.IO;
|
||||
using Steamworks.Data;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -34,14 +37,35 @@ namespace Barotrauma
|
||||
public const string FileListFileName = "filelist.xml";
|
||||
public const string DefaultModVersion = "1.0.0";
|
||||
|
||||
public readonly string Name;
|
||||
public string Name { get; private set; }
|
||||
public readonly ImmutableArray<string> AltNames;
|
||||
public readonly string Path;
|
||||
public string Path { get; private set; }
|
||||
public string Dir => Barotrauma.IO.Path.GetDirectoryName(Path) ?? "";
|
||||
public readonly Option<ContentPackageId> UgcId;
|
||||
|
||||
public readonly Version GameVersion;
|
||||
public readonly string ModVersion;
|
||||
|
||||
public enum UgcStatus
|
||||
{
|
||||
NotFetched = 0,
|
||||
Fetching = 1,
|
||||
Fetched = 2,
|
||||
Unavailable = 3
|
||||
}
|
||||
|
||||
public UgcStatus UgcItemStatus { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ugc item (workshop item) data that this content package corresponds to. Needs to be fetched with <see cref="TryFetchUgcItem(Action)"/>.
|
||||
/// You can also check <see cref="UgcItemStatus"/> to see if the item is available or not.
|
||||
/// </summary>
|
||||
public Option<Steamworks.Ugc.Item> UgcItem
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public Md5Hash Hash { get; private set; }
|
||||
public readonly Option<SerializableDateTime> InstallTime;
|
||||
|
||||
@@ -63,8 +87,15 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public Option<ContentPackageManager.LoadProgress.Error> EnableError { get; private set; }
|
||||
= Option.None;
|
||||
|
||||
public bool HasAnyErrors => FatalLoadErrors.Length > 0 || EnableError.IsSome();
|
||||
|
||||
private readonly HashSet<PublishedFileId> missingDependencies = new HashSet<PublishedFileId>();
|
||||
/// <summary>
|
||||
/// An error caused by missing dependencies (Workshop items required by the package).
|
||||
/// Can be safe to ignore.
|
||||
/// </summary>
|
||||
public IEnumerable<PublishedFileId> MissingDependencies => missingDependencies;
|
||||
|
||||
public bool HasAnyErrors => FatalLoadErrors.Length > 0 || EnableError.IsSome() || missingDependencies.Any();
|
||||
|
||||
public async Task<bool> IsUpToDate()
|
||||
{
|
||||
@@ -230,6 +261,16 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void AddMissingDependency(PublishedFileId missingItemID)
|
||||
{
|
||||
missingDependencies.Add(missingItemID);
|
||||
}
|
||||
|
||||
public void ClearMissingDependencies()
|
||||
{
|
||||
missingDependencies.Clear();
|
||||
}
|
||||
|
||||
public void LoadFilesOfType<T>() where T : ContentFile
|
||||
{
|
||||
Files.Where(f => f is T).ForEach(f => f.LoadFile());
|
||||
@@ -265,7 +306,7 @@ namespace Barotrauma
|
||||
//The game should be able to work just fine with a completely arbitrary file load order.
|
||||
//To make sure we don't mess this up, debug builds randomize it so it has a higher chance
|
||||
//of breaking anything that's not implemented correctly.
|
||||
.Randomize()
|
||||
.Randomize(Rand.RandSync.Unsynced)
|
||||
#endif
|
||||
;
|
||||
|
||||
@@ -326,6 +367,76 @@ namespace Barotrauma
|
||||
errorCatcher.Dispose();
|
||||
}
|
||||
|
||||
public void TryFetchUgcDescription(Action<string?> onFinished)
|
||||
{
|
||||
TryFetchUgcItem((Steamworks.Ugc.Item? item) =>
|
||||
{
|
||||
onFinished?.Invoke(item?.Description ?? string.Empty);
|
||||
});
|
||||
}
|
||||
|
||||
public void TryFetchUgcChildren(Action<PublishedFileId[]?> onFinished)
|
||||
{
|
||||
TryFetchUgcItem((Steamworks.Ugc.Item? item) =>
|
||||
{
|
||||
onFinished?.Invoke(item?.Children ?? Array.Empty<PublishedFileId>());
|
||||
});
|
||||
}
|
||||
|
||||
private void TryFetchUgcItem(Action<Steamworks.Ugc.Item?> onFinished)
|
||||
{
|
||||
switch (UgcItemStatus)
|
||||
{
|
||||
case UgcStatus.NotFetched:
|
||||
TryFetchUgcItem(onFinished: () =>
|
||||
{
|
||||
if (UgcItemStatus == UgcStatus.Fetched &&
|
||||
UgcItem.TryUnwrap(out var cachedItem))
|
||||
{
|
||||
onFinished?.Invoke(cachedItem);
|
||||
}
|
||||
});
|
||||
break;
|
||||
case UgcStatus.Fetched when UgcItem.TryUnwrap(out var cachedItem):
|
||||
onFinished?.Invoke(cachedItem);
|
||||
break;
|
||||
default:
|
||||
onFinished?.Invoke(null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to fetch the UgcItem (workshop item) data from Steamworks, and if successful, caches it in <see cref="UgcItem"/>.
|
||||
/// </summary>
|
||||
/// <param name="onFinished">Triggers when the query finishes or fails (or immediately if the item has been already cached)</param>
|
||||
public void TryFetchUgcItem(Action onFinished)
|
||||
{
|
||||
if (UgcItemStatus != UgcStatus.NotFetched)
|
||||
{
|
||||
onFinished?.Invoke();
|
||||
}
|
||||
if (!UgcId.TryUnwrap(out var ugcId) || ugcId is not SteamWorkshopId workshopId)
|
||||
{
|
||||
UgcItemStatus = UgcStatus.Unavailable;
|
||||
return;
|
||||
}
|
||||
|
||||
UgcItemStatus = UgcStatus.Fetching;
|
||||
TaskPool.Add($"PrepareToShow{UgcId}Info", SteamManager.Workshop.GetItem(workshopId.Value),
|
||||
task =>
|
||||
{
|
||||
if (!task.TryGetResult(out Option<Steamworks.Ugc.Item> itemOption) || !itemOption.TryUnwrap(out var item))
|
||||
{
|
||||
UgcItemStatus = UgcStatus.Unavailable;
|
||||
return;
|
||||
}
|
||||
UgcItem = Option<Steamworks.Ugc.Item>.Some(item);
|
||||
UgcItemStatus = UgcStatus.Fetched;
|
||||
onFinished?.Invoke();
|
||||
});
|
||||
}
|
||||
|
||||
public void UnloadContent()
|
||||
{
|
||||
Files.ForEach(f => f.UnloadFile());
|
||||
@@ -397,5 +508,51 @@ namespace Barotrauma
|
||||
static string errorToStr(LoadError error)
|
||||
=> error.ToString();
|
||||
}
|
||||
|
||||
public bool TryRenameLocal(string newName)
|
||||
{
|
||||
if (!ContentPackageManager.LocalPackages.Contains(this)) { return false; }
|
||||
|
||||
if (newName.IsNullOrWhiteSpace())
|
||||
{
|
||||
DebugConsole.ThrowError($"New name is blank!");
|
||||
return false;
|
||||
}
|
||||
|
||||
string newDir = IO.Path.Combine(IO.Path.GetFullPath(LocalModsDir), File.SanitizeName(newName));
|
||||
if (ContentPackageManager.LocalPackages.Any(lp => lp.NameMatches(newName)) || Directory.Exists(newDir))
|
||||
{
|
||||
DebugConsole.ThrowError($"A local package with the name or directory \"{newName}\" already exists!");
|
||||
return false;
|
||||
}
|
||||
|
||||
XDocument doc = XMLExtensions.TryLoadXml(Path);
|
||||
doc.Root!.SetAttributeValue("name", newName);
|
||||
using (IO.XmlWriter writer = IO.XmlWriter.Create(Path, new XmlWriterSettings { Indent = true }))
|
||||
{
|
||||
doc.WriteTo(writer);
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
Directory.Move(Dir, newDir);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryDeleteLocal() => ContentPackageManager.LocalPackages.Contains(this) && Directory.TryDelete(Dir);
|
||||
|
||||
public bool TryCreateLocalFromWorkshop()
|
||||
{
|
||||
if (!ContentPackageManager.WorkshopPackages.Contains(this)) { return false; }
|
||||
|
||||
string newDir = IO.Path.Combine(IO.Path.GetFullPath(LocalModsDir), File.SanitizeName(Name));
|
||||
if (ContentPackageManager.LocalPackages.Any(lp => lp.NameMatches(Name)) || Directory.Exists(newDir))
|
||||
{
|
||||
DebugConsole.ThrowError($"A local package with the name or directory \"{Name}\" already exists!");
|
||||
return false;
|
||||
}
|
||||
|
||||
Directory.Copy(Dir, newDir);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
-1
@@ -1,4 +1,4 @@
|
||||
#nullable enable
|
||||
#nullable enable
|
||||
using Barotrauma.Extensions;
|
||||
using System;
|
||||
using System.Collections;
|
||||
@@ -569,6 +569,26 @@ namespace Barotrauma
|
||||
yield return LoadProgress.Progress(1.0f);
|
||||
}
|
||||
|
||||
public static void CheckMissingDependencies()
|
||||
{
|
||||
foreach (var enabledPackage in EnabledPackages.All)
|
||||
{
|
||||
enabledPackage.ClearMissingDependencies();
|
||||
enabledPackage.TryFetchUgcChildren((Steamworks.Data.PublishedFileId[]? children) =>
|
||||
{
|
||||
if (children == null) { return; }
|
||||
var missingChildren = children
|
||||
.Where(childUgcItemId =>
|
||||
EnabledPackages.All.None(package =>
|
||||
package.UgcId.TryUnwrap(out var ugcId) && ugcId is SteamWorkshopId workshopId && workshopId.Value == childUgcItemId.Value));
|
||||
foreach (var missingChild in missingChildren)
|
||||
{
|
||||
enabledPackage.AddMissingDependency(missingChild);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void LogEnabledRegularPackageErrors()
|
||||
{
|
||||
foreach (var p in EnabledPackages.Regular)
|
||||
|
||||
@@ -93,6 +93,7 @@ namespace Barotrauma
|
||||
public Rectangle GetAttributeRect(string key, in Rectangle def) => Element.GetAttributeRect(key, def);
|
||||
public Version GetAttributeVersion(string key, Version def) => Element.GetAttributeVersion(key, def);
|
||||
public T GetAttributeEnum<T>(string key, in T def) where T : struct, Enum => Element.GetAttributeEnum(key, def);
|
||||
public T[] GetAttributeEnumArray<T>(string key, T[] def) where T : struct, Enum => Element.GetAttributeEnumArray(key, def);
|
||||
public (T1, T2) GetAttributeTuple<T1, T2>(string key, in (T1, T2) def) => Element.GetAttributeTuple(key, def);
|
||||
public (T1, T2)[] GetAttributeTupleArray<T1, T2>(string key, in (T1, T2)[] def) => Element.GetAttributeTupleArray(key, def);
|
||||
public Range<int> GetAttributeRange(string key, in Range<int> def) => Element.GetAttributeRange(key, def);
|
||||
|
||||
Reference in New Issue
Block a user