Client LuaCsForBarotrauma
BarotraumaShared/SharedSource/Map/ItemAssemblyPrefab.cs
2 using Microsoft.Xna.Framework;
3 using System;
4 using System.Collections.Generic;
5 using Barotrauma.IO;
6 using System.Linq;
7 using System.Xml.Linq;
8 using System.Collections.Immutable;
9 using System.Net;
10 
11 namespace Barotrauma
12 {
13  #warning TODO: MapEntityPrefab should be constrained further to not include item assemblies, as assemblies are effectively not entities at all
15  {
17 
18  private readonly XElement configElement;
19 
20  public readonly record struct DisplayEntity(
22  Rectangle Rect,
23  float RotationRad);
24 
25  public readonly ImmutableArray<DisplayEntity> DisplayEntities;
26 
27  public readonly Rectangle Bounds;
28 
29  public override LocalizedString Name { get; }
30 
31  public override Sprite Sprite => null;
32 
33  public override string OriginalName => Name.Value;
34 
35  public override ImmutableHashSet<Identifier> Tags { get; }
36 
37  public override ImmutableHashSet<Identifier> AllowedLinks => null;
38 
39  public override MapEntityCategory Category => MapEntityCategory.ItemAssembly;
40 
41  public override ImmutableHashSet<string> Aliases => null;
42 
43  protected override Identifier DetermineIdentifier(XElement element)
44  {
45  return element.GetAttributeIdentifier("identifier", element.GetAttributeIdentifier("name", ""));
46  }
47 
48  public ItemAssemblyPrefab(ContentXElement element, ItemAssemblyFile file) : base(element, file)
49  {
50  configElement = element;
51 
52  SerializableProperty.DeserializeProperties(this, configElement);
53 
54  Name = TextManager.Get($"EntityName.{Identifier}").Fallback(element.GetAttributeString("name", ""));
55  Description = TextManager.Get($"EntityDescription.{Identifier}");
56  Tags = Enumerable.Empty<Identifier>().ToImmutableHashSet();
57 
58  string description = element.GetAttributeString("description", string.Empty);
59  if (!description.IsNullOrEmpty())
60  {
61  Description = Description.Fallback(description);
62  }
63 
64  List<ushort> containedItemIDs = new List<ushort>();
65  foreach (XElement entityElement in element.Elements())
66  {
67  var containerElement = entityElement.GetChildElement("itemcontainer");
68  if (containerElement == null) { continue; }
69 
70  string containedString = containerElement.GetAttributeString("contained", "");
71  string[] itemIdStrings = containedString.Split(',');
72  var itemIds = new List<ushort>[itemIdStrings.Length];
73  for (int i = 0; i < itemIdStrings.Length; i++)
74  {
75  itemIds[i] ??= new List<ushort>();
76  foreach (string idStr in itemIdStrings[i].Split(';'))
77  {
78  if (int.TryParse(idStr, out int id))
79  {
80  itemIds[i].Add((ushort)id);
81  containedItemIDs.Add((ushort)id);
82  }
83  }
84  }
85  }
86 
87  int minX = int.MaxValue, minY = int.MaxValue;
88  int maxX = int.MinValue, maxY = int.MinValue;
89  var displayEntities = new List<DisplayEntity>();
90  foreach (XElement entityElement in element.Elements())
91  {
92  ushort id = (ushort)entityElement.GetAttributeInt("ID", 0);
93  if (id > 0 && containedItemIDs.Contains(id)) { continue; }
94 
95  if (entityElement.Elements().Any(e => e.Name.LocalName.Equals("wire", StringComparison.OrdinalIgnoreCase))) { continue; }
96 
97  Identifier identifier = entityElement.GetAttributeIdentifier("identifier", entityElement.Name.ToString().ToLowerInvariant());
98  Rectangle rect = entityElement.GetAttributeRect("rect", Rectangle.Empty);
99  float rotation = MathHelper.ToRadians(entityElement.GetAttributeFloat("rotation", 0.0f));
100  if (!entityElement.GetAttributeBool("hideinassemblypreview", false))
101  {
102  displayEntities.Add(new DisplayEntity(identifier, rect, rotation));
103  }
104  minX = Math.Min(minX, rect.X);
105  minY = Math.Min(minY, rect.Y - rect.Height);
106  maxX = Math.Max(maxX, rect.Right);
107  maxY = Math.Max(maxY, rect.Y);
108  }
109  DisplayEntities = displayEntities.ToImmutableArray();
110 
111  Bounds = minX == int.MaxValue ?
112  new Rectangle(0, 0, 1, 1) :
113  new Rectangle(minX, minY, maxX - minX, maxY - minY);
114  }
115 
116  protected override void CreateInstance(Rectangle rect)
117  {
118 #if CLIENT
119  var loaded = CreateInstance(rect.Location.ToVector2(), Submarine.MainSub, selectInstance: Screen.Selected == GameMain.SubEditorScreen);
120  if (Screen.Selected is SubEditorScreen && loaded.Any())
121  {
122  SubEditorScreen.StoreCommand(new AddOrDeleteCommand(loaded, false, handleInventoryBehavior: false));
123  }
124 #else
125  var loaded = CreateInstance(rect.Location.ToVector2(), Submarine.MainSub);
126 #endif
127  }
128 
129  public List<MapEntity> CreateInstance(Vector2 position, Submarine sub, bool selectInstance = false)
130  {
131  var retVal = PasteEntities(position, sub, configElement, ContentFile.Path.Value, selectInstance);
132 #if CLIENT
134 #endif
135  return retVal;
136  }
137 
138  public static List<MapEntity> PasteEntities(Vector2 position, Submarine sub, XElement configElement, string filePath = null, bool selectInstance = false)
139  {
140  int idOffset = Entity.FindFreeIdBlock(configElement.Elements().Count());
141  List<MapEntity> entities = MapEntity.LoadAll(sub, configElement, filePath, idOffset);
142  if (entities.Count == 0) { return entities; }
143 
144  Vector2 offset = sub?.HiddenSubPosition ?? Vector2.Zero;
145 
146  foreach (MapEntity me in entities)
147  {
148  me.Move(position);
149  me.Submarine = sub;
150  if (me is not Item item) { continue; }
151  Wire wire = item.GetComponent<Wire>();
152  //Vector2 subPosition = Submarine == null ? Vector2.Zero : Submarine.HiddenSubPosition;
153  if (wire != null)
154  {
155  //fix wires that have been erroneously saved at the "hidden position"
156  if (sub != null && Vector2.Distance(me.Position, sub.HiddenSubPosition) > sub.HiddenSubPosition.Length() / 2)
157  {
158  me.Move(position);
159  }
160  wire.MoveNodes(position - offset);
161  }
162  }
163 
164  MapEntity.MapLoaded(entities, true);
165 #if CLIENT
166  if (Screen.Selected == GameMain.SubEditorScreen && selectInstance)
167  {
168  MapEntity.SelectedList.Clear();
169  entities.ForEach(MapEntity.AddSelection);
170  }
171 #endif
172  return entities;
173  }
174 
175  public void Delete()
176  {
177  Prefabs.Remove(this);
178  try
179  {
180  if (ContentPackage is { Files: { Length: 1 } }
181  && ContentPackageManager.LocalPackages.Contains(ContentPackage))
182  {
183  Directory.Delete(ContentPackage.Dir, recursive: true);
184  ContentPackageManager.LocalPackages.Refresh();
185  ContentPackageManager.EnabledPackages.DisableRemovedMods();
186  }
187  }
188  catch (Exception e)
189  {
190  DebugConsole.ThrowErrorLocalized("Deleting item assembly \"" + Name + "\" failed.", e);
191  }
192  }
193 
194  public override void Dispose() { }
195  }
196 }
Base class for content file types, which are loaded from filelist.xml via reflection....
Definition: ContentFile.cs:23
readonly ContentPath Path
Definition: ContentFile.cs:137
string???????????? Value
Definition: ContentPath.cs:27
string? GetAttributeString(string key, string? def)
static int FindFreeIdBlock(int minBlockSize)
Finds a contiguous block of free IDs of at least the given size
Definition: Entity.cs:180
Submarine Submarine
Definition: Entity.cs:53
static SubEditorScreen SubEditorScreen
Definition: GameMain.cs:68
List< MapEntity > CreateInstance(Vector2 position, Submarine sub, bool selectInstance=false)
static List< MapEntity > PasteEntities(Vector2 position, Submarine sub, XElement configElement, string filePath=null, bool selectInstance=false)
static readonly PrefabCollection< ItemAssemblyPrefab > Prefabs
readonly record struct DisplayEntity(Identifier Identifier, Rectangle Rect, float RotationRad)
ItemAssemblyPrefab(ContentXElement element, ItemAssemblyFile file)
LocalizedString Fallback(LocalizedString fallback, bool useDefaultLanguageIfFound=true)
Use this text instead if the original text cannot be found.
static void MapLoaded(List< MapEntity > entities, bool updateHulls)
virtual void Move(Vector2 amount, bool ignoreContacts=true)
static List< MapEntity > LoadAll(Submarine submarine, XElement parentElement, string filePath, int idOffset)
readonly Identifier Identifier
Definition: Prefab.cs:34
static Dictionary< Identifier, SerializableProperty > DeserializeProperties(object obj, XElement element=null)
static void StoreCommand(Command command)