(7e0adb991) Fixed legacy items failing to load if a sub is saved with a language other than English and the language then changed to something else.

This commit is contained in:
Joonas Rikkonen
2019-06-04 15:29:55 +03:00
parent ebd916e95c
commit bce99f2e6f
17 changed files with 89 additions and 82 deletions
@@ -223,6 +223,7 @@
<CopyToOutputDirectory>Never</CopyToOutputDirectory> <CopyToOutputDirectory>Never</CopyToOutputDirectory>
</Compile> </Compile>
<Compile Include="$(MSBuildThisFileDirectory)Source\Utils\MathUtils.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Source\Utils\MathUtils.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Utils\OpenFileDialog.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Utils\TextureLoader.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Source\Utils\TextureLoader.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Source\Utils\ToolBox.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Source\Utils\ToolBox.cs" />
</ItemGroup> </ItemGroup>
@@ -247,6 +247,9 @@
<None Include="System.Configuration.dll"> <None Include="System.Configuration.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
<None Include="Accessibility.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="System.Core.dll"> <None Include="System.Core.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
@@ -268,6 +271,12 @@
<None Include="System.Security.dll"> <None Include="System.Security.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
<None Include="System.Windows.Forms.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="System.Windows.Forms.dll.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="System.Xml.dll"> <None Include="System.Xml.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
@@ -606,7 +606,7 @@ namespace Barotrauma
.ThenByDescending(a => a.Strength).FirstOrDefault(); .ThenByDescending(a => a.Strength).FirstOrDefault();
if (affliction.DamagePerSecond > 0 || affliction.Strength > 0) if (affliction.DamagePerSecond > 0 || affliction.Strength > 0)
{ {
var limbHealth = GetMathingLimbHealth(affliction); var limbHealth = GetMatchingLimbHealth(affliction);
if (limbHealth != null) if (limbHealth != null)
{ {
selectedLimbIndex = limbHealths.IndexOf(limbHealth); selectedLimbIndex = limbHealths.IndexOf(limbHealth);
@@ -256,4 +256,4 @@ namespace EventInput
} }
#endif #endif
} }
} }
@@ -118,27 +118,21 @@ namespace Barotrauma
switch (subElement.Name.ToString().ToLowerInvariant()) switch (subElement.Name.ToString().ToLowerInvariant())
{ {
case "font": case "font":
if (Font == null) { continue; }
Font.Size = GetFontSize(subElement); Font.Size = GetFontSize(subElement);
break; break;
case "smallfont": case "smallfont":
if (SmallFont == null) { continue; }
SmallFont.Size = GetFontSize(subElement); SmallFont.Size = GetFontSize(subElement);
break; break;
case "largefont": case "largefont":
if (LargeFont == null) { continue; }
LargeFont.Size = GetFontSize(subElement); LargeFont.Size = GetFontSize(subElement);
break; break;
case "objectivetitle": case "objectivetitle":
if (ObjectiveTitleFont == null) { continue; }
ObjectiveTitleFont.Size = GetFontSize(subElement); ObjectiveTitleFont.Size = GetFontSize(subElement);
break; break;
case "objectivename": case "objectivename":
if (ObjectiveNameFont == null) { continue; }
ObjectiveNameFont.Size = GetFontSize(subElement); ObjectiveNameFont.Size = GetFontSize(subElement);
break; break;
case "videotitle": case "videotitle":
if (VideoTitleFont == null) { continue; }
VideoTitleFont.Size = GetFontSize(subElement); VideoTitleFont.Size = GetFontSize(subElement);
break; break;
} }
+3 -33
View File
@@ -236,6 +236,8 @@ namespace Barotrauma
GraphicsDeviceManager.PreferredBackBufferWidth = GraphicsWidth; GraphicsDeviceManager.PreferredBackBufferWidth = GraphicsWidth;
GraphicsDeviceManager.PreferredBackBufferHeight = GraphicsHeight; GraphicsDeviceManager.PreferredBackBufferHeight = GraphicsHeight;
GraphicsDeviceManager.ApplyChanges();
} }
public void ResetViewPort() public void ResetViewPort()
@@ -253,7 +255,7 @@ namespace Barotrauma
{ {
base.Initialize(); base.Initialize();
RequestGraphicsSettings(); ApplyGraphicsSettings();
ScissorTestEnable = new RasterizerState() { ScissorTestEnable = true }; ScissorTestEnable = new RasterizerState() { ScissorTestEnable = true };
@@ -292,38 +294,6 @@ namespace Barotrauma
#endif #endif
loadingCoroutine = CoroutineManager.StartCoroutine(Load(canLoadInSeparateThread), "", canLoadInSeparateThread); loadingCoroutine = CoroutineManager.StartCoroutine(Load(canLoadInSeparateThread), "", canLoadInSeparateThread);
#if WINDOWS
var gameForm = (System.Windows.Forms.Form)System.Windows.Forms.Form.FromHandle(Window.Handle);
gameForm.Activated += new EventHandler(HandleFocus);
gameForm.Deactivate += new EventHandler(HandleDefocus);
if (WindowActive) { HandleFocus(null, null); }
#endif
}
#if WINDOWS
private void HandleFocus(object sender, EventArgs e)
{
CoroutineManager.StopCoroutines("FocusCoroutine");
CoroutineManager.StartCoroutine(FocusCoroutine(),"FocusCoroutine");
}
private IEnumerable<object> FocusCoroutine()
{
yield return new WaitForSeconds(0.01f);
ApplyGraphicsSettings();
yield return CoroutineStatus.Success;
}
private void HandleDefocus(object sender, EventArgs e)
{
CoroutineManager.StopCoroutines("FocusCoroutine");
GraphicsDeviceManager.IsFullScreen = false;
GraphicsDeviceManager.ApplyChanges();
}
#endif
loadingCoroutine = CoroutineManager.StartCoroutine(Load(canLoadInSeparateThread), "", canLoadInSeparateThread);
} }
private void InitUserStats() private void InitUserStats()
@@ -841,7 +841,7 @@ namespace Barotrauma
GraphicsWidth = mode.Width; GraphicsWidth = mode.Width;
GraphicsHeight = mode.Height; GraphicsHeight = mode.Height;
GameMain.Instance.RequestGraphicsSettings(); GameMain.Instance.ApplyGraphicsSettings();
UnsavedSettings = true; UnsavedSettings = true;
return true; return true;
@@ -980,7 +980,7 @@ namespace Barotrauma
if (GameMain.WindowMode != GameMain.Config.WindowMode) if (GameMain.WindowMode != GameMain.Config.WindowMode)
{ {
GameMain.Instance.RequestGraphicsSettings(); GameMain.Instance.ApplyGraphicsSettings();
} }
if (GameMain.GraphicsWidth != GameMain.Config.GraphicsWidth || GameMain.GraphicsHeight != GameMain.Config.GraphicsHeight) if (GameMain.GraphicsWidth != GameMain.Config.GraphicsWidth || GameMain.GraphicsHeight != GameMain.Config.GraphicsHeight)
@@ -967,7 +967,7 @@ namespace Barotrauma
{ {
try try
{ {
OpenFileDialog ofd = new OpenFileDialog() Barotrauma.OpenFileDialog ofd = new Barotrauma.OpenFileDialog()
{ {
Multiselect = true, Multiselect = true,
InitialDirectory = Path.GetFullPath(SteamManager.WorkshopItemStagingFolder), InitialDirectory = Path.GetFullPath(SteamManager.WorkshopItemStagingFolder),
@@ -1078,7 +1078,7 @@ namespace Barotrauma
{ {
try try
{ {
OpenFileDialog ofd = new OpenFileDialog() Barotrauma.OpenFileDialog ofd = new Barotrauma.OpenFileDialog()
{ {
InitialDirectory = Path.GetFullPath(SteamManager.WorkshopItemStagingFolder), InitialDirectory = Path.GetFullPath(SteamManager.WorkshopItemStagingFolder),
Title = TextManager.Get("workshopitemaddfiles"), Title = TextManager.Get("workshopitemaddfiles"),
@@ -1074,7 +1074,7 @@ namespace Barotrauma
{ {
OnClicked = (btn, userdata) => OnClicked = (btn, userdata) =>
{ {
OpenFileDialog ofd = new OpenFileDialog() Barotrauma.OpenFileDialog ofd = new Barotrauma.OpenFileDialog()
{ {
InitialDirectory = Path.GetFullPath(Submarine.SavePath), InitialDirectory = Path.GetFullPath(Submarine.SavePath),
Filter = "PNG file|*.png", Filter = "PNG file|*.png",
@@ -202,22 +202,18 @@ namespace Barotrauma
if (run || speedMultiplier <= 0.0f) targetMovement *= speedMultiplier; if (run || speedMultiplier <= 0.0f) targetMovement *= speedMultiplier;
Character.ResetSpeedMultiplier(); // Reset, items will set the value before the next update Character.ResetSpeedMultiplier(); // Reset, items will set the value before the next update
Character.AnimController.TargetMovement = targetMovement; Character.AnimController.TargetMovement = targetMovement;
if (!NeedsDivingGear(Character.CurrentHull)) if (!NeedsDivingGear(Character.CurrentHull))
{ {
bool oxygenLow = Character.OxygenAvailable < CharacterHealth.LowOxygenThreshold; bool oxygenLow = Character.OxygenAvailable < CharacterHealth.LowOxygenThreshold;
bool highPressure = Character.CurrentHull == null || Character.CurrentHull.LethalPressure > 0 && Character.PressureProtection <= 0; bool highPressure = Character.CurrentHull == null || Character.CurrentHull.LethalPressure > 0 && Character.PressureProtection <= 0;
bool shouldKeepTheGearOn = !ObjectiveManager.IsCurrentObjective<AIObjectiveIdle>(); bool shouldKeepTheGearOn = !ObjectiveManager.IsCurrentObjective<AIObjectiveIdle>();
bool removeDivingSuit = oxygenLow && !highPressure;
// Don't allow to drop the diving suit in water or while climbing or if the current path has stairs if (!removeDivingSuit)
bool removeDivingSuit = {
(oxygenLow && !highPressure) || bool targetHasNoSuit = objectiveManager.CurrentOrder is AIObjectiveGoTo gtObj && gtObj.mimic && !HasDivingSuit(gtObj.Target as Character);
(!shouldKeepTheGearOn && bool canDropTheSuit = Character.CurrentHull.WaterPercentage < 1 && !Character.IsClimbing && steeringManager == insideSteering && !PathSteering.InStairs;
Character.CurrentHull.WaterPercentage < 1 && removeDivingSuit = (!shouldKeepTheGearOn || targetHasNoSuit) && canDropTheSuit;
!Character.IsClimbing && }
steeringManager == insideSteering &&
!PathSteering.InStairs);
if (removeDivingSuit) if (removeDivingSuit)
{ {
var divingSuit = Character.Inventory.FindItemByIdentifier("divingsuit") ?? Character.Inventory.FindItemByTag("divingsuit"); var divingSuit = Character.Inventory.FindItemByIdentifier("divingsuit") ?? Character.Inventory.FindItemByTag("divingsuit");
@@ -227,7 +223,8 @@ namespace Barotrauma
divingSuit.Drop(Character); divingSuit.Drop(Character);
} }
} }
bool takeMaskOff = oxygenLow || (!shouldKeepTheGearOn && Character.CurrentHull.WaterPercentage < 20); bool targetHasNoMask = objectiveManager.CurrentOrder is AIObjectiveGoTo gotoObjective && gotoObjective.mimic && !HasDivingMask(gotoObjective.Target as Character);
bool takeMaskOff = oxygenLow || (!shouldKeepTheGearOn && Character.CurrentHull.WaterPercentage < 20) || targetHasNoMask;
if (takeMaskOff) if (takeMaskOff)
{ {
var mask = Character.Inventory.FindItemByIdentifier("divingmask"); var mask = Character.Inventory.FindItemByIdentifier("divingmask");
@@ -336,7 +333,7 @@ namespace Barotrauma
if (AIObjectiveFixLeaks.IsValidTarget(gap, Character)) if (AIObjectiveFixLeaks.IsValidTarget(gap, Character))
{ {
AddTargets<AIObjectiveFixLeaks, Gap>(Character, gap); AddTargets<AIObjectiveFixLeaks, Gap>(Character, gap);
if (newOrder == null) if (newOrder == null && !gap.IsRoomToRoom)
{ {
var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportbreach"); var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportbreach");
newOrder = new Order(orderPrefab, hull, null, orderGiver: Character); newOrder = new Order(orderPrefab, hull, null, orderGiver: Character);
@@ -122,9 +122,8 @@ namespace Barotrauma
goToObjective = null; goToObjective = null;
} }
TryAddSubObjective(ref goToObjective, TryAddSubObjective(ref goToObjective,
constructor: () => new AIObjectiveGoTo(currentSafeHull, character, objectiveManager, getDivingGearIfNeeded: false) constructor: () => new AIObjectiveGoTo(currentSafeHull, character, objectiveManager, getDivingGearIfNeeded: true)
{ {
// If we need diving gear, we should already have it, if possible.
AllowGoingOutside = HumanAIController.HasDivingSuit(character) AllowGoingOutside = HumanAIController.HasDivingSuit(character)
}, },
onAbandon: () => unreachable.Add(goToObjective.Target as Hull)); onAbandon: () => unreachable.Add(goToObjective.Target as Hull));
@@ -36,7 +36,8 @@ namespace Barotrauma
[Serialize(1.0f, true), Editable(MIN_SCALE, MAX_SCALE, DecimalCount = 3)] [Serialize(1.0f, true), Editable(MIN_SCALE, MAX_SCALE, DecimalCount = 3)]
public float JointScale { get; set; } public float JointScale { get; set; }
[Serialize(1f, true), Editable(DecimalCount = 2)] // Don't show in the editor, because shouldn't be edited in runtime. Requires that the limb scale and the collider sizes are adjusted. TODO: automatize.
[Serialize(1f, false)]
public float TextureScale { get; set; } public float TextureScale { get; set; }
[Serialize(45f, true), Editable(0f, 1000f)] [Serialize(45f, true), Editable(0f, 1000f)]
@@ -232,13 +232,13 @@ namespace Barotrauma
} }
private LimbHealth GetMatchingLimbHealth(Limb limb) => limbHealths[limb.HealthIndex]; private LimbHealth GetMatchingLimbHealth(Limb limb) => limbHealths[limb.HealthIndex];
private LimbHealth GetMathingLimbHealth(Affliction affliction) => GetMatchingLimbHealth(Character.AnimController.GetLimb(affliction.Prefab.IndicatorLimb)); private LimbHealth GetMatchingLimbHealth(Affliction affliction) => GetMatchingLimbHealth(Character.AnimController.GetLimb(affliction.Prefab.IndicatorLimb));
/// <summary> /// <summary>
/// Returns the limb afflictions and non-limbspecific afflictions that are set to be displayed on this limb. /// Returns the limb afflictions and non-limbspecific afflictions that are set to be displayed on this limb.
/// </summary> /// </summary>
private IEnumerable<Affliction> GetMatchingAfflictions(LimbHealth limb, Func<Affliction, bool> predicate) private IEnumerable<Affliction> GetMatchingAfflictions(LimbHealth limb, Func<Affliction, bool> predicate)
=> limb.Afflictions.Where(predicate).Union(afflictions.Where(a => predicate(a) && GetMathingLimbHealth(a) == limb)); => limb.Afflictions.Where(predicate).Union(afflictions.Where(a => predicate(a) && GetMatchingLimbHealth(a) == limb));
public Affliction GetAffliction(string afflictionType, bool allowLimbAfflictions = true) public Affliction GetAffliction(string afflictionType, bool allowLimbAfflictions = true)
{ {
@@ -40,6 +40,9 @@ namespace Barotrauma.Items.Components
[Serialize(false, false)] [Serialize(false, false)]
public bool RepairThroughWalls { get; set; } public bool RepairThroughWalls { get; set; }
[Serialize(false, false)]
public bool RepairMultiple { get; set; }
public Vector2 TransformedBarrelPos public Vector2 TransformedBarrelPos
{ {
get get
@@ -158,12 +161,22 @@ namespace Barotrauma.Items.Components
private void Repair(Vector2 rayStart, Vector2 rayEnd, float deltaTime, Character user, float degreeOfSuccess, List<Body> ignoredBodies) private void Repair(Vector2 rayStart, Vector2 rayEnd, float deltaTime, Character user, float degreeOfSuccess, List<Body> ignoredBodies)
{ {
var collisionCategories = Physics.CollisionWall | Physics.CollisionCharacter | Physics.CollisionItem | Physics.CollisionLevel | Physics.CollisionRepair; var collisionCategories = Physics.CollisionWall | Physics.CollisionCharacter | Physics.CollisionItem | Physics.CollisionLevel | Physics.CollisionRepair;
if (RepairThroughWalls) if (RepairMultiple)
{ {
var bodies = Submarine.PickBodies(rayStart, rayEnd, ignoredBodies, collisionCategories, ignoreSensors: false, allowInsideFixture: true); var bodies = Submarine.PickBodies(rayStart, rayEnd, ignoredBodies, collisionCategories, ignoreSensors: false, allowInsideFixture: true);
Type lastHitType = null;
foreach (Body body in bodies) foreach (Body body in bodies)
{ {
FixBody(user, deltaTime, degreeOfSuccess, body); Type bodyType = body.UserData?.GetType();
if (!RepairThroughWalls && bodyType != null && bodyType != lastHitType)
{
//stop the ray if it already hit a door/wall and is now about to hit some other type of entity
if (lastHitType == typeof(Item) || lastHitType == typeof(Structure)) { break; }
}
if (FixBody(user, deltaTime, degreeOfSuccess, body))
{
if (bodyType != null) { lastHitType = bodyType; }
}
} }
} }
else else
@@ -202,19 +215,19 @@ namespace Barotrauma.Items.Components
} }
} }
private void FixBody(Character user, float deltaTime, float degreeOfSuccess, Body targetBody) private bool FixBody(Character user, float deltaTime, float degreeOfSuccess, Body targetBody)
{ {
if (targetBody?.UserData == null) { return; } if (targetBody?.UserData == null) { return false; }
pickedPosition = Submarine.LastPickedPosition; pickedPosition = Submarine.LastPickedPosition;
if (targetBody.UserData is Structure targetStructure) if (targetBody.UserData is Structure targetStructure)
{ {
if (!fixableEntities.Contains("structure") && !fixableEntities.Contains(targetStructure.Prefab.Identifier)) return; if (!fixableEntities.Contains("structure") && !fixableEntities.Contains(targetStructure.Prefab.Identifier)) { return false; }
if (targetStructure.IsPlatform) return; if (targetStructure.IsPlatform) { return false; }
int sectionIndex = targetStructure.FindSectionIndex(ConvertUnits.ToDisplayUnits(pickedPosition)); int sectionIndex = targetStructure.FindSectionIndex(ConvertUnits.ToDisplayUnits(pickedPosition));
if (sectionIndex < 0) return; if (sectionIndex < 0) { return false; }
FixStructureProjSpecific(user, deltaTime, targetStructure, sectionIndex); FixStructureProjSpecific(user, deltaTime, targetStructure, sectionIndex);
targetStructure.AddDamage(sectionIndex, -StructureFixAmount * degreeOfSuccess, user); targetStructure.AddDamage(sectionIndex, -StructureFixAmount * degreeOfSuccess, user);
@@ -239,12 +252,14 @@ namespace Barotrauma.Items.Components
targetCharacter.LastDamageSource = item; targetCharacter.LastDamageSource = item;
ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, new List<ISerializableEntity>() { targetCharacter }); ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, new List<ISerializableEntity>() { targetCharacter });
FixCharacterProjSpecific(user, deltaTime, targetCharacter); FixCharacterProjSpecific(user, deltaTime, targetCharacter);
return true;
} }
else if (targetBody.UserData is Limb targetLimb) else if (targetBody.UserData is Limb targetLimb)
{ {
targetLimb.character.LastDamageSource = item; targetLimb.character.LastDamageSource = item;
ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, new List<ISerializableEntity>() { targetLimb.character, targetLimb }); ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, new List<ISerializableEntity>() { targetLimb.character, targetLimb });
FixCharacterProjSpecific(user, deltaTime, targetLimb.character); FixCharacterProjSpecific(user, deltaTime, targetLimb.character);
return true;
} }
else if (targetBody.UserData is Item targetItem) else if (targetBody.UserData is Item targetItem)
{ {
@@ -269,6 +284,7 @@ namespace Barotrauma.Items.Components
#endif #endif
} }
FixItemProjSpecific(user, deltaTime, targetItem, prevCondition); FixItemProjSpecific(user, deltaTime, targetItem, prevCondition);
return true;
} }
return false; return false;
} }
@@ -2033,8 +2033,8 @@ namespace Barotrauma
XElement element = new XElement("Item"); XElement element = new XElement("Item");
element.Add( element.Add(
new XAttribute("name", prefab.Name), new XAttribute("name", Prefab.OriginalName),
new XAttribute("identifier", prefab.Identifier), new XAttribute("identifier", Prefab.Identifier),
new XAttribute("ID", ID)); new XAttribute("ID", ID));
if (FlippedX) element.Add(new XAttribute("flippedx", true)); if (FlippedX) element.Add(new XAttribute("flippedx", true));
@@ -145,6 +145,11 @@ namespace Barotrauma
private List<XElement> fabricationRecipeElements = new List<XElement>(); private List<XElement> fabricationRecipeElements = new List<XElement>();
/// <summary>
/// Original, non-translated name as defined in the xml
/// </summary>
public readonly string OriginalName;
public string ConfigFile public string ConfigFile
{ {
get { return configFile; } get { return configFile; }
@@ -440,7 +445,7 @@ namespace Barotrauma
configFile = filePath; configFile = filePath;
ConfigElement = element; ConfigElement = element;
string nonTranslatedName = element.GetAttributeString("name", ""); OriginalName = element.GetAttributeString("name", "");
identifier = element.GetAttributeString("identifier", ""); identifier = element.GetAttributeString("identifier", "");
//nameidentifier can be used to make multiple items use the same names and descriptions //nameidentifier can be used to make multiple items use the same names and descriptions
@@ -448,11 +453,11 @@ namespace Barotrauma
if (string.IsNullOrEmpty(nameIdentifier)) if (string.IsNullOrEmpty(nameIdentifier))
{ {
name = TextManager.Get("EntityName." + identifier, true) ?? nonTranslatedName; name = TextManager.Get("EntityName." + identifier, true) ?? OriginalName;
} }
else else
{ {
name = TextManager.Get("EntityName." + nameIdentifier, true) ?? nonTranslatedName; name = TextManager.Get("EntityName." + nameIdentifier, true) ?? OriginalName;
} }
if (name == "") { DebugConsole.ThrowError("Unnamed item in " + filePath + "!"); } if (name == "") { DebugConsole.ThrowError("Unnamed item in " + filePath + "!"); }
@@ -462,7 +467,7 @@ namespace Barotrauma
Aliases = new HashSet<string> Aliases = new HashSet<string>
(element.GetAttributeStringArray("aliases", null, convertToLowerInvariant: true) ?? (element.GetAttributeStringArray("aliases", null, convertToLowerInvariant: true) ??
element.GetAttributeStringArray("Aliases", new string[0], convertToLowerInvariant: true)); element.GetAttributeStringArray("Aliases", new string[0], convertToLowerInvariant: true));
Aliases.Add(nonTranslatedName.ToLowerInvariant()); Aliases.Add(OriginalName.ToLowerInvariant());
if (!Enum.TryParse(element.GetAttributeString("category", "Misc"), true, out MapEntityCategory category)) if (!Enum.TryParse(element.GetAttributeString("category", "Misc"), true, out MapEntityCategory category))
{ {
@@ -730,7 +730,15 @@ namespace Barotrauma
return closestBody; return closestBody;
} }
public static List<Body> PickBodies(Vector2 rayStart, Vector2 rayEnd, IEnumerable<Body> ignoredBodies = null, Category? collisionCategory = null, bool ignoreSensors = true, Predicate<Fixture> customPredicate = null, bool allowInsideFixture = false) private static readonly Dictionary<Body, float> bodyDist = new Dictionary<Body, float>();
private static readonly List<Body> bodies = new List<Body>();
/// <summary>
/// Returns a list of physics bodies the ray intersects with, sorted according to distance (the closest body is at the beginning of the list).
/// </summary>
/// <param name="customPredicate">Can be used to filter the bodies based on some condition. If the predicate returns false, the body isignored.</param>
/// <param name="allowInsideFixture">Should fixtures that the start of the ray is inside be returned</param>
public static IEnumerable<Body> PickBodies(Vector2 rayStart, Vector2 rayEnd, IEnumerable<Body> ignoredBodies = null, Category? collisionCategory = null, bool ignoreSensors = true, Predicate<Fixture> customPredicate = null, bool allowInsideFixture = false)
{ {
if (Vector2.DistanceSquared(rayStart, rayEnd) < 0.00001f) if (Vector2.DistanceSquared(rayStart, rayEnd) < 0.00001f)
{ {
@@ -738,20 +746,25 @@ namespace Barotrauma
} }
float closestFraction = 1.0f; float closestFraction = 1.0f;
List<Body> bodies = new List<Body>(); bodies.Clear();
bodyDist.Clear();
GameMain.World.RayCast((fixture, point, normal, fraction) => GameMain.World.RayCast((fixture, point, normal, fraction) =>
{ {
if (!CheckFixtureCollision(fixture, ignoredBodies, collisionCategory, ignoreSensors, customPredicate)) { return -1; } if (!CheckFixtureCollision(fixture, ignoredBodies, collisionCategory, ignoreSensors, customPredicate)) { return -1; }
if (fixture.Body != null) { bodies.Add(fixture.Body); } if (fixture.Body != null)
{
bodies.Add(fixture.Body);
bodyDist[fixture.Body] = fraction;
}
if (fraction < closestFraction) if (fraction < closestFraction)
{ {
lastPickedPosition = rayStart + (rayEnd - rayStart) * fraction; lastPickedPosition = rayStart + (rayEnd - rayStart) * fraction;
lastPickedFraction = fraction; lastPickedFraction = fraction;
lastPickedNormal = normal; lastPickedNormal = normal;
} }
//continue
return fraction; return -1;
}, rayStart, rayEnd); }, rayStart, rayEnd);
if (allowInsideFixture) if (allowInsideFixture)
@@ -770,10 +783,12 @@ namespace Barotrauma
lastPickedFraction = 0.0f; lastPickedFraction = 0.0f;
lastPickedNormal = Vector2.Normalize(rayEnd - rayStart); lastPickedNormal = Vector2.Normalize(rayEnd - rayStart);
bodies.Add(fixture.Body); bodies.Add(fixture.Body);
bodyDist[fixture.Body] = 0.0f;
return false; return false;
}, ref aabb); }, ref aabb);
} }
bodies.Sort((b1, b2) => { return bodyDist[b1].CompareTo(bodyDist[b2]); });
return bodies; return bodies;
} }