2 using Microsoft.Xna.Framework;
4 using System.Collections.Generic;
8 using System.Collections.Immutable;
13 #warning TODO: MapEntityPrefab should be constrained further to not include item assemblies, as assemblies are effectively not entities at all
18 private readonly XElement configElement;
35 public override ImmutableHashSet<Identifier>
Tags {
get; }
41 public override ImmutableHashSet<string>
Aliases =>
null;
45 return element.GetAttributeIdentifier(
"identifier", element.GetAttributeIdentifier(
"name",
""));
50 configElement = element;
55 Description = TextManager.Get($
"EntityDescription.{Identifier}");
59 if (!description.IsNullOrEmpty())
64 List<ushort> containedItemIDs =
new List<ushort>();
65 foreach (XElement entityElement
in element.Elements())
67 var containerElement = entityElement.GetChildElement(
"itemcontainer");
68 if (containerElement ==
null) {
continue; }
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++)
75 itemIds[i] ??=
new List<ushort>();
76 foreach (
string idStr
in itemIdStrings[i].Split(
';'))
78 if (
int.TryParse(idStr, out
int id))
80 itemIds[i].Add((ushort)
id);
81 containedItemIDs.Add((ushort)
id);
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())
92 ushort
id = (ushort)entityElement.GetAttributeInt(
"ID", 0);
93 if (
id > 0 && containedItemIDs.Contains(
id)) {
continue; }
95 if (entityElement.Elements().Any(e => e.Name.LocalName.Equals(
"wire", StringComparison.OrdinalIgnoreCase))) {
continue; }
97 Identifier identifier = entityElement.GetAttributeIdentifier(
"identifier", entityElement.Name.ToString().ToLowerInvariant());
98 Rectangle rect = entityElement.GetAttributeRect(
"rect", Rectangle.Empty);
99 float scale = entityElement.GetAttributeFloat(
"scale", 1.0f);
100 float rotation = MathHelper.ToRadians(entityElement.GetAttributeFloat(
"rotation", 0.0f));
101 if (!entityElement.GetAttributeBool(
"hideinassemblypreview",
false))
103 displayEntities.Add(
new DisplayEntity(identifier, rect, rotation));
105 minX = Math.Min(minX, rect.X);
106 minY = Math.Min(minY, rect.Y - rect.Height);
107 maxX = Math.Max(maxX, rect.Right);
108 maxY = Math.Max(maxY, rect.Y);
112 Bounds = minX ==
int.MaxValue ?
113 new Rectangle(0, 0, 1, 1) :
114 new Rectangle(minX, minY, maxX - minX, maxY - minY);
123 SubEditorScreen.StoreCommand(
new AddOrDeleteCommand(loaded,
false, handleInventoryBehavior:
false));
139 public static List<MapEntity>
PasteEntities(Vector2 position,
Submarine sub, XElement configElement,
string filePath =
null,
bool selectInstance =
false)
142 List<MapEntity> entities =
MapEntity.
LoadAll(sub, configElement, filePath, idOffset);
143 if (entities.Count == 0) {
return entities; }
151 if (me is not
Item item) {
continue; }
152 Wire wire = item.GetComponent<
Wire>();
157 if (sub !=
null && Vector2.Distance(me.
Position, sub.HiddenSubPosition) > sub.HiddenSubPosition.Length() / 2)
170 entities.ForEach(
MapEntity.AddSelection);
184 Directory.Delete(
ContentPackage.
Dir, recursive:
true, catchUnauthorizedAccessExceptions:
false);
185 ContentPackageManager.LocalPackages.Refresh();
186 ContentPackageManager.EnabledPackages.DisableRemovedMods();
191 DebugConsole.ThrowErrorLocalized(
"Deleting item assembly \"" +
Name +
"\" failed.", e);
Base class for content file types, which are loaded from filelist.xml via reflection....
readonly ContentPath Path
string? GetAttributeString(string key, string? def)
static int FindFreeIdBlock(int minBlockSize)
Finds a contiguous block of free IDs of at least the given size
static readonly Screen SubEditorScreen
override Identifier DetermineIdentifier(XElement element)
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)
override ImmutableHashSet< Identifier > Tags
static readonly PrefabCollection< ItemAssemblyPrefab > Prefabs
override LocalizedString Name
override MapEntityCategory Category
override ImmutableHashSet< Identifier > AllowedLinks
readonly record struct DisplayEntity(Identifier Identifier, Rectangle Rect, float RotationRad)
override ImmutableHashSet< string > Aliases
override string OriginalName
override void CreateInstance(Rectangle rect)
ItemAssemblyPrefab(ContentXElement element, ItemAssemblyFile file)
readonly Rectangle Bounds
readonly ImmutableArray< DisplayEntity > DisplayEntities
void MoveNodes(Vector2 amount)
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)
override Vector2 Position
static List< MapEntity > LoadAll(Submarine submarine, XElement parentElement, string filePath, int idOffset)
LocalizedString Description
readonly Identifier Identifier
static Dictionary< Identifier, SerializableProperty > DeserializeProperties(object obj, XElement element=null)
static Submarine MainSub
Note that this can be null in some situations, e.g. editors and missions that don't load a submarine.
Vector2 HiddenSubPosition