Build 0.20.7.0

This commit is contained in:
Markus Isberg
2022-11-18 18:13:38 +02:00
parent 8c8fd865c5
commit ecb6d40b4b
111 changed files with 1346 additions and 701 deletions
@@ -657,12 +657,9 @@ namespace Barotrauma
{
if (Controlled == null || Controlled == this || (Controlled.CharacterHealth.GetAffliction("psychosis")?.Strength ?? 0.0f) <= 0.0f)
{
InvisibleTimer = 0.0f;
}
else
{
InvisibleTimer -= deltaTime;
InvisibleTimer = Math.Min(InvisibleTimer, 1.0f);
}
InvisibleTimer -= deltaTime;
}
foreach (GUIMessage message in guiMessages)
@@ -394,6 +394,7 @@ namespace Barotrauma
showHiddenAfflictionsButton = new GUIButton(new RectTransform(new Point(afflictionIconContainer.Rect.Height), afflictionIconContainer.RectTransform), style: "GUIButtonCircular")
{
Visible = false,
CanBeFocused = false
};
@@ -2219,6 +2219,15 @@ namespace Barotrauma
}
}));
commands.Add(new Command("spawnallitems", "", (string[] args) =>
{
var cursorPos = Screen.Selected.Cam?.ScreenToWorld(PlayerInput.MousePosition) ?? Vector2.Zero;
foreach (ItemPrefab itemPrefab in ItemPrefab.Prefabs)
{
Entity.Spawner?.AddItemToSpawnQueue(itemPrefab, cursorPos);
}
}));
commands.Add(new Command("camerasettings", "camerasettings [defaultzoom] [zoomsmoothness] [movesmoothness] [minzoom] [maxzoom]: debug command for testing camera settings. The values default to 1.1, 8.0, 8.0, 0.1 and 2.0.", (string[] args) =>
{
float defaultZoom = Screen.Selected.Cam.DefaultZoom;
@@ -1,4 +1,5 @@
using Microsoft.Xna.Framework;
using System;
using System.Linq;
namespace Barotrauma;
@@ -10,37 +11,66 @@ partial class UIHighlightAction : EventAction
partial void UpdateProjSpecific()
{
bool useCircularFlash = false;
GUIComponent component = null;
if (Id != ElementId.None)
{
component = GUI.GetAdditions().FirstOrDefault(c => Equals(Id, c.UserData));
FindAndFlashComponents(c => Equals(Id, c.UserData));
}
else if (!EntityIdentifier.IsEmpty)
{
component = GUI.GetAdditions().FirstOrDefault(c =>
FindAndFlashComponents(c =>
c.UserData is MapEntityPrefab mep && mep.Identifier == EntityIdentifier || c.UserData is MapEntity me && me.Prefab.Identifier == EntityIdentifier);
}
else if (!OrderIdentifier.IsEmpty)
{
useCircularFlash = true;
bool foundMinimapNode = false;
if (!OrderTargetTag.IsEmpty)
{
component =
GUI.GetAdditions().FirstOrDefault(c =>
c.UserData is CrewManager.MinimapNodeData nodeData && nodeData.Order is Order order &&
order.Identifier == OrderIdentifier && order.Option == OrderOption && order.TargetEntity is Item item && item.HasTag(OrderTargetTag));
foundMinimapNode = FindAndFlashComponents(c =>
c.UserData is CrewManager.MinimapNodeData nodeData && nodeData.Order is Order order &&
order.Identifier == OrderIdentifier && order.Option == OrderOption && order.TargetEntity is Item item && item.HasTag(OrderTargetTag));
}
if (!foundMinimapNode)
{
FindAndFlashComponents(c => c.UserData is Order order && order.Identifier == OrderIdentifier && order.Option == OrderOption,
c => c.UserData is Order order && order.Identifier == OrderIdentifier,
c => Equals(OrderCategory, c.UserData));
}
component ??=
GUI.GetAdditions().FirstOrDefault(c => c.UserData is Order order && order.Identifier == OrderIdentifier && order.Option == OrderOption) ??
GUI.GetAdditions().FirstOrDefault(c => c.UserData is Order order && order.Identifier == OrderIdentifier) ??
GUI.GetAdditions().FirstOrDefault(c => Equals(OrderCategory, c.UserData));
}
if (component != null && component.FlashTimer <= 0.0f)
bool FindAndFlashComponents(params Func<GUIComponent, bool>[] predicates)
{
component.Flash(highlightColor, useCircularFlash: useCircularFlash);
component.Bounce |= Bounce;
foreach (var predicate in predicates)
{
if (HighlightMultiple)
{
bool found = false;
foreach (var component in GUI.GetAdditions())
{
if (predicate(component))
{
Flash(component);
found = true;
}
};
return found;
}
else if (GUI.GetAdditions().FirstOrDefault(predicate) is GUIComponent component)
{
Flash(component);
return true;
}
}
return false;
}
void Flash(GUIComponent component)
{
if (component.FlashTimer <= 0.0f)
{
component.Flash(highlightColor, useCircularFlash: useCircularFlash);
component.Bounce |= Bounce;
}
}
}
}
@@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Xml.Linq;
using Barotrauma.Threading;
namespace Barotrauma
@@ -37,7 +38,7 @@ namespace Barotrauma
private set;
}
public bool IsCJK
public TextManager.SpeciallyHandledCharCategory SpeciallyHandledCharCategory
{
get;
private set;
@@ -84,17 +85,35 @@ namespace Barotrauma
}
}
public static TextManager.SpeciallyHandledCharCategory ExtractShccFromXElement(XElement element)
=> TextManager.SpeciallyHandledCharCategories
.Where(category => element.GetAttributeBool($"is{category}", category switch {
// CJK isn't supported by default
TextManager.SpeciallyHandledCharCategory.CJK => false,
// For backwards compatibility, we assume that Cyrillic is supported by default
TextManager.SpeciallyHandledCharCategory.Cyrillic => true,
_ => throw new Exception("unreachable")
}))
.Aggregate(TextManager.SpeciallyHandledCharCategory.None, (current, category) => current | category);
public ScalableFont(ContentXElement element, GraphicsDevice gd = null)
: this(
element.GetAttributeContentPath("file")?.Value,
(uint)element.GetAttributeInt("size", 14),
gd,
element.GetAttributeBool("dynamicloading", false),
element.GetAttributeBool("iscjk", false))
ExtractShccFromXElement(element))
{
}
public ScalableFont(string filename, uint size, GraphicsDevice gd = null, bool dynamicLoading = false, bool isCJK = false)
public ScalableFont(
string filename,
uint size,
GraphicsDevice gd = null,
bool dynamicLoading = false,
TextManager.SpeciallyHandledCharCategory speciallyHandledCharCategory = TextManager.SpeciallyHandledCharCategory.None)
{
lock (globalMutex)
{
@@ -120,7 +139,7 @@ namespace Barotrauma
this.textures = new List<Texture2D>();
this.texCoords = new Dictionary<uint, GlyphData>();
this.DynamicLoading = dynamicLoading;
this.IsCJK = isCJK;
this.SpeciallyHandledCharCategory = speciallyHandledCharCategory;
this.graphicsDevice = gd;
if (gd != null && !dynamicLoading)
@@ -150,7 +150,6 @@ namespace Barotrauma
}
}
// TODO: fix implicit hiding
public override bool Selected
{
get { return isSelected; }
@@ -179,6 +179,11 @@ namespace Barotrauma
private set;
}
/// <summary>
/// If enabled, the value wraps around to Max when you go below Min, and vice versa
/// </summary>
public bool WrapAround;
public float valueStep;
private float pressedTimer;
@@ -403,13 +408,19 @@ namespace Barotrauma
{
if (MinValueFloat != null)
{
floatValue = Math.Max(floatValue, MinValueFloat.Value);
MinusButton.Enabled = floatValue > MinValueFloat;
floatValue =
WrapAround && MinValueFloat.HasValue && floatValue < MinValueFloat.Value ?
MaxValueFloat.Value :
Math.Max(floatValue, MinValueFloat.Value);
MinusButton.Enabled = WrapAround || floatValue > MinValueFloat;
}
if (MaxValueFloat != null)
{
floatValue = Math.Min(floatValue, MaxValueFloat.Value);
PlusButton.Enabled = floatValue < MaxValueFloat;
floatValue =
WrapAround && MaxValueFloat.HasValue && floatValue > MaxValueFloat.Value ?
MinValueFloat.Value :
Math.Min(floatValue, MaxValueFloat.Value);
PlusButton.Enabled = WrapAround || floatValue < MaxValueFloat;
}
}
@@ -417,16 +428,16 @@ namespace Barotrauma
{
if (MinValueInt != null && intValue < MinValueInt.Value)
{
intValue = Math.Max(intValue, MinValueInt.Value);
intValue = WrapAround && MaxValueInt.HasValue ? MaxValueInt.Value : Math.Max(intValue, MinValueInt.Value);
UpdateText();
}
if (MaxValueInt != null && intValue > MaxValueInt.Value)
{
intValue = Math.Min(intValue, MaxValueInt.Value);
intValue = WrapAround && MinValueInt.HasValue ? MinValueInt.Value : Math.Min(intValue, MaxValueInt.Value);
UpdateText();
}
PlusButton.Enabled = MaxValueInt == null || intValue < MaxValueInt;
MinusButton.Enabled = MinValueInt == null || intValue > MinValueInt;
PlusButton.Enabled = WrapAround || MaxValueInt == null || intValue < MaxValueInt;
MinusButton.Enabled = WrapAround || MinValueInt == null || intValue > MinValueInt;
}
private void UpdateText()
@@ -8,6 +8,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Barotrauma.Extensions;
namespace Barotrauma
{
@@ -45,16 +46,17 @@ namespace Barotrauma
}
}
private ScalableFont cjkFont;
private ImmutableDictionary<TextManager.SpeciallyHandledCharCategory, ScalableFont> specialHandlingFonts;
public ScalableFont CjkFont
public ScalableFont GetFontForCategory(TextManager.SpeciallyHandledCharCategory category)
{
get
{
if (Language != GameSettings.CurrentConfig.Language) { LoadFont(); }
if (font.IsCJK) { return font; }
return cjkFont;
}
if (Language != GameSettings.CurrentConfig.Language) { LoadFont(); }
if (font.SpeciallyHandledCharCategory.HasFlag(category)) { return font; }
return specialHandlingFonts.TryGetValue(category, out var resultFont)
? resultFont
: specialHandlingFonts.TryGetValue(TextManager.SpeciallyHandledCharCategory.CJK, out resultFont)
? resultFont
: font;
}
public LanguageIdentifier Language { get; private set; }
@@ -70,40 +72,68 @@ namespace Barotrauma
string fontPath = GetFontFilePath(element);
uint size = GetFontSize(element);
bool dynamicLoading = GetFontDynamicLoading(element);
bool isCJK = GetIsCJK(element);
var shcc = GetShcc(element);
font?.Dispose();
cjkFont?.Dispose();
font = new ScalableFont(fontPath, size, GameMain.Instance.GraphicsDevice, dynamicLoading, isCJK)
specialHandlingFonts?.Values.ForEach(f => f.Dispose());
font = new ScalableFont(
fontPath,
size,
GameMain.Instance.GraphicsDevice,
dynamicLoading,
shcc)
{
ForceUpperCase = element.GetAttributeBool("forceuppercase", false)
};
if (!isCJK)
var fallbackFonts = new Dictionary<TextManager.SpeciallyHandledCharCategory, ScalableFont>();
foreach (var flag in TextManager.SpeciallyHandledCharCategories)
{
cjkFont = ExtractCjkFont(element)
?? new ScalableFont("Content/Fonts/NotoSans/NotoSansCJKsc-Bold.otf",
font.Size, GameMain.Instance.GraphicsDevice, dynamicLoading: true, isCJK: true);
cjkFont.ForceUpperCase = font.ForceUpperCase;
if (shcc.HasFlag(flag)) { continue; }
var extractedFont = ExtractFont(flag, element);
if (extractedFont is null) { continue; }
fallbackFonts.Add(flag, extractedFont);
}
fallbackFonts.Values.ForEach(ff => ff.ForceUpperCase = font.ForceUpperCase);
specialHandlingFonts = fallbackFonts.ToImmutableDictionary();
Language = GameSettings.CurrentConfig.Language;
}
public override void Dispose()
{
font?.Dispose(); font = null;
cjkFont?.Dispose(); cjkFont = null;
font?.Dispose();
font = null;
specialHandlingFonts?.Values.ForEach(f => f.Dispose());
specialHandlingFonts = null;
}
private ScalableFont ExtractCjkFont(ContentXElement element)
private ScalableFont ExtractFont(TextManager.SpeciallyHandledCharCategory flag, ContentXElement element)
{
foreach (var subElement in element.Elements().Reverse())
{
if (subElement.NameAsIdentifier() != "override") { continue; }
if (subElement.GetAttributeBool("iscjk", false))
if (ScalableFont.ExtractShccFromXElement(subElement).HasFlag(flag))
{
return new ScalableFont(subElement, GameMain.Instance.GraphicsDevice);
}
}
return null;
ScalableFont hardcodedFallback(string path)
=> new ScalableFont(
path,
font.Size,
GameMain.Instance.GraphicsDevice,
dynamicLoading: true,
speciallyHandledCharCategory: flag);
return flag switch
{
TextManager.SpeciallyHandledCharCategory.CJK
=> hardcodedFallback("Content/Fonts/NotoSans/NotoSansCJKsc-Bold.otf"),
TextManager.SpeciallyHandledCharCategory.Cyrillic
=> hardcodedFallback("Content/Fonts/Oswald-Bold.ttf"),
_ => null
};
}
private string GetFontFilePath(ContentXElement element)
@@ -154,21 +184,21 @@ namespace Barotrauma
return element.GetAttributeBool("dynamicloading", false);
}
private bool GetIsCJK(XElement element)
private TextManager.SpeciallyHandledCharCategory GetShcc(XElement element)
{
foreach (var subElement in element.Elements())
{
if (IsValidOverride(subElement))
{
return subElement.GetAttributeBool("iscjk", false);
return ScalableFont.ExtractShccFromXElement(subElement);
}
}
return element.GetAttributeBool("iscjk", false);
return ScalableFont.ExtractShccFromXElement(element);
}
private bool IsValidOverride(XElement element)
{
if (!element.Name.ToString().Equals("override", StringComparison.OrdinalIgnoreCase)) { return false; }
if (!element.IsOverride()) { return false; }
var languages = element.GetAttributeIdentifierArray("language", Array.Empty<Identifier>());
return languages.Any(l => l.ToLanguageIdentifier() == GameSettings.CurrentConfig.Language);
}
@@ -191,7 +221,7 @@ namespace Barotrauma
private ScalableFont GetFontForStr(LocalizedString str) => GetFontForStr(str.Value);
public ScalableFont GetFontForStr(string str) =>
TextManager.IsCJK(str) ? Prefabs.ActivePrefab.CjkFont : Prefabs.ActivePrefab.Font;
Prefabs.ActivePrefab.GetFontForCategory(TextManager.GetSpeciallyHandledCategories(str));
public void DrawString(SpriteBatch sb, LocalizedString text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects se, float layerDepth)
{
@@ -617,9 +617,9 @@ namespace Barotrauma
Stretch = true
};
var shoppingCrateListContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.8f), shoppingCrateInventoryContainer.RectTransform), style: null);
shoppingCrateBuyList = new GUIListBox(new RectTransform(Vector2.One, shoppingCrateListContainer.RectTransform)) { Visible = false };
shoppingCrateSellList = new GUIListBox(new RectTransform(Vector2.One, shoppingCrateListContainer.RectTransform)) { Visible = false };
shoppingCrateSellFromSubList = new GUIListBox(new RectTransform(Vector2.One, shoppingCrateListContainer.RectTransform)) { Visible = false };
shoppingCrateBuyList = new GUIListBox(new RectTransform(Vector2.One, shoppingCrateListContainer.RectTransform)) { Visible = false, KeepSpaceForScrollBar = true };
shoppingCrateSellList = new GUIListBox(new RectTransform(Vector2.One, shoppingCrateListContainer.RectTransform)) { Visible = false, KeepSpaceForScrollBar = true };
shoppingCrateSellFromSubList = new GUIListBox(new RectTransform(Vector2.One, shoppingCrateListContainer.RectTransform)) { Visible = false, KeepSpaceForScrollBar = true };
var relevantBalanceContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), shoppingCrateInventoryContainer.RectTransform), isHorizontal: true)
{
@@ -325,7 +325,7 @@ namespace Barotrauma
}
var specializationList = GetSpecializationList();
GetSpecializationList().RectTransform.Resize(new Point(specializationList.Content.Children.Sum(static c => c.Rect.Width), specializationList.Rect.Height));
GetSpecializationList().Content.RectTransform.Resize(new Point(specializationList.Content.Children.Sum(static c => c.Rect.Width), specializationList.Rect.Height), resizeChildren: false);
GUITextBlock.AutoScaleAndNormalize(subTreeNames);
@@ -439,7 +439,8 @@ namespace Barotrauma
}
if (character is null) { return false; }
Identifier talentIdentifier = (Identifier)userData;
if (talentOption.MaxChosenTalents is 1)
{
// deselect other buttons in tier by removing their selected talents from pool
@@ -454,9 +455,11 @@ namespace Barotrauma
}
}
Identifier talentIdentifier = (Identifier)userData;
if (IsViableTalentForCharacter(info.Character, talentIdentifier, selectedTalents))
if (character.HasTalent(talentIdentifier))
{
return true;
}
else if (IsViableTalentForCharacter(info.Character, talentIdentifier, selectedTalents))
{
if (!selectedTalents.Contains(talentIdentifier))
{
@@ -467,7 +470,7 @@ namespace Barotrauma
selectedTalents.Remove(talentIdentifier);
}
}
else if (!character.HasTalent(talentIdentifier))
else
{
selectedTalents.Remove(talentIdentifier);
}
@@ -314,7 +314,7 @@ namespace Barotrauma
GraphicsDeviceManager.SynchronizeWithVerticalRetrace = GameSettings.CurrentConfig.Graphics.VSync;
SetWindowMode(GameSettings.CurrentConfig.Graphics.DisplayMode);
defaultViewport = GraphicsDevice.Viewport;
defaultViewport = new Viewport(0, 0, GraphicsWidth, GraphicsHeight);
if (recalculateFontsAndStyles)
{
@@ -353,6 +353,7 @@ namespace Barotrauma
public void ResetViewPort()
{
GraphicsDevice.Viewport = defaultViewport;
GraphicsDevice.ScissorRectangle = defaultViewport.Bounds;
}
/// <summary>
@@ -28,18 +28,27 @@ namespace Barotrauma.Items.Components
if (node.ParentIndex > -1)
{
Vector2 diff = nodes[node.ParentIndex].WorldPosition - node.WorldPosition;
float dist = diff.Length();
Vector2 normalizedDiff = diff / dist;
for (float x = 0.0f; x < dist; x += 50.0f)
{
var spark = GameMain.ParticleManager.CreateParticle("ElectricShock", node.WorldPosition + normalizedDiff * x, Vector2.Zero);
if (spark != null)
{
spark.Size *= 0.3f;
}
}
CreateParticlesBetween(nodes[node.ParentIndex].WorldPosition, node.WorldPosition);
}
}
foreach (var character in charactersInRange)
{
CreateParticlesBetween(character.character.WorldPosition, character.node.WorldPosition);
}
static void CreateParticlesBetween(Vector2 start, Vector2 end)
{
const float ParticleInterval = 50.0f;
Vector2 diff = end - start;
float dist = diff.Length();
Vector2 normalizedDiff = MathUtils.NearlyEqual(dist, 0.0f) ? Vector2.Zero : diff / dist;
for (float x = 0.0f; x < dist; x += ParticleInterval)
{
var spark = GameMain.ParticleManager.CreateParticle("ElectricShock", start + normalizedDiff * x, Vector2.Zero);
if (spark != null)
{
spark.Size *= 0.3f;
}
}
}
}
@@ -14,7 +14,10 @@ namespace Barotrauma.Items.Components
private GUIFrame selectedItemFrame;
private GUIFrame selectedItemReqsFrame;
private GUITextBlock amountTextMin, amountTextMax;
private GUIScrollBar amountInput;
public GUIButton ActivateButton
{
get { return activateButton; }
@@ -160,14 +163,46 @@ namespace Barotrauma.Items.Components
new GUICustomComponent(new RectTransform(Vector2.One, inputInventoryHolder.RectTransform), DrawInputOverLay) { CanBeFocused = false };
// === ACTIVATE BUTTON === //
var buttonFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.3f, 0.8f), inputArea.RectTransform), childAnchor: Anchor.CenterRight);
activateButton = new GUIButton(new RectTransform(new Vector2(1f, 0.6f), buttonFrame.RectTransform),
TextManager.Get(CreateButtonText), style: "DeviceButtonFixedSize")
var buttonFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.3f, 0.9f), inputArea.RectTransform))
{
Stretch = true,
RelativeSpacing = 0.05f
};
var amountInputHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.4f), buttonFrame.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft)
{
Stretch = true
};
amountTextMin = new GUITextBlock(new RectTransform(new Vector2(0.15f, 1.0f), amountInputHolder.RectTransform), "1", textAlignment: Alignment.Center);
amountInput = new GUIScrollBar(new RectTransform(new Vector2(0.7f, 1.0f), amountInputHolder.RectTransform), barSize: 0.1f, style: "GUISlider")
{
OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
{
scrollBar.Step = 1.0f / Math.Max(scrollBar.Range.Y - 1, 1);
AmountToFabricate = (int)MathF.Round(scrollBar.BarScrollValue);
RefreshActivateButtonText();
if (GameMain.Client != null)
{
item.CreateClientEvent(this);
}
return true;
}
};
amountTextMax = new GUITextBlock(new RectTransform(new Vector2(0.15f, 1.0f), amountInputHolder.RectTransform), "1", textAlignment: Alignment.Center);
activateButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.6f), buttonFrame.RectTransform),
TextManager.Get(CreateButtonText), style: "DeviceButton")
{
OnClicked = StartButtonClicked,
UserData = selectedItem,
Enabled = false
};
};
//spacing
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.01f), buttonFrame.RectTransform), style: null);
}
else
{
@@ -192,6 +227,21 @@ namespace Barotrauma.Items.Components
CreateRecipes();
}
private void RefreshActivateButtonText()
{
if (amountInput == null)
{
activateButton.Text = TextManager.Get(IsActive ? "FabricatorCancel" : CreateButtonText);
}
else
{
activateButton.Text =
IsActive ?
$"{TextManager.Get("FabricatorCancel")} ({amountRemaining})" :
$"{TextManager.Get(CreateButtonText)} ({AmountToFabricate})";
}
}
partial void CreateRecipes()
{
itemList.Content.RectTransform.ClearChildren();
@@ -247,7 +297,7 @@ namespace Barotrauma.Items.Components
outputContainer.Inventory.RectTransform = outputInventoryHolder.RectTransform;
}
private LocalizedString GetRecipeNameAndAmount(FabricationRecipe fabricationRecipe)
private static LocalizedString GetRecipeNameAndAmount(FabricationRecipe fabricationRecipe)
{
if (fabricationRecipe == null) { return ""; }
if (fabricationRecipe.Amount > 1)
@@ -269,7 +319,7 @@ namespace Barotrauma.Items.Components
partial void SelectProjSpecific(Character character)
{
var nonItems = itemList.Content.Children.Where(c => !(c.UserData is FabricationRecipe)).ToList();
var nonItems = itemList.Content.Children.Where(c => c.UserData is not FabricationRecipe).ToList();
nonItems.ForEach(i => itemList.Content.RemoveChild(i));
itemList.Content.RectTransform.SortChildren((c1, c2) =>
@@ -567,7 +617,7 @@ namespace Barotrauma.Items.Components
bool recipeVisible = false;
foreach (GUIComponent child in itemList.Content.Children.Reverse())
{
if (!(child.UserData is FabricationRecipe recipe))
if (child.UserData is not FabricationRecipe recipe)
{
if (child.Enabled)
{
@@ -598,9 +648,23 @@ namespace Barotrauma.Items.Components
{
this.selectedItem = selectedItem;
int max = Math.Max(selectedItem.TargetItem.MaxStackSize / selectedItem.Amount, 1);
if (amountInput != null)
{
float prevBarScroll = amountInput.BarScroll;
amountInput.Range = new Vector2(1, max);
amountInput.BarScroll = prevBarScroll;
amountTextMax.Text = max.ToString();
amountInput.Enabled = amountTextMax.Enabled = max > 1;
AmountToFabricate = Math.Min((int)amountInput.BarScrollValue, max);
}
RefreshActivateButtonText();
selectedItemFrame.ClearChildren();
selectedItemReqsFrame.ClearChildren();
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.9f), selectedItemFrame.RectTransform, Anchor.Center)) { RelativeSpacing = 0.03f };
var paddedReqFrame = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.9f), selectedItemReqsFrame.RectTransform, Anchor.Center)) { RelativeSpacing = 0.03f };
@@ -734,7 +798,9 @@ namespace Barotrauma.Items.Components
outputSlot.Flash(GUIStyle.Red);
return false;
}
amountRemaining = AmountToFabricate;
if (GameMain.Client != null)
{
pendingFabricatedItem = fabricatedItem != null ? null : selectedItem;
@@ -777,7 +843,7 @@ namespace Barotrauma.Items.Components
{
foreach (GUIComponent child in itemList.Content.Children)
{
if (!(child.UserData is FabricationRecipe recipe)) { continue; }
if (child.UserData is not FabricationRecipe recipe) { continue; }
if (recipe != selectedItem &&
(child.Rect.Y > itemList.Rect.Bottom || child.Rect.Bottom < itemList.Rect.Y))
@@ -811,11 +877,14 @@ namespace Barotrauma.Items.Components
{
uint recipeHash = pendingFabricatedItem?.RecipeHash ?? 0;
msg.WriteUInt32(recipeHash);
msg.WriteRangedInteger(AmountToFabricate, 1, MaxAmountToFabricate);
}
public void ClientEventRead(IReadMessage msg, float sendingTime)
{
FabricatorState newState = (FabricatorState)msg.ReadByte();
int amountToFabricate = msg.ReadRangedInteger(0, MaxAmountToFabricate);
int amountRemaining = msg.ReadRangedInteger(0, MaxAmountToFabricate);
float newTimeUntilReady = msg.ReadSingle();
uint recipeHash = msg.ReadUInt32();
UInt16 userID = msg.ReadUInt16();
@@ -828,6 +897,8 @@ namespace Barotrauma.Items.Components
}
State = newState;
this.amountToFabricate = amountToFabricate;
this.amountRemaining = amountRemaining;
if (newState == FabricatorState.Stopped || recipeHash == 0)
{
CancelFabricating();
@@ -802,21 +802,34 @@ namespace Barotrauma.Items.Components
if (passivePingRadius > 0.0f)
{
if (activePingsCount == 0) { disruptedDirections.Clear(); }
//emit "pings" from nearby sound-emitting AITargets to reveal what's around them
foreach (AITarget t in AITarget.List)
{
if (t.Entity is Character c && !c.IsUnconscious && c.Params.HideInSonar) { continue; }
if (t.SoundRange <= 0.0f || float.IsNaN(t.SoundRange) || float.IsInfinity(t.SoundRange)) { continue; }
float distSqr = Vector2.DistanceSquared(t.WorldPosition, transducerCenter);
if (distSqr > t.SoundRange * t.SoundRange * 2) { continue; }
float dist = (float)Math.Sqrt(distSqr);
if (dist > prevPassivePingRadius * Range && dist <= passivePingRadius * Range && Rand.Int(sonarBlips.Count) < 500 && t.IsWithinSector(transducerCenter))
if (dist > prevPassivePingRadius * Range && dist <= passivePingRadius * Range && Rand.Int(sonarBlips.Count) < 500)
{
int prevBlipCount = sonarBlips.Count;
Ping(t.WorldPosition, transducerCenter,
Math.Min(t.SoundRange, range * 0.5f) * displayScale, 0, displayScale, Math.Min(t.SoundRange, range * 0.5f),
Math.Min(t.SoundRange, range * 0.5f) * displayScale, 0, displayScale, Math.Min(t.SoundRange, range * 0.5f),
passive: true, pingStrength: 0.5f);
sonarBlips.Add(new SonarBlip(t.WorldPosition, 1.0f, 1.0f));
//remove blips that weren't in the AITarget's sector
if (t.HasSector())
{
for (int i = sonarBlips.Count - 1; i >= prevBlipCount; i--)
{
if (!t.IsWithinSector(sonarBlips[i].Position))
{
sonarBlips.RemoveAt(i);
}
}
}
}
}
}
@@ -411,6 +411,14 @@ namespace Barotrauma.Items.Components
SpriteEffects.None, newDepth);
}
if (GameMain.DebugDraw)
{
Vector2 firingPos = GetRelativeFiringPosition();
firingPos.Y = -firingPos.Y;
GUI.DrawLine(spriteBatch, firingPos - Vector2.UnitX * 5, firingPos + Vector2.UnitX * 5, Color.Red);
GUI.DrawLine(spriteBatch, firingPos - Vector2.UnitY * 5, firingPos + Vector2.UnitY * 5, Color.Red);
}
if (!editing || GUI.DisableHUD || !item.IsSelected) { return; }
const float widgetRadius = 60.0f;
@@ -343,38 +343,31 @@ namespace Barotrauma.Lights
{
SolidColorEffect.CurrentTechnique = SolidColorEffect.Techniques["SolidVertexColor"];
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, effect: SolidColorEffect, transformMatrix: spriteBatchTransform);
foreach (Character character in Character.CharacterList)
{
if (character.CurrentHull == null || !character.Enabled || !character.IsVisible) { continue; }
if (Character.Controlled?.FocusedCharacter == character) { continue; }
Color lightColor = character.CurrentHull.AmbientLight == Color.TransparentBlack ?
Color.Black :
character.CurrentHull.AmbientLight.Multiply(character.CurrentHull.AmbientLight.A / 255.0f).Opaque();
foreach (Limb limb in character.AnimController.Limbs)
{
if (limb.DeformSprite != null) { continue; }
limb.Draw(spriteBatch, cam, lightColor);
}
}
DrawCharacters(spriteBatch, cam, drawDeformSprites: false);
spriteBatch.End();
DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques["DeformShaderSolidVertexColor"];
DeformableSprite.Effect.CurrentTechnique.Passes[0].Apply();
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, transformMatrix: spriteBatchTransform);
DrawCharacters(spriteBatch, cam, drawDeformSprites: true);
spriteBatch.End();
}
static void DrawCharacters(SpriteBatch spriteBatch, Camera cam, bool drawDeformSprites)
{
foreach (Character character in Character.CharacterList)
{
if (character.CurrentHull == null || !character.Enabled || !character.IsVisible) { continue; }
if (character.CurrentHull == null || !character.Enabled || !character.IsVisible || character.InvisibleTimer > 0.0f) { continue; }
if (Character.Controlled?.FocusedCharacter == character) { continue; }
Color lightColor = character.CurrentHull.AmbientLight == Color.TransparentBlack ?
Color.Black :
character.CurrentHull.AmbientLight.Multiply(character.CurrentHull.AmbientLight.A / 255.0f).Opaque();
foreach (Limb limb in character.AnimController.Limbs)
{
if (limb.DeformSprite == null) { continue; }
if (drawDeformSprites == (limb.DeformSprite == null)) { continue; }
limb.Draw(spriteBatch, cam, lightColor);
}
}
spriteBatch.End();
}
DeformableSprite.Effect.CurrentTechnique = DeformableSprite.Effect.Techniques["DeformShader"];
@@ -697,17 +697,22 @@ namespace Barotrauma
Vector2 size = new Vector2(Math.Max(nameSize.X, Math.Max(typeSize.X, descSize.X)), nameSize.Y + typeSize.Y + descSize.Y);
int highestSubTier = HighlightedLocation.HighestSubmarineTierAvailable();
var overrideTiers = new List<(SubmarineClass subClass, int tier)>();
foreach (SubmarineClass subClass in Enum.GetValues(typeof(SubmarineClass)))
List<(SubmarineClass subClass, int tier)> overrideTiers = null;
if (HighlightedLocation.CanHaveSubsForSale())
{
if (subClass == SubmarineClass.Undefined) { continue; }
int highestClassTier = HighlightedLocation.HighestSubmarineTierAvailable(subClass);
if (highestClassTier > 0 && highestClassTier > highestSubTier)
overrideTiers = new List<(SubmarineClass subClass, int tier)>();
foreach (SubmarineClass subClass in Enum.GetValues(typeof(SubmarineClass)))
{
overrideTiers.Add((subClass, highestClassTier));
if (subClass == SubmarineClass.Undefined) { continue; }
int highestClassTier = HighlightedLocation.HighestSubmarineTierAvailable(subClass);
if (highestClassTier > 0 && highestClassTier > highestSubTier)
{
overrideTiers.Add((subClass, highestClassTier));
}
}
}
size.Y += ((highestSubTier > 0 ? 1 : 0) + overrideTiers.Count) * GUIStyle.SmallFont.MeasureString(TextManager.Get("advancedsub.all")).Y;
int subAvailabilityTextCount = (highestSubTier > 0 ? 1 : 0) + (overrideTiers?.Count ?? 0);
size.Y += subAvailabilityTextCount * GUIStyle.SmallFont.MeasureString(TextManager.Get("advancedsub.all")).Y;
bool showReputation = hudVisibility > 0.0f && HighlightedLocation.Discovered && HighlightedLocation.Type.HasOutpost && HighlightedLocation.Reputation != null;
LocalizedString repLabelText = null, repValueText = null;
@@ -745,9 +750,12 @@ namespace Barotrauma
{
DrawSubAvailabilityText("advancedsub.all", highestSubTier);
}
foreach (var (subClass, tier) in overrideTiers)
if (overrideTiers != null)
{
DrawSubAvailabilityText($"advancedsub.{subClass}", tier);
foreach (var (subClass, tier) in overrideTiers)
{
DrawSubAvailabilityText($"advancedsub.{subClass}", tier);
}
}
void DrawSubAvailabilityText(string tag, int tier)
{
@@ -14,6 +14,16 @@ namespace Barotrauma.Networking
set;
}
private SoundChannel radioNoiseChannel;
private float radioNoise;
public float RadioNoise
{
get { return radioNoise; }
set { radioNoise = MathHelper.Clamp(value, 0.0f, 1.0f); }
}
private bool mutedLocally;
public bool MutedLocally
{
@@ -42,35 +52,64 @@ namespace Barotrauma.Networking
!HasPermission(ClientPermissions.Kick) &&
!HasPermission(ClientPermissions.Unban);
public void UpdateSoundPosition()
public void UpdateVoipSound()
{
if (VoipSound == null) { return; }
if (!VoipSound.IsPlaying)
if (VoipSound == null || !VoipSound.IsPlaying)
{
DebugConsole.Log("Destroying voipsound");
VoipSound.Dispose();
radioNoiseChannel?.Dispose();
radioNoiseChannel = null;
if (VoipSound != null)
{
DebugConsole.Log("Destroying voipsound");
VoipSound.Dispose();
}
VoipSound = null;
return;
return;
}
if (Screen.Selected is ModDownloadScreen)
{
VoipSound.Gain = 0.0f;
}
float gain = 1.0f;
float noiseGain = 0.0f;
Vector3? position = null;
if (character != null)
{
if (GameSettings.CurrentConfig.Audio.UseDirectionalVoiceChat)
{
VoipSound.SetPosition(new Vector3(character.WorldPosition.X, character.WorldPosition.Y, 0.0f));
position = new Vector3(character.WorldPosition.X, character.WorldPosition.Y, 0.0f);
}
else
{
VoipSound.SetPosition(null);
float dist = Vector3.Distance(new Vector3(character.WorldPosition, 0.0f), GameMain.SoundManager.ListenerPosition);
VoipSound.Gain = 1.0f - MathUtils.InverseLerp(VoipSound.Near, VoipSound.Far, dist);
gain = 1.0f - MathUtils.InverseLerp(VoipSound.Near, VoipSound.Far, dist);
}
if (RadioNoise > 0.0f)
{
noiseGain = gain * RadioNoise;
gain *= 1.0f - RadioNoise;
}
}
else
VoipSound.SetPosition(position);
VoipSound.Gain = gain;
if (noiseGain > 0.0f)
{
VoipSound.SetPosition(null);
VoipSound.Gain = 1.0f;
if (radioNoiseChannel == null || !radioNoiseChannel.IsPlaying)
{
radioNoiseChannel = SoundPlayer.PlaySound("radiostatic");
radioNoiseChannel.Category = "voip";
radioNoiseChannel.Looping = true;
}
radioNoiseChannel.Near = VoipSound.Near;
radioNoiseChannel.Far = VoipSound.Far;
radioNoiseChannel.Position = position;
radioNoiseChannel.Gain = noiseGain;
}
else if (radioNoiseChannel != null)
{
radioNoiseChannel.Gain = 0.0f;
}
}
@@ -158,6 +197,11 @@ namespace Barotrauma.Networking
VoipSound.Dispose();
VoipSound = null;
}
if (radioNoiseChannel != null)
{
radioNoiseChannel.Dispose();
radioNoiseChannel = null;
}
}
}
}
@@ -449,7 +449,7 @@ namespace Barotrauma.Networking
foreach (Client c in ConnectedClients)
{
if (c.Character != null && c.Character.Removed) { c.Character = null; }
c.UpdateSoundPosition();
c.UpdateVoipSound();
}
if (VoipCapture.Instance != null)
@@ -111,7 +111,7 @@ namespace Barotrauma.Networking
foreach (NetIncomingMessage inc in incomingLidgrenMessages)
{
if (!inc.SenderConnection.RemoteEndPoint.Equals(lidgrenEndpoint.NetEndpoint))
if (!inc.SenderConnection.RemoteEndPoint.EquivalentTo(lidgrenEndpoint.NetEndpoint))
{
DebugConsole.AddWarning($"Mismatched endpoint: expected {lidgrenEndpoint.NetEndpoint}, got {inc.SenderConnection.RemoteEndPoint}");
continue;
@@ -260,6 +260,13 @@ namespace Barotrauma.Networking
}
}
}
if (Screen.Selected is ModDownloadScreen)
{
allowEnqueue = false;
captureTimer = 0;
}
if (allowEnqueue || captureTimer > 0)
{
LastEnqueueAudio = DateTime.Now;
@@ -1,20 +1,23 @@
using Barotrauma.Sounds;
using Barotrauma.Items.Components;
using Barotrauma.Sounds;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;
using Barotrauma.Items.Components;
namespace Barotrauma.Networking
{
class VoipClient : IDisposable
{
private GameClient gameClient;
private ClientPeer netClient;
/// <summary>
/// The "near" range of the voice chat (a percentage of either SpeakRange or radio range), further than this the volume starts to diminish
/// </summary>
const float RangeNear = 0.4f;
private readonly GameClient gameClient;
private readonly ClientPeer netClient;
private DateTime lastSendTime;
private List<VoipQueue> queues;
private readonly List<VoipQueue> queues;
private UInt16 storedBufferID = 0;
@@ -32,13 +35,13 @@ namespace Barotrauma.Networking
public void RegisterQueue(VoipQueue queue)
{
if (queue == VoipCapture.Instance) return;
if (!queues.Contains(queue)) queues.Add(queue);
if (queue == VoipCapture.Instance) { return; }
if (!queues.Contains(queue)) { queues.Add(queue); }
}
public void UnregisterQueue(VoipQueue queue)
{
if (queues.Contains(queue)) queues.Remove(queue);
if (queues.Contains(queue)) { queues.Remove(queue); }
}
public void SendToServer()
@@ -85,6 +88,7 @@ namespace Barotrauma.Networking
public void Read(IReadMessage msg)
{
byte queueId = msg.ReadByte();
float distanceFactor = msg.ReadRangedSingle(0.0f, 1.0f, 8);
VoipQueue queue = queues.Find(q => q.QueueID == queueId);
if (queue == null)
@@ -105,9 +109,12 @@ namespace Barotrauma.Networking
client.VoipSound = new VoipSound(client.Name, GameMain.SoundManager, client.VoipQueue);
}
GameMain.SoundManager.ForceStreamUpdate();
client.RadioNoise = 0.0f;
if (client.Character != null && !client.Character.IsDead && !client.Character.Removed && client.Character.SpeechImpediment <= 100.0f)
{
float speechImpedimentMultiplier = 1.0f - client.Character.SpeechImpediment / 100.0f;
bool spectating = Character.Controlled == null;
float rangeMultiplier = spectating ? 2.0f : 1.0f;
WifiComponent radio = null;
var messageType = !client.VoipQueue.ForceLocal && ChatMessage.CanUseRadio(client.Character, out radio) ? ChatMessageType.Radio : ChatMessageType.Default;
client.Character.ShowSpeechBubble(1.25f, ChatMessage.MessageColor[(int)messageType]);
@@ -115,11 +122,17 @@ namespace Barotrauma.Networking
client.VoipSound.UseRadioFilter = messageType == ChatMessageType.Radio && !GameSettings.CurrentConfig.Audio.DisableVoiceChatFilters;
if (messageType == ChatMessageType.Radio)
{
client.VoipSound.SetRange(radio.Range * 0.8f, radio.Range);
client.VoipSound.SetRange(radio.Range * RangeNear * speechImpedimentMultiplier * rangeMultiplier, radio.Range * speechImpedimentMultiplier * rangeMultiplier);
if (distanceFactor > RangeNear && !spectating)
{
//noise starts increasing exponentially after 40% range
client.RadioNoise = MathF.Pow(MathUtils.InverseLerp(RangeNear, 1.0f, distanceFactor), 2);
}
}
else
{
client.VoipSound.SetRange(ChatMessage.SpeakRange * 0.4f, ChatMessage.SpeakRange);
client.VoipSound.SetRange(ChatMessage.SpeakRange * RangeNear * speechImpedimentMultiplier * rangeMultiplier, ChatMessage.SpeakRange * speechImpedimentMultiplier * rangeMultiplier);
}
client.VoipSound.UseMuffleFilter =
messageType != ChatMessageType.Radio && Character.Controlled != null && !GameSettings.CurrentConfig.Audio.DisableVoiceChatFilters &&
@@ -35,14 +35,14 @@ namespace Barotrauma
};
// New game
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.03f), nameSeedLayout.RectTransform) { MinSize = new Point(0, 20) }, TextManager.Get("SaveName"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.BottomLeft);
saveNameBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.03f), nameSeedLayout.RectTransform) { MinSize = new Point(0, 20) }, string.Empty)
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.03f), nameSeedLayout.RectTransform) { MinSize = new Point(0, GUI.IntScale(24)) }, TextManager.Get("SaveName"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.BottomLeft);
saveNameBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.03f), nameSeedLayout.RectTransform), string.Empty)
{
textFilterFunction = ToolBox.RemoveInvalidFileNameChars
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.03f), nameSeedLayout.RectTransform) { MinSize = new Point(0, 20) }, TextManager.Get("MapSeed"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.BottomLeft);
seedBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.03f), nameSeedLayout.RectTransform) { MinSize = new Point(0, 20) }, ToolBox.RandomSeed(8));
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.03f), nameSeedLayout.RectTransform) { MinSize = new Point(0, GUI.IntScale(24)) }, TextManager.Get("MapSeed"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.BottomLeft);
seedBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.03f), nameSeedLayout.RectTransform), ToolBox.RandomSeed(8));
nameSeedLayout.RectTransform.MinSize = new Point(0, nameSeedLayout.Children.Sum(c => c.RectTransform.MinSize.Y));
@@ -11,7 +11,7 @@ namespace Barotrauma.Sounds
private VorbisReader reader;
//key = sample rate, value = filter
private static Dictionary<int, BiQuad> muffleFilters = new Dictionary<int, BiQuad>();
private static readonly Dictionary<int, BiQuad> muffleFilters = new Dictionary<int, BiQuad>();
private static List<float> playbackAmplitude;
private const int AMPLITUDE_SAMPLE_COUNT = 4410; //100ms in a 44100hz file
@@ -29,8 +29,8 @@ namespace Barotrauma.Sounds
public override int FillStreamBuffer(int samplePos, short[] buffer)
{
if (!Stream) throw new Exception("Called FillStreamBuffer on a non-streamed sound!");
if (reader == null) throw new Exception("Called FillStreamBuffer when the reader is null!");
if (!Stream) { throw new Exception("Called FillStreamBuffer on a non-streamed sound!"); }
if (reader == null) { throw new Exception("Called FillStreamBuffer when the reader is null!"); }
if (samplePos >= reader.TotalSamples * reader.Channels * 2) return 0;
@@ -24,11 +24,12 @@ namespace Barotrauma.Sounds
public readonly bool StreamsReliably;
private readonly SoundManager.SourcePoolIndex sourcePoolIndex = SoundManager.SourcePoolIndex.Default;
public virtual SoundManager.SourcePoolIndex SourcePoolIndex
{
get
{
return SoundManager.SourcePoolIndex.Default;
return sourcePoolIndex;
}
}
@@ -59,13 +60,14 @@ namespace Barotrauma.Sounds
public float BaseNear;
public float BaseFar;
public Sound(SoundManager owner, string filename, bool stream, bool streamsReliably, XElement xElement=null, bool getFullPath=true)
public Sound(SoundManager owner, string filename, bool stream, bool streamsReliably, XElement xElement = null, bool getFullPath = true)
{
Owner = owner;
Filename = getFullPath ? Path.GetFullPath(filename.CleanUpPath()).CleanUpPath() : filename;
Stream = stream;
StreamsReliably = streamsReliably;
XElement = xElement;
sourcePoolIndex = XElement.GetAttributeEnum("sourcepool", SoundManager.SourcePoolIndex.Default);
BaseGain = 1.0f;
BaseNear = 100.0f;
@@ -1,9 +1,7 @@
using System;
using Microsoft.Xna.Framework;
using OpenAL;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System;
using System.Threading;
using System.Diagnostics;
namespace Barotrauma.Sounds
{
@@ -17,7 +15,7 @@ namespace Barotrauma.Sounds
public SoundSourcePool(int sourceCount = SoundManager.SOURCE_COUNT)
{
int alError = Al.NoError;
int alError;
ALSources = new uint[sourceCount];
for (int i = 0; i < sourceCount; i++)
@@ -83,7 +81,7 @@ namespace Barotrauma.Sounds
class SoundChannel : IDisposable
{
private const int STREAM_BUFFER_SIZE = 8820;
private short[] streamShortBuffer;
private readonly short[] streamShortBuffer;
private string debugName = "SoundChannel";
@@ -312,12 +310,12 @@ namespace Barotrauma.Sounds
if (ALSourceIndex < 0) { return; }
if (!IsPlaying) return;
if (!IsPlaying) { return; }
if (!IsStream)
{
uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex);
int playbackPos; Al.GetSourcei(alSource, Al.SampleOffset, out playbackPos);
Al.GetSourcei(alSource, Al.SampleOffset, out int playbackPos);
int alError = Al.GetError();
if (alError != Al.NoError)
{
@@ -379,7 +377,7 @@ namespace Barotrauma.Sounds
if (!IsStream)
{
int playbackPos; Al.GetSourcei(alSource, Al.SampleOffset, out playbackPos);
Al.GetSourcei(alSource, Al.SampleOffset, out int playbackPos);
int alError = Al.GetError();
if (alError != Al.NoError)
{
@@ -390,7 +388,7 @@ namespace Barotrauma.Sounds
}
else
{
float retVal = -1.0f;
float retVal;
Monitor.Enter(mutex);
retVal = streamAmplitude;
Monitor.Exit(mutex);
@@ -432,8 +430,8 @@ namespace Barotrauma.Sounds
private bool reachedEndSample;
private int queueStartIndex;
private readonly uint[] streamBuffers;
private uint[] unqueuedBuffers;
private float[] streamBufferAmplitudes;
private readonly uint[] unqueuedBuffers;
private readonly float[] streamBufferAmplitudes;
public int StreamSeekPos
{
@@ -448,18 +446,17 @@ namespace Barotrauma.Sounds
}
}
private object mutex;
private readonly object mutex;
public bool IsPlaying
{
get
{
if (ALSourceIndex < 0) return false;
if (IsStream && !reachedEndSample) return true;
int state;
if (ALSourceIndex < 0) { return false; }
if (IsStream && !reachedEndSample) { return true; }
uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex);
if (!Al.IsSource(alSource)) return false;
Al.GetSourcei(alSource, Al.SourceState, out state);
if (!Al.IsSource(alSource)) { return false; }
Al.GetSourcei(alSource, Al.SourceState, out int state);
int alError = Al.GetError();
if (alError != Al.NoError)
{
@@ -710,8 +707,7 @@ namespace Barotrauma.Sounds
{
uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex);
int state;
Al.GetSourcei(alSource, Al.SourceState, out state);
Al.GetSourcei(alSource, Al.SourceState, out int state);
bool playing = state == Al.Playing;
int alError = Al.GetError();
if (alError != Al.NoError)
@@ -719,8 +715,7 @@ namespace Barotrauma.Sounds
throw new Exception("Failed to determine playing state from streamed source: " + debugName + ", " + Al.GetErrorString(alError));
}
int unqueuedBufferCount;
Al.GetSourcei(alSource, Al.BuffersProcessed, out unqueuedBufferCount);
Al.GetSourcei(alSource, Al.BuffersProcessed, out int unqueuedBufferCount);
alError = Al.GetError();
if (alError != Al.NoError)
{
@@ -1,10 +1,8 @@
using Barotrauma.IO;
using Barotrauma.Networking;
using Barotrauma.Networking;
using Concentus.Structs;
using Microsoft.Xna.Framework;
using OpenAL;
using System;
using System.Collections.Generic;
namespace Barotrauma.Sounds
{
@@ -26,12 +24,12 @@ namespace Barotrauma.Sounds
}
}
private VoipQueue queue;
private readonly VoipQueue queue;
private int bufferID = 0;
private SoundChannel soundChannel;
private OpusDecoder decoder;
private readonly OpusDecoder decoder;
public bool UseRadioFilter;
public bool UseMuffleFilter;
@@ -39,11 +37,11 @@ namespace Barotrauma.Sounds
public float Near { get; private set; }
public float Far { get; private set; }
private BiQuad[] muffleFilters = new BiQuad[]
private readonly BiQuad[] muffleFilters = new BiQuad[]
{
new LowpassFilter(VoipConfig.FREQUENCY, 800)
};
private BiQuad[] radioFilters = new BiQuad[]
private readonly BiQuad[] radioFilters = new BiQuad[]
{
new BandpassFilter(VoipConfig.FREQUENCY, 2000)
};
@@ -101,13 +99,14 @@ namespace Barotrauma.Sounds
public void ApplyFilters(short[] buffer, int readSamples)
{
float finalGain = gain * GameSettings.CurrentConfig.Audio.VoiceChatVolume;
for (int i = 0; i < readSamples; i++)
{
float fVal = ShortToFloat(buffer[i]);
if (gain * GameSettings.CurrentConfig.Audio.VoiceChatVolume > 1.0f) //TODO: take distance into account?
if (finalGain > 1.0f) //TODO: take distance into account?
{
fVal = Math.Clamp(fVal * gain * GameSettings.CurrentConfig.Audio.VoiceChatVolume, -1f, 1f);
fVal = Math.Clamp(fVal * finalGain, -1f, 1f);
}
if (UseMuffleFilter)