Client LuaCsForBarotrauma
ContentPath.cs
1 #nullable enable
2 
3 using Barotrauma.IO;
4 using System;
5 using System.Linq;
6 using System.Text.RegularExpressions;
7 
8 namespace Barotrauma
9 {
10  public sealed class ContentPath
11  {
12  public readonly static ContentPath Empty = new ContentPath(null, "");
13 
14  public const string ModDirStr = "%ModDir%";
15  public const string OtherModDirFmt = "%ModDir:{0}%";
16  private static readonly Regex OtherModDirRegex = new Regex(
17  string.Format(OtherModDirFmt, "(.+?)"));
18 
19  public readonly string? RawValue;
20 
21  public readonly ContentPackage? ContentPackage;
22 
23  private string? cachedValue;
24  private string? cachedFullPath;
25 
26  public string Value
27  {
28  get
29  {
30  if (RawValue.IsNullOrEmpty()) { return ""; }
31  if (!cachedValue.IsNullOrEmpty()) { return cachedValue!; }
32 
33  string? modName = ContentPackage?.Name;
34 
35  var otherMods = OtherModDirRegex.Matches(RawValue ?? throw new NullReferenceException($"{nameof(RawValue)} is null."))
36  .Select(m => m.Groups[1].Value.Trim().ToIdentifier())
37  .Distinct().Where(id => !id.IsEmpty && id != modName).ToHashSet();
38  cachedValue = RawValue!;
39  if (!(ContentPackage is null))
40  {
41  string modPath = Path.GetDirectoryName(ContentPackage.Path)!;
42  cachedValue = cachedValue
43  .Replace(ModDirStr, modPath, StringComparison.OrdinalIgnoreCase)
44  .Replace(string.Format(OtherModDirFmt, ContentPackage.Name), modPath, StringComparison.OrdinalIgnoreCase);
45  if (ContentPackage.UgcId.TryUnwrap(out var ugcId))
46  {
47  cachedValue = cachedValue
48  .Replace(string.Format(OtherModDirFmt, ugcId.StringRepresentation), modPath, StringComparison.OrdinalIgnoreCase);
49  }
50  }
51  var allPackages = ContentPackageManager.AllPackages;
52 #if CLIENT
53  if (GameMain.ModDownloadScreen?.DownloadedPackages != null) { allPackages = allPackages.Concat(GameMain.ModDownloadScreen.DownloadedPackages); }
54 #endif
55  foreach (Identifier otherModName in otherMods)
56  {
57  Option<ContentPackageId> ugcId = ContentPackageId.Parse(otherModName.Value);
58  ContentPackage? otherMod =
59  allPackages.FirstOrDefault(p => ugcId.IsSome() && ugcId == p.UgcId)
60  ?? allPackages.FirstOrDefault(p => p.Name == otherModName)
61  ?? allPackages.FirstOrDefault(p => p.NameMatches(otherModName))
62  ?? throw new MissingContentPackageException(ContentPackage, otherModName.Value);
63  cachedValue = cachedValue.Replace(string.Format(OtherModDirFmt, otherModName.Value), Path.GetDirectoryName(otherMod.Path));
64  }
65  cachedValue = cachedValue.CleanUpPath();
66  return cachedValue;
67  }
68  }
69 
70  public string FullPath
71  {
72  get
73  {
74  if (cachedFullPath.IsNullOrEmpty())
75  {
76  if (Value.IsNullOrEmpty())
77  {
78  return "";
79  }
80  cachedFullPath = Path.GetFullPath(Value).CleanUpPathCrossPlatform(correctFilenameCase: false);
81  }
82  return cachedFullPath!;
83  }
84  }
85 
86  private ContentPath(ContentPackage? contentPackage, string? rawValue)
87  {
88  ContentPackage = contentPackage;
89  RawValue = rawValue;
90  cachedValue = null;
91  cachedFullPath = null;
92  }
93 
94  public static ContentPath FromRaw(string? rawValue)
95  => FromRaw(null, rawValue);
96 
97  private static ContentPath? prevCreatedRaw;
98 
99  public static ContentPath FromRaw(ContentPackage? contentPackage, string? rawValue)
100  {
101  var newRaw = new ContentPath(contentPackage, rawValue);
102  if (prevCreatedRaw is not null && prevCreatedRaw.ContentPackage == contentPackage &&
103  prevCreatedRaw.RawValue == rawValue)
104  {
105  newRaw.cachedValue = prevCreatedRaw.Value;
106  }
107  prevCreatedRaw = newRaw;
108  return newRaw;
109  }
110 
111  private static bool StringEquality(string? a, string? b)
112  {
113  if (a.IsNullOrEmpty() || b.IsNullOrEmpty())
114  {
115  return a.IsNullOrEmpty() == b.IsNullOrEmpty();
116  }
117  return string.Equals(Path.GetFullPath(a.CleanUpPathCrossPlatform(correctFilenameCase: false) ?? ""),
118  Path.GetFullPath(b.CleanUpPathCrossPlatform(correctFilenameCase: false) ?? ""), StringComparison.OrdinalIgnoreCase);
119  }
120 
121  public static bool operator==(ContentPath a, ContentPath b)
122  => StringEquality(a?.Value, b?.Value);
123 
124  public static bool operator!=(ContentPath a, ContentPath b) => !(a == b);
125 
126  public static bool operator==(ContentPath a, string? b)
127  => StringEquality(a?.Value, b);
128 
129  public static bool operator!=(ContentPath a, string? b) => !(a == b);
130 
131  public static bool operator==(string? a, ContentPath b)
132  => StringEquality(a, b?.Value);
133 
134  public static bool operator!=(string? a, ContentPath b) => !(a == b);
135 
136  protected bool Equals(ContentPath other)
137  {
138  return RawValue == other.RawValue && Equals(ContentPackage, other.ContentPackage) && cachedValue == other.cachedValue && cachedFullPath == other.cachedFullPath;
139  }
140 
141  public override bool Equals(object? obj)
142  {
143  if (ReferenceEquals(null, obj)) { return false; }
144  if (ReferenceEquals(this, obj)) { return true; }
145  if (obj.GetType() != this.GetType()) { return false; }
146  return Equals((ContentPath)obj);
147  }
148 
149  public override int GetHashCode()
150  {
151  return HashCode.Combine(RawValue, ContentPackage, cachedValue, cachedFullPath);
152  }
153 
154  public bool IsPathNullOrEmpty() => string.IsNullOrEmpty(Value);
155  public bool IsPathNullOrWhiteSpace() => string.IsNullOrWhiteSpace(Value);
156 
157  public bool EndsWith(string suffix) => Value.EndsWith(suffix, StringComparison.OrdinalIgnoreCase);
158 
159  public override string? ToString() => Value;
160  }
161 }
readonly Option< ContentPackageId > UgcId
static Option< ContentPackageId > Parse(string s)
static bool operator!=(string? a, ContentPath b)
readonly? ContentPackage ContentPackage
Definition: ContentPath.cs:21
override int GetHashCode()
Definition: ContentPath.cs:149
const string OtherModDirFmt
Definition: ContentPath.cs:15
static bool operator==(string? a, ContentPath b)
readonly? string RawValue
Definition: ContentPath.cs:19
override? string ToString()
bool EndsWith(string suffix)
static ContentPath FromRaw(string? rawValue)
static readonly ContentPath Empty
Definition: ContentPath.cs:12
static bool operator==(ContentPath a, ContentPath b)
const string ModDirStr
Definition: ContentPath.cs:14
string???????????? Value
Definition: ContentPath.cs:27
static bool operator!=(ContentPath a, string? b)
static bool operator==(ContentPath a, string? b)
override bool Equals(object? obj)
Definition: ContentPath.cs:141
static ContentPath FromRaw(ContentPackage? contentPackage, string? rawValue)
Definition: ContentPath.cs:99
bool Equals(ContentPath other)
Definition: ContentPath.cs:136
static bool operator!=(ContentPath a, ContentPath b)
static ModDownloadScreen ModDownloadScreen
Definition: GameMain.cs:56
IEnumerable< ContentPackage > DownloadedPackages