Server LuaCsForBarotrauma
MapEntityPrefab.cs
1 using Microsoft.Xna.Framework;
2 using System;
3 using System.Collections.Generic;
4 using System.Collections.Immutable;
5 using System.Linq;
7 
8 namespace Barotrauma
9 {
10  [Flags]
12  {
13  None = 0,
14  Structure = 1,
15  Decorative = 2,
16  Machine = 4,
17  Medical = 8,
18  Weapon = 16,
19  Diving = 32,
20  Equipment = 64,
21  Fuel = 128,
22  Electrical = 256,
23  Material = 1024,
24  Alien = 2048,
25  Wrecked = 4096,
26  ItemAssembly = 8192,
27  Legacy = 16384,
28  Misc = 32768
29  }
30 
31  abstract partial class MapEntityPrefab : PrefabWithUintIdentifier
32  {
33  public static IEnumerable<MapEntityPrefab> List
34  {
35  get
36  {
37  foreach (var ep in CoreEntityPrefab.Prefabs)
38  {
39  yield return ep;
40  }
41 
42  foreach (var ep in StructurePrefab.Prefabs)
43  {
44  yield return ep;
45  }
46 
47  foreach (var ep in ItemPrefab.Prefabs)
48  {
49  yield return ep;
50  }
51 
52  foreach (var ep in ItemAssemblyPrefab.Prefabs)
53  {
54  yield return ep;
55  }
56  }
57  }
58 
59  //which prefab has been selected for placing
60  public static MapEntityPrefab Selected { get; set; }
61 
62  //the position where the structure is being placed (needed when stretching the structure)
63  protected static Vector2 placePosition;
64 
65  public static bool SelectPrefab(object selection)
66  {
67  if ((Selected = selection as MapEntityPrefab) != null)
68  {
69  placePosition = Vector2.Zero;
70  return true;
71  }
72  else
73  {
74  return false;
75  }
76  }
77 
78  //a method that allows the GUIListBoxes to check through a delegate if the entityprefab is still selected
79  public static object GetSelected()
80  {
81  return (object)Selected;
82  }
83 
89  [Obsolete("Prefer MapEntityPrefab.FindByIdentifier or MapEntityPrefab.FindByName")]
90  public static MapEntityPrefab Find(string name, string identifier = null, bool showErrorMessages = true)
91  {
92  return Find(name, (identifier ?? "").ToIdentifier(), showErrorMessages);
93  }
94 
95  [Obsolete("Prefer MapEntityPrefab.FindByIdentifier or MapEntityPrefab.FindByName")]
96  public static MapEntityPrefab Find(string name, Identifier identifier, bool showErrorMessages = true)
97  {
98  //try to search based on identifier first
99  if (string.IsNullOrEmpty(name) && !identifier.IsEmpty)
100  {
101  if (CoreEntityPrefab.Prefabs.ContainsKey(identifier)) { return CoreEntityPrefab.Prefabs[identifier]; }
102  if (StructurePrefab.Prefabs.ContainsKey(identifier)) { return StructurePrefab.Prefabs[identifier]; }
103  if (ItemPrefab.Prefabs.ContainsKey(identifier)) { return ItemPrefab.Prefabs[identifier]; }
104  if (ItemAssemblyPrefab.Prefabs.ContainsKey(identifier)) { return ItemAssemblyPrefab.Prefabs[identifier]; }
105  }
106 
107  foreach (MapEntityPrefab prefab in List)
108  {
109  if (!identifier.IsEmpty)
110  {
111  if (prefab.Identifier != identifier)
112  {
113  if (prefab.Aliases != null && prefab.Aliases.Any(a => a == identifier))
114  {
115  return prefab;
116  }
117  continue;
118  }
119  else
120  {
121  if (string.IsNullOrEmpty(name)) { return prefab; }
122  }
123  }
124  if (!string.IsNullOrEmpty(name))
125  {
126  if (prefab.Name.Equals(name, StringComparison.OrdinalIgnoreCase) ||
127  prefab.OriginalName.Equals(name, StringComparison.OrdinalIgnoreCase) ||
128  (prefab.Aliases != null && prefab.Aliases.Any(a => a.Equals(name, StringComparison.OrdinalIgnoreCase))))
129  {
130  return prefab;
131  }
132  }
133  }
134 
135  if (showErrorMessages)
136  {
137  DebugConsole.ThrowError("Failed to find a matching MapEntityPrefab (name: \"" + name + "\", identifier: \"" + identifier + "\").\n" + Environment.StackTrace.CleanupStackTrace());
138  }
139  return null;
140  }
141 
142  public static MapEntityPrefab GetRandom(Predicate<MapEntityPrefab> predicate, Rand.RandSync sync)
143  {
144  return List.GetRandom(p => predicate(p), sync);
145  }
146 
151  public static MapEntityPrefab Find(Predicate<MapEntityPrefab> predicate)
152  {
153  return List.FirstOrDefault(p => predicate(p));
154  }
155 
156 
157  public static MapEntityPrefab FindByName(string name)
158  {
159  if (name.IsNullOrEmpty()) { throw new ArgumentException($"{nameof(name)} must not be null or empty"); }
160 
161  var matches =
162  List.Where(prefab =>
163  prefab.Name.Equals(name, StringComparison.OrdinalIgnoreCase) ||
164  prefab.OriginalName.Equals(name, StringComparison.OrdinalIgnoreCase) ||
165  (prefab.Aliases != null &&
166  prefab.Aliases.Any(a => a.Equals(name, StringComparison.OrdinalIgnoreCase))));
167  //if there's multiple matches, prefer ones that aren't hidden in menus and base items
168  //(hidden ones and variants are often e.g. some kind of special ones used in an event or versions unlockable with talents)
169  if (matches.Count() > 1)
170  {
171  var bestMatch =
172  matches.FirstOrDefault(prefab => !prefab.HideInMenus) ??
173  matches.FirstOrDefault(prefab => prefab is ItemPrefab ip && ip.VariantOf.IsEmpty);
174  if (bestMatch != null) { return bestMatch; }
175  }
176  return matches.FirstOrDefault();
177  }
178 
179  public static MapEntityPrefab FindByIdentifier(Identifier identifier)
180  => CoreEntityPrefab.Prefabs.TryGet(identifier, out var corePrefab) ? corePrefab
181  : ItemPrefab.Prefabs.TryGet(identifier, out var itemPrefab) ? itemPrefab
182  : StructurePrefab.Prefabs.TryGet(identifier, out var structurePrefab) ? structurePrefab
183  : ItemAssemblyPrefab.Prefabs.TryGet(identifier, out var itemAssemblyPrefab) ? itemAssemblyPrefab
184  : (MapEntityPrefab)null;
185 
186  public abstract Sprite Sprite { get; }
187 
188  public virtual bool CanSpriteFlipX { get; } = false;
189  public virtual bool CanSpriteFlipY { get; } = false;
190 
191  public abstract string OriginalName { get; }
192 
193  public abstract LocalizedString Name { get; }
194 
195  public abstract ImmutableHashSet<Identifier> Tags { get; }
196 
200  public abstract ImmutableHashSet<Identifier> AllowedLinks { get; }
201 
202  public abstract MapEntityCategory Category { get; }
203 
204  //If a matching prefab is not found when loading a sub, the game will attempt to find a prefab with a matching alias.
205  //(allows changing names while keeping backwards compatibility with older sub files)
206  public abstract ImmutableHashSet<string> Aliases { get; }
207 
208  //is it possible to stretch the entity horizontally/vertically
209  [Serialize(false, IsPropertySaveable.No)]
210  public bool ResizeHorizontal { get; protected set; }
211 
212  [Serialize(false, IsPropertySaveable.No)]
213  public bool ResizeVertical { get; protected set; }
214 
215  [Serialize("", IsPropertySaveable.No)]
216  public LocalizedString Description { get; protected set; }
217 
218  [Serialize("", IsPropertySaveable.No)]
219  public string AllowedUpgrades { get; protected set; }
220 
221  [Serialize(false, IsPropertySaveable.No)]
222  public bool HideInMenus { get; protected set; }
223 
224  [Serialize(false, IsPropertySaveable.No)]
225  public bool HideInEditors { get; protected set; }
226 
227  [Serialize("", IsPropertySaveable.No)]
228  public string Subcategory { get; protected set; }
229 
230  [Serialize(false, IsPropertySaveable.No)]
231  public bool Linkable { get; protected set; }
232 
233  [Serialize("1.0,1.0,1.0,1.0", IsPropertySaveable.No)]
234  public Color SpriteColor { get; protected set; }
235 
236  [Serialize(1f, IsPropertySaveable.Yes), Editable(0.1f, 10f, DecimalCount = 3)]
237  public float Scale { get; protected set; }
238 
239  protected MapEntityPrefab(Identifier identifier) : base(null, identifier) { }
240 
241  public MapEntityPrefab(ContentXElement element, ContentFile file) : base(file, element) { }
242 
243  public string GetItemNameTextId()
244  {
245  var textId = $"entityname.{Identifier}";
246  return TextManager.ContainsTag(textId) ? textId : null;
247  }
248 
249  public string GetHullNameTextId()
250  {
251  var textId = $"roomname.{Identifier}";
252  return TextManager.ContainsTag(textId) ? textId : null;
253  }
254 
255  private string cachedAllowedUpgrades = "";
256  private ImmutableHashSet<Identifier> allowedUpgradeSet;
257  public IEnumerable<Identifier> GetAllowedUpgrades()
258  {
259  if (string.IsNullOrWhiteSpace(AllowedUpgrades)) { return Enumerable.Empty<Identifier>(); }
260  if (allowedUpgradeSet is null || cachedAllowedUpgrades != AllowedUpgrades)
261  {
262  allowedUpgradeSet = AllowedUpgrades.ToIdentifiers().ToImmutableHashSet();
263  cachedAllowedUpgrades = AllowedUpgrades;
264  }
265 
266  return allowedUpgradeSet;
267  }
268 
269  public bool HasSubCategory(string subcategory)
270  {
271  return subcategory?.Equals(this.Subcategory, StringComparison.OrdinalIgnoreCase) ?? false;
272  }
273 
274  protected abstract void CreateInstance(Rectangle rect);
275 
276 #if DEBUG
277  public void DebugCreateInstance()
278  {
279  Rectangle rect = new Rectangle(new Point((int)Screen.Selected.Cam.WorldViewCenter.X, (int)Screen.Selected.Cam.WorldViewCenter.Y), new Point((int)Submarine.GridSize.X, (int)Submarine.GridSize.Y));
280  CreateInstance(rect);
281  }
282 #endif
283 
287  public bool NameMatches(string name, StringComparison comparisonType) => OriginalName.Equals(name, comparisonType) || (Aliases != null && Aliases.Any(a => a.Equals(name, comparisonType)));
288 
289  public bool NameMatches(IEnumerable<string> allowedNames, StringComparison comparisonType) => allowedNames.Any(n => NameMatches(n, comparisonType));
290 
291  public bool IsLinkAllowed(MapEntityPrefab target)
292  {
293  if (target == null) { return false; }
294  if (target is StructurePrefab && AllowedLinks.Contains("structure".ToIdentifier())) { return true; }
295  if (target is ItemPrefab && AllowedLinks.Contains("item".ToIdentifier())) { return true; }
296  if (target is LinkedSubmarinePrefab && Tags.Contains("dock".ToIdentifier())) { return true; }
297  if (this is LinkedSubmarinePrefab && target.Tags.Contains("dock".ToIdentifier())) { return true; }
298  return AllowedLinks.Contains(target.Identifier) || target.AllowedLinks.Contains(Identifier)
299  || target.Tags.Any(t => AllowedLinks.Contains(t)) || Tags.Any(t => target.AllowedLinks.Contains(t));
300  }
301 
302  protected void LoadDescription(ContentXElement element)
303  {
304  Identifier descriptionIdentifier = element.GetAttributeIdentifier("descriptionidentifier", "");
305  Identifier nameIdentifier = element.GetAttributeIdentifier("nameidentifier", "");
306 
307  string originalDescription = Description.Value;
308  if (descriptionIdentifier != Identifier.Empty)
309  {
310  Description = TextManager.Get($"EntityDescription.{descriptionIdentifier}");
311  }
312  else if (nameIdentifier == Identifier.Empty)
313  {
314  Description = TextManager.Get($"EntityDescription.{Identifier}");
315  }
316  else
317  {
318  Description = TextManager.Get($"EntityDescription.{nameIdentifier}");
319  }
320  if (!originalDescription.IsNullOrEmpty())
321  {
322  Description = Description.Fallback(originalDescription);
323  }
324  }
325  }
326 }
Vector2 WorldViewCenter
Definition: Camera.cs:83
Base class for content file types, which are loaded from filelist.xml via reflection....
Definition: ContentFile.cs:23
Identifier GetAttributeIdentifier(string key, string def)
static readonly PrefabCollection< CoreEntityPrefab > Prefabs
static readonly PrefabCollection< ItemAssemblyPrefab > Prefabs
static readonly PrefabCollection< ItemPrefab > Prefabs
Definition: ItemPrefab.cs:483
LocalizedString Fallback(LocalizedString fallback, bool useDefaultLanguageIfFound=true)
Use this text instead if the original text cannot be found.
override bool Equals(object? obj)
MapEntityPrefab(ContentXElement element, ContentFile file)
abstract ImmutableHashSet< string > Aliases
bool NameMatches(IEnumerable< string > allowedNames, StringComparison comparisonType)
abstract ImmutableHashSet< Identifier > AllowedLinks
Links defined to identifiers.
static MapEntityPrefab GetRandom(Predicate< MapEntityPrefab > predicate, Rand.RandSync sync)
bool NameMatches(string name, StringComparison comparisonType)
Check if the name or any of the aliases of this prefab match the given name.
bool IsLinkAllowed(MapEntityPrefab target)
static MapEntityPrefab FindByName(string name)
static IEnumerable< MapEntityPrefab > List
abstract ImmutableHashSet< Identifier > Tags
static MapEntityPrefab FindByIdentifier(Identifier identifier)
static bool SelectPrefab(object selection)
IEnumerable< Identifier > GetAllowedUpgrades()
static MapEntityPrefab Find(Predicate< MapEntityPrefab > predicate)
Find a matching map entity prefab
static MapEntityPrefab Selected
MapEntityPrefab(Identifier identifier)
void LoadDescription(ContentXElement element)
abstract LocalizedString Name
abstract MapEntityCategory Category
abstract void CreateInstance(Rectangle rect)
static MapEntityPrefab Find(string name, Identifier identifier, bool showErrorMessages=true)
static MapEntityPrefab Find(string name, string identifier=null, bool showErrorMessages=true)
Find a matching map entity prefab
bool HasSubCategory(string subcategory)
readonly Identifier Identifier
Definition: Prefab.cs:34
Prefab that has a property serves as a deterministic hash of a prefab's identifier....
static Screen Selected
Definition: Screen.cs:5
virtual Camera Cam
Definition: Screen.cs:48
static readonly PrefabCollection< StructurePrefab > Prefabs