using System; using System.Collections.Generic; using Content.Shared.BodySystem; using Robust.Shared.ViewVariables; namespace Content.Server.BodySystem { /// /// This class is a data capsule representing the standard format of a . For instance, the "humanoid" BodyTemplate /// defines two arms, each connected to a torso and so on. Capable of loading data from a . /// public class BodyTemplate { [ViewVariables] public string Name; /// /// The name of the center BodyPart. For humans, this is set to "torso". Used in many calculations. /// [ViewVariables] public string CenterSlot { get; set; } /// /// Maps all parts on this template to its BodyPartType. For instance, "right arm" is mapped to "BodyPartType.arm" on the humanoid template. /// [ViewVariables] public Dictionary Slots { get; set; } /// /// Maps limb name to the list of their connections to other limbs. For instance, on the humanoid template "torso" is mapped to a list containing "right arm", "left arm", /// "left leg", and "right leg". This is mapped both ways during runtime, but in the prototype only one way has to be defined, i.e., "torso" to "left arm" will automatically /// map "left arm" to "torso". /// [ViewVariables] public Dictionary> Connections { get; set; } public BodyTemplate() { Name = "empty"; Slots = new Dictionary(); Connections = new Dictionary>(); CenterSlot = ""; } public BodyTemplate(BodyTemplatePrototype data) { LoadFromPrototype(data); } public bool Equals(BodyTemplate other) { return GetHashCode() == other.GetHashCode(); } /// /// Returns whether the given slot exists in this BodyTemplate. /// public bool SlotExists(string slotName) { foreach (string slot in Slots.Keys) { if (slot == slotName) //string comparison xd return true; } return false; } /// /// Returns an integer unique to this BodyTemplate's layout. It does not matter in which order the Connections or Slots are defined. /// public override int GetHashCode() { int slotsHash = 0; int connectionsHash = 0; foreach (var(key, value) in Slots) { int slot = key.GetHashCode(); slot = HashCode.Combine(slot, value.GetHashCode()); slotsHash = slotsHash ^ slot; } List connections = new List(); foreach (var (key, value) in Connections) { foreach (var targetBodyPart in value) { int connection = key.GetHashCode() ^ targetBodyPart.GetHashCode(); if (!connections.Contains(connection)) connections.Add(connection); } } foreach (int connection in connections) { connectionsHash = connectionsHash ^ connection; } int hash = HashCode.Combine(slotsHash, connectionsHash, CenterSlot.GetHashCode()); if (hash == 0) //One of the unit tests considers 0 to be an error, but it will be 0 if the BodyTemplate is empty, so let's shift that up to 1. hash++; return hash; } public virtual void LoadFromPrototype(BodyTemplatePrototype data) { Name = data.Name; CenterSlot = data.CenterSlot; Slots = data.Slots; Connections = data.Connections; } } }