1 using Microsoft.Xna.Framework;
3 using System.Collections.Generic;
4 using System.Diagnostics;
52 [
Serialize(
"",
IsPropertySaveable.Yes, description:
"Default path for the limb sprite textures. Used only if the limb specific path for the limb is not defined"),
Editable]
56 public Color Color {
get;
set; }
59 "Defines the \"forward direction\" of the sprites. Should be configured as the direction pointing outwards from the main limb. " +
60 "Incorrectly defined orientations may lead to limbs being rotated incorrectly when e.g. when the character aims or flips to face a different direction. " +
61 "Can be overridden per sprite by setting a value for Limb's 'Sprite Orientation'."),
Editable(-360, 360)]
74 private float limbScale;
78 get {
return limbScale; }
82 private float jointScale;
86 get {
return jointScale; }
105 [
Serialize(45f,
IsPropertySaveable.Yes, description:
"How high from the ground the main collider levitates when the character is standing? Doesn't affect swimming."),
Editable(0f, 1000f)]
108 [
Serialize(50f,
IsPropertySaveable.Yes, description:
"How much impact is required before the character takes impact damage?"),
Editable(MinValueFloat = 0, MaxValueFloat = 1000)]
128 private static readonly Dictionary<Identifier, Dictionary<string, RagdollParams>> allRagdolls =
new Dictionary<Identifier, Dictionary<string, RagdollParams>>();
130 public List<ColliderParams>
Colliders {
get;
private set; } =
new List<ColliderParams>();
131 public List<LimbParams>
Limbs {
get;
private set; } =
new List<LimbParams>();
132 public List<JointParams>
Joints {
get;
private set; } =
new List<JointParams>();
139 public static string GetDefaultFileName(Identifier speciesName) => $
"{speciesName.Value.CapitaliseFirstInvariant()}DefaultRagdoll";
141 => IO.Path.Combine(
GetFolder(speciesName, contentPackage), $
"{GetDefaultFileName(speciesName)}.xml");
146 if (prefab?.ConfigElement ==
null)
148 DebugConsole.ThrowError($
"Failed to find config file for '{speciesName}'", contentPackage: contentPackage);
156 Debug.Assert(filePath !=
null);
157 Debug.Assert(root !=
null);
159 if (folder.IsNullOrEmpty() || folder.Equals(
"default", StringComparison.OrdinalIgnoreCase))
161 folder = IO.Path.Combine(IO.Path.GetDirectoryName(filePath),
"Ragdolls") + IO.Path.DirectorySeparatorChar;
163 return folder.CleanUpPathCrossPlatform(correctFilenameCase:
true);
170 XElement mainElement = characterParams.VariantFile?.Root ?? characterParams.
MainElement;
176 Debug.Assert(contentPackage !=
null);
177 if (characterRootElement.IsOverride())
179 characterRootElement = characterRootElement.FirstElement();
181 Identifier ragdollSpecies = speciesName;
182 Identifier variantOf = characterRootElement.VariantOf();
183 if (characterRootElement !=
null && (characterRootElement.GetChildElement(
"ragdolls") ?? characterRootElement.GetChildElement(
"ragdoll")) is XElement ragdollElement)
185 if ((ragdollElement.GetAttributeContentPath(
"path", contentPackage) ?? ragdollElement.GetAttributeContentPath(
"file", contentPackage)) is
ContentPath path)
189 else if (!variantOf.IsEmpty)
191 string folder = ragdollElement.GetAttributeContentPath(
"folder", contentPackage)?.Value;
192 if (folder.IsNullOrEmpty() || folder.Equals(
"default", StringComparison.OrdinalIgnoreCase))
197 ragdollSpecies = prefab.GetBaseCharacterSpeciesName(variantOf);
205 ragdollSpecies = prefab.GetBaseCharacterSpeciesName(variantOf);
213 Debug.Assert(!speciesName.IsEmpty);
214 Debug.Assert(!ragdollSpecies.IsEmpty);
216 string fileName =
null;
219 if (!file.TryGet(out fileName))
221 file.TryGet(out contentPath);
223 Debug.Assert(!fileName.IsNullOrWhiteSpace() || !contentPath.IsNullOrWhiteSpace());
225 Debug.Assert(contentPackage !=
null);
226 if (!allRagdolls.TryGetValue(speciesName, out Dictionary<string, RagdollParams> ragdolls))
228 ragdolls =
new Dictionary<string, RagdollParams>();
229 allRagdolls.Add(speciesName, ragdolls);
237 if (!contentPath.IsNullOrEmpty())
240 T ragdollInstance =
new T();
241 if (ragdollInstance.Load(contentPath, ragdollSpecies))
243 ragdolls.TryAdd(contentPath.
Value, ragdollInstance);
244 return ragdollInstance;
248 DebugConsole.ThrowError($
"[AnimationParams] Failed to load an animation {ragdollInstance} from {contentPath.Value} for the character {speciesName}. Using the default ragdoll.", contentPackage: contentPackage);
253 string folder =
GetFolder(ragdollSpecies);
254 if (Directory.Exists(folder))
256 var files = Directory.GetFiles(folder).OrderBy(f => f, StringComparer.OrdinalIgnoreCase);
259 DebugConsole.ThrowError($
"[RagdollParams] Could not find any ragdoll files from the folder: {folder}. Using the default ragdoll.", contentPackage: contentPackage);
264 if (
string.IsNullOrEmpty(fileName))
269 selectedFile = files.FirstOrDefault(f => f.Contains(defaultFileName, StringComparison.OrdinalIgnoreCase)) ?? files.First();
273 selectedFile = files.FirstOrDefault(f => IO.Path.GetFileNameWithoutExtension(f).Equals(fileName, StringComparison.OrdinalIgnoreCase));
274 if (selectedFile ==
null)
276 DebugConsole.ThrowError($
"[RagdollParams] Could not find a ragdoll file that matches the name {fileName}. Using the default ragdoll.", contentPackage: contentPackage);
284 DebugConsole.ThrowError($
"[RagdollParams] Invalid directory: {folder}. Using the default ragdoll.", contentPackage: contentPackage);
288 Debug.Assert(selectedFile !=
null);
289 DebugConsole.Log($
"[RagdollParams] Loading the ragdoll from {selectedFile}.");
293 ragdolls.TryAdd(key, r);
298 throw new Exception($
"[RagdollParams] Failed to load ragdoll {r.Name} from {selectedFile} for the character {speciesName}.");
310 if (allRagdolls.ContainsKey(speciesName))
312 DebugConsole.NewMessage($
"[RagdollParams] Removing the old ragdolls from {speciesName}.", Color.Red);
313 allRagdolls.Remove(speciesName);
315 var ragdolls =
new Dictionary<string, RagdollParams>();
316 allRagdolls.Add(speciesName, ragdolls);
319 doc =
new XDocument(mainElement)
323 instance.UpdatePath(contentPath);
324 instance.IsLoaded = instance.Deserialize(mainElement);
326 instance.Load(contentPath, speciesName);
327 ragdolls.Add(instance.FileNameWithoutExtension, instance);
328 DebugConsole.NewMessage(
"[RagdollParams] New default ragdoll params successfully created at " + fullPath, Color.NavajoWhite);
338 base.UpdatePath(fullPath);
344 if (allRagdolls.TryGetValue(
SpeciesName, out Dictionary<string, RagdollParams> ragdolls))
346 ragdolls.Remove(fileName);
348 base.UpdatePath(fullPath);
349 if (ragdolls !=
null)
351 if (!ragdolls.ContainsKey(fileName))
353 ragdolls.Add(fileName,
this);
359 public bool Save(
string fileNameWithoutExtension =
null)
362 GetAllSubParams().ForEach(p => p.SetCurrentElementAsOriginalElement());
364 return base.Save(fileNameWithoutExtension,
new XmlWriterSettings
367 OmitXmlDeclaration =
true,
368 NewLineOnAttributes =
false
376 isVariantScaleApplied =
false;
397 public override bool Reset(
bool forceReload =
false)
412 if (
MainElement?.GetChildElements(
"collider") is { } colliderElements)
414 for (
int i = 0; i < colliderElements.Count(); i++)
416 var element = colliderElements.ElementAt(i);
417 string name = i > 0 ?
"Secondary Collider" :
"Main Collider";
426 if (
MainElement?.GetChildElements(
"limb") is { } childElements)
428 foreach (var element
in childElements)
445 public bool Deserialize(XElement element =
null,
bool alsoChildren =
true,
bool recursive =
true)
447 if (base.Deserialize(element))
458 public bool Serialize(XElement element =
null,
bool alsoChildren =
true,
bool recursive =
true)
460 if (base.Serialize(element))
474 base.AddToEditor(editor);
478 foreach (var subParam
in subParams)
480 subParam.AddToEditor(editor,
true, space);
493 private bool isVariantScaleApplied;
496 if (isVariantScaleApplied) {
return; }
497 if (variantFile ==
null) {
return; }
498 if (variantFile.GetRootExcludingOverride() is XElement root)
500 if ((root.GetChildElement(
"ragdoll") ?? root.GetChildElement(
"ragdolls")) is XElement ragdollElement)
502 float scaleMultiplier = ragdollElement.GetAttributeFloat(
"scalemultiplier", 1f);
505 float textureScale = ragdollElement.GetAttributeFloat(nameof(
TextureScale), 0f);
506 if (textureScale > 0)
511 float sourceRectScale = ragdollElement.GetAttributeFloat(nameof(
SourceRectScale), 0f);
512 if (sourceRectScale > 0)
519 isVariantScaleApplied =
true;
531 DebugConsole.ThrowError(
"[RagdollParams] The source XML Document is null!");
541 copy.CreateColliders();
556 DebugConsole.ThrowError(
"[RagdollParams] The source XML Element of the given RagdollParams is null!",
564 if (sourceSubParams.Count != subParams.Count)
566 DebugConsole.ThrowError(
"[RagdollParams] The count of the sub params differs! Failed to revert to the previous snapshot! Please reset the ragdoll to undo the changes.",
570 for (
int i = 0; i < subParams.Count; i++)
572 var subSubParams = subParams[i].SubParams;
573 if (subSubParams.Count != sourceSubParams[i].SubParams.Count)
575 DebugConsole.ThrowError(
"[RagdollParams] The count of the sub sub params differs! Failed to revert to the previous snapshot! Please reset the ragdoll to undo the changes.",
579 subParams[i].Deserialize(sourceSubParams[i].Element, recursive:
false);
580 for (
int j = 0; j < subSubParams.Count; j++)
582 subSubParams[j].Deserialize(sourceSubParams[i].SubParams[j].Element, recursive:
false);
598 if (
string.IsNullOrWhiteSpace(name))
633 [
Serialize(0f,
IsPropertySaveable.Yes, description:
"Default 0 (Can't be severed when the creature is alive). Modifies the severance probability (defined per item/attack) when the character is alive. Currently only affects non-humanoid ragdolls. Also note that if CanBeSevered is false, this property doesn't have any effect."),
Editable(MinValueFloat = 0, MaxValueFloat = 10, ValueStep = 0.1f, DecimalCount = 2)]
657 [
Serialize(1f,
IsPropertySaveable.Yes, description:
"CAUTION: Not fully implemented. Only use for limb joints that connect non-animated limbs!"),
Editable(DecimalCount = 2)]
679 public List<DamageModifierParams>
DamageModifiers {
get;
private set; } =
new List<DamageModifierParams>();
687 if (
string.IsNullOrWhiteSpace(name))
704 public int ID {
get;
set; }
706 [
Serialize(
LimbType.None,
IsPropertySaveable.Yes, description:
"The limb type affects many things, like the animations. Torso or Head are considered as the main limbs. Every character should have at least one Torso or Head."),
Editable()]
738 "Defines the \"forward direction\" of the sprite. Should be configured as the direction pointing outwards from the main limb." +
739 "Incorrectly defined orientations may lead to limbs being rotated incorrectly when e.g. when the character aims or flips to face a different direction. " +
740 "Overrides the value of 'Spritesheet Orientation' for this limb."),
Editable(-360, 360, ValueStep = 90, DecimalCount = 0)]
743 [
Serialize(
LimbType.None,
IsPropertySaveable.Yes, description:
"If set, the limb sprite will use the same sprite depth as the specified limb. Generally only useful for limbs that get added on the ragdoll on the fly (e.g. extra limbs added via gene splicing).")]
758 [
Serialize(10f,
IsPropertySaveable.Yes, description:
"The more the density the heavier the limb is."),
Editable(MinValueFloat = 0.01f, MaxValueFloat = 100, DecimalCount = 2)]
770 [
Serialize(
"0, 0",
IsPropertySaveable.Yes, description:
"The position which is used to lead the IK chain to the IK goal. Only applicable if the limb is hand or foot."),
Editable()]
773 [
Serialize(
"0, 0",
IsPropertySaveable.Yes, description:
"Only applicable if this limb is a foot. Determines the \"neutral position\" of the foot relative to a joint determined by the \"RefJoint\" parameter. For example, a value of {-100, 0} would mean that the foot is positioned on the floor, 100 units behind the reference joint."),
Editable()]
776 [
Serialize(-1,
IsPropertySaveable.Yes, description:
"The id of the refecence joint. Determines which joint is used as the \"neutral x-position\" for the foot movement. For example in the case of a humanoid-shaped characters this would usually be the waist. The position can be offset using the StepOffset parameter. Only applicable if this limb is a foot."),
Editable()]
779 [
Serialize(
"0, 0",
IsPropertySaveable.Yes, description:
"Relative offset for the mouth position (starting from the center). Only applicable for LimbType.Head. Used for eating."),
Editable(DecimalCount = 2, MinValueFloat = -10f, MaxValueFloat = 10f)]
797 [
Serialize(1f,
IsPropertySaveable.Yes, description:
"How much damage must be done by the attack in order to be able to cut off the limb. Note that it's evaluated after the damage modifiers."),
Editable(DecimalCount = 0, MinValueFloat = 0, MaxValueFloat = 1000)]
800 [
Serialize(
true,
IsPropertySaveable.Yes, description:
"Disable if you don't want to allow severing this joint while the creature is alive. Note: Does nothing if the 'Severance Probability Modifier' in the joint settings is 0 (default). Also note that the setting doesn't override certain limitations, e.g. severing the main limb, or legs of a walking creature is not allowed."),
Editable]
807 [
Serialize(
false,
IsPropertySaveable.Yes, description:
"Should the tail angle be applied on this limb? If none of the limbs have been defined to use the angle and an angle is defined in the animation parameters, the first tail limb is used."),
Editable]
810 [
Serialize(
false,
IsPropertySaveable.Yes, description:
"Should this limb be moved like a tail when swimming? Always true for tail limbs. On tails, disable by setting SineFrequencyMultiplier to 0."),
Editable]
869 [
Serialize(
true,
IsPropertySaveable.Yes, description:
"Can the limb enter submarines? Only valid if the ragdoll's CanEnterSubmarine is set to Partial, otherwise the limb can enter if the ragdoll can."),
Editable]
875 if (spriteElement !=
null)
881 if (damagedSpriteElement !=
null)
888 if (deformSpriteElement !=
null)
893 foreach (var decorativeSpriteElement
in element.GetChildElements(
"decorativesprite"))
899 var attackElement = element.GetChildElement(
"attack");
900 if (attackElement !=
null)
905 foreach (var damageElement
in element.GetChildElements(
"damagemodifier"))
911 var soundElement = element.GetChildElement(
"sound");
912 if (soundElement !=
null)
917 var lightElement = element.GetChildElement(
"lightsource");
918 if (lightElement !=
null)
927 if (
Attack !=
null) {
return false; }
936 if (
Sound !=
null) {
return false; }
939 return Sound !=
null;
946 new XElement(
"lighttexture",
new XAttribute(
"texture",
"Content/Lights/pointlight_bright.png")));
956 if (RemoveSubParam(
Attack))
966 if (RemoveSubParam(
Sound))
988 subParam = constructor(element,
Ragdoll);
989 if (collection !=
null && filter !=
null)
991 if (filter(collection)) {
return false; }
995 collection?.Add(subParam);
996 return subParam !=
null;
1001 if (subParam ==
null || subParam.Element ==
null || subParam.Element.Parent ==
null) {
return false; }
1002 if (collection !=
null && !collection.Contains(subParam)) {
return false; }
1003 if (!
SubParams.Contains(subParam)) {
return false; }
1004 collection?.Remove(subParam);
1006 subParam.Element.Remove();
1025 base.Deserialize(element, recursive);
1032 base.Serialize(element, recursive);
1064 [
Serialize(0f,
IsPropertySaveable.Yes, description:
"The Z-depth of the limb relative to other limbs of the same character. 1 is front, 0 is behind."),
Editable(MinValueFloat = 0, MaxValueFloat = 1, DecimalCount = 3)]
1074 public Color Color {
get;
set; }
1079 [
Serialize(0f,
IsPropertySaveable.Yes,
"How long it takes to fade into the dead color? 0 = Not applied."),
Editable(DecimalCount = 1, MinValueFloat = 0, MaxValueFloat = 10)]
1082 public override string Name =>
"Sprite";
1094 Deformations =
new Dictionary<SpriteDeformationParams, XElement>();
1095 foreach (var deformationElement
in element.GetChildElements(
"spritedeformation"))
1097 string typeName = deformationElement.GetAttributeString(
"type",
null) ?? deformationElement.GetAttributeString(
"typename",
string.Empty);
1099 switch (typeName.ToLowerInvariant())
1114 case "reacttotriggerers":
1118 DebugConsole.ThrowError($
"SpriteDeformationParams not implemented: '{typeName}'",
1119 contentPackage: element.ContentPackage);
1122 if (deformation !=
null)
1124 deformation.
Type = typeName;
1132 public Dictionary<SpriteDeformationParams, XElement>
Deformations {
get;
private set; }
1136 base.Deserialize(element, recursive);
1143 base.Serialize(element, recursive);
1158 private string name;
1164 if (
string.IsNullOrWhiteSpace(name))
1198 public override string Name =>
"Light Texture";
1224 if (lightTextureElement !=
null)
1234 base.Deserialize(element, recursive);
1241 base.Serialize(element, recursive);
1266 base.Deserialize(element, recursive);
1273 base.Serialize(element, recursive);
1289 new XAttribute(
"identifier",
"internaldamage"),
1290 new XAttribute(
"strength", 0f),
1291 new XAttribute(
"probability", 1.0f));
1301 affliction.Remove();
1318 base.Deserialize(element, recursive);
1325 base.Serialize(element, recursive);
1339 public override string Name =>
"Sound";
1342 public string Tag {
get;
private set; }
1349 public virtual string Name {
get;
set; }
1353 public List<SubParam>
SubParams {
get;
set; } =
new List<SubParam>();
1375 SubParams.ForEach(sp => sp.Deserialize(recursive:
true));
1386 SubParams.ForEach(sp => sp.Serialize(recursive:
true));
1394 SubParams.ForEach(sp => sp.SetCurrentElementAsOriginalElement());
1416 foreach (var deformation
in deformSpriteParams.Deformation.Deformations.Keys)
1432 foreach (var affliction
in attackParams.Attack.Afflictions.Keys)
1449 SubParams.ForEach(sp => sp.AddToEditor(editor,
true));
1455 CanBeFocused =
false
Attacks are used to deal damage to characters, structures and items. They can be defined in the weapo...
void Deserialize(ContentXElement element, string parentDebugName)
void Serialize(ContentXElement element)
void ReloadAfflictions(ContentXElement element, string parentDebugName)
Contains character data that should be editable in the character editor.
static CharacterPrefab Find(Predicate< CharacterPrefab > predicate)
static CharacterPrefab FindBySpeciesName(Identifier speciesName)
ContentXElement ConfigElement
static readonly PrefabCollection< CharacterPrefab > Prefabs
readonly ContentPath Path
static ContentPath FromRaw(string? rawValue)
void Add(ContentXElement elem)
ContentPackage? ContentPackage
IEnumerable< ContentXElement > GetChildElements(string name)
ContentXElement? GetChildElement(string name)
void Serialize(XElement element)
void Deserialize(XElement element)
Dictionary< Identifier, SerializableProperty > SerializableProperties
string FileNameWithoutExtension
ContentXElement OriginalElement
virtual ContentXElement? MainElement
static FishRagdollParams GetDefaultRagdollParams(Character character)
RectTransform RectTransform
GUIFrame Content
A frame that contains the contents of the listbox. The frame itself is not rendered.
static HumanRagdollParams GetDefaultRagdollParams(Character character)
readonly ContentFile ContentFile
override bool Serialize(ContentXElement element=null, bool recursive=true)
bool RemoveAffliction(XElement affliction)
AttackParams(ContentXElement element, RagdollParams ragdoll)
override bool Deserialize(ContentXElement element=null, bool recursive=true)
ColliderParams(ContentXElement element, RagdollParams ragdoll, string name=null)
DamageModifier DamageModifier
DamageModifierParams(ContentXElement element, RagdollParams ragdoll)
override bool Deserialize(ContentXElement element=null, bool recursive=true)
override bool Serialize(ContentXElement element=null, bool recursive=true)
DecorativeSpriteParams(ContentXElement element, RagdollParams ragdoll)
override bool Deserialize(ContentXElement element=null, bool recursive=true)
override bool Serialize(ContentXElement element=null, bool recursive=true)
DecorativeSprite DecorativeSprite
float LowerLimit
In degrees.
override string GenerateName()
Vector2 Limb1Anchor
Should be converted to sim units.
float SeveranceProbabilityModifier
JointParams(ContentXElement element, RagdollParams ragdoll)
Vector2 Limb2Anchor
Should be converted to sim units.
float UpperLimit
In degrees.
LightTexture(ContentXElement element, RagdollParams ragdoll)
override bool Deserialize(ContentXElement element=null, bool recursive=true)
Lights.LightSourceParams LightSource
LightSourceParams(ContentXElement element, RagdollParams ragdoll)
override bool Serialize(ContentXElement element=null, bool recursive=true)
Vector2 BlinkTextureOffsetOut
LimbParams(ContentXElement element, RagdollParams ragdoll)
readonly DeformSpriteParams deformSpriteParams
LimbType InheritLimbDepth
TransitionMode BlinkTransitionIn
TransitionMode BlinkTransitionOut
float SineAmplitudeMultiplier
List< DamageModifierParams > DamageModifiers
override string GenerateName()
readonly List< DecorativeSpriteParams > decorativeSpriteParams
readonly SpriteParams damagedSpriteParams
readonly SpriteParams normalSpriteParams
float GetSpriteOrientation()
The orientation of the sprite as drawn on the sprite sheet (in radians).
float AttackForceMultiplier
LightSourceParams LightSource
bool RemoveDamageModifier(DamageModifierParams damageModifier)
float SineFrequencyMultiplier
float GetSpriteOrientationInDegrees()
bool UseTextureOffsetForBlinking
Vector2 BlinkTextureOffsetIn
bool RemoveSubParam< T >(T subParam, IList< T > collection=null)
bool TryAddSubParam< T >(ContentXElement element, Func< ContentXElement, RagdollParams, T > constructor, out T subParam, IList< T > collection=null, Func< IList< T >, bool > filter=null)
SoundParams(ContentXElement element, RagdollParams ragdoll)
SpriteParams(ContentXElement element, RagdollParams ragdoll)
List< SubParam > SubParams
virtual bool Serialize(ContentXElement element=null, bool recursive=true)
virtual void AddToEditor(ParamsEditor editor, bool recursive=true, int space=0)
virtual void SetCurrentElementAsOriginalElement()
ContentXElement CreateElement(string name, params object[] attrs)
Dictionary< Identifier, SerializableProperty > SerializableProperties
Dictionary< Affliction, SerializableEntityEditor > AfflictionEditors
SubParam(ContentXElement element, RagdollParams ragdoll)
ContentXElement OriginalElement
virtual bool Deserialize(ContentXElement element=null, bool recursive=true)
virtual string GenerateName()
SerializableEntityEditor SerializableEntityEditor
override bool Reset(bool forceReload=false)
Resets the current properties to the xml (stored in memory). Force reload reloads the file from disk.
float SourceRectScale
Multiplies both the position and the size of the source rects. Used for scaling the textures when we ...
float SpritesheetOrientation
static T CreateDefault< T >(string fullPath, Identifier speciesName, XElement mainElement)
Creates a default ragdoll for the species using a predefined configuration. Note: Use only to create ...
bool Serialize(XElement element=null, bool alsoChildren=true, bool recursive=true)
override void UpdatePath(ContentPath fullPath)
IEnumerable< SubParam > GetAllSubParams()
static string GetDefaultFile(Identifier speciesName, ContentPackage contentPackage=null)
void TryApplyVariantScale(XDocument variantFile)
bool Save(string fileNameWithoutExtension=null)
void AddToEditor(ParamsEditor editor, bool alsoChildren=true, int space=0)
static T GetDefaultRagdollParams< T >(Character character)
static string GetFolder(Identifier speciesName, ContentPackage contentPackage=null)
bool Deserialize(XElement element=null, bool alsoChildren=true, bool recursive=true)
List< ColliderParams > Colliders
static string GetDefaultFileName(Identifier speciesName)
static T GetRagdollParams< T >(Identifier speciesName, Identifier ragdollSpecies, Either< string, ContentPath > file, ContentPackage contentPackage)
float TextureScale
Can be used for scaling the textures without having to readjust the entire ragdoll....
float ColliderHeightFromFloor
bool IsSpritesheetOrientationHorizontal
void Apply()
Applies the current properties to the xml definition without saving to file.
bool Load(ContentPath file, Identifier speciesName)
List< JointParams > Joints
void AddCustomContent(GUIComponent component, int childIndex)
static Dictionary< Identifier, SerializableProperty > DeserializeProperties(object obj, XElement element=null)
static void SerializeProperties(ISerializableEntity obj, XElement element, bool saveIfDefault=false, bool ignoreEditable=false)
@ Partial
The ragdoll's limbs can enter the sub, but the collider can't. Can be used to e.g....
@ True
Can fully enter a submarine. Make sure to only allow this on small/medium sized creatures that can re...
@ False
No part of the ragdoll can go inside a submarine