Unstable 0.17.7.0
This commit is contained in:
@@ -62,9 +62,9 @@ namespace Barotrauma
|
||||
private float enemycheckTimer;
|
||||
|
||||
/// <summary>
|
||||
/// How far other characters can hear reports done by this character (e.g. reports for fires, intruders).
|
||||
/// How far other characters can hear reports done by this character (e.g. reports for fires, intruders). Defaults to infinity.
|
||||
/// </summary>
|
||||
public float ReportRange { get; set; }
|
||||
public float ReportRange { get; set; } = float.PositiveInfinity;
|
||||
|
||||
private float _aimSpeed = 1;
|
||||
public float AimSpeed
|
||||
@@ -166,7 +166,6 @@ namespace Barotrauma
|
||||
objectiveManager = new AIObjectiveManager(c);
|
||||
reactTimer = GetReactionTime();
|
||||
SortTimer = Rand.Range(0f, sortObjectiveInterval);
|
||||
ReportRange = Character.IsOnPlayerTeam ? float.PositiveInfinity : 1000;
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
|
||||
@@ -269,6 +269,18 @@ namespace Barotrauma
|
||||
if (!character.AnimController.InWater || character.Submarine != null) { return; }
|
||||
if (CurrentPath == null || CurrentPath.Unreachable || CurrentPath.Finished) { return; }
|
||||
if (CurrentPath.CurrentIndex < 0 || CurrentPath.CurrentIndex >= CurrentPath.Nodes.Count - 1) { return; }
|
||||
var lastNode = CurrentPath.Nodes.Last();
|
||||
Submarine targetSub = lastNode.Submarine;
|
||||
if (targetSub != null)
|
||||
{
|
||||
float subSize = Math.Max(targetSub.Borders.Size.X, targetSub.Borders.Size.Y) / 2;
|
||||
float margin = 500;
|
||||
if (Vector2.DistanceSquared(character.WorldPosition, targetSub.WorldPosition) < MathUtils.Pow2(subSize + margin))
|
||||
{
|
||||
// Don't skip nodes when close to the target submarine.
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Check if we could skip ahead to NextNode when the character is swimming and using waypoints outside.
|
||||
// Do this to optimize the old path before creating and evaluating a new path.
|
||||
// In general, this is to avoid behavior where:
|
||||
@@ -280,7 +292,7 @@ namespace Barotrauma
|
||||
{
|
||||
var waypoint = CurrentPath.Nodes[i];
|
||||
float directDistance = Vector2.DistanceSquared(character.WorldPosition, waypoint.WorldPosition);
|
||||
if (directDistance > (pathDistance * pathDistance) || Submarine.PickBody(host.SimPosition, waypoint.SimPosition, collisionCategory: Physics.CollisionLevel | Physics.CollisionWall) != null)
|
||||
if (directDistance > MathUtils.Pow2(pathDistance) || !character.CanSeeTarget(waypoint))
|
||||
{
|
||||
pathDistance -= CurrentPath.GetLength(startIndex: i - 1, endIndex: i);
|
||||
continue;
|
||||
@@ -336,6 +348,7 @@ namespace Barotrauma
|
||||
return Vector2.Zero;
|
||||
}
|
||||
Vector2 pos = host.WorldPosition;
|
||||
Vector2 diff = currentPath.CurrentNode.WorldPosition - pos;
|
||||
bool isDiving = character.AnimController.InWater && character.AnimController.HeadInWater;
|
||||
// Only humanoids can climb ladders
|
||||
bool canClimb = character.AnimController is HumanoidAnimController && !character.LockHands;
|
||||
@@ -346,7 +359,7 @@ namespace Barotrauma
|
||||
}
|
||||
Ladder nextLadder = GetNextLadder();
|
||||
var ladders = currentLadder ?? nextLadder;
|
||||
bool useLadders = canClimb && ladders != null && (!isDiving || Math.Abs(steering.X) < 0.1f && steering.Y > 1);
|
||||
bool useLadders = canClimb && ladders != null && steering.LengthSquared() > 0.1f && (!isDiving || steering.Y > 1);
|
||||
if (useLadders && character.SelectedConstruction != ladders.Item)
|
||||
{
|
||||
if (character.CanInteractWith(ladders.Item))
|
||||
@@ -374,7 +387,6 @@ namespace Barotrauma
|
||||
}
|
||||
if (character.IsClimbing && useLadders)
|
||||
{
|
||||
Vector2 diff = currentPath.CurrentNode.WorldPosition - pos;
|
||||
bool nextLadderSameAsCurrent = IsNextLadderSameAsCurrent;
|
||||
if (nextLadderSameAsCurrent || currentLadder != null && nextLadder != null && Math.Abs(currentLadder.Item.Position.X - nextLadder.Item.Position.X) < 50)
|
||||
{
|
||||
@@ -398,7 +410,7 @@ namespace Barotrauma
|
||||
else if (nextLadder != null && !nextLadderSameAsCurrent)
|
||||
{
|
||||
// Try to change the ladder (hatches between two submarines)
|
||||
if (character.SelectedConstruction != nextLadder.Item && nextLadder.Item.IsInsideTrigger(character.WorldPosition))
|
||||
if (character.SelectedConstruction != nextLadder.Item && character.CanInteractWith(nextLadder.Item))
|
||||
{
|
||||
if (nextLadder.Item.TryInteract(character, forceSelectKey: true))
|
||||
{
|
||||
@@ -406,7 +418,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isAboveFloor || nextLadderSameAsCurrent)
|
||||
if (isAboveFloor || nextLadderSameAsCurrent || nextLadder == null && Math.Abs(diff.Y) < 10)
|
||||
{
|
||||
NextNode(!doorsChecked);
|
||||
}
|
||||
@@ -484,7 +496,7 @@ namespace Barotrauma
|
||||
{
|
||||
return Vector2.Zero;
|
||||
}
|
||||
return ConvertUnits.ToSimUnits(currentPath.CurrentNode.WorldPosition - pos);
|
||||
return ConvertUnits.ToSimUnits(diff);
|
||||
}
|
||||
|
||||
private void NextNode(bool checkDoors)
|
||||
|
||||
+7
-3
@@ -212,10 +212,14 @@ namespace Barotrauma
|
||||
|
||||
protected override bool CheckObjectiveSpecific()
|
||||
{
|
||||
if (sqrDistance > maxDistance * maxDistance)
|
||||
if (character.Submarine == null || character.Submarine.TeamID != CharacterTeamType.FriendlyNPC)
|
||||
{
|
||||
// The target escaped from us.
|
||||
return true;
|
||||
// Can't lose the target in friendly outposts.
|
||||
if (sqrDistance > maxDistance * maxDistance)
|
||||
{
|
||||
// The target escaped from us.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return IsEnemyDisabled || (AllowCoolDown && coolDownTimer <= 0);
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (InWater || !CanWalk)
|
||||
{
|
||||
return TargetMovement.LengthSquared() > SwimSlowParams.MovementSpeed;
|
||||
return TargetMovement.LengthSquared() > MathUtils.Pow2(SwimSlowParams.MovementSpeed);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -302,7 +302,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
// used for talents/ability conditions
|
||||
public Item SourceItem { get; }
|
||||
public Item SourceItem { get; set; }
|
||||
|
||||
public List<Affliction> GetMultipliedAfflictions(float multiplier)
|
||||
{
|
||||
|
||||
@@ -308,6 +308,10 @@ namespace Barotrauma
|
||||
public bool IsHumanoid => Params.Humanoid;
|
||||
public bool IsHusk => Params.Husk;
|
||||
|
||||
public bool IsMale => info?.IsMale ?? false;
|
||||
|
||||
public bool IsFemale => info?.IsFemale ?? false;
|
||||
|
||||
public string BloodDecalName => Params.BloodDecal;
|
||||
|
||||
public bool CanSpeak
|
||||
@@ -557,10 +561,11 @@ namespace Barotrauma
|
||||
#if CLIENT
|
||||
CharacterHealth.SetHealthBarVisibility(value == null);
|
||||
#elif SERVER
|
||||
if (value is { IsDead: true, Wallet: { Balance: var balance } grabbedWallet })
|
||||
if (value is { IsDead: true, Wallet: { Balance: var balance } grabbedWallet } && balance > 0)
|
||||
{
|
||||
Wallet.Give(balance);
|
||||
grabbedWallet.Deduct(balance);
|
||||
GameServer.Log($"{Name} grabbed {value.Name}'s body and received {grabbedWallet.Balance} mk.", ServerLog.MessageType.Money);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -3587,21 +3592,8 @@ namespace Barotrauma
|
||||
|
||||
float attackImpulse = attack.TargetImpulse + attack.TargetForce * attack.ImpactMultiplier * deltaTime;
|
||||
|
||||
AbilityAttackData attackData = new AbilityAttackData(attack, this);
|
||||
if (attacker != null)
|
||||
{
|
||||
attackData.Attacker = attacker;
|
||||
attacker.CheckTalents(AbilityEffectType.OnAttack, attackData);
|
||||
CheckTalents(AbilityEffectType.OnAttacked, attackData);
|
||||
attackData.DamageMultiplier *= 1 + attacker.GetStatValue(StatTypes.AttackMultiplier);
|
||||
if (attacker.TeamID == TeamID)
|
||||
{
|
||||
attackData.DamageMultiplier *= 1 + attacker.GetStatValue(StatTypes.TeamAttackMultiplier);
|
||||
}
|
||||
}
|
||||
|
||||
AbilityAttackData attackData = new AbilityAttackData(attack, this, attacker);
|
||||
IEnumerable<Affliction> attackAfflictions;
|
||||
|
||||
if (attackData.Afflictions != null)
|
||||
{
|
||||
attackAfflictions = attackData.Afflictions.Union(attack.Afflictions.Keys);
|
||||
@@ -4916,10 +4908,21 @@ namespace Barotrauma
|
||||
public Character Character { get; set; }
|
||||
public Character Attacker { get; set; }
|
||||
|
||||
public AbilityAttackData(Attack sourceAttack, Character character)
|
||||
public AbilityAttackData(Attack sourceAttack, Character target, Character attacker)
|
||||
{
|
||||
SourceAttack = sourceAttack;
|
||||
Character = character;
|
||||
Character = target;
|
||||
if (attacker != null)
|
||||
{
|
||||
Attacker = attacker;
|
||||
attacker.CheckTalents(AbilityEffectType.OnAttack, this);
|
||||
target.CheckTalents(AbilityEffectType.OnAttacked, this);
|
||||
DamageMultiplier *= 1 + attacker.GetStatValue(StatTypes.AttackMultiplier);
|
||||
if (attacker.TeamID == target.TeamID)
|
||||
{
|
||||
DamageMultiplier *= 1 + attacker.GetStatValue(StatTypes.TeamAttackMultiplier);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -130,17 +130,22 @@ namespace Barotrauma
|
||||
head = value;
|
||||
HeadSprite = null;
|
||||
AttachmentSprites = null;
|
||||
IsMale = value.Preset?.TagSet?.Contains("Male".ToIdentifier()) ?? false;
|
||||
IsFemale = value.Preset?.TagSet?.Contains("Female".ToIdentifier()) ?? false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsMale { get; private set; }
|
||||
|
||||
public bool IsFemale { get; private set; }
|
||||
|
||||
public CharacterInfoPrefab Prefab => CharacterPrefab.Prefabs[SpeciesName].CharacterInfoPrefab;
|
||||
public class HeadPreset : ISerializableEntity
|
||||
{
|
||||
private readonly CharacterInfoPrefab characterInfoPrefab;
|
||||
public Identifier MenuCategory => TagSet.First(t => characterInfoPrefab.VarTags[characterInfoPrefab.MenuCategoryVar].Contains(t));
|
||||
|
||||
|
||||
public ImmutableHashSet<Identifier> TagSet { get; private set; }
|
||||
|
||||
[Serialize("", IsPropertySaveable.No)]
|
||||
|
||||
+4
-4
@@ -71,8 +71,8 @@ namespace Barotrauma
|
||||
|
||||
public static Result<ContentFile, string> CreateFromXElement(ContentPackage contentPackage, XElement element)
|
||||
{
|
||||
static Result<ContentFile, string> fail(string error)
|
||||
=> Result<ContentFile, string>.Failure(error);
|
||||
static Result<ContentFile, string> fail(string error, string? stackTrace = null)
|
||||
=> Result<ContentFile, string>.Failure(error, stackTrace);
|
||||
|
||||
Identifier elemName = element.NameAsIdentifier();
|
||||
var type = Types.FirstOrDefault(t => t.Names.Contains(elemName));
|
||||
@@ -99,10 +99,10 @@ namespace Barotrauma
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return fail($"Failed to load file \"{filePath}\" of type \"{elemName}\": {e.Message}\n{e.StackTrace.CleanupStackTrace()}");
|
||||
return fail($"Failed to load file \"{filePath}\" of type \"{elemName}\": {e.Message}", e.StackTrace.CleanupStackTrace());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected ContentFile(ContentPackage contentPackage, ContentPath path)
|
||||
{
|
||||
ContentPackage = contentPackage;
|
||||
|
||||
+9
-1
@@ -34,7 +34,15 @@ namespace Barotrauma
|
||||
else if (MatchesSingular(elemName))
|
||||
{
|
||||
T prefab = CreatePrefab(parentElement);
|
||||
prefabs.Add(prefab, overriding);
|
||||
try
|
||||
{
|
||||
prefabs.Add(prefab, overriding);
|
||||
}
|
||||
catch
|
||||
{
|
||||
prefab.Dispose(); //clean up before rethrowing, since some prefab types might lock resources
|
||||
throw;
|
||||
}
|
||||
}
|
||||
else if (MatchesPlural(elemName))
|
||||
{
|
||||
|
||||
+22
-4
@@ -1,6 +1,6 @@
|
||||
#nullable enable
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Barotrauma.Steam;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
@@ -9,7 +9,6 @@ using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Steam;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -39,7 +38,7 @@ namespace Barotrauma
|
||||
public readonly DateTime? InstallTime;
|
||||
|
||||
public readonly ImmutableArray<ContentFile> Files;
|
||||
public readonly ImmutableArray<string> Errors;
|
||||
public readonly ImmutableArray<(string error, string? stackTrace)> Errors;
|
||||
|
||||
public async Task<bool> IsUpToDate()
|
||||
{
|
||||
@@ -92,7 +91,7 @@ namespace Barotrauma
|
||||
|
||||
Errors = fileResults
|
||||
.OfType<Failure<ContentFile, string>>()
|
||||
.Select(f => f.Error)
|
||||
.Select(f => (f.Error, f.StackTrace))
|
||||
.ToImmutableArray();
|
||||
|
||||
HasMultiplayerSyncedContent = Files.Any(f => !f.NotSyncedInMultiplayer);
|
||||
@@ -304,5 +303,24 @@ namespace Barotrauma
|
||||
}
|
||||
return path == LocalModsDir;
|
||||
}
|
||||
|
||||
public void LogErrors()
|
||||
{
|
||||
if (Errors.Any())
|
||||
{
|
||||
DebugConsole.AddWarning(
|
||||
$"The following errors occurred while loading the content package\"{Name}\". The package might not work correctly.\n" +
|
||||
string.Join('\n', Errors.Select(e => errorToStr(e.error, e.stackTrace))));
|
||||
static string errorToStr(string error, string? stackTrace)
|
||||
{
|
||||
string str = error;
|
||||
if (stackTrace != null)
|
||||
{
|
||||
str += '\n' + stackTrace;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
-4
@@ -430,9 +430,9 @@ namespace Barotrauma
|
||||
public static void LoadVanillaFileList()
|
||||
{
|
||||
VanillaCorePackage = new CorePackage(XDocument.Load(VanillaFileList), VanillaFileList);
|
||||
foreach (string error in VanillaCorePackage.Errors)
|
||||
foreach ((string error, string? stackTrace) in VanillaCorePackage.Errors)
|
||||
{
|
||||
DebugConsole.ThrowError(error);
|
||||
DebugConsole.ThrowError(error + (stackTrace == null ? string.Empty : '\n' + stackTrace));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -469,8 +469,17 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
var corePackageElement = contentPackagesElement.GetChildElement(CorePackageElementName);
|
||||
enabledCorePackage = findPackage(CorePackages, corePackageElement) ?? VanillaCorePackage!;
|
||||
|
||||
var configEnabledCorePackage = findPackage(CorePackages, corePackageElement);
|
||||
if (configEnabledCorePackage == null)
|
||||
{
|
||||
string packageStr = corePackageElement.GetAttributeString("name", null) ?? corePackageElement.GetAttributeStringUnrestricted("path", "UNKNOWN");
|
||||
DebugConsole.ThrowError($"Could not find the selected core package \"{packageStr}\". Switching to the \"{enabledCorePackage.Name}\" package.");
|
||||
}
|
||||
else
|
||||
{
|
||||
enabledCorePackage = configEnabledCorePackage;
|
||||
}
|
||||
|
||||
var regularPackagesElement = contentPackagesElement.GetChildElement(RegularPackagesElementName);
|
||||
if (regularPackagesElement != null)
|
||||
{
|
||||
@@ -499,5 +508,13 @@ namespace Barotrauma
|
||||
|
||||
yield return new LoadProgress(1.0f);
|
||||
}
|
||||
|
||||
public static void LogEnabledRegularPackageErrors()
|
||||
{
|
||||
foreach (var p in EnabledPackages.Regular)
|
||||
{
|
||||
p.LogErrors();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1562,17 +1562,24 @@ namespace Barotrauma
|
||||
commands.Add(new Command("money", "money [amount] [character]: Gives the specified amount of money to the crew when a campaign is active.", args =>
|
||||
{
|
||||
if (args.Length == 0) { return; }
|
||||
if (GameMain.GameSession?.GameMode is CampaignMode campaign)
|
||||
|
||||
if (!(GameMain.GameSession?.GameMode is CampaignMode campaign)) { return; }
|
||||
Character targetCharacter = null;
|
||||
|
||||
if (args.Length >= 2)
|
||||
{
|
||||
if (int.TryParse(args[0], out int money))
|
||||
{
|
||||
campaign.Bank.Give(money);
|
||||
GameAnalyticsManager.AddMoneyGainedEvent(money, GameAnalyticsManager.MoneySource.Cheat, "console");
|
||||
}
|
||||
else
|
||||
{
|
||||
ThrowError($"\"{args[0]}\" is not a valid numeric value.");
|
||||
}
|
||||
targetCharacter = FindMatchingCharacter(args.Skip(1).ToArray());
|
||||
}
|
||||
|
||||
if (int.TryParse(args[0], out int money))
|
||||
{
|
||||
Wallet wallet = targetCharacter is null || GameMain.IsSingleplayer ? campaign.Bank : targetCharacter.Wallet;
|
||||
wallet.Give(money);
|
||||
GameAnalyticsManager.AddMoneyGainedEvent(money, GameAnalyticsManager.MoneySource.Cheat, "console");
|
||||
}
|
||||
else
|
||||
{
|
||||
ThrowError($"\"{args[0]}\" is not a valid numeric value.");
|
||||
}
|
||||
}, isCheat: true, getValidArgs: () => new []
|
||||
{
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -33,11 +31,11 @@ namespace Barotrauma
|
||||
public static int GrimeSpriteCount { get; private set; } = 0;
|
||||
|
||||
public static readonly PrefabCollection<GrimeSprite> GrimeSprites = new PrefabCollection<GrimeSprite>(
|
||||
onAdd: (sprite, b) => GrimeSpriteCount = Math.Max(GrimeSpriteCount, sprite.IndexInFile+1),
|
||||
onAdd: (sprite, b) => GrimeSpriteCount = Math.Max(GrimeSpriteCount, sprite.IndexInFile + 1),
|
||||
onRemove: (s) =>
|
||||
GrimeSpriteCount = GrimeSprites.AllPrefabs
|
||||
.SelectMany(kvp => kvp.Value)
|
||||
.Where(p => p != s).Select(p => p.IndexInFile+1).MaxOrNull() ?? 0,
|
||||
.Where(p => p != s).Select(p => p.IndexInFile + 1).MaxOrNull() ?? 0,
|
||||
onSort: null, onAddOverrideFile: null, onRemoveOverrideFile: null);
|
||||
|
||||
public static void LoadFromFile(DecalsFile configFile)
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace Barotrauma
|
||||
item.GetComponent<PowerContainer>() != null ||
|
||||
item.GetComponent<Reactor>() != null)
|
||||
{
|
||||
item.Indestructible = true;
|
||||
item.InvulnerableToDamage = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -210,6 +210,13 @@ namespace Barotrauma
|
||||
};
|
||||
}
|
||||
|
||||
public string GetOwnerLogName() => Owner switch
|
||||
{
|
||||
Some<Character> { Value: var character } => character.Name,
|
||||
None<Character> _ => "the bank",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(Owner))
|
||||
};
|
||||
|
||||
partial void SettingsChanged(Option<int> balanceChanged, Option<int> rewardChanged);
|
||||
|
||||
private static int ClampBalance(int value) => Math.Clamp(value, 0, CampaignMode.MaxMoney);
|
||||
|
||||
@@ -147,22 +147,23 @@ namespace Barotrauma
|
||||
var campaign = SinglePlayerCampaign.Load(subElement);
|
||||
campaign.LoadNewLevel();
|
||||
GameMode = campaign;
|
||||
InitOwnedSubs(submarineInfo, ownedSubmarines);
|
||||
break;
|
||||
#endif
|
||||
case "multiplayercampaign":
|
||||
CrewManager = new CrewManager(false);
|
||||
var mpCampaign = MultiPlayerCampaign.LoadNew(subElement);
|
||||
GameMode = mpCampaign;
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
mpCampaign.LoadNewLevel();
|
||||
mpCampaign.LoadNewLevel();
|
||||
InitOwnedSubs(submarineInfo, ownedSubmarines);
|
||||
//save to ensure the campaign ID in the save file matches the one that got assigned to this campaign instance
|
||||
SaveUtil.SaveGame(saveFile);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
InitOwnedSubs(submarineInfo);
|
||||
}
|
||||
|
||||
private void InitOwnedSubs(SubmarineInfo submarineInfo, List<SubmarineInfo>? ownedSubmarines = null)
|
||||
@@ -409,14 +410,16 @@ namespace Barotrauma
|
||||
|
||||
if (GameMain.NetworkMember?.ServerSettings?.LockAllDefaultWires ?? false)
|
||||
{
|
||||
foreach (Item item in Item.ItemList)
|
||||
List<Item> items = new List<Item>();
|
||||
items.AddRange(Submarine.MainSubs[0].GetItems(alsoFromConnectedSubs: true));
|
||||
if (Submarine.MainSubs[1] != null)
|
||||
{
|
||||
if (item.Submarine == Submarine.MainSubs[0] ||
|
||||
(Submarine.MainSubs[1] != null && item.Submarine == Submarine.MainSubs[1]))
|
||||
{
|
||||
Wire wire = item.GetComponent<Wire>();
|
||||
if (wire != null && !wire.NoAutoLock && wire.Connections.Any(c => c != null)) { wire.Locked = true; }
|
||||
}
|
||||
items.AddRange(Submarine.MainSubs[1].GetItems(alsoFromConnectedSubs: true));
|
||||
}
|
||||
foreach (Item item in items)
|
||||
{
|
||||
Wire wire = item.GetComponent<Wire>();
|
||||
if (wire != null && !wire.NoAutoLock && wire.Connections.Any(c => c != null)) { wire.Locked = true; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -228,9 +228,12 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (MathUtils.GetLineRectangleIntersection(ConvertUnits.ToDisplayUnits(sourcePos), ConvertUnits.ToDisplayUnits(rayStart), item.CurrentHull.Rect, out Vector2 hullIntersection))
|
||||
{
|
||||
Vector2 rayDir = rayStart.NearlyEquals(sourcePos) ? Vector2.Zero : Vector2.Normalize(rayStart - sourcePos);
|
||||
rayStartWorld = ConvertUnits.ToSimUnits(hullIntersection - rayDir * 5.0f);
|
||||
if (item.Submarine != null) { rayStartWorld += item.Submarine.SimPosition; }
|
||||
if (!item.CurrentHull.ConnectedGaps.Any(g => g.Open > 0.0f && Submarine.RectContains(g.Rect, hullIntersection)))
|
||||
{
|
||||
Vector2 rayDir = rayStart.NearlyEquals(sourcePos) ? Vector2.Zero : Vector2.Normalize(rayStart - sourcePos);
|
||||
rayStartWorld = ConvertUnits.ToSimUnits(hullIntersection - rayDir * 5.0f);
|
||||
if (item.Submarine != null) { rayStartWorld += item.Submarine.SimPosition; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,7 +251,7 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (HiddenInGame) { return false; }
|
||||
if (character != null && character.IsOnPlayerTeam)
|
||||
{
|
||||
return IsPlayerTeamInteractable;
|
||||
@@ -1438,7 +1438,6 @@ namespace Barotrauma
|
||||
|
||||
public bool HasAccess(Character character)
|
||||
{
|
||||
if (HiddenInGame) { return false; }
|
||||
if (character.IsBot && IgnoreByAI(character)) { return false; }
|
||||
if (!IsInteractable(character)) { return false; }
|
||||
var itemContainer = GetComponent<ItemContainer>();
|
||||
@@ -1834,10 +1833,29 @@ namespace Barotrauma
|
||||
Submarine prevSub = Submarine;
|
||||
|
||||
var projectile = GetComponent<Projectile>();
|
||||
if (projectile?.StickTarget?.UserData is Limb limb && limb.character != null)
|
||||
if (projectile?.StickTarget != null)
|
||||
{
|
||||
Submarine = body.Submarine = limb.character.Submarine;
|
||||
currentHull = limb.character.CurrentHull;
|
||||
if (projectile?.StickTarget.UserData is Limb limb && limb.character != null)
|
||||
{
|
||||
Submarine = body.Submarine = limb.character.Submarine;
|
||||
currentHull = limb.character.CurrentHull;
|
||||
}
|
||||
else if (projectile.StickTarget.UserData is Structure structure)
|
||||
{
|
||||
Submarine = body.Submarine = structure.Submarine;
|
||||
currentHull = Hull.FindHull(WorldPosition, CurrentHull);
|
||||
}
|
||||
else if (projectile.StickTarget.UserData is Item targetItem)
|
||||
{
|
||||
Submarine = body.Submarine = targetItem.Submarine;
|
||||
currentHull = targetItem.CurrentHull;
|
||||
}
|
||||
else if (projectile.StickTarget.UserData is Submarine)
|
||||
{
|
||||
//attached to a sub from the outside -> don't move inside the sub
|
||||
Submarine = body.Submarine = null;
|
||||
currentHull = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -133,6 +133,7 @@ namespace Barotrauma
|
||||
{
|
||||
displayRange *= 1.0f + sourceItem.GetQualityModifier(Quality.StatType.ExplosionRadius);
|
||||
Attack.DamageMultiplier *= 1.0f + sourceItem.GetQualityModifier(Quality.StatType.ExplosionDamage);
|
||||
Attack.SourceItem ??= sourceItem;
|
||||
}
|
||||
|
||||
Vector2 cameraPos = GameMain.GameScreen.Cam.Position;
|
||||
@@ -337,11 +338,17 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
AbilityAttackData attackData = new AbilityAttackData(Attack, c, attacker);
|
||||
if (attackData.Afflictions != null)
|
||||
{
|
||||
modifiedAfflictions.AddRange(attackData.Afflictions);
|
||||
}
|
||||
|
||||
//use a position slightly from the limb's position towards the explosion
|
||||
//ensures that the attack hits the correct limb and that the direction of the hit can be determined correctly in the AddDamage methods
|
||||
Vector2 dir = worldPosition - limb.WorldPosition;
|
||||
Vector2 hitPos = limb.WorldPosition + (dir.LengthSquared() <= 0.001f ? Rand.Vector(1.0f) : Vector2.Normalize(dir)) * 0.01f;
|
||||
AttackResult attackResult = c.AddDamage(hitPos, modifiedAfflictions, attack.Stun * distFactor, false, attacker: attacker, damageMultiplier: attack.DamageMultiplier);
|
||||
AttackResult attackResult = c.AddDamage(hitPos, modifiedAfflictions, attack.Stun * distFactor, false, attacker: attacker, damageMultiplier: attack.DamageMultiplier * attackData.DamageMultiplier);
|
||||
damages.Add(limb, attackResult.Damage);
|
||||
|
||||
if (attack.StatusEffects != null && attack.StatusEffects.Any())
|
||||
|
||||
@@ -23,6 +23,10 @@ namespace Barotrauma
|
||||
public readonly Vector2 Noise;
|
||||
public readonly Color DirtColor;
|
||||
|
||||
#if CLIENT
|
||||
public Sprite GrimeSprite;
|
||||
#endif
|
||||
|
||||
public float ColorStrength
|
||||
{
|
||||
get;
|
||||
@@ -51,6 +55,9 @@ namespace Barotrauma
|
||||
PerlinNoise.GetPerlin(Rect.Y / 1000.0f + 0.5f, Rect.X / 1000.0f + 0.5f));
|
||||
|
||||
Color = DirtColor = Color.Lerp(new Color(10, 10, 10, 100), new Color(54, 57, 28, 200), Noise.X);
|
||||
#if CLIENT
|
||||
GrimeSprite = DecalManager.GrimeSprites[$"{nameof(GrimeSprite)}{index % DecalManager.GrimeSpriteCount}"].Sprite;
|
||||
#endif
|
||||
}
|
||||
|
||||
public BackgroundSection(Rectangle rect, ushort index, float colorStrength, Color color, ushort rowIndex)
|
||||
@@ -68,6 +75,9 @@ namespace Barotrauma
|
||||
PerlinNoise.GetPerlin(Rect.Y / 1000.0f + 0.5f, Rect.X / 1000.0f + 0.5f));
|
||||
|
||||
DirtColor = Color.Lerp(new Color(10, 10, 10, 100), new Color(54, 57, 28, 200), Noise.X);
|
||||
#if CLIENT
|
||||
GrimeSprite = DecalManager.GrimeSprites[$"{nameof(GrimeSprite)}{index % DecalManager.GrimeSpriteCount}"].Sprite;
|
||||
#endif
|
||||
}
|
||||
|
||||
public bool SetColor(Color color)
|
||||
@@ -274,33 +284,17 @@ namespace Barotrauma
|
||||
get { return Submarine == null ? surface : surface + Submarine.Position.Y; }
|
||||
}
|
||||
|
||||
private float dirtiedVolume = 0.0f;
|
||||
|
||||
public float WaterVolume
|
||||
{
|
||||
get { return waterVolume; }
|
||||
set
|
||||
{
|
||||
if (!MathUtils.IsValid(value)) return;
|
||||
if (!MathUtils.IsValid(value)) { return; }
|
||||
waterVolume = MathHelper.Clamp(value, 0.0f, Volume * MaxCompress);
|
||||
if (waterVolume < Volume) { Pressure = rect.Y - rect.Height + waterVolume / rect.Width; }
|
||||
if (waterVolume > 0.0f)
|
||||
{
|
||||
update = true;
|
||||
if (BackgroundSections != null)
|
||||
{
|
||||
float volumeMultiplier = Math.Clamp(waterVolume / Volume, 0f, 1f);
|
||||
if (Math.Abs(volumeMultiplier - dirtiedVolume) > 0.075f)
|
||||
{
|
||||
RefreshSubmergedSections(new Rectangle(new Point(0, -rect.Height), new Point(rect.Width, (int)(rect.Height * volumeMultiplier))));
|
||||
dirtiedVolume = volumeMultiplier;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
submergedSections.Clear();
|
||||
dirtiedVolume = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -391,8 +385,6 @@ namespace Barotrauma
|
||||
|
||||
private readonly HashSet<int> pendingSectionUpdates = new HashSet<int>();
|
||||
|
||||
private readonly List<BackgroundSection> submergedSections = new List<BackgroundSection>();
|
||||
|
||||
public int xBackgroundMax, yBackgroundMax;
|
||||
|
||||
public bool SupportsPaintedColors
|
||||
@@ -664,7 +656,6 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
BackgroundSections?.Clear();
|
||||
submergedSections?.Clear();
|
||||
|
||||
List<FireSource> fireSourcesToRemove = new List<FireSource>(FireSources);
|
||||
foreach (FireSource fireSource in fireSourcesToRemove)
|
||||
@@ -973,12 +964,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
//0.016 increase every ~2000 frames = reaches full dirtiness in ~35 minutes
|
||||
if (submergedSections.Count > 0 && Submarine != null && Submarine.Info.Type == SubmarineType.Player && Rand.Int(2000) == 1)
|
||||
{
|
||||
DirtySections(submergedSections, deltaTime);
|
||||
}
|
||||
|
||||
if (waterVolume < Volume)
|
||||
{
|
||||
LethalPressure -= 10.0f * deltaTime;
|
||||
@@ -1451,17 +1436,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshSubmergedSections(Rectangle waterArea)
|
||||
{
|
||||
if (BackgroundSections == null) { return; }
|
||||
|
||||
submergedSections.Clear();
|
||||
foreach (var section in GetBackgroundSectionsViaContaining(waterArea))
|
||||
{
|
||||
submergedSections.Add(section);
|
||||
}
|
||||
}
|
||||
|
||||
public bool DoesSectionMatch(int index, int row)
|
||||
{
|
||||
return index >= 0 && row >= 0 && BackgroundSections.Count > index && BackgroundSections[index] != null && BackgroundSections[index].RowIndex == row;
|
||||
@@ -1528,15 +1502,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void DirtySections(List<BackgroundSection> sections, float dirtyVal)
|
||||
{
|
||||
if (sections == null) { return; }
|
||||
for (int i = 0; i < sections.Count; i++)
|
||||
{
|
||||
IncreaseSectionColorOrStrength(sections[i], sections[i].DirtColor, dirtyVal, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void CleanSection(BackgroundSection section, float cleanVal, bool updateRequired)
|
||||
{
|
||||
bool decalsCleaned = false;
|
||||
|
||||
@@ -37,10 +37,14 @@ namespace Barotrauma.RuinGeneration
|
||||
Indent = true,
|
||||
NewLineOnAttributes = true
|
||||
};
|
||||
|
||||
|
||||
IEnumerable<ContentPackage> packages = ContentPackageManager.LocalPackages;
|
||||
#if DEBUG
|
||||
packages = packages.Union(ContentPackageManager.VanillaCorePackage.ToEnumerable());
|
||||
#endif
|
||||
foreach (RuinGenerationParams generationParams in RuinParams)
|
||||
{
|
||||
foreach (RuinConfigFile configFile in ContentPackageManager.AllPackages.SelectMany(p => p.GetFiles<RuinConfigFile>()))
|
||||
foreach (RuinConfigFile configFile in packages.SelectMany(p => p.GetFiles<RuinConfigFile>()))
|
||||
{
|
||||
if (configFile.Path != generationParams.ContentFile.Path) { continue; }
|
||||
|
||||
|
||||
@@ -3,8 +3,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
|
||||
namespace Barotrauma
|
||||
@@ -13,16 +11,20 @@ namespace Barotrauma
|
||||
enum MapEntityCategory
|
||||
{
|
||||
Structure = 1,
|
||||
Decorative = 2,
|
||||
Machine = 4,
|
||||
Equipment = 8,
|
||||
Electrical = 16,
|
||||
Material = 32,
|
||||
Misc = 64,
|
||||
Alien = 128,
|
||||
Wrecked = 256,
|
||||
ItemAssembly = 512,
|
||||
Legacy = 1024
|
||||
Decorative = 2,
|
||||
Machine = 4,
|
||||
Medical = 8,
|
||||
Weapon = 16,
|
||||
Diving = 32,
|
||||
Equipment = 64,
|
||||
Fuel = 128,
|
||||
Electrical = 256,
|
||||
Material = 1024,
|
||||
Alien = 2048,
|
||||
Wrecked = 4096,
|
||||
ItemAssembly = 8192,
|
||||
Legacy = 16384,
|
||||
Misc = 32768
|
||||
}
|
||||
|
||||
abstract partial class MapEntityPrefab : PrefabWithUintIdentifier
|
||||
|
||||
@@ -1540,8 +1540,10 @@ namespace Barotrauma
|
||||
List<HumanPrefab> killedCharacters = new List<HumanPrefab>();
|
||||
List<(HumanPrefab HumanPrefab, CharacterInfo CharacterInfo)> selectedCharacters
|
||||
= new List<(HumanPrefab HumanPrefab, CharacterInfo CharacterInfo)>();
|
||||
foreach (HumanPrefab humanPrefab in outpost.Info.OutpostGenerationParams.GetHumanPrefabs(Rand.RandSync.ServerAndClient))
|
||||
var humanPrefabs = outpost.Info.OutpostGenerationParams.GetHumanPrefabs(Rand.RandSync.ServerAndClient);
|
||||
foreach (HumanPrefab humanPrefab in humanPrefabs)
|
||||
{
|
||||
if (humanPrefab is null) { continue; }
|
||||
var characterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: humanPrefab.GetJobPrefab(Rand.RandSync.ServerAndClient), randSync: Rand.RandSync.ServerAndClient);
|
||||
if (location != null && location.KilledCharacterIdentifiers.Contains(characterInfo.GetIdentifier()))
|
||||
{
|
||||
|
||||
@@ -153,6 +153,7 @@ namespace Barotrauma
|
||||
{
|
||||
Name = TextManager.GetWithVariable("wreckeditemformat", "[name]", Name);
|
||||
}
|
||||
Name = Name.Fallback(OriginalName);
|
||||
|
||||
var tags = new HashSet<Identifier>();
|
||||
string joinedTags = element.GetAttributeString("tags", "");
|
||||
|
||||
@@ -139,7 +139,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasPermissions = false;
|
||||
public bool HasPermissions => Permissions != ClientPermissions.None;
|
||||
|
||||
public VoipQueue VoipQueue
|
||||
{
|
||||
|
||||
@@ -38,6 +38,7 @@ namespace Barotrauma.Networking
|
||||
Wiring,
|
||||
ServerMessage,
|
||||
ConsoleUsage,
|
||||
Money,
|
||||
Karma,
|
||||
Talent,
|
||||
Error,
|
||||
@@ -53,9 +54,10 @@ namespace Barotrauma.Networking
|
||||
{ MessageType.Wiring, new Color(255, 157, 85) },
|
||||
{ MessageType.ServerMessage, new Color(157, 225, 160) },
|
||||
{ MessageType.ConsoleUsage, new Color(0, 162, 232) },
|
||||
{ MessageType.Money, Color.Green },
|
||||
{ MessageType.Karma, new Color(75, 88, 255) },
|
||||
{ MessageType.Talent, new Color(125, 125, 255) },
|
||||
{ MessageType.Error, Color.Red },
|
||||
{ MessageType.Error, Color.Red }
|
||||
};
|
||||
|
||||
private readonly Dictionary<MessageType, string> messageTypeName = new Dictionary<MessageType, string>
|
||||
@@ -68,6 +70,7 @@ namespace Barotrauma.Networking
|
||||
{ MessageType.Wiring, "Wiring" },
|
||||
{ MessageType.ServerMessage, "ServerMessage" },
|
||||
{ MessageType.ConsoleUsage, "ConsoleUsage" },
|
||||
{ MessageType.Money, "Money" },
|
||||
{ MessageType.Karma, "Karma" },
|
||||
{ MessageType.Talent, "Talent" },
|
||||
{ MessageType.Error, "Error" }
|
||||
|
||||
@@ -1007,6 +1007,19 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (attributeName == "move")
|
||||
{
|
||||
Vector2 moveAmount = subElement.GetAttributeVector2("move", Vector2.Zero);
|
||||
if (entity is Structure structure)
|
||||
{
|
||||
structure.Move(moveAmount);
|
||||
}
|
||||
else if (entity is Item item)
|
||||
{
|
||||
item.Move(moveAmount);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entity.SerializableProperties.TryGetValue(attributeName, out SerializableProperty property))
|
||||
{
|
||||
|
||||
@@ -148,6 +148,8 @@ namespace Barotrauma
|
||||
|
||||
public struct GraphicsSettings
|
||||
{
|
||||
public static readonly Point MinSupportedResolution = new Point(1024, 540);
|
||||
|
||||
public static GraphicsSettings GetDefault()
|
||||
{
|
||||
GraphicsSettings gfxSettings = new GraphicsSettings
|
||||
|
||||
@@ -167,16 +167,9 @@ namespace Barotrauma
|
||||
var type = Type;
|
||||
if (type == ConditionType.Uncertain)
|
||||
{
|
||||
if (AfflictionPrefab.Prefabs.ContainsKey(AttributeName))
|
||||
{
|
||||
type = ConditionType.Affliction;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = (target?.SerializableProperties?.ContainsKey(AttributeName) ?? false)
|
||||
? ConditionType.PropertyValue
|
||||
: ConditionType.HasSpecifierTag;
|
||||
}
|
||||
type = AfflictionPrefab.Prefabs.ContainsKey(AttributeName)
|
||||
? ConditionType.Affliction
|
||||
: ConditionType.PropertyValue;
|
||||
}
|
||||
|
||||
if (checkContained)
|
||||
@@ -250,6 +243,14 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
return Operator == OperatorType.Equals ? matches >= SplitAttributeValue.Length : matches <= 0;
|
||||
case ConditionType.HasSpecifierTag:
|
||||
{
|
||||
if (target == null) { return Operator == OperatorType.NotEquals; }
|
||||
if (!(target is Character { Info: { } characterInfo })) { return false; }
|
||||
|
||||
return (Operator == OperatorType.Equals) ==
|
||||
SplitAttributeValue.All(v => characterInfo.Head.Preset.TagSet.Contains(v));
|
||||
}
|
||||
case ConditionType.SpeciesName:
|
||||
{
|
||||
if (target == null) { return Operator == OperatorType.NotEquals; }
|
||||
|
||||
@@ -309,6 +309,11 @@ namespace Barotrauma.Steam
|
||||
|
||||
XDocument fileListSrc = XMLExtensions.TryLoadXml(Path.Combine(itemDirectory, ContentPackage.FileListFileName));
|
||||
string modName = fileListSrc.Root.GetAttributeString("name", item.Title).Trim();
|
||||
string[] modPathSplit = fileListSrc.Root.GetAttributeString("path", "")
|
||||
.CleanUpPathCrossPlatform(correctFilenameCase: false).Split("/");
|
||||
string? modPathDirName = modPathSplit.Length > 1 && modPathSplit[0] == "Mods"
|
||||
? modPathSplit[1]
|
||||
: null;
|
||||
string modVersion = fileListSrc.Root.GetAttributeString("modversion", ContentPackage.DefaultModVersion);
|
||||
Version gameVersion = fileListSrc.Root.GetAttributeVersion("gameversion", GameMain.Version);
|
||||
bool isCorePackage = fileListSrc.Root.GetAttributeBool("corepackage", false);
|
||||
@@ -316,7 +321,7 @@ namespace Barotrauma.Steam
|
||||
|
||||
using (var copyIndicator = new CopyIndicator(copyIndicatorPath))
|
||||
{
|
||||
await CopyDirectory(itemDirectory, modName, itemDirectory, installDir);
|
||||
await CopyDirectory(itemDirectory, modPathDirName ?? modName, itemDirectory, installDir);
|
||||
|
||||
string fileListDestPath = Path.Combine(installDir, ContentPackage.FileListFileName);
|
||||
XDocument fileListDest = XMLExtensions.TryLoadXml(fileListDestPath);
|
||||
@@ -330,9 +335,9 @@ namespace Barotrauma.Steam
|
||||
new XAttribute("modversion", modVersion),
|
||||
new XAttribute("gameversion", gameVersion),
|
||||
new XAttribute("installtime", ToolBox.Epoch.FromDateTime(updateTime)));
|
||||
if (modName.ToIdentifier() != itemTitle)
|
||||
if ((modPathDirName ?? modName).ToIdentifier() != itemTitle)
|
||||
{
|
||||
root.Add(new XAttribute("altnames", modName));
|
||||
root.Add(new XAttribute("altnames", modPathDirName ?? modName));
|
||||
}
|
||||
if (!expectedHash.IsNullOrEmpty())
|
||||
{
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace Barotrauma
|
||||
if (Debugger.IsAttached) { Debugger.Break(); }
|
||||
}
|
||||
#endif
|
||||
return Plain(lStr);
|
||||
return Plain(lStr ?? string.Empty);
|
||||
}
|
||||
public static implicit operator RichString(string str) => (LocalizedString)str;
|
||||
|
||||
|
||||
@@ -149,22 +149,34 @@ namespace Barotrauma
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < Texts.Count; i++)
|
||||
XDocument doc = XMLExtensions.TryLoadXml(ContentFile.Path);
|
||||
if (doc == null) { return; }
|
||||
|
||||
List<(string key, string value)> texts = new List<(string key, string value)>();
|
||||
|
||||
foreach (var element in doc.Root.Elements())
|
||||
{
|
||||
Identifier key = Texts.Keys.ElementAt(i);
|
||||
Texts.TryGetValue(key, out ImmutableArray<string> infoList);
|
||||
string text = element.ElementInnerText()
|
||||
.Replace("&", "&")
|
||||
.Replace("<", "<")
|
||||
.Replace(">", ">")
|
||||
.Replace(""", "\"")
|
||||
.Replace("'", "'");
|
||||
|
||||
texts.Add((element.Name.ToString(), text));
|
||||
}
|
||||
|
||||
foreach ((string key, string value) in texts)
|
||||
{
|
||||
sb.Append(key); // ID
|
||||
sb.Append('*');
|
||||
sb.Append(value); // Original
|
||||
sb.Append('*');
|
||||
// Translated
|
||||
sb.Append('*');
|
||||
// Comments
|
||||
sb.AppendLine();
|
||||
|
||||
for (int j = 0; j < infoList.Length; j++)
|
||||
{
|
||||
sb.Append(key); // ID
|
||||
sb.Append('*');
|
||||
sb.Append(infoList[j]); // Original
|
||||
sb.Append('*');
|
||||
// Translated
|
||||
sb.Append('*');
|
||||
// Comments
|
||||
sb.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
Barotrauma.IO.File.WriteAllText($"csv_{Language.ToString().ToLower()}_{index}.csv", sb.ToString());
|
||||
|
||||
@@ -11,8 +11,8 @@ namespace Barotrauma
|
||||
public static Success<T, TError> Success(T value)
|
||||
=> new Success<T, TError>(value);
|
||||
|
||||
public static Failure<T, TError> Failure(TError error)
|
||||
=> new Failure<T, TError>(error);
|
||||
public static Failure<T, TError> Failure(TError error, string? stackTrace)
|
||||
=> new Failure<T, TError>(error, stackTrace);
|
||||
}
|
||||
|
||||
public sealed class Success<T, TError> : Result<T, TError>
|
||||
@@ -33,11 +33,15 @@ namespace Barotrauma
|
||||
where TError: notnull
|
||||
{
|
||||
public readonly TError Error;
|
||||
|
||||
public readonly string? StackTrace;
|
||||
|
||||
public override bool IsSuccess => false;
|
||||
|
||||
public Failure(TError error)
|
||||
public Failure(TError error, string? stackTrace)
|
||||
{
|
||||
Error = error;
|
||||
StackTrace = stackTrace;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma.IO
|
||||
{
|
||||
@@ -23,9 +24,15 @@ namespace Barotrauma.IO
|
||||
|
||||
public static bool CanWrite(string path, bool isDirectory)
|
||||
{
|
||||
path = System.IO.Path.GetFullPath(path).CleanUpPath();
|
||||
string localModsDir = System.IO.Path.GetFullPath(ContentPackage.LocalModsDir).CleanUpPath();
|
||||
string workshopModsDir = System.IO.Path.GetFullPath(ContentPackage.WorkshopModsDir).CleanUpPath();
|
||||
string getFullPath(string p)
|
||||
=> System.IO.Path.GetFullPath(p).CleanUpPath();
|
||||
|
||||
path = getFullPath(path);
|
||||
string localModsDir = getFullPath(ContentPackage.LocalModsDir);
|
||||
string workshopModsDir = getFullPath(ContentPackage.WorkshopModsDir);
|
||||
#if CLIENT
|
||||
string tempDownloadDir = getFullPath(ModReceiver.DownloadFolder);
|
||||
#endif
|
||||
|
||||
if (!isDirectory)
|
||||
{
|
||||
@@ -34,8 +41,15 @@ namespace Barotrauma.IO
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!path.StartsWith(workshopModsDir, StringComparison.OrdinalIgnoreCase)
|
||||
&& !path.StartsWith(localModsDir, StringComparison.OrdinalIgnoreCase)
|
||||
|
||||
bool pathStartsWith(string prefix)
|
||||
=> path.StartsWith(prefix, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (!pathStartsWith(workshopModsDir)
|
||||
&& !pathStartsWith(localModsDir)
|
||||
#if CLIENT
|
||||
&& !pathStartsWith(tempDownloadDir)
|
||||
#endif
|
||||
&& (extension == ".dll" || extension == ".exe" || extension == ".json"))
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -13,7 +13,7 @@ using System.Text.RegularExpressions;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class SaveUtil
|
||||
static class SaveUtil
|
||||
{
|
||||
private static readonly string LegacySaveFolder = Path.Combine("Data", "Saves");
|
||||
private static readonly string LegacyMultiplayerSaveFolder = Path.Combine(LegacySaveFolder, "Multiplayer");
|
||||
|
||||
Reference in New Issue
Block a user