Server LuaCsForBarotrauma
Sprite.cs
1 using Microsoft.Xna.Framework;
2 using System.Xml.Linq;
3 using System.Linq;
5 using System;
6 using SpriteParams = Barotrauma.RagdollParams.SpriteParams;
7 #if CLIENT
8 using Microsoft.Xna.Framework.Graphics;
9 #endif
10 
11 namespace Barotrauma
12 {
13  public partial class Sprite
14  {
18  public ContentXElement SourceElement { get; private set; }
19 
20  //the area in the texture that is supposed to be drawn
21  private Rectangle sourceRect;
22 
23  //the offset used when drawing the sprite
24  protected Vector2 offset;
25 
26  public bool LazyLoad
27  {
28  get;
29  private set;
30  }
31 
32  protected Vector2 origin;
33 
34  //the size of the drawn sprite, if larger than the source,
35  //the sprite is tiled to fill the target size
36  public Vector2 size = Vector2.One;
37 
38  public float rotation;
39 
40 #if CLIENT
41  public SpriteEffects effects = SpriteEffects.None;
42 #endif
43 
44  protected float depth;
45 
46  public Rectangle SourceRect
47  {
48  get { return sourceRect; }
49  set { sourceRect = value; }
50  }
51 
52  public float Depth
53  {
54  get { return depth; }
55  set { depth = MathHelper.Clamp(value, 0.001f, 0.999f); }
56  }
57 
61  public Vector2 Origin
62  {
63  get { return origin; }
64  set
65  {
66  origin = value;
67  _relativeOrigin = new Vector2(origin.X / sourceRect.Width, origin.Y / sourceRect.Height);
68  }
69  }
70 
71  private Vector2 _relativeOrigin;
75  public Vector2 RelativeOrigin
76  {
77  get => _relativeOrigin;
78  set
79  {
80  _relativeOrigin = value;
81  origin = new Vector2(_relativeOrigin.X * sourceRect.Width, _relativeOrigin.Y * sourceRect.Height);
82  }
83  }
84 
85  public Vector2 RelativeSize { get; private set; }
86 
87  public ContentPath FilePath { get; private set; }
88 
89  public string FullPath => FilePath.FullPath;
90 
91  public bool Compress { get; private set; }
92 
93  public override string ToString()
94  {
95  return FilePath + ": " + sourceRect;
96  }
97 
101  public Identifier EntityIdentifier { get; set; }
102  public string Name { get; set; }
103 
104  partial void LoadTexture(ref Vector4 sourceVector, ref bool shouldReturn);
105 
106  partial void CalculateSourceRect();
107 
108  static partial void AddToList(Sprite sprite);
109 
110  public Sprite(ContentXElement element, string path = "", string file = "", bool lazyLoad = false, float sourceRectScale = 1)
111  {
112  if (element is null)
113  {
114  DebugConsole.ThrowError($"Sprite: xml element null in {file}. Failed to create the sprite!");
115  return;
116  }
117  this.LazyLoad = lazyLoad;
118  SourceElement = element;
119  if (!ParseTexturePath(path, file)) { return; }
120  Name = SourceElement.GetAttributeString("name", null);
121  Vector4 sourceVector = SourceElement.GetAttributeVector4("sourcerect", Vector4.Zero);
122  var overrideElement = GetLocalizationOverrideElement();
123  if (overrideElement != null && overrideElement.Attribute("sourcerect") != null)
124  {
125  sourceVector = overrideElement.GetAttributeVector4("sourcerect", Vector4.Zero);
126  }
127  if ((overrideElement ?? SourceElement).Attribute("sheetindex") != null)
128  {
129  Point sheetElementSize = (overrideElement ?? SourceElement).GetAttributePoint("sheetelementsize", Point.Zero);
130  Point sheetIndex = (overrideElement ?? SourceElement).GetAttributePoint("sheetindex", Point.Zero);
131  sourceVector = new Vector4(sheetIndex.X * sheetElementSize.X, sheetIndex.Y * sheetElementSize.Y, sheetElementSize.X, sheetElementSize.Y);
132  }
133  Compress = SourceElement.GetAttributeBool("compress", true);
134  bool shouldReturn = false;
135  if (!lazyLoad)
136  {
137  LoadTexture(ref sourceVector, ref shouldReturn);
138  }
139  if (shouldReturn) { return; }
140  sourceRect = new Rectangle((int)(sourceVector.X * sourceRectScale), (int)(sourceVector.Y * sourceRectScale), (int)(sourceVector.Z * sourceRectScale), (int)(sourceVector.W * sourceRectScale));
141  size = SourceElement.GetAttributeVector2("size", Vector2.One);
142  RelativeSize = size;
143  size.X *= sourceRect.Width;
144  size.Y *= sourceRect.Height;
145  RelativeOrigin = SourceElement.GetAttributeVector2("origin", new Vector2(0.5f, 0.5f));
146  Depth = SourceElement.GetAttributeFloat("depth", 0.001f);
147 #if CLIENT
148  AddToList(this);
149 #endif
150  }
151 
152  internal void LoadParams(SpriteParams spriteParams, bool isFlipped)
153  {
154  SourceElement = spriteParams.Element;
155  sourceRect = spriteParams.SourceRect;
156  RelativeOrigin = spriteParams.Origin;
157  if (isFlipped)
158  {
159  Origin = new Vector2(sourceRect.Width - origin.X, origin.Y);
160  }
161  depth = spriteParams.Depth;
162  }
163 
164  public Sprite(string newFile, Vector2 newOrigin)
165  {
166  Init(newFile, newOrigin: newOrigin);
167  AddToList(this);
168  }
169 
170  public Sprite(string newFile, Rectangle? sourceRectangle, Vector2? origin = null, float rotation = 0)
171  {
172  Init(newFile, sourceRectangle: sourceRectangle, newOrigin: origin, newRotation: rotation);
173  AddToList(this);
174  }
175 
176  private void Init(string newFile, Rectangle? sourceRectangle = null, Vector2? newOrigin = null, Vector2? newOffset = null, float newRotation = 0)
177  {
178  FilePath = ContentPath.FromRaw(newFile);
179  Vector4 sourceVector = Vector4.Zero;
180  bool shouldReturn = false;
181  LoadTexture(ref sourceVector, ref shouldReturn);
182  if (shouldReturn) return;
183  if (sourceRectangle.HasValue)
184  {
185  sourceRect = sourceRectangle.Value;
186  }
187  else
188  {
189  CalculateSourceRect();
190  }
191  offset = newOffset ?? Vector2.Zero;
192  if (newOrigin.HasValue)
193  {
194  RelativeOrigin = newOrigin.Value;
195  }
196  size = new Vector2(sourceRect.Width, sourceRect.Height);
197  rotation = newRotation;
198  }
199 
205  public static Identifier GetIdentifier(XElement sourceElement)
206  {
207  if (sourceElement == null) { return "".ToIdentifier(); }
208  var parentElement = sourceElement.Parent;
209  return $"{sourceElement}{parentElement?.ToString() ?? ""}".ToIdentifier();
210  }
211 
212  static partial void RemoveFromList(Sprite sprite);
213 
214  public void Remove()
215  {
216  RemoveFromList(this);
217  DisposeTexture();
218  }
219 
220  ~Sprite()
221  {
222  Remove();
223  }
224 
225  partial void DisposeTexture();
226 
230  public void ReloadXML()
231  {
232  if (SourceElement == null) { return; }
233  string path = SourceElement.ParseContentPathFromUri();
234  if (string.IsNullOrWhiteSpace(path))
235  {
236  DebugConsole.NewMessage($"[Sprite] Could not parse the content path from the source element ({SourceElement}) uri: {SourceElement.BaseUri}", Color.Yellow);
237  return;
238  }
239  var doc = XMLExtensions.TryLoadXml(path);
240  if (doc == null) { return; }
241  if (string.IsNullOrWhiteSpace(Name) && string.IsNullOrWhiteSpace(EntityIdentifier.Value)) { return; }
242  var spriteElements = doc.Descendants("sprite").Concat(doc.Descendants("Sprite"));
243  var sourceElements = spriteElements.Where(e => e.GetAttributeString("name", null) == Name);
244  if (sourceElements.None())
245  {
246  // Try parents by first comparing the entity id and then the name, if no match was found.
247  sourceElements = spriteElements.Where(e => e.Parent?.GetAttributeString("identifier", null) == EntityIdentifier);
248  if (sourceElements.None())
249  {
250  sourceElements = spriteElements.Where(e => e.Parent?.GetAttributeString("name", null) == Name);
251  }
252  }
253  if (sourceElements.Multiple())
254  {
255  DebugConsole.NewMessage($"[Sprite] Multiple matching elements found by name ({Name}) or identifier ({EntityIdentifier})!: {SourceElement}", Color.Yellow);
256  }
257  else if (sourceElements.None())
258  {
259  DebugConsole.NewMessage($"[Sprite] Cannot find matching source element by comparing the name attribute ({Name}) or identifier ({EntityIdentifier})! Cannot reload the xml for sprite element \"{SourceElement.ToString()}\"!", Color.Yellow);
260  }
261  else
262  {
263  SourceElement = sourceElements.Single().FromPackage(SourceElement.ContentPackage);
264  }
265  if (SourceElement != null)
266  {
267  sourceRect = SourceElement.GetAttributeRect("sourcerect", Rectangle.Empty);
268  var overrideElement = GetLocalizationOverrideElement();
269  if (overrideElement != null && overrideElement.Attribute("sourcerect") != null)
270  {
271  sourceRect = overrideElement.GetAttributeRect("sourcerect", Rectangle.Empty);
272  }
273  if ((overrideElement ?? SourceElement).Attribute("sheetindex") != null)
274  {
275  Point sheetElementSize = (overrideElement ?? SourceElement).GetAttributePoint("sheetelementsize", Point.Zero);
276  Point sheetIndex = (overrideElement ?? SourceElement).GetAttributePoint("sheetindex", Point.Zero);
277  sourceRect = new Rectangle(sheetIndex.X * sheetElementSize.X, sheetIndex.Y * sheetElementSize.Y, sheetElementSize.X, sheetElementSize.Y);
278  }
279  size = SourceElement.GetAttributeVector2("size", Vector2.One);
280  size.X *= sourceRect.Width;
281  size.Y *= sourceRect.Height;
282  RelativeOrigin = SourceElement.GetAttributeVector2("origin", new Vector2(0.5f, 0.5f));
283  Depth = SourceElement.GetAttributeFloat("depth", 0.001f);
284  }
285  }
286 
287  public bool ParseTexturePath(string path = "", string file = "")
288  {
289 #if SERVER
290  // Server doesn't care about texture paths at all
291  return true;
292 #endif
293  if (file == "")
294  {
295  file = SourceElement.GetAttributeStringUnrestricted("texture", "");
296  var overrideElement = GetLocalizationOverrideElement();
297  if (overrideElement != null)
298  {
299  string overrideFile = overrideElement.GetAttributeStringUnrestricted("texture", "");
300  if (!string.IsNullOrEmpty(overrideFile)) { file = overrideFile; }
301  }
302  }
303  if (file == "")
304  {
305  DebugConsole.ThrowError("Sprite " + SourceElement.Element + " doesn't have a texture specified!",
306  contentPackage: SourceElement.ContentPackage);
307  return false;
308  }
309  if (!string.IsNullOrEmpty(path))
310  {
311  if (!path.EndsWith("/")) path += "/";
312  }
313  FilePath = ContentPath.FromRaw(SourceElement.ContentPackage, (path + file).CleanUpPathCrossPlatform(correctFilenameCase: true));
314  return true;
315  }
316 
317  private XElement GetLocalizationOverrideElement()
318  {
319  foreach (var subElement in SourceElement.Elements())
320  {
321  if (subElement.Name.ToString().Equals("override", StringComparison.OrdinalIgnoreCase))
322  {
323  LanguageIdentifier language = subElement.GetAttributeIdentifier("language", "").ToLanguageIdentifier();
324  if (GameSettings.CurrentConfig.Language == language)
325  {
326  return subElement;
327  }
328  }
329  }
330  return null;
331  }
332  }
333 }
334 
static ContentPath FromRaw(string? rawValue)
string? GetAttributeString(string key, string? def)
Vector4 GetAttributeVector4(string key, in Vector4 def)
float GetAttributeFloat(string key, float def)
ContentPackage? ContentPackage
string GetAttributeStringUnrestricted(string key, string def)
IEnumerable< ContentXElement > Elements()
readonly XElement Element
Vector2 GetAttributeVector2(string key, in Vector2 def)
bool GetAttributeBool(string key, bool def)
Rectangle GetAttributeRect(string key, in Rectangle def)
Vector2 RelativeOrigin
0 - 1
Definition: Sprite.cs:76
Sprite(string newFile, Rectangle? sourceRectangle, Vector2? origin=null, float rotation=0)
Definition: Sprite.cs:170
void Remove()
Definition: Sprite.cs:214
Vector2 RelativeSize
Definition: Sprite.cs:85
Vector2 size
Definition: Sprite.cs:36
string FullPath
Definition: Sprite.cs:89
static Identifier GetIdentifier(XElement sourceElement)
Creates a supposedly unique identifier from the parent element. If the parent element is not found,...
Definition: Sprite.cs:205
float rotation
Definition: Sprite.cs:38
Identifier EntityIdentifier
Identifier of the Map Entity so that we can link the sprite to its owner.
Definition: Sprite.cs:101
Rectangle SourceRect
Definition: Sprite.cs:47
Vector2 offset
Definition: Sprite.cs:24
Vector2 origin
Definition: Sprite.cs:32
bool ParseTexturePath(string path="", string file="")
Definition: Sprite.cs:287
Sprite(string newFile, Vector2 newOrigin)
Definition: Sprite.cs:164
override string ToString()
Definition: Sprite.cs:93
Sprite(ContentXElement element, string path="", string file="", bool lazyLoad=false, float sourceRectScale=1)
Definition: Sprite.cs:110
ContentPath FilePath
Definition: Sprite.cs:87
ContentXElement SourceElement
Reference to the xml element from where the sprite was created. Can be null if the sprite was not def...
Definition: Sprite.cs:18
Vector2 Origin
In pixels
Definition: Sprite.cs:62
void ReloadXML()
Works only if there is a name attribute defined for the sprite. For items and structures,...
Definition: Sprite.cs:230