This commit is contained in:
EvilFactory
2022-10-20 12:14:02 -03:00
63 changed files with 579 additions and 339 deletions
@@ -186,8 +186,8 @@ namespace Barotrauma
{
if (character.SelectedItem != Item)
{
if (Item.TryInteract(character, ignoreRequiredItems: true, forceSelectKey: true) ||
Item.TryInteract(character, ignoreRequiredItems: true, forceUseKey: true))
if (Item.TryInteract(character, ignoreRequiredItems: true, forceUseKey: true) ||
Item.TryInteract(character, ignoreRequiredItems: true, forceSelectKey: true))
{
character.SelectedItem = Item;
}
@@ -1345,7 +1345,7 @@ namespace Barotrauma
bool limbsValid = true;
foreach (Limb limb in limbs)
{
if (limb.body == null || !limb.body.Enabled) { continue; }
if (limb?.body == null || !limb.body.Enabled) { continue; }
if (!CheckValidity(limb.body))
{
limbsValid = false;
@@ -1967,7 +1967,7 @@ namespace Barotrauma
{
foreach (Limb l in Limbs)
{
l.Remove();
l?.Remove();
}
limbs = null;
}
@@ -1976,7 +1976,7 @@ namespace Barotrauma
{
foreach (PhysicsBody b in collider)
{
b.Remove();
b?.Remove();
}
collider = null;
}
@@ -1985,7 +1985,7 @@ namespace Barotrauma
{
foreach (var joint in LimbJoints)
{
var j = joint.Joint;
var j = joint?.Joint;
if (GameMain.World.JointList.Contains(j))
{
GameMain.World.Remove(j);
@@ -2728,6 +2728,11 @@ namespace Barotrauma
}
}
bool selectInputSameAsDeselect = false;
#if CLIENT
selectInputSameAsDeselect = GameSettings.CurrentConfig.KeyMap.Bindings[InputType.Select] == GameSettings.CurrentConfig.KeyMap.Bindings[InputType.Deselect];
#endif
if (SelectedCharacter != null && (IsKeyHit(InputType.Grab) || IsKeyHit(InputType.Health))) //Let people use ladders and buttons and stuff when dragging chars
{
DeselectCharacter();
@@ -2767,14 +2772,16 @@ namespace Barotrauma
{
FocusedCharacter.onCustomInteract(FocusedCharacter, this);
}
else if (IsKeyHit(InputType.Deselect) && SelectedItem != null)
else if (IsKeyHit(InputType.Deselect) && SelectedItem != null &&
(focusedItem == null || focusedItem == SelectedItem || !selectInputSameAsDeselect))
{
SelectedItem = null;
#if CLIENT
CharacterHealth.OpenHealthWindow = null;
#endif
}
else if (IsKeyHit(InputType.Deselect) && SelectedSecondaryItem != null)
else if (IsKeyHit(InputType.Deselect) && SelectedSecondaryItem != null && SelectedSecondaryItem.GetComponent<Ladder>() == null &&
(focusedItem == null || focusedItem == SelectedSecondaryItem || !selectInputSameAsDeselect))
{
SelectedSecondaryItem = null;
#if CLIENT
@@ -2789,6 +2796,10 @@ namespace Barotrauma
{
#if CLIENT
if (CharacterInventory.DraggingItemToWorld) { return; }
if (selectInputSameAsDeselect)
{
keys[(int)InputType.Deselect].Reset();
}
#endif
bool canInteract = focusedItem.TryInteract(this);
#if CLIENT
@@ -543,7 +543,7 @@ namespace Barotrauma
private void GetName(Rand.RandSync randSync, out string name)
{
var nameElement = CharacterConfigElement.GetChildElement("names") ?? CharacterConfigElement.GetChildElement("name");
ContentXElement nameElement = CharacterConfigElement.GetChildElement("names") ?? CharacterConfigElement.GetChildElement("name");
ContentPath namesXmlFile = nameElement?.GetAttributeContentPath("path") ?? ContentPath.Empty;
XElement namesXml = null;
if (!namesXmlFile.IsNullOrEmpty()) //names.xml is defined
@@ -554,8 +554,8 @@ namespace Barotrauma
else //the legacy firstnames.txt/lastnames.txt shit is defined
{
namesXml = new XElement("names", new XAttribute("format", "[firstname] [lastname]"));
var firstNamesPath = ReplaceVars(nameElement.GetAttributeContentPath("firstname")?.Value ?? "");
var lastNamesPath = ReplaceVars(nameElement.GetAttributeContentPath("lastname")?.Value ?? "");
string firstNamesPath = nameElement == null ? string.Empty : ReplaceVars(nameElement.GetAttributeContentPath("firstname")?.Value ?? "");
string lastNamesPath = nameElement == null ? string.Empty : ReplaceVars(nameElement.GetAttributeContentPath("lastname")?.Value ?? "");
if (File.Exists(firstNamesPath) && File.Exists(lastNamesPath))
{
var firstNames = File.ReadAllLines(firstNamesPath);
@@ -17,7 +17,7 @@
{
var affliction = character.CharacterHealth.GetAffliction(afflictionIdentifier);
if (affliction == null) { return false; }
return minimumPercentage <= affliction.Strength / affliction.Prefab.MaxStrength;
return affliction.Strength >= affliction.Prefab.ActivationThreshold && minimumPercentage <= affliction.Strength / affliction.Prefab.MaxStrength;
}
return false;
}
@@ -13,21 +13,23 @@ namespace Barotrauma.Abilities
protected override void ApplyEffect()
{
if (!SelectedItemHasTag(Character)) { return; }
if (!SelectedItemHasTag(Character, tag)) { return; }
Character closestCharacter = null;
float closestDistance = squaredMaxDistance;
foreach (Character crewCharacter in Character.GetFriendlyCrew(Character))
{
if (crewCharacter != Character && Vector2.DistanceSquared(Character.SimPosition, Character.GetRelativeSimPosition(crewCharacter)) is float tempDistance && tempDistance < closestDistance)
if (crewCharacter != Character &&
Vector2.DistanceSquared(Character.WorldPosition, crewCharacter.WorldPosition) is float tempDistance && tempDistance < closestDistance &&
SelectedItemHasTag(crewCharacter, tag))
{
closestCharacter = crewCharacter;
closestDistance = tempDistance;
}
}
if (closestCharacter == null || !SelectedItemHasTag(closestCharacter)) { return; }
if (closestCharacter == null) { return; }
if (closestDistance < squaredMaxDistance)
{
@@ -35,7 +37,7 @@ namespace Barotrauma.Abilities
ApplyEffectSpecific(closestCharacter);
}
bool SelectedItemHasTag(Character character) =>
static bool SelectedItemHasTag(Character character, string tag) =>
(character.SelectedItem != null && character.SelectedItem.HasTag(tag)) ||
(character.SelectedSecondaryItem != null && character.SelectedSecondaryItem.HasTag(tag));
}
@@ -57,7 +57,7 @@ namespace Barotrauma
{
Option<ContentPackageId> ugcId = ContentPackageId.Parse(otherModName.Value);
ContentPackage? otherMod =
allPackages.FirstOrDefault(p => ugcId == p.UgcId)
allPackages.FirstOrDefault(p => ugcId.IsSome() && ugcId == p.UgcId)
?? allPackages.FirstOrDefault(p => p.Name == otherModName)
?? allPackages.FirstOrDefault(p => p.NameMatches(otherModName))
?? throw new MissingContentPackageException(ContentPackage, otherModName.Value);
@@ -1335,7 +1335,7 @@ namespace Barotrauma
if (!prefab.UpgradeCategories.Contains(category)) { continue; }
if (!string.IsNullOrWhiteSpace(prefabIdentifier) && prefab.Identifier != prefabIdentifier) { continue; }
int targetLevel = prefab.MaxLevel - upgradeManager.GetRealUpgradeLevel(prefab, category);
int targetLevel = prefab.GetMaxLevelForCurrentSub() - upgradeManager.GetRealUpgradeLevel(prefab, category);
for (int i = 0; i < targetLevel; i++)
{
upgradeManager.PurchaseUpgrade(prefab, category, force: true);
@@ -139,7 +139,7 @@ namespace Barotrauma
humanPrefab.GiveItems(newCharacter, newCharacter.Submarine);
if (LootingIsStealing)
{
foreach (Item item in newCharacter.Inventory.AllItems)
foreach (Item item in newCharacter.Inventory.FindAllItems(recursive: true))
{
item.SpawnedInCurrentOutpost = true;
item.AllowStealing = false;
@@ -273,13 +273,13 @@ namespace Barotrauma
IsCampaignSet = element.GetAttributeBool("campaign", LevelType == LevelData.LevelType.Outpost || (parentSet?.IsCampaignSet ?? false));
ResetTime = element.GetAttributeFloat("resettime", 0);
DefaultCommonness = 1.0f;
DefaultCommonness = element.GetAttributeFloat("commonness", 1.0f);
foreach (var subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "commonness":
DefaultCommonness = subElement.GetAttributeFloat("commonness", 0.0f);
DefaultCommonness = subElement.GetAttributeFloat("commonness", DefaultCommonness);
foreach (XElement overrideElement in subElement.Elements())
{
if (overrideElement.NameAsIdentifier() == "override")
@@ -156,7 +156,7 @@ namespace Barotrauma
{
if (!(e.ChangedData.BalanceChanged is Some<int> { Value: var changed })) { return; }
if (changed != 0) { return; }
if (changed == 0) { return; }
bool isGain = changed > 0;
Color clr = isGain ? GUIStyle.Yellow : GUIStyle.Red;
@@ -177,12 +177,13 @@ namespace Barotrauma
return;
}
int price = prefab.Price.GetBuyprice(GetUpgradeLevel(prefab, category), Campaign.Map?.CurrentLocation);
int price = prefab.Price.GetBuyPrice(GetUpgradeLevel(prefab, category), Campaign.Map?.CurrentLocation);
int currentLevel = GetUpgradeLevel(prefab, category);
if (currentLevel + 1 > prefab.MaxLevel)
int maxLevel = prefab.GetMaxLevelForCurrentSub();
if (currentLevel + 1 > maxLevel)
{
DebugConsole.ThrowError($"Tried to purchase \"{prefab.Name}\" over the max level! ({currentLevel + 1} > {prefab.MaxLevel}). The transaction has been cancelled.");
DebugConsole.ThrowError($"Tried to purchase \"{prefab.Name}\" over the max level! ({currentLevel + 1} > {maxLevel}). The transaction has been cancelled.");
return;
}
@@ -472,7 +473,7 @@ namespace Barotrauma
{
int newLevel = BuyUpgrade(prefab, category, Submarine.MainSub, level);
DebugConsole.Log($" - {category.Identifier}.{prefab.Identifier} lvl. {level}, new: ({newLevel})");
SetUpgradeLevel(prefab, category, Math.Clamp(GetRealUpgradeLevel(prefab, category) + level, 0, prefab.MaxLevel));
SetUpgradeLevel(prefab, category, GetRealUpgradeLevel(prefab, category) + level);
}
PendingUpgrades.Clear();
@@ -652,16 +653,13 @@ namespace Barotrauma
/// <summary>
/// Gets the progress that is shown on the store interface.
/// Includes values stored in the metadata and <see cref="PendingUpgrades"/>
/// Includes values stored in the metadata and <see cref="PendingUpgrades"/>, and takes submarine tier and class restrictions into account
/// </summary>
/// <param name="prefab"></param>
/// <param name="category"></param>
/// <returns></returns>
public int GetUpgradeLevel(UpgradePrefab prefab, UpgradeCategory category)
{
if (!Metadata.HasKey(FormatIdentifier(prefab, category))) { return GetPendingLevel(); }
return GetRealUpgradeLevel(prefab, category) + GetPendingLevel();
return Math.Min(GetRealUpgradeLevel(prefab, category) + GetPendingLevel(), prefab.GetMaxLevelForCurrentSub());
int GetPendingLevel()
{
@@ -671,11 +669,8 @@ namespace Barotrauma
}
/// <summary>
/// Gets the level of the upgrade that is stored in the metadata.
/// Gets the level of the upgrade that is stored in the metadata. May be higher than the apparent level on the current sub if the player has switched to a lower-tier sub
/// </summary>
/// <param name="prefab"></param>
/// <param name="category"></param>
/// <returns></returns>
public int GetRealUpgradeLevel(UpgradePrefab prefab, UpgradeCategory category)
{
return !Metadata.HasKey(FormatIdentifier(prefab, category)) ? 0 : Metadata.GetInt(FormatIdentifier(prefab, category), 0);
@@ -684,9 +679,6 @@ namespace Barotrauma
/// <summary>
/// Stores the target upgrade level in the campaign metadata.
/// </summary>
/// <param name="prefab"></param>
/// <param name="category"></param>
/// <param name="level"></param>
private void SetUpgradeLevel(UpgradePrefab prefab, UpgradeCategory category, int level)
{
Metadata.SetValue(FormatIdentifier(prefab, category), level);
@@ -1164,11 +1164,14 @@ namespace Barotrauma.Items.Components
public override void ReceiveSignal(Signal signal, Connection connection)
{
#if CLIENT
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient &&
!(GameMain.GameSession?.Campaign?.AllowedToManageCampaign(ClientPermissions.ManageMap) ?? false))
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient)
{
return;
}
if (GameMain.GameSession?.Campaign != null && !CampaignMode.AllowedToManageCampaign(ClientPermissions.ManageMap))
{
return;
}
#endif
if (dockingCooldown > 0.0f) { return; }
@@ -22,7 +22,7 @@ namespace Barotrauma.Items.Components
}
}
const float MaxAttachDistance = 150.0f;
private const float MaxAttachDistance = ItemPrefab.DefaultInteractDistance * 0.95f;
//the position(s) in the item that the Character grabs
protected Vector2[] handlePos;
@@ -731,10 +731,24 @@ namespace Barotrauma.Items.Components
mouseDiff = mouseDiff.ClampLength(MaxAttachDistance);
Vector2 userPos = useWorldCoordinates ? user.WorldPosition : user.Position;
Vector2 attachPos = userPos + mouseDiff;
if (user.Submarine == null && Level.Loaded != null)
if (user.Submarine != null)
{
if (Submarine.PickBody(
ConvertUnits.ToSimUnits(user.Position),
ConvertUnits.ToSimUnits(user.Position + mouseDiff), collisionCategory: Physics.CollisionWall) != null)
{
attachPos = userPos + mouseDiff * Submarine.LastPickedFraction;
//round down if we're placing on the right side and vice versa: ensures we don't round the position inside a wall
return
new Vector2(
mouseDiff.X > 0 ? (float)Math.Floor(attachPos.X / Submarine.GridSize.X) * Submarine.GridSize.X : (float)Math.Ceiling(attachPos.X / Submarine.GridSize.X) * Submarine.GridSize.X,
mouseDiff.Y > 0 ? (float)Math.Floor(attachPos.Y / Submarine.GridSize.Y) * Submarine.GridSize.X : (float)Math.Ceiling(attachPos.Y / Submarine.GridSize.Y) * Submarine.GridSize.Y);
}
}
else if (Level.Loaded != null)
{
bool edgeFound = false;
foreach (var cell in Level.Loaded.GetCells(attachPos))
@@ -112,7 +112,7 @@ namespace Barotrauma.Items.Components
reloadTimer = reload;
reloadTimer /= 1f + character.GetStatValue(StatTypes.MeleeAttackSpeed);
reloadTimer /= 1f + item.GetQualityModifier(Quality.StatType.StrikingSpeedMultiplier);
character.AnimController.LockFlippingUntil = (float)Timing.TotalTime + reloadTimer;
character.AnimController.LockFlippingUntil = (float)Timing.TotalTime + reloadTimer * 0.9f;
item.body.FarseerBody.CollisionCategories = Physics.CollisionProjectile;
item.body.FarseerBody.CollidesWith = Physics.CollisionCharacter | Physics.CollisionWall | Physics.CollisionItemBlocking;
@@ -514,7 +514,7 @@ namespace Barotrauma.Items.Components
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
{
if (Rand.Range(0.0f, 1.0f) < FireProbability * deltaTime)
if (Rand.Range(0.0f, 1.0f) < FireProbability * deltaTime && item.CurrentHull != null)
{
Vector2 displayPos = ConvertUnits.ToDisplayUnits(rayStart + (rayEnd - rayStart) * lastPickedFraction * 0.9f);
if (item.CurrentHull.Submarine != null) { displayPos += item.CurrentHull.Submarine.Position; }
@@ -284,9 +284,10 @@ namespace Barotrauma.Items.Components
{
Entity.Spawner.AddItemToSpawnQueue(itemPrefab, outputContainer.Inventory, condition, onSpawned: (Item spawnedItem) =>
{
spawnedItem.SpawnedInCurrentOutpost = item.SpawnedInCurrentOutpost;
spawnedItem.StolenDuringRound = targetItem.StolenDuringRound;
spawnedItem.AllowStealing = targetItem.AllowStealing;
spawnedItem.OriginalOutpost = targetItem.OriginalOutpost;
spawnedItem.SpawnedInCurrentOutpost = targetItem.SpawnedInCurrentOutpost;
for (int i = 0; i < outputContainer.Capacity; i++)
{
var containedItem = outputContainer.Inventory.GetItemAt(i);
@@ -83,8 +83,16 @@ namespace Barotrauma.Items.Components
{
if (lastUser == value) { return; }
lastUser = value;
degreeOfSuccess = lastUser == null ? 0.0f : Math.Min(DegreeOfSuccess(lastUser), 1.0f);
LastUserWasPlayer = lastUser.IsPlayer;
if (lastUser == null)
{
degreeOfSuccess = 0.0f;
LastUserWasPlayer = false;
}
else
{
degreeOfSuccess = Math.Min(DegreeOfSuccess(lastUser), 1.0f);
LastUserWasPlayer = lastUser.IsPlayer;
}
}
}
@@ -390,6 +390,8 @@ namespace Barotrauma
{
public static readonly PrefabCollection<ItemPrefab> Prefabs = new PrefabCollection<ItemPrefab>();
public const float DefaultInteractDistance = 120.0f;
//default size
public Vector2 Size { get; private set; }
@@ -590,7 +592,7 @@ namespace Barotrauma
public override ImmutableHashSet<string> Aliases => aliases;
//how close the Character has to be to the item to pick it up
[Serialize(120.0f, IsPropertySaveable.No)]
[Serialize(DefaultInteractDistance, IsPropertySaveable.No)]
public float InteractDistance { get; private set; }
// this can be used to allow items which are behind other items tp
@@ -3015,6 +3015,7 @@ namespace Barotrauma
var selectedLocation = allValidLocations.FirstOrDefault(l =>
Vector2.Distance(l.Edge.Point1, l.Edge.Point2) is float edgeLength &&
!l.Edge.OutsideLevel &&
((l.Edge.Cell1?.IsDestructible ?? false) || (l.Edge.Cell2?.IsDestructible ?? false)) &&
requiredAmount <= (int)Math.Floor(edgeLength / ((1.0f - maxResourceOverlap) * prefab.Size.X)));
@@ -3905,7 +3906,7 @@ namespace Barotrauma
private bool HasEndOutpost()
{
if (preSelectedStartOutpost != null) { return true; }
if (preSelectedEndOutpost != null) { return true; }
//don't create an end outpost for locations
if (LevelData.Type == LevelData.LevelType.Outpost) { return false; }
if (EndLocation != null && !EndLocation.Type.HasOutpost) { return false; }
@@ -906,11 +906,17 @@ namespace Barotrauma
public LocationType GetLocationType()
{
if (IsCriticallyRadiated() && LocationType.Prefabs[Type.ReplaceInRadiation] is { } newLocationType)
if (IsCriticallyRadiated() && !Type.ReplaceInRadiation.IsEmpty)
{
return newLocationType;
if (LocationType.Prefabs.TryGet(Type.ReplaceInRadiation, out LocationType newLocationType))
{
return newLocationType;
}
else
{
DebugConsole.ThrowError($"Error when trying to get a new location type for an irradiated location - location type \"{newLocationType}\" not found.");
}
}
return Type;
}
@@ -65,7 +65,7 @@ namespace Barotrauma
private set;
}
public string ReplaceInRadiation { get; }
public Identifier ReplaceInRadiation { get; }
public Sprite Sprite { get; private set; }
public Sprite RadiationSprite { get; }
@@ -108,7 +108,7 @@ namespace Barotrauma
HideEntitySubcategories = element.GetAttributeStringArray("hideentitysubcategories", Array.Empty<string>()).ToList();
ReplaceInRadiation = element.GetAttributeString(nameof(ReplaceInRadiation).ToLower(), "");
ReplaceInRadiation = element.GetAttributeIdentifier(nameof(ReplaceInRadiation), Identifier.Empty);
string teamStr = element.GetAttributeString("outpostteam", "FriendlyNPC");
Enum.TryParse(teamStr, out OutpostTeam);
@@ -560,6 +560,42 @@ namespace Barotrauma
}
}
//make sure the location at the right side of the gate between biomes isn't a dead-end
//those may sometimes generate if all the connections of the right-side location lead to the previous biome
//(i.e. a situation where the adjacent locations happen to be at the left side of the border of the biomes, see see Regalis11/Barotrauma#10047)
for (int i = 0; i < Connections.Count; i++)
{
var connection = Connections[i];
if (!connection.Locked) { continue; }
var rightMostLocation =
connection.Locations[0].MapPosition.X > connection.Locations[1].MapPosition.X ?
connection.Locations[0] :
connection.Locations[1];
//if there's only one connection (= the connection between biomes), create a new connection to the closest location to the right
if (rightMostLocation.Connections.Count == 1)
{
Location closestLocation = null;
float closestDist = float.PositiveInfinity;
foreach (Location otherLocation in Locations)
{
if (otherLocation == rightMostLocation || otherLocation.MapPosition.X < rightMostLocation.MapPosition.X) { continue; }
float dist = Vector2.DistanceSquared(rightMostLocation.MapPosition, otherLocation.MapPosition);
if (dist < closestDist || closestLocation == null)
{
closestLocation = otherLocation;
closestDist = dist;
}
}
var newConnection = new LocationConnection(rightMostLocation, closestLocation);
rightMostLocation.Connections.Add(newConnection);
closestLocation.Connections.Add(newConnection);
Connections.Add(newConnection);
GenerateLocationConnectionVisuals(newConnection);
}
}
//remove orphans
Locations.RemoveAll(l => !Connections.Any(c => c.Locations.Contains(l)));
@@ -606,7 +642,9 @@ namespace Barotrauma
}
}
partial void GenerateLocationConnectionVisuals();
partial void GenerateAllLocationConnectionVisuals();
partial void GenerateLocationConnectionVisuals(LocationConnection connection);
private int GetZoneIndex(float xPos)
{
@@ -8,23 +8,7 @@ using Lidgren.Network;
namespace Barotrauma
{
interface IWritableBitField
{
public void WriteBoolean(bool b);
public void WriteInteger(int value, int min, int max);
public void WriteFloat(float value, float min, float max, int numberOfBits);
public void WriteToMessage(IWriteMessage msg);
}
interface IReadableBitField
{
public bool ReadBoolean();
public int ReadInteger(int min, int max);
public float ReadFloat(float min, float max, int numberOfBits);
}
sealed class WriteOnlyBitField : IWritableBitField, IDisposable
sealed class WriteOnlyBitField : IDisposable
{
private const int AmountOfBoolsInByte = 7; // Reserve last bit for end marker
private readonly List<byte> Buffer = new List<byte>();
@@ -100,7 +84,7 @@ namespace Barotrauma
}
}
sealed class ReadOnlyBitField : IReadableBitField
sealed class ReadOnlyBitField
{
private const int AmountOfBoolsInByte = 7; // Reserve last bit for end marker
private readonly ImmutableArray<byte> buffer;
@@ -110,17 +94,14 @@ namespace Barotrauma
{
List<byte> bytes = new List<byte>();
byte currentByte;
int reads = 0;
do
{
if (inc.BitPosition >= inc.LengthBits)
{
throw new Exception("Failed to find the end of the bit field: end of the message reached.");
}
currentByte = inc.ReadByte();
bytes.Add(currentByte);
reads++;
if (reads > 100)
{
throw new Exception($"Failed to find the end of the bit field after 100 reads. Terminating to prevent the game from freezing.");
}
}
while (!IsBitSet(currentByte, AmountOfBoolsInByte));
@@ -113,6 +113,11 @@ namespace Barotrauma.Networking
break;
}
}
catch (AggregateException aggregateException)
{
if (aggregateException.InnerException is OperationCanceledException) { return -1; }
throw;
}
catch (OperationCanceledException)
{
return -1;
@@ -61,9 +61,9 @@ namespace Barotrauma
{
public interface IReadWriteBehavior
{
public delegate object? ReadDelegate(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField);
public delegate object? ReadDelegate(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField);
public delegate void WriteDelegate(object? obj, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField);
public delegate void WriteDelegate(object? obj, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField);
public ReadDelegate ReadAction { get; }
public WriteDelegate WriteAction { get; }
@@ -71,9 +71,9 @@ namespace Barotrauma
public readonly struct ReadWriteBehavior<T> : IReadWriteBehavior
{
public delegate T ReadDelegate(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField);
public delegate T ReadDelegate(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField);
public delegate void WriteDelegate(T obj, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField);
public delegate void WriteDelegate(T obj, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField);
public IReadWriteBehavior.ReadDelegate ReadAction { get; }
public IReadWriteBehavior.WriteDelegate WriteAction { get; }
@@ -256,18 +256,18 @@ namespace Barotrauma
ReadImmutableArray<object>,
WriteImmutableArray<object>);
private static ImmutableArray<T> ReadImmutableArray<T>(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) where T : notnull
private static ImmutableArray<T> ReadImmutableArray<T>(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) where T : notnull
{
return ReadArray<T>(inc, attribute, bitField).ToImmutableArray();
}
private static void WriteImmutableArray<T>(ImmutableArray<T> array, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) where T : notnull
private static void WriteImmutableArray<T>(ImmutableArray<T> array, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) where T : notnull
{
ToolBox.ThrowIfNull(array);
WriteIReadOnlyCollection<T>(array, attribute, msg, bitField);
}
private static T[] ReadArray<T>(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) where T : notnull
private static T[] ReadArray<T>(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) where T : notnull
{
int length = bitField.ReadInteger(0, attribute.ArrayMaxSize);
@@ -286,13 +286,13 @@ namespace Barotrauma
return array;
}
private static void WriteArray<T>(T[] array, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) where T : notnull
private static void WriteArray<T>(T[] array, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) where T : notnull
{
ToolBox.ThrowIfNull(array);
WriteIReadOnlyCollection(array, attribute, msg, bitField);
}
private static void WriteIReadOnlyCollection<T>(IReadOnlyCollection<T> array, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) where T : notnull
private static void WriteIReadOnlyCollection<T>(IReadOnlyCollection<T> array, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) where T : notnull
{
bitField.WriteInteger(array.Count, 0, attribute.ArrayMaxSize);
@@ -307,18 +307,18 @@ namespace Barotrauma
}
}
private static T ReadINetSerializableStruct<T>(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) where T : INetSerializableStruct
private static T ReadINetSerializableStruct<T>(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) where T : INetSerializableStruct
{
return INetSerializableStruct.ReadInternal<T>(inc, bitField);
}
private static void WriteINetSerializableStruct<T>(T serializableStruct, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) where T : INetSerializableStruct
private static void WriteINetSerializableStruct<T>(T serializableStruct, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) where T : INetSerializableStruct
{
ToolBox.ThrowIfNull(serializableStruct);
serializableStruct.WriteInternal(msg, bitField);
}
private static T ReadEnum<T>(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) where T : Enum
private static T ReadEnum<T>(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) where T : Enum
{
var type = typeof(T);
@@ -338,7 +338,7 @@ namespace Barotrauma
throw new InvalidOperationException($"An enum {type} with value {enumIndex} could not be found in {nameof(ReadEnum)}");
}
private static void WriteEnum<T>(T value, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) where T : Enum
private static void WriteEnum<T>(T value, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) where T : Enum
{
ToolBox.ThrowIfNull(value);
@@ -346,7 +346,7 @@ namespace Barotrauma
bitField.WriteInteger((int)Convert.ChangeType(value, value.GetTypeCode()), range.Start, range.End);
}
private static T? ReadNullable<T>(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) where T : struct =>
private static T? ReadNullable<T>(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) where T : struct =>
ReadOption<T>(inc, attribute, bitField) switch
{
Some<T> { Value: var value } => value,
@@ -354,10 +354,10 @@ namespace Barotrauma
_ => throw new ArgumentOutOfRangeException()
};
private static void WriteNullable<T>(T? value, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) where T : struct =>
private static void WriteNullable<T>(T? value, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) where T : struct =>
WriteOption<T>(value.HasValue ? Option<T>.Some(value.Value) : Option<T>.None(), attribute, msg, bitField);
private static Option<T> ReadOption<T>(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) where T : notnull
private static Option<T> ReadOption<T>(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) where T : notnull
{
bool hasValue = bitField.ReadBoolean();
if (!hasValue)
@@ -373,7 +373,7 @@ namespace Barotrauma
throw new InvalidOperationException($"Could not find suitable behavior for type {typeof(T)} in {nameof(ReadOption)}");
}
private static void WriteOption<T>(Option<T> option, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) where T : notnull
private static void WriteOption<T>(Option<T> option, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) where T : notnull
{
ToolBox.ThrowIfNull(option);
@@ -391,22 +391,22 @@ namespace Barotrauma
}
}
private static bool ReadBoolean(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) => bitField.ReadBoolean();
private static void WriteBoolean(bool b, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) { bitField.WriteBoolean(b); }
private static bool ReadBoolean(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) => bitField.ReadBoolean();
private static void WriteBoolean(bool b, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) { bitField.WriteBoolean(b); }
private static byte ReadByte(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) => inc.ReadByte();
private static void WriteByte(byte b, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) { msg.WriteByte(b); }
private static byte ReadByte(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) => inc.ReadByte();
private static void WriteByte(byte b, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) { msg.WriteByte(b); }
private static ushort ReadUInt16(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) => inc.ReadUInt16();
private static void WriteUInt16(ushort b, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) { msg.WriteUInt16(b); }
private static ushort ReadUInt16(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) => inc.ReadUInt16();
private static void WriteUInt16(ushort b, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) { msg.WriteUInt16(b); }
private static short ReadInt16(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) => inc.ReadInt16();
private static void WriteInt16(short b, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) { msg.WriteInt16(b); }
private static short ReadInt16(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) => inc.ReadInt16();
private static void WriteInt16(short b, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) { msg.WriteInt16(b); }
private static uint ReadUInt32(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) => inc.ReadUInt32();
private static void WriteUInt32(uint b, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) { msg.WriteUInt32(b); }
private static uint ReadUInt32(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) => inc.ReadUInt32();
private static void WriteUInt32(uint b, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) { msg.WriteUInt32(b); }
private static int ReadInt32(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField)
private static int ReadInt32(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField)
{
if (IsRanged(attribute.MinValueInt, attribute.MaxValueInt))
{
@@ -416,7 +416,7 @@ namespace Barotrauma
return inc.ReadInt32();
}
private static void WriteInt32(int i, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField)
private static void WriteInt32(int i, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField)
{
ToolBox.ThrowIfNull(i);
@@ -429,13 +429,13 @@ namespace Barotrauma
msg.WriteInt32(i);
}
private static ulong ReadUInt64(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) => inc.ReadUInt64();
private static void WriteUInt64(ulong b, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) { msg.WriteUInt64(b); }
private static ulong ReadUInt64(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) => inc.ReadUInt64();
private static void WriteUInt64(ulong b, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) { msg.WriteUInt64(b); }
private static long ReadInt64(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) => inc.ReadInt64();
private static void WriteInt64(long b, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) { msg.WriteInt64(b); }
private static long ReadInt64(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) => inc.ReadInt64();
private static void WriteInt64(long b, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) { msg.WriteInt64(b); }
private static float ReadSingle(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField)
private static float ReadSingle(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField)
{
if (IsRanged(attribute.MinValueFloat, attribute.MaxValueFloat))
{
@@ -445,7 +445,7 @@ namespace Barotrauma
return inc.ReadSingle();
}
private static void WriteSingle(float f, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField)
private static void WriteSingle(float f, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField)
{
ToolBox.ThrowIfNull(f);
@@ -458,16 +458,16 @@ namespace Barotrauma
msg.WriteSingle(f);
}
private static double ReadDouble(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) => inc.ReadDouble();
private static void WriteDouble(double b, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) { msg.WriteDouble(b); }
private static double ReadDouble(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) => inc.ReadDouble();
private static void WriteDouble(double b, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) { msg.WriteDouble(b); }
private static string ReadString(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) => inc.ReadString();
private static void WriteString(string b, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) { msg.WriteString(b); }
private static string ReadString(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) => inc.ReadString();
private static void WriteString(string b, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) { msg.WriteString(b); }
private static Identifier ReadIdentifier(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) => inc.ReadIdentifier();
private static void WriteIdentifier(Identifier b, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) { msg.WriteIdentifier(b); }
private static Identifier ReadIdentifier(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) => inc.ReadIdentifier();
private static void WriteIdentifier(Identifier b, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) { msg.WriteIdentifier(b); }
private static AccountId ReadAccountId(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField)
private static AccountId ReadAccountId(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField)
{
string str = inc.ReadString();
return AccountId.Parse(str).TryUnwrap(out var accountId)
@@ -475,14 +475,14 @@ namespace Barotrauma
: throw new InvalidCastException($"Could not parse \"{str}\" as an {nameof(AccountId)}");
}
private static void WriteAccountId(AccountId accountId, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField)
private static void WriteAccountId(AccountId accountId, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField)
{
msg.WriteString(accountId.StringRepresentation);
}
private static Color ReadColor(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) => attribute.IncludeColorAlpha ? inc.ReadColorR8G8B8A8() : inc.ReadColorR8G8B8();
private static Color ReadColor(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) => attribute.IncludeColorAlpha ? inc.ReadColorR8G8B8A8() : inc.ReadColorR8G8B8();
private static void WriteColor(Color color, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField)
private static void WriteColor(Color color, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField)
{
ToolBox.ThrowIfNull(color);
@@ -495,7 +495,7 @@ namespace Barotrauma
msg.WriteColorR8G8B8(color);
}
private static Vector2 ReadVector2(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField)
private static Vector2 ReadVector2(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField)
{
float x = ReadSingle(inc, attribute, bitField);
float y = ReadSingle(inc, attribute, bitField);
@@ -503,7 +503,7 @@ namespace Barotrauma
return new Vector2(x, y);
}
private static void WriteVector2(Vector2 vector2, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField)
private static void WriteVector2(Vector2 vector2, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField)
{
ToolBox.ThrowIfNull(vector2);
@@ -690,11 +690,11 @@ namespace Barotrauma
/// <returns>A new struct of type T with fields and properties deserialized</returns>
public static T Read<T>(IReadMessage inc) where T : INetSerializableStruct
{
IReadableBitField bitField = new ReadOnlyBitField(inc);
ReadOnlyBitField bitField = new ReadOnlyBitField(inc);
return ReadInternal<T>(inc, bitField);
}
public static T ReadInternal<T>(IReadMessage inc, IReadableBitField bitField) where T : INetSerializableStruct
public static T ReadInternal<T>(IReadMessage inc, ReadOnlyBitField bitField) where T : INetSerializableStruct
{
object? newObject = Activator.CreateInstance(typeof(T));
if (newObject is null) { return default!; }
@@ -744,14 +744,14 @@ namespace Barotrauma
/// <param name="msg">Outgoing network message</param>
public void Write(IWriteMessage msg)
{
IWritableBitField bitField = new WriteOnlyBitField();
WriteOnlyBitField bitField = new WriteOnlyBitField();
IWriteMessage structWriteMsg = new WriteOnlyMessage();
WriteInternal(structWriteMsg, bitField);
bitField.WriteToMessage(msg);
msg.WriteBytes(structWriteMsg.Buffer, 0, structWriteMsg.LengthBytes);
}
public void WriteInternal(IWriteMessage msg, IWritableBitField bitField)
public void WriteInternal(IWriteMessage msg, WriteOnlyBitField bitField)
{
var properties = NetSerializableProperties.GetPropertiesAndFields(GetType());
@@ -40,6 +40,25 @@ namespace Barotrauma.Networking
return Option<LidgrenAddress>.None();
}
public static Option<LidgrenAddress> ParseHostName(string endpointStr)
{
try
{
var resolvedAddresses = Dns.GetHostAddresses(endpointStr);
return resolvedAddresses.Any()
? Option<LidgrenAddress>.Some(new LidgrenAddress(resolvedAddresses.First()))
: Option<LidgrenAddress>.None();
}
catch (SocketException)
{
return Option<LidgrenAddress>.None();
}
catch (ArgumentOutOfRangeException)
{
return Option<LidgrenAddress>.None();
}
}
public override bool Equals(object? obj)
=> obj switch
{
@@ -23,6 +23,11 @@ namespace Barotrauma.Networking
}
public new static Option<LidgrenEndpoint> Parse(string endpointStr)
{
return ParseFromWithHostNameCheck(endpointStr, tryParseHostName: false);
}
public static Option<LidgrenEndpoint> ParseFromWithHostNameCheck(string endpointStr, bool tryParseHostName)
{
string hostName = endpointStr;
int port = NetConfig.DefaultPort;
@@ -33,7 +38,8 @@ namespace Barotrauma.Networking
port = int.TryParse(split[1], out var tmpPort) ? tmpPort : port;
}
if (LidgrenAddress.Parse(hostName).TryUnwrap(out var adr))
if (LidgrenAddress.Parse(hostName).TryUnwrap(out var adr) ||
(tryParseHostName && LidgrenAddress.ParseHostName(hostName).TryUnwrap(out adr)))
{
return Option<LidgrenEndpoint>.Some(new LidgrenEndpoint(adr.NetAddress, port));
}
@@ -37,7 +37,12 @@ namespace Barotrauma.Networking
internal static class MsgWriter
{
internal static void Write(ref byte[] buf, ref int bitPos, bool val)
internal static void UpdateBitLength(ref int bitLength, int bitPos)
{
bitLength = Math.Max(bitLength, bitPos);
}
internal static void WriteBoolean(ref byte[] buf, ref int bitPos, ref int bitLength, bool val)
{
#if DEBUG
int resetPos = bitPos;
@@ -52,7 +57,7 @@ namespace Barotrauma.Networking
buf[bytePos] &= bitMask;
if (val) buf[bytePos] |= bitFlag;
bitPos++;
UpdateBitLength(ref bitLength, bitPos);
#if DEBUG
bool testVal = MsgReader.ReadBoolean(buf, ref resetPos);
if (testVal != val || resetPos != bitPos)
@@ -62,63 +67,71 @@ namespace Barotrauma.Networking
#endif
}
internal static void WritePadBits(ref byte[] buf, ref int bitPos)
internal static void WritePadBits(ref byte[] buf, ref int bitPos, ref int bitLength)
{
int bitOffset = bitPos % 8;
bitPos += ((8 - bitOffset) % 8);
UpdateBitLength(ref bitLength, bitPos);
EnsureBufferSize(ref buf, bitPos);
}
internal static void Write(ref byte[] buf, ref int bitPos, byte val)
internal static void WriteByte(ref byte[] buf, ref int bitPos, ref int bitLength, byte val)
{
EnsureBufferSize(ref buf, bitPos + 8);
NetBitWriter.WriteByte(val, 8, buf, bitPos);
bitPos += 8;
UpdateBitLength(ref bitLength, bitPos);
}
internal static void Write(ref byte[] buf, ref int bitPos, UInt16 val)
internal static void WriteUInt16(ref byte[] buf, ref int bitPos, ref int bitLength, UInt16 val)
{
EnsureBufferSize(ref buf, bitPos + 16);
NetBitWriter.WriteUInt16(val, 16, buf, bitPos);
bitPos += 16;
UpdateBitLength(ref bitLength, bitPos);
}
internal static void Write(ref byte[] buf, ref int bitPos, Int16 val)
internal static void WriteInt16(ref byte[] buf, ref int bitPos, ref int bitLength, Int16 val)
{
EnsureBufferSize(ref buf, bitPos + 16);
NetBitWriter.WriteUInt16((UInt16)val, 16, buf, bitPos);
bitPos += 16;
UpdateBitLength(ref bitLength, bitPos);
}
internal static void Write(ref byte[] buf, ref int bitPos, UInt32 val)
internal static void WriteUInt32(ref byte[] buf, ref int bitPos, ref int bitLength, UInt32 val)
{
EnsureBufferSize(ref buf, bitPos + 32);
NetBitWriter.WriteUInt32(val, 32, buf, bitPos);
bitPos += 32;
UpdateBitLength(ref bitLength, bitPos);
}
internal static void Write(ref byte[] buf, ref int bitPos, Int32 val)
internal static void WriteInt32(ref byte[] buf, ref int bitPos, ref int bitLength, Int32 val)
{
EnsureBufferSize(ref buf, bitPos + 32);
NetBitWriter.WriteUInt32((UInt32)val, 32, buf, bitPos);
bitPos += 32;
UpdateBitLength(ref bitLength, bitPos);
}
internal static void Write(ref byte[] buf, ref int bitPos, UInt64 val)
internal static void WriteUInt64(ref byte[] buf, ref int bitPos, ref int bitLength, UInt64 val)
{
EnsureBufferSize(ref buf, bitPos + 64);
NetBitWriter.WriteUInt64(val, 64, buf, bitPos);
bitPos += 64;
UpdateBitLength(ref bitLength, bitPos);
}
internal static void Write(ref byte[] buf, ref int bitPos, Int64 val)
internal static void WriteInt64(ref byte[] buf, ref int bitPos, ref int bitLength, Int64 val)
{
EnsureBufferSize(ref buf, bitPos + 64);
NetBitWriter.WriteUInt64((UInt64)val, 64, buf, bitPos);
bitPos += 64;
UpdateBitLength(ref bitLength, bitPos);
}
internal static void Write(ref byte[] buf, ref int bitPos, Single val)
internal static void WriteSingle(ref byte[] buf, ref int bitPos, ref int bitLength, Single val)
{
// Use union to avoid BitConverter.GetBytes() which allocates memory on the heap
SingleUIntUnion su;
@@ -129,61 +142,62 @@ namespace Barotrauma.Networking
NetBitWriter.WriteUInt32(su.UIntValue, 32, buf, bitPos);
bitPos += 32;
UpdateBitLength(ref bitLength, bitPos);
}
internal static void Write(ref byte[] buf, ref int bitPos, Double val)
internal static void WriteDouble(ref byte[] buf, ref int bitPos, ref int bitLength, Double val)
{
EnsureBufferSize(ref buf, bitPos + 64);
byte[] bytes = BitConverter.GetBytes(val);
WriteBytes(ref buf, ref bitPos, bytes, 0, 8);
WriteBytes(ref buf, ref bitPos, ref bitLength, bytes, 0, 8);
}
internal static void WriteColorR8G8B8(ref byte[] buf, ref int bitPos, Color val)
internal static void WriteColorR8G8B8(ref byte[] buf, ref int bitPos, ref int bitLength, Color val)
{
EnsureBufferSize(ref buf, bitPos + 24);
Write(ref buf, ref bitPos, val.R);
Write(ref buf, ref bitPos, val.G);
Write(ref buf, ref bitPos, val.B);
WriteByte(ref buf, ref bitPos, ref bitLength, val.R);
WriteByte(ref buf, ref bitPos, ref bitLength, val.G);
WriteByte(ref buf, ref bitPos, ref bitLength, val.B);
}
internal static void WriteColorR8G8B8A8(ref byte[] buf, ref int bitPos, Color val)
internal static void WriteColorR8G8B8A8(ref byte[] buf, ref int bitPos, ref int bitLength, Color val)
{
EnsureBufferSize(ref buf, bitPos + 32);
Write(ref buf, ref bitPos, val.R);
Write(ref buf, ref bitPos, val.G);
Write(ref buf, ref bitPos, val.B);
Write(ref buf, ref bitPos, val.A);
WriteByte(ref buf, ref bitPos, ref bitLength, val.R);
WriteByte(ref buf, ref bitPos, ref bitLength, val.G);
WriteByte(ref buf, ref bitPos, ref bitLength, val.B);
WriteByte(ref buf, ref bitPos, ref bitLength, val.A);
}
internal static void Write(ref byte[] buf, ref int bitPos, string val)
internal static void WriteString(ref byte[] buf, ref int bitPos, ref int bitLength, string val)
{
if (string.IsNullOrEmpty(val))
{
WriteVariableUInt32(ref buf, ref bitPos, 0u);
WriteVariableUInt32(ref buf, ref bitPos, ref bitLength, 0u);
return;
}
byte[] bytes = Encoding.UTF8.GetBytes(val);
WriteVariableUInt32(ref buf, ref bitPos, (uint)bytes.Length);
WriteBytes(ref buf, ref bitPos, bytes, 0, bytes.Length);
WriteVariableUInt32(ref buf, ref bitPos, ref bitLength, (uint)bytes.Length);
WriteBytes(ref buf, ref bitPos, ref bitLength, bytes, 0, bytes.Length);
}
internal static void WriteVariableUInt32(ref byte[] buf, ref int bitPos, uint value)
internal static void WriteVariableUInt32(ref byte[] buf, ref int bitPos, ref int bitLength, uint value)
{
uint remainingValue = value;
while (remainingValue >= 0x80)
{
Write(ref buf, ref bitPos, (byte)(remainingValue | 0x80));
WriteByte(ref buf, ref bitPos, ref bitLength, (byte)(remainingValue | 0x80));
remainingValue >>= 7;
}
Write(ref buf, ref bitPos, (byte)remainingValue);
WriteByte(ref buf, ref bitPos, ref bitLength, (byte)remainingValue);
}
internal static void WriteRangedInteger(ref byte[] buf, ref int bitPos, int val, int min, int max)
internal static void WriteRangedInteger(ref byte[] buf, ref int bitPos, ref int bitLength, int val, int min, int max)
{
uint range = (uint)(max - min);
int numberOfBits = NetUtility.BitsToHoldUInt(range);
@@ -193,9 +207,10 @@ namespace Barotrauma.Networking
uint rvalue = (uint)(val - min);
NetBitWriter.WriteUInt32(rvalue, numberOfBits, buf, bitPos);
bitPos += numberOfBits;
UpdateBitLength(ref bitLength, bitPos);
}
internal static void WriteRangedSingle(ref byte[] buf, ref int bitPos, Single val, Single min, Single max, int numberOfBits)
internal static void WriteRangedSingle(ref byte[] buf, ref int bitPos, ref int bitLength, Single val, Single min, Single max, int numberOfBits)
{
float range = max - min;
float unit = ((val - min) / range);
@@ -205,13 +220,15 @@ namespace Barotrauma.Networking
NetBitWriter.WriteUInt32((UInt32)(maxVal * unit), numberOfBits, buf, bitPos);
bitPos += numberOfBits;
UpdateBitLength(ref bitLength, bitPos);
}
internal static void WriteBytes(ref byte[] buf, ref int bitPos, byte[] val, int pos, int length)
internal static void WriteBytes(ref byte[] buf, ref int bitPos, ref int bitLength, byte[] val, int pos, int length)
{
EnsureBufferSize(ref buf, bitPos + length * 8);
NetBitWriter.WriteBytes(val, pos, length, buf, bitPos);
bitPos += length * 8;
UpdateBitLength(ref bitLength, bitPos);
}
internal static void EnsureBufferSize(ref byte[] buf, int numberOfBits)
@@ -447,77 +464,77 @@ namespace Barotrauma.Networking
public void WriteBoolean(bool val)
{
MsgWriter.Write(ref buf, ref seekPos, val);
MsgWriter.WriteBoolean(ref buf, ref seekPos, ref lengthBits, val);
}
public void WritePadBits()
{
MsgWriter.WritePadBits(ref buf, ref seekPos);
MsgWriter.WritePadBits(ref buf, ref seekPos, ref lengthBits);
}
public void WriteByte(byte val)
{
MsgWriter.Write(ref buf, ref seekPos, val);
MsgWriter.WriteByte(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteUInt16(UInt16 val)
{
MsgWriter.Write(ref buf, ref seekPos, val);
MsgWriter.WriteUInt16(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteInt16(Int16 val)
{
MsgWriter.Write(ref buf, ref seekPos, val);
MsgWriter.WriteInt16(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteUInt32(UInt32 val)
{
MsgWriter.Write(ref buf, ref seekPos, val);
MsgWriter.WriteUInt32(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteInt32(Int32 val)
{
MsgWriter.Write(ref buf, ref seekPos, val);
MsgWriter.WriteInt32(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteUInt64(UInt64 val)
{
MsgWriter.Write(ref buf, ref seekPos, val);
MsgWriter.WriteUInt64(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteInt64(Int64 val)
{
MsgWriter.Write(ref buf, ref seekPos, val);
MsgWriter.WriteInt64(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteSingle(Single val)
{
MsgWriter.Write(ref buf, ref seekPos, val);
MsgWriter.WriteSingle(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteDouble(Double val)
{
MsgWriter.Write(ref buf, ref seekPos, val);
MsgWriter.WriteDouble(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteColorR8G8B8(Color val)
{
MsgWriter.WriteColorR8G8B8(ref buf, ref seekPos, val);
MsgWriter.WriteColorR8G8B8(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteColorR8G8B8A8(Color val)
{
MsgWriter.WriteColorR8G8B8A8(ref buf, ref seekPos, val);
MsgWriter.WriteColorR8G8B8A8(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteVariableUInt32(UInt32 val)
{
MsgWriter.WriteVariableUInt32(ref buf, ref seekPos, val);
MsgWriter.WriteVariableUInt32(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteString(String val)
{
MsgWriter.Write(ref buf, ref seekPos, val);
MsgWriter.WriteString(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteIdentifier(Identifier val)
@@ -527,17 +544,17 @@ namespace Barotrauma.Networking
public void WriteRangedInteger(int val, int min, int max)
{
MsgWriter.WriteRangedInteger(ref buf, ref seekPos, val, min, max);
MsgWriter.WriteRangedInteger(ref buf, ref seekPos, ref lengthBits, val, min, max);
}
public void WriteRangedSingle(Single val, Single min, Single max, int bitCount)
{
MsgWriter.WriteRangedSingle(ref buf, ref seekPos, val, min, max, bitCount);
MsgWriter.WriteRangedSingle(ref buf, ref seekPos, ref lengthBits, val, min, max, bitCount);
}
public void WriteBytes(byte[] val, int startPos, int length)
{
MsgWriter.WriteBytes(ref buf, ref seekPos, val, startPos, length);
MsgWriter.WriteBytes(ref buf, ref seekPos, ref lengthBits, val, startPos, length);
}
public byte[] PrepareForSending(bool compressPastThreshold, out bool isCompressed, out int length)
@@ -814,77 +831,77 @@ namespace Barotrauma.Networking
public void WriteBoolean(bool val)
{
MsgWriter.Write(ref buf, ref seekPos, val);
MsgWriter.WriteBoolean(ref buf, ref seekPos, ref lengthBits, val);
}
public void WritePadBits()
{
MsgWriter.WritePadBits(ref buf, ref seekPos);
MsgWriter.WritePadBits(ref buf, ref seekPos, ref lengthBits);
}
public void WriteByte(byte val)
{
MsgWriter.Write(ref buf, ref seekPos, val);
MsgWriter.WriteByte(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteUInt16(UInt16 val)
{
MsgWriter.Write(ref buf, ref seekPos, val);
MsgWriter.WriteUInt16(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteInt16(Int16 val)
{
MsgWriter.Write(ref buf, ref seekPos, val);
MsgWriter.WriteInt16(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteUInt32(UInt32 val)
{
MsgWriter.Write(ref buf, ref seekPos, val);
MsgWriter.WriteUInt32(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteInt32(Int32 val)
{
MsgWriter.Write(ref buf, ref seekPos, val);
MsgWriter.WriteInt32(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteUInt64(UInt64 val)
{
MsgWriter.Write(ref buf, ref seekPos, val);
MsgWriter.WriteUInt64(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteInt64(Int64 val)
{
MsgWriter.Write(ref buf, ref seekPos, val);
MsgWriter.WriteInt64(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteSingle(Single val)
{
MsgWriter.Write(ref buf, ref seekPos, val);
MsgWriter.WriteSingle(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteDouble(Double val)
{
MsgWriter.Write(ref buf, ref seekPos, val);
MsgWriter.WriteDouble(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteColorR8G8B8(Color val)
{
MsgWriter.WriteColorR8G8B8(ref buf, ref seekPos, val);
MsgWriter.WriteColorR8G8B8(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteColorR8G8B8A8(Color val)
{
MsgWriter.WriteColorR8G8B8A8(ref buf, ref seekPos, val);
MsgWriter.WriteColorR8G8B8A8(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteVariableUInt32(UInt32 val)
{
MsgWriter.WriteVariableUInt32(ref buf, ref seekPos, val);
MsgWriter.WriteVariableUInt32(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteString(String val)
{
MsgWriter.Write(ref buf, ref seekPos, val);
MsgWriter.WriteString(ref buf, ref seekPos, ref lengthBits, val);
}
public void WriteIdentifier(Identifier val)
@@ -894,17 +911,17 @@ namespace Barotrauma.Networking
public void WriteRangedInteger(int val, int min, int max)
{
MsgWriter.WriteRangedInteger(ref buf, ref seekPos, val, min, max);
MsgWriter.WriteRangedInteger(ref buf, ref seekPos, ref lengthBits, val, min, max);
}
public void WriteRangedSingle(Single val, Single min, Single max, int bitCount)
{
MsgWriter.WriteRangedSingle(ref buf, ref seekPos, val, min, max, bitCount);
MsgWriter.WriteRangedSingle(ref buf, ref seekPos, ref lengthBits, val, min, max, bitCount);
}
public void WriteBytes(byte[] val, int startPos, int length)
{
MsgWriter.WriteBytes(ref buf, ref seekPos, val, startPos, length);
MsgWriter.WriteBytes(ref buf, ref seekPos, ref lengthBits, val, startPos, length);
}
public bool ReadBoolean()
@@ -286,8 +286,13 @@ namespace Barotrauma.Networking
}
public DateTime InstallTime => cachedDateTime ??= DateTime.UtcNow + TimeSpan.FromSeconds(InstallTimeDiffInSeconds);
public RegularPackage? RegularPackage => ContentPackageManager.RegularPackages.FirstOrDefault(p => p.Hash.Equals(Hash));
public CorePackage? CorePackage => ContentPackageManager.CorePackages.FirstOrDefault(p => p.Hash.Equals(Hash));
public RegularPackage? RegularPackage =>
ContentPackageManager.RegularPackages.FirstOrDefault(p => p.Name.Equals(Name) && p.Hash.Equals(Hash)) ??
ContentPackageManager.RegularPackages.FirstOrDefault(p => p.Hash.Equals(Hash));
public CorePackage? CorePackage =>
ContentPackageManager.CorePackages.FirstOrDefault(p => p.Name.Equals(Name) && p.Hash.Equals(Hash)) ??
ContentPackageManager.CorePackages.FirstOrDefault(p => p.Hash.Equals(Hash));
public ContentPackage? ContentPackage => (ContentPackage?)RegularPackage ?? CorePackage;
public ServerContentPackage() { }
@@ -1750,19 +1750,7 @@ namespace Barotrauma
}
float spread = Rand.Range(-chosenItemSpawnInfo.AimSpreadRad, chosenItemSpawnInfo.AimSpreadRad);
float rotation = chosenItemSpawnInfo.RotationRad;
Vector2 worldPos;
if (sourceBody != null)
{
worldPos = sourceBody.Position;
if (user?.Submarine != null)
{
worldPos += user.Submarine.Position;
}
}
else
{
worldPos = entity.WorldPosition;
}
Vector2 spawnPos = sourceBody != null ? sourceBody.SimPosition : entity.SimPosition;
switch (chosenItemSpawnInfo.RotationType)
{
case ItemSpawnInfo.SpawnRotationType.Fixed:
@@ -1776,7 +1764,7 @@ namespace Barotrauma
}
break;
case ItemSpawnInfo.SpawnRotationType.Target:
rotation = MathUtils.VectorToAngle(entity.WorldPosition - worldPos);
rotation = MathUtils.VectorToAngle(entity.SimPosition - spawnPos);
break;
case ItemSpawnInfo.SpawnRotationType.Limb:
if (sourceBody != null)
@@ -1820,10 +1808,7 @@ namespace Barotrauma
rotation += spread;
if (projectile != null)
{
projectile.Shoot(user,
ConvertUnits.ToSimUnits(worldPos),
ConvertUnits.ToSimUnits(worldPos),
rotation,
projectile.Shoot(user, spawnPos, spawnPos, rotation,
ignoredBodies: user?.AnimController.Limbs.Where(l => !l.IsSevered).Select(l => l.body.FarseerBody).ToList(), createNetworkEvent: true);
}
else if (newItem.body != null)
@@ -43,9 +43,9 @@ namespace Barotrauma
}
}
public int GetBuyprice(int level, Location? location = null)
public int GetBuyPrice(int level, Location? location = null)
{
int maxLevel = Prefab.MaxLevel;
int maxLevel = Prefab.GetMaxLevelForCurrentSub();
if (level > maxLevel) { maxLevel = level; }
@@ -292,16 +292,10 @@ namespace Barotrauma
onRemoveOverrideFile: null
);
private readonly int maxLevel;
public int MaxLevel
{
get
{
Submarine? sub = GameMain.GameSession?.Submarine ?? Submarine.MainSub;
return sub is { Info: var info } ? GetMaxLevel(info) : maxLevel;
}
}
/// <summary>
/// Maximum upgrade level without taking submarine tier or class restrictions into account
/// </summary>
public readonly int MaxLevel;
public LocalizedString Name { get; }
@@ -343,7 +337,7 @@ namespace Barotrauma
{
Name = element.GetAttributeString("name", string.Empty)!;
Description = element.GetAttributeString("description", string.Empty)!;
maxLevel = element.GetAttributeInt("maxlevel", 1);
MaxLevel = element.GetAttributeInt("maxlevel", 1);
SuppressWarnings = element.GetAttributeBool("supresswarnings", false);
HideInMenus = element.GetAttributeBool("hideinmenus", false);
SourceElement = element;
@@ -428,9 +422,21 @@ namespace Barotrauma
.ToImmutableHashSet() ?? ImmutableHashSet<Identifier>.Empty;
}
/// <summary>
/// Returns the maximum upgrade level for the current sub, taking tier and class restrictions into account
/// </summary>
public int GetMaxLevelForCurrentSub()
{
Submarine? sub = GameMain.GameSession?.Submarine ?? Submarine.MainSub;
return sub is { Info: var info } ? GetMaxLevel(info) : MaxLevel;
}
/// <summary>
/// Returns the maximum upgrade level for the specified sub, taking tier and class restrictions into account
/// </summary>
public int GetMaxLevel(SubmarineInfo info)
{
int level = maxLevel;
int level = MaxLevel;
foreach (UpgradeMaxLevelMod mod in MaxLevelsMods)
{