Unstable v0.15.17.0 (Hex is out of town edition)

This commit is contained in:
Juan Pablo Arce
2021-12-03 13:31:10 -03:00
parent cd5c8f3e13
commit 617d9ede88
245 changed files with 8088 additions and 5842 deletions
@@ -63,7 +63,10 @@ namespace Barotrauma
{
foreach (var ic in character.MemState[0].SelectedItem.Components)
{
if (ic.CanBeSelected) ic.Select(character);
if (ic.CanBeSelected)
{
ic.Select(character);
}
}
}
character.SelectedConstruction = character.MemState[0].SelectedItem;
@@ -98,6 +101,16 @@ namespace Barotrauma
if (distSqrd > 10.0f || !character.CanMove)
{
Collider.TargetRotation = newRotation;
if (distSqrd > 10.0f)
{
//teleported very far - see if we need to move to another sub
Hull serverHull = Hull.FindHull(ConvertUnits.ToDisplayUnits(newPosition), CurrentHull, newPosition.Y < lowestSubPos);
if (currentHull != null && serverHull != null && serverHull.Submarine != currentHull.Submarine)
{
character.Submarine = serverHull.Submarine;
character.CurrentHull = CurrentHull = serverHull;
}
}
SetPosition(newPosition, lerp: distSqrd < 5.0f, ignorePlatforms: false);
}
else
@@ -194,7 +207,7 @@ namespace Barotrauma
{
if (character.SelectedConstruction != serverPos.SelectedItem)
{
serverPos.SelectedItem.TryInteract(character, true, true);
serverPos.SelectedItem.TryInteract(character, ignoreRequiredItems: true, forceSelectKey: true);
}
character.SelectedConstruction = serverPos.SelectedItem;
}
@@ -448,8 +461,8 @@ namespace Barotrauma
{
DebugConsole.ThrowError("Failed to draw a ragdoll, limbs have been removed. Character: \"" + character.Name + "\", removed: " + character.Removed + "\n" + Environment.StackTrace.CleanupStackTrace());
GameAnalyticsManager.AddErrorEventOnce("Ragdoll.Draw:LimbsRemoved",
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Failed to draw a ragdoll, limbs have been removed. Character: \"" + character.Name + "\", removed: " + character.Removed + "\n" + Environment.StackTrace.CleanupStackTrace());
GameAnalyticsManager.ErrorSeverity.Error,
"Failed to draw a ragdoll, limbs have been removed. Character: \"" + character.SpeciesName + "\", removed: " + character.Removed + "\n" + Environment.StackTrace.CleanupStackTrace());
return;
}
@@ -460,12 +473,17 @@ namespace Barotrauma
}
float depthOffset = GetDepthOffset();
if (!MathUtils.NearlyEqual(depthOffset, 0.0f))
{
foreach (Limb limb in limbs) { limb.ActiveSprite.Depth += depthOffset; }
}
for (int i = 0; i < limbs.Length; i++)
{
var limb = inversedLimbDrawOrder[i];
if (depthOffset != 0.0f) { limb.ActiveSprite.Depth += depthOffset; }
limb.Draw(spriteBatch, cam, color);
if (depthOffset != 0.0f) { limb.ActiveSprite.Depth -= depthOffset; }
inversedLimbDrawOrder[i].Draw(spriteBatch, cam, color);
}
if (!MathUtils.NearlyEqual(depthOffset, 0.0f))
{
foreach (Limb limb in limbs) { limb.ActiveSprite.Depth -= depthOffset; }
}
LimbJoints.ForEach(j => j.Draw(spriteBatch));
}
@@ -486,7 +504,14 @@ namespace Barotrauma
if (character.WorldPosition.X < character.SelectedConstruction.WorldPosition.X)
{
//at the left side of the ladder, needs to be drawn in front of the rungs
depthOffset = Math.Max(ladder.BackgroundSpriteDepth - 0.01f - maxDepth, 0.0f);
if (maxDepth > ladder.BackgroundSpriteDepth)
{
depthOffset = Math.Max(ladder.BackgroundSpriteDepth - 0.01f - maxDepth, 0.0f);
}
else
{
depthOffset = Math.Max(ladder.Item.GetDrawDepth() + 0.0001f - minDepth, -minDepth);
}
}
else
{
@@ -305,9 +305,9 @@ namespace Barotrauma
case 0: //NetEntityEvent.Type.InventoryState
if (Inventory == null)
{
string errorMsg = "Received an inventory update message for an entity with no inventory (" + Name + ", removed: " + Removed + ")";
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ClientRead:NoInventory" + ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
string errorMsg = "Received an inventory update message for an entity with no inventory ([name], removed: " + Removed + ")";
DebugConsole.ThrowError(errorMsg.Replace("[name]", Name));
GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ClientRead:NoInventory" + ID, GameAnalyticsManager.ErrorSeverity.Error, errorMsg.Replace("[name]", SpeciesName));
//read anyway to prevent messing up reading the rest of the message
_ = msg.ReadUInt16();
@@ -651,7 +651,7 @@ namespace Barotrauma
{
string errorMsg = $"Error in CharacterNetworking.ReadStatus: affliction not found ({afflictionName})";
causeOfDeathType = CauseOfDeathType.Unknown;
GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ReadStatus:AfflictionIndexOutOfBounts", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ReadStatus:AfflictionIndexOutOfBounts", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
}
else
{
@@ -682,7 +682,7 @@ namespace Barotrauma
if (severedJointIndex < 0 || severedJointIndex >= AnimController.LimbJoints.Length)
{
string errorMsg = $"Error in CharacterNetworking.ReadStatus: severed joint index out of bounds (index: {severedJointIndex}, joint count: {AnimController.LimbJoints.Length})";
GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ReadStatus:JointIndexOutOfBounts", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ReadStatus:JointIndexOutOfBounts", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
}
else
{
@@ -453,13 +453,14 @@ namespace Barotrauma
{
case Alignment.Left:
healthWindow.RectTransform.SetPosition(Anchor.BottomLeft);
healthWindow.RectTransform.AbsoluteOffset = new Point(HUDLayoutSettings.InventoryAreaLower.X, screenResolution.Y - HUDLayoutSettings.ChatBoxArea.Y + HUDLayoutSettings.Padding);
break;
case Alignment.Right:
healthWindow.RectTransform.SetPosition(Anchor.BottomRight);
healthWindow.RectTransform.AbsoluteOffset = new Point(HUDLayoutSettings.Padding, screenResolution.Y - HUDLayoutSettings.ChatBoxArea.Y + HUDLayoutSettings.Padding);
break;
}
healthWindow.RectTransform.AbsoluteOffset = new Point(HUDLayoutSettings.Padding, screenResolution.Y - HUDLayoutSettings.ChatBoxArea.Y + HUDLayoutSettings.Padding);
healthWindow.RectTransform.RecalculateChildren(false);
}
@@ -648,8 +649,9 @@ namespace Barotrauma
grainColor = oxygenLowGrainColor;
}
foreach (Affliction affliction in afflictions)
foreach (KeyValuePair<Affliction, LimbHealth> kvp in afflictions)
{
var affliction = kvp.Key;
distortStrength = Math.Max(distortStrength, affliction.GetScreenDistortStrength());
blurStrength = Math.Max(blurStrength, affliction.GetScreenBlurStrength());
radialDistortStrength = Math.Max(radialDistortStrength, affliction.GetRadialDistortStrength());
@@ -662,16 +664,6 @@ namespace Barotrauma
grainColor = Color.Lerp(grainColor, afflictionGrainColor, (float)Math.Pow(1.0f - oxygenLowStrength, 2));
}
}
foreach (LimbHealth limbHealth in limbHealths)
{
foreach (Affliction affliction in limbHealth.Afflictions)
{
distortStrength = Math.Max(distortStrength, affliction.GetScreenDistortStrength());
blurStrength = Math.Max(blurStrength, affliction.GetScreenBlurStrength());
radialDistortStrength = Math.Max(radialDistortStrength, affliction.GetRadialDistortStrength());
chromaticAberrationStrength = Math.Max(chromaticAberrationStrength, affliction.GetChromaticAberrationStrength());
}
}
Character.RadialDistortStrength = radialDistortStrength;
Character.ChromaticAberrationStrength = chromaticAberrationStrength;
@@ -777,7 +769,7 @@ namespace Barotrauma
{
// If no limb is selected or highlighted, select the one with the most critical afflictions.
var affliction = SortAfflictionsBySeverity(GetAllAfflictions(a => a.Prefab.IndicatorLimb != LimbType.None)).FirstOrDefault();
if (affliction.DamagePerSecond > 0 || affliction.Strength > 0)
if (affliction != null && (affliction.DamagePerSecond > 0 || affliction.Strength > 0))
{
var limbHealth = GetMatchingLimbHealth(affliction);
if (limbHealth != null)
@@ -788,7 +780,7 @@ namespace Barotrauma
else
{
// If no affliction is critical, select the limb which has most damage.
var limbHealth = limbHealths.OrderByDescending(l => l.TotalDamage).FirstOrDefault();
var limbHealth = limbHealths.OrderByDescending(l => GetTotalDamage(l)).FirstOrDefault();
selectedLimbIndex = limbHealths.IndexOf(limbHealth);
}
}
@@ -971,8 +963,9 @@ namespace Barotrauma
UpdateAlignment();
}
foreach (Affliction affliction in afflictions)
foreach (KeyValuePair<Affliction, LimbHealth> kvp in afflictions)
{
var affliction = kvp.Key;
if (affliction.Prefab.AfflictionOverlay != null)
{
Sprite ScreenAfflictionOverlay = affliction.Prefab.AfflictionOverlay;
@@ -984,7 +977,7 @@ namespace Barotrauma
float damageOverlayAlpha = DamageOverlayTimer;
if (Vitality < MaxVitality * 0.1f)
{
damageOverlayAlpha = Math.Max(1.0f - (Vitality / maxVitality * 10.0f), damageOverlayAlpha);
damageOverlayAlpha = Math.Max(1.0f - (Vitality / UnmodifiedMaxVitality * 10.0f), damageOverlayAlpha);
}
else
{
@@ -1159,18 +1152,34 @@ namespace Barotrauma
afflictionIconContainer.Content.ClearChildren();
return;
}
var currentAfflictions = GetMatchingAfflictions(selectedLimb, a => a.ShouldShowIcon(Character));
if (currentAfflictions.Any(a => !displayedAfflictions.Any(d => d.affliction == a)) ||
displayedAfflictions.Any(a => !currentAfflictions.Contains(a.affliction)))
if (afflictionsDirty())
{
var currentAfflictions = afflictions.Where(a => a.Value == selectedLimb && a.Key.ShouldShowIcon(Character)).Select(a => a.Key);
CreateAfflictionInfos(currentAfflictions);
CreateRecommendedTreatments();
}
//update recommended treatments if the strength of some displayed affliction has changed by > 1
else if (displayedAfflictions.Any(d => Math.Abs(d.strength - currentAfflictions.First(a => a == d.affliction).Strength) > 1.0f))
else if (displayedAfflictions.Any(d => Math.Abs(d.strength - d.affliction.Strength) > 1.0f))
{
CreateRecommendedTreatments();
}
bool afflictionsDirty()
{
//not displaying one of the current afflictions -> dirty
foreach (KeyValuePair<Affliction, LimbHealth> kvp in afflictions)
{
if (kvp.Value != selectedLimb || !kvp.Key.ShouldShowIcon(Character)) { continue; }
if (!displayedAfflictions.Any(d => d.affliction == kvp.Key)) { return true; }
}
//displaying an affliction we no longer have -> dirty
foreach ((Affliction affliction, float strength) in displayedAfflictions)
{
if (!afflictions.Any(a => a.Key == affliction)) { return true; }
}
return false;
}
}
private void CreateAfflictionInfos(IEnumerable<Affliction> afflictions)
@@ -1604,7 +1613,7 @@ namespace Barotrauma
int i = 0;
foreach (LimbHealth limbHealth in limbHealths)
{
if (limbHealth.IndicatorSprite == null) continue;
if (limbHealth.IndicatorSprite == null) { continue; }
float scale = Math.Min(drawArea.Width / (float)limbHealth.IndicatorSprite.SourceRect.Width, drawArea.Height / (float)limbHealth.IndicatorSprite.SourceRect.Height);
@@ -1623,6 +1632,7 @@ namespace Barotrauma
}
}
private static readonly List<Affliction> afflictionsDisplayedOnLimb = new List<Affliction>();
private void DrawHealthWindow(SpriteBatch spriteBatch, Rectangle drawArea, bool allowHighlight)
{
if (Character.Removed) { return; }
@@ -1633,21 +1643,32 @@ namespace Barotrauma
int i = 0;
foreach (LimbHealth limbHealth in limbHealths)
{
if (limbHealth.IndicatorSprite == null) continue;
if (limbHealth.IndicatorSprite == null) { continue; }
Rectangle limbEffectiveArea = new Rectangle(limbHealth.IndicatorSprite.SourceRect.X + limbHealth.HighlightArea.X,
limbHealth.IndicatorSprite.SourceRect.Y + limbHealth.HighlightArea.Y,
limbHealth.HighlightArea.Width,
limbHealth.HighlightArea.Height);
float damageLerp = limbHealth.TotalDamage > 0.0f ? MathHelper.Lerp(0.2f, 1.0f, limbHealth.TotalDamage / 100.0f) : 0.0f;
float totalDamage = GetTotalDamage(limbHealth);
var tempAfflictions = GetMatchingAfflictions(limbHealth, a => true);
float damageLerp = totalDamage > 0.0f ? MathHelper.Lerp(0.2f, 1.0f, totalDamage / 100.0f) : 0.0f;
float negativeEffect = tempAfflictions.Where(a => !a.Prefab.IsBuff && a.ShouldShowIcon(Character)).Sum(a => a.Strength);
//float negativeMaxEffect = tempAfflictions.Where(a => !a.Prefab.IsBuff).Sum(a => a.Prefab.MaxStrength);
float positiveEffect = tempAfflictions.Where(a => a.Prefab.IsBuff && a.ShouldShowIcon(Character)).Sum(a => a.Strength * 0.2f);
//float positiveMaxEffect = tempAfflictions.Where(a => a.Prefab.IsBuff).Sum(a => a.Prefab.MaxStrength);
float negativeEffect = 0.0f, positiveEffect = 0.0f;
foreach (KeyValuePair<Affliction, LimbHealth> kvp in afflictions)
{
if (kvp.Value != limbHealth) { continue; }
var affliction = kvp.Key;
if (!affliction.ShouldShowIcon(Character)) { continue; }
if (!affliction.Prefab.IsBuff)
{
negativeEffect += affliction.Strength;
}
else
{
positiveEffect += affliction.Strength * 0.2f;
}
}
float midPoint = (float)limbEffectiveArea.Center.Y / (float)limbHealth.IndicatorSprite.Texture.Height;
float fadeDist = 0.6f * (float)limbEffectiveArea.Height / (float)limbHealth.IndicatorSprite.Texture.Height;
@@ -1714,7 +1735,7 @@ namespace Barotrauma
drawArea.Width / (float)limbIndicatorOverlay.FrameSize.X,
drawArea.Height / (float)limbIndicatorOverlay.FrameSize.Y);
int frame = 0;
int frame;
int frameCount = 17;
if (limbIndicatorOverlayAnimState >= frameCount * 2) limbIndicatorOverlayAnimState = 0.0f;
if (limbIndicatorOverlayAnimState < frameCount)
@@ -1758,14 +1779,28 @@ namespace Barotrauma
i = 0;
foreach (LimbHealth limbHealth in limbHealths)
{
IEnumerable<Affliction> thisAfflictions = limbHealth.Afflictions.Where(a => a.ShouldShowIcon(Character));
thisAfflictions = thisAfflictions.Concat(afflictions.Where(a =>
bool shouldDisplayAffliction(KeyValuePair<Affliction, LimbHealth> kvp, LimbHealth limbHealth)
{
Limb indicatorLimb = Character.AnimController.GetLimb(a.Prefab.IndicatorLimb);
return indicatorLimb != null && indicatorLimb.HealthIndex == i && a.ShouldShowIcon(Character);
}));
if (!kvp.Key.ShouldShowIcon(Character)) { return false; }
if (kvp.Value == limbHealth)
{
return true;
}
else if (kvp.Value == null)
{
Limb indicatorLimb = Character.AnimController.GetLimb(kvp.Key.Prefab.IndicatorLimb);
return indicatorLimb != null && indicatorLimb.HealthIndex == i;
}
return false;
}
if (thisAfflictions.Count() <= 0) { i++; continue; }
afflictionsDisplayedOnLimb.Clear();
foreach (var affliction in afflictions)
{
if (shouldDisplayAffliction(affliction, limbHealth)) { afflictionsDisplayedOnLimb.Add(affliction.Key); }
}
if (!afflictionsDisplayedOnLimb.Any()) { i++; continue; }
if (limbHealth.IndicatorSprite == null) { continue; }
float scale = Math.Min(drawArea.Width / (float)limbHealth.IndicatorSprite.SourceRect.Width, drawArea.Height / (float)limbHealth.IndicatorSprite.SourceRect.Height);
@@ -1776,12 +1811,12 @@ namespace Barotrauma
Vector2 iconPos = highlightArea.Center.ToVector2();
//Affliction mostSevereAffliction = thisAfflictions.FirstOrDefault(a => !a.Prefab.IsBuff && !thisAfflictions.Any(a2 => !a2.Prefab.IsBuff && a2.Strength > a.Strength)) ?? thisAfflictions.FirstOrDefault();
Affliction mostSevereAffliction = SortAfflictionsBySeverity(thisAfflictions, excludeBuffs: false).FirstOrDefault();
Affliction mostSevereAffliction = SortAfflictionsBySeverity(afflictionsDisplayedOnLimb, excludeBuffs: false).FirstOrDefault();
if (mostSevereAffliction != null) { DrawLimbAfflictionIcon(spriteBatch, mostSevereAffliction, iconScale, ref iconPos); }
if (thisAfflictions.Count() > 1)
if (afflictionsDisplayedOnLimb.Count() > 1)
{
string additionalAfflictionCount = $"+{thisAfflictions.Count() - 1}";
string additionalAfflictionCount = $"+{afflictionsDisplayedOnLimb.Count() - 1}";
Vector2 displace = GUI.SubHeadingFont.MeasureString(additionalAfflictionCount);
GUI.SubHeadingFont.DrawString(spriteBatch, additionalAfflictionCount, iconPos + new Vector2(displace.X * 1.1f, -displace.Y * 0.45f), Color.Black * 0.75f);
GUI.SubHeadingFont.DrawString(spriteBatch, additionalAfflictionCount, iconPos + new Vector2(displace.X, -displace.Y * 0.5f), Color.White);
@@ -1834,8 +1869,7 @@ namespace Barotrauma
healthBarHolder.Visible = value;
}
private readonly List<(AfflictionPrefab afflictionPrefab, float strength)> newAfflictions = new List<(AfflictionPrefab afflictionPrefab, float strength)>();
private readonly List<(LimbHealth limb, AfflictionPrefab afflictionPrefab, float strength)> newLimbAfflictions = new List<(LimbHealth limb, AfflictionPrefab afflictionPrefab, float strength)>();
private readonly List<(LimbHealth limb, AfflictionPrefab afflictionPrefab, float strength)> newAfflictions = new List<(LimbHealth limb, AfflictionPrefab afflictionPrefab, float strength)>();
private readonly List<(AfflictionPrefab.PeriodicEffect effect, float timer)> newPeriodicEffects = new List<(AfflictionPrefab.PeriodicEffect effect, float timer)>();
public void ClientRead(IReadMessage inc)
@@ -1865,47 +1899,9 @@ namespace Barotrauma
float periodicAfflictionTimer = inc.ReadRangedSingle(afflictionPrefab.PeriodicEffects[j].MinInterval, afflictionPrefab.PeriodicEffects[j].MaxInterval, 8);
newPeriodicEffects.Add((afflictionPrefab.PeriodicEffects[j], periodicAfflictionTimer));
}
newAfflictions.Add((afflictionPrefab, afflictionStrength));
newAfflictions.Add((null, afflictionPrefab, afflictionStrength));
}
foreach (Affliction affliction in afflictions)
{
//deactivate afflictions that weren't included in the network message
if (!newAfflictions.Any(a => a.afflictionPrefab == affliction.Prefab))
{
affliction.Strength = 0.0f;
}
}
foreach (var (afflictionPrefab, strength) in newAfflictions)
{
Affliction existingAffliction = afflictions.Find(a => a.Prefab == afflictionPrefab);
if (existingAffliction == null)
{
existingAffliction = afflictionPrefab.Instantiate(strength);
afflictions.Add(existingAffliction);
}
existingAffliction.SetStrength(strength);
if (existingAffliction == stunAffliction)
{
Character.SetStun(existingAffliction.Strength, true, true);
}
foreach (var periodicEffect in newPeriodicEffects)
{
if (!existingAffliction.Prefab.PeriodicEffects.Contains(periodicEffect.effect)) { continue; }
//timer has wrapped around, apply the effect
if (periodicEffect.timer - existingAffliction.PeriodicEffectTimers[periodicEffect.effect] > periodicEffect.effect.MinInterval / 2)
{
existingAffliction.PeriodicEffectTimers[periodicEffect.effect] = periodicEffect.timer;
foreach (StatusEffect effect in periodicEffect.effect.StatusEffects)
{
existingAffliction.ApplyStatusEffect(ActionType.OnActive, effect, deltaTime: 1.0f, this, targetLimb: null);
}
}
}
}
newLimbAfflictions.Clear();
byte limbAfflictionCount = inc.ReadByte();
for (int i = 0; i < limbAfflictionCount; i++)
{
@@ -1931,43 +1927,50 @@ namespace Barotrauma
float periodicAfflictionTimer = inc.ReadRangedSingle(afflictionPrefab.PeriodicEffects[j].MinInterval, afflictionPrefab.PeriodicEffects[j].MaxInterval, 8);
newPeriodicEffects.Add((afflictionPrefab.PeriodicEffects[j], periodicAfflictionTimer));
}
newLimbAfflictions.Add((limbHealths[limbIndex], afflictionPrefab, afflictionStrength));
newAfflictions.Add((limbHealths[limbIndex], afflictionPrefab, afflictionStrength));
}
foreach (LimbHealth limbHealth in limbHealths)
foreach (KeyValuePair<Affliction, LimbHealth> kvp in afflictions)
{
foreach (Affliction affliction in limbHealth.Afflictions)
//deactivate afflictions that weren't included in the network message
if (!newAfflictions.Any(a => kvp.Key.Prefab == a.afflictionPrefab && kvp.Value == a.limb))
{
//deactivate afflictions that weren't included in the network message
if (!newLimbAfflictions.Any(a => a.limb == limbHealth && a.afflictionPrefab == affliction.Prefab))
kvp.Key.Strength = 0.0f;
}
}
foreach (var (limb, afflictionPrefab, strength) in newAfflictions)
{
Affliction existingAffliction = null;
foreach (KeyValuePair<Affliction, LimbHealth> kvp in afflictions)
{
if (kvp.Key.Prefab == afflictionPrefab && kvp.Value == limb)
{
affliction.Strength = 0.0f;
existingAffliction = kvp.Key;
break;
}
}
foreach (var (limb, afflictionPrefab, strength) in newLimbAfflictions)
if (existingAffliction == null)
{
if (limb != limbHealth) { continue; }
Affliction existingAffliction = limbHealth.Afflictions.Find(a => a.Prefab == afflictionPrefab);
if (existingAffliction == null)
existingAffliction = afflictionPrefab.Instantiate(strength);
afflictions.Add(existingAffliction, limb);
}
existingAffliction.SetStrength(strength);
if (existingAffliction == stunAffliction)
{
Character.SetStun(existingAffliction.Strength, true, true);
}
foreach (var periodicEffect in newPeriodicEffects)
{
if (!existingAffliction.Prefab.PeriodicEffects.Contains(periodicEffect.effect)) { continue; }
//timer has wrapped around, apply the effect
if (periodicEffect.timer - existingAffliction.PeriodicEffectTimers[periodicEffect.effect] > periodicEffect.effect.MinInterval / 2)
{
existingAffliction = afflictionPrefab.Instantiate(strength);
limbHealth.Afflictions.Add(existingAffliction);
}
existingAffliction.SetStrength(strength);
foreach (var periodicEffect in newPeriodicEffects)
{
if (!existingAffliction.Prefab.PeriodicEffects.Contains(periodicEffect.effect)) { continue; }
//timer has wrapped around, apply the effect
if (periodicEffect.timer - existingAffliction.PeriodicEffectTimers[periodicEffect.effect] > periodicEffect.effect.MinInterval / 2)
existingAffliction.PeriodicEffectTimers[periodicEffect.effect] = periodicEffect.timer;
foreach (StatusEffect effect in periodicEffect.effect.StatusEffects)
{
existingAffliction.PeriodicEffectTimers[periodicEffect.effect] = periodicEffect.timer;
foreach (StatusEffect effect in periodicEffect.effect.StatusEffects)
{
Limb targetLimb = Character.AnimController.Limbs.FirstOrDefault(l => l.HealthIndex == limbHealths.IndexOf(limb));
existingAffliction.ApplyStatusEffect(ActionType.OnActive, effect, deltaTime: 1.0f, this, targetLimb: targetLimb);
}
Limb targetLimb = Character.AnimController.Limbs.FirstOrDefault(l => l.HealthIndex == limbHealths.IndexOf(limb));
existingAffliction.ApplyStatusEffect(ActionType.OnActive, effect, deltaTime: 1.0f, this, targetLimb: targetLimb);
}
}
}
@@ -1985,14 +1988,13 @@ namespace Barotrauma
limb.BurnOverlayStrength = 0.0f;
limb.DamageOverlayStrength = 0.0f;
if (limbHealths[limb.HealthIndex].Afflictions.Count == 0) continue;
foreach (Affliction a in limbHealths[limb.HealthIndex].Afflictions)
foreach (KeyValuePair<Affliction, LimbHealth> kvp in afflictions)
{
limb.BurnOverlayStrength += a.Strength / Math.Min(a.Prefab.MaxStrength, 100) * a.Prefab.BurnOverlayAlpha;
limb.DamageOverlayStrength += a.Strength / Math.Min(a.Prefab.MaxStrength, 100) * a.Prefab.DamageOverlayAlpha;
if (kvp.Value != limbHealths[limb.HealthIndex]) { continue; }
var affliction = kvp.Key;
limb.BurnOverlayStrength += affliction.Strength / Math.Min(affliction.Prefab.MaxStrength, 100) * affliction.Prefab.BurnOverlayAlpha;
limb.DamageOverlayStrength += affliction.Strength / Math.Min(affliction.Prefab.MaxStrength, 100) * affliction.Prefab.DamageOverlayAlpha;
}
limb.BurnOverlayStrength /= limbHealths[limb.HealthIndex].Afflictions.Count;
limb.DamageOverlayStrength /= limbHealths[limb.HealthIndex].Afflictions.Count;
}
}
@@ -553,6 +553,12 @@ namespace Barotrauma
levelGenerationParams = LevelGenerationParams.LevelParams.FirstOrDefault(p => p.Identifier == levelGenerationIdentifier);
}
if (SubmarineInfo.SavedSubmarines.None(s => s.Name.ToLowerInvariant() == subName.ToLowerInvariant()))
{
ThrowError($"Cannot find a sub that matches the name \"{subName}\".");
return;
}
GameMain.MainMenuScreen.QuickStart(fixedSeed: false, subName, difficulty, levelGenerationParams);
}, getValidArgs: () => new[] { SubmarineInfo.SavedSubmarines.Select(s => s.Name).Distinct().ToArray() }));
@@ -1461,10 +1467,11 @@ namespace Barotrauma
{
foreach (ItemPrefab ingredientItemPrefab in ingredient.ItemPrefabs)
{
NewMessage(" Its ingredient " + ingredientItemPrefab.Name + " has base cost " + ingredientItemPrefab.DefaultPrice.Price);
totalPrice += ingredientItemPrefab.DefaultPrice.Price;
int defaultPrice = ingredientItemPrefab.DefaultPrice?.Price ?? 0;
NewMessage(" Its ingredient " + ingredientItemPrefab.Name + " has base cost " + defaultPrice);
totalPrice += defaultPrice;
totalBestPrice += ingredientItemPrefab.GetMinPrice();
int basePrice = ingredientItemPrefab.DefaultPrice.Price;
int basePrice = defaultPrice;
foreach (KeyValuePair<string, PriceInfo> ingredientItemLocationPrice in ingredientItemPrefab.GetBuyPricesUnder())
{
if (basePrice > ingredientItemLocationPrice.Value.Price)
@@ -1630,7 +1637,7 @@ namespace Barotrauma
var fabricationRecipe = fabricableItems.Find(f => f.TargetItem == parentItem);
int totalValue = 0;
NewMessage(parentItem.Name + " has the price " + parentItem.DefaultPrice.Price);
NewMessage(parentItem.Name + " has the price " + (parentItem.DefaultPrice?.Price ?? 0));
if (fabricationRecipe != null)
{
NewMessage(" It constructs from:");
@@ -1639,8 +1646,9 @@ namespace Barotrauma
{
foreach (ItemPrefab itemPrefab in requiredItem.ItemPrefabs)
{
NewMessage(" " + itemPrefab.Name + " has the price " + itemPrefab.DefaultPrice.Price);
totalValue += itemPrefab.DefaultPrice.Price;
int defaultPrice = itemPrefab.DefaultPrice?.Price ?? 0;
NewMessage(" " + itemPrefab.Name + " has the price " + defaultPrice);
totalValue += defaultPrice;
}
}
NewMessage("Its total value was: " + totalValue);
@@ -1651,10 +1659,16 @@ namespace Barotrauma
{
ItemPrefab itemPrefab =
(MapEntityPrefab.Find(deconstructItem.ItemIdentifier, identifier: null, showErrorMessages: false) ??
MapEntityPrefab.Find(null, identifier: itemNameOrId, showErrorMessages: false)) as ItemPrefab;
MapEntityPrefab.Find(null, identifier: deconstructItem.ItemIdentifier, showErrorMessages: false)) as ItemPrefab;
if (itemPrefab == null)
{
ThrowError($" Couldn't find deconstruct product \"{deconstructItem.ItemIdentifier}\"!");
continue;
}
NewMessage(" " + itemPrefab.Name + " has the price " + itemPrefab.DefaultPrice.Price);
totalValue += itemPrefab.DefaultPrice.Price;
int defaultPrice = itemPrefab.DefaultPrice?.Price ?? 0;
NewMessage(" " + itemPrefab.Name + " has the price " + defaultPrice);
totalValue += defaultPrice;
}
NewMessage("Its deconstruct value was: " + totalValue);
@@ -2485,8 +2499,6 @@ namespace Barotrauma
NewMessage("Resolution set to 0 x 0 (screen resolution will be used)", Color.Green);
NewMessage("Fullscreen enabled", Color.Green);
GameSettings.ShowUserStatisticsPrompt = true;
GameSettings.VerboseLogging = false;
if (GameMain.Config.MasterServerUrl != "http://www.undertowgames.com/baromaster")
@@ -3162,7 +3174,7 @@ namespace Barotrauma
{
string errorMsg = "Failed to spawn a submarine. Arguments: \"" + string.Join(" ", args) + "\".";
ThrowError(errorMsg, e);
GameAnalyticsManager.AddErrorEventOnce("DebugConsole.SpawnSubmarine:Error", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + '\n' + e.Message + '\n' + e.StackTrace.CleanupStackTrace());
GameAnalyticsManager.AddErrorEventOnce("DebugConsole.SpawnSubmarine:Error", GameAnalyticsManager.ErrorSeverity.Error, errorMsg + '\n' + e.Message + '\n' + e.StackTrace.CleanupStackTrace());
}
},
() =>
@@ -363,7 +363,7 @@ namespace Barotrauma
OnSecondaryClicked = (_, o) =>
{
if (!(o is Client client)) { return false; }
GameMain.GameSession?.CrewManager?.CreateModerationContextMenu(PlayerInput.MousePosition.ToPoint(), client);
NetLobbyScreen.CreateModerationContextMenu(client);
return true;
},
Text = senderName
@@ -397,6 +397,7 @@ namespace Barotrauma
if (GameMain.NetLobbyScreen != null && GameMain.NetworkMember != null)
{
clickableArea.OnClick = GameMain.NetLobbyScreen.SelectPlayer;
clickableArea.OnSecondaryClick = GameMain.NetLobbyScreen.ShowPlayerContextMenu;
}
msgText.ClickableAreas.Add(clickableArea);
}
@@ -79,6 +79,8 @@ namespace Barotrauma
public bool AllowMouseWheelScroll { get; set; } = true;
public bool AllowArrowKeyScroll { get; set; } = true;
/// <summary>
/// Scrolls the list smoothly
/// </summary>
@@ -1254,10 +1256,16 @@ namespace Barotrauma
switch (key)
{
case Keys.Down:
SelectNext();
if (!isHorizontal && AllowArrowKeyScroll) { SelectNext(); }
break;
case Keys.Up:
SelectPrevious();
if (!isHorizontal && AllowArrowKeyScroll) { SelectPrevious(); }
break;
case Keys.Left:
if (isHorizontal && AllowArrowKeyScroll) { SelectPrevious(); }
break;
case Keys.Right:
if (isHorizontal && AllowArrowKeyScroll) { SelectNext(); }
break;
case Keys.Enter:
case Keys.Space:
@@ -30,7 +30,7 @@ namespace Barotrauma
{
GameAnalyticsManager.AddErrorEventOnce(
"GUIProgressBar.BarSize_setter",
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
GameAnalyticsManager.ErrorSeverity.Error,
"Attempted to set the BarSize of a GUIProgressBar to an invalid value (" + value + ")\n" + Environment.StackTrace.CleanupStackTrace());
return;
}
@@ -105,7 +105,7 @@ namespace Barotrauma
{
GameAnalyticsManager.AddErrorEventOnce(
"GUIProgressBar.Draw:GetProgress",
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
GameAnalyticsManager.ErrorSeverity.Error,
"ProgressGetter of a GUIProgressBar (" + ProgressGetter.Target.ToString() + " - " + ProgressGetter.Method.ToString() + ") returned an invalid value (" + newSize + ")\n" + Environment.StackTrace.CleanupStackTrace());
}
else
@@ -276,6 +276,7 @@ namespace Barotrauma
public delegate void OnClickDelegate(GUITextBlock textBlock, ClickableArea area);
public OnClickDelegate OnClick;
public OnClickDelegate OnSecondaryClick;
}
public List<ClickableArea> ClickableAreas { get; private set; } = new List<ClickableArea>();
@@ -528,7 +529,7 @@ namespace Barotrauma
{
base.Update(deltaTime);
if (ClickableAreas.Any() && (GUI.MouseOn?.IsParentOf(this) ?? true))
if (ClickableAreas.Any() && ((GUI.MouseOn?.IsParentOf(this) ?? true) || GUI.MouseOn == this))
{
if (!Rect.Contains(PlayerInput.MousePosition)) { return; }
int index = GetCaretIndexFromScreenPos(PlayerInput.MousePosition);
@@ -541,6 +542,10 @@ namespace Barotrauma
{
clickableArea.OnClick?.Invoke(this, clickableArea);
}
if (PlayerInput.SecondaryMouseButtonClicked())
{
clickableArea.OnSecondaryClick?.Invoke(this, clickableArea);
}
break;
}
}
@@ -562,7 +562,7 @@ namespace Barotrauma
frame.OnSecondaryClicked += (component, data) =>
{
GameMain.GameSession?.CrewManager?.CreateModerationContextMenu(PlayerInput.MousePosition.ToPoint(), client);
NetLobbyScreen.CreateModerationContextMenu(client);
return true;
};
@@ -917,7 +917,8 @@ namespace Barotrauma
textBlock.ClickableAreas.Add(new GUITextBlock.ClickableArea()
{
Data = data,
OnClick = GameMain.NetLobbyScreen.SelectPlayer
OnClick = GameMain.NetLobbyScreen.SelectPlayer,
OnSecondaryClick = GameMain.NetLobbyScreen.ShowPlayerContextMenu
});
}
}
@@ -1486,12 +1487,13 @@ namespace Barotrauma
experienceBar = new GUIProgressBar(new RectTransform(new Vector2(1f, 1f), experienceBarFrame.RectTransform, Anchor.CenterLeft),
barSize: controlledCharacter.Info.GetProgressTowardsNextLevel(), color: GUI.Style.Green)
{
IsHorizontal = true
IsHorizontal = true,
};
experienceText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), experienceBarFrame.RectTransform, anchor: Anchor.Center), "", font: GUI.Font, textAlignment: Alignment.CenterRight)
{
Shadow = true
Shadow = true,
ToolTip = TextManager.Get("experiencetooltip")
};
talentPointText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), experienceLayout.RectTransform, anchor: Anchor.Center), "", font: GUI.SubHeadingFont, parseRichText: true, textAlignment: Alignment.CenterRight) { AutoScaleVertical = true };
@@ -1643,6 +1645,7 @@ namespace Barotrauma
GameMain.Client.CreateEntityEvent(controlledCharacter, new object[] { NetEntityEvent.Type.UpdateTalents });
}
}
selectedTalents = controlledCharacter.Info.GetUnlockedTalentsInTree().ToList();
UpdateTalentButtons();
}
@@ -846,23 +846,27 @@ namespace Barotrauma
var currentOrPending = item.PendingItemSwap ?? item.Prefab;
string name = currentOrPending.Name;
string quantityText = "";
string nameWithQuantity = "";
if (linkedItems.Count > 1)
{
foreach (ItemPrefab distinctItem in linkedItems.Select(it => it.Prefab).Distinct())
{
if (quantityText != string.Empty)
if (nameWithQuantity != string.Empty)
{
quantityText += ", ";
nameWithQuantity += ", ";
}
int count = linkedItems.Count(it => it.Prefab == distinctItem);
quantityText += distinctItem.Name;
nameWithQuantity += distinctItem.Name;
if (count > 1)
{
quantityText += " " + TextManager.GetWithVariable("campaignstore.quantity", "[amount]", count.ToString());
nameWithQuantity += " " + TextManager.GetWithVariable("campaignstore.quantity", "[amount]", count.ToString());
}
}
}
else
{
nameWithQuantity = name;
}
bool isOpen = false;
GUIButton toggleButton = new GUIButton(rectT(1f, 0.1f, parent.Content), text: string.Empty, style: "SlideDown")
@@ -884,7 +888,7 @@ namespace Barotrauma
new GUITextBlock(rectT(0.3f, 1f, buttonLayout), text: slotText, font: GUI.SubHeadingFont);
GUILayoutGroup group = new GUILayoutGroup(rectT(0.7f, 1f, buttonLayout), isHorizontal: true) { Stretch = true };
string title = item.PendingItemSwap != null ? TextManager.GetWithVariable("upgrades.pendingitem", "[itemname]", name) : quantityText;
string title = item.PendingItemSwap != null ? TextManager.GetWithVariable("upgrades.pendingitem", "[itemname]", name) : nameWithQuantity;
GUITextBlock text = new GUITextBlock(rectT(0.7f, 1f, group), text: title, font: GUI.SubHeadingFont, textAlignment: Alignment.Right, parseRichText: true)
{
TextColor = GUI.Style.Orange
@@ -907,7 +911,7 @@ namespace Barotrauma
if (isUninstallPending) { canUninstall = false; }
frames.Add(CreateUpgradeEntry(rectT(1f, 0.25f, parent.Content), currentOrPending.UpgradePreviewSprite,
item.PendingItemSwap != null ? TextManager.GetWithVariable("upgrades.pendingitem", "[itemname]", name) : TextManager.GetWithVariable("upgrades.installeditem", "[itemname]", quantityText),
item.PendingItemSwap != null ? TextManager.GetWithVariable("upgrades.pendingitem", "[itemname]", name) : TextManager.GetWithVariable("upgrades.installeditem", "[itemname]", nameWithQuantity),
currentOrPending.Description,
0, null, addBuyButton: canUninstall, addProgressBar: false, buttonStyle: "WeaponUninstallButton"));
@@ -0,0 +1,114 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Barotrauma.IO;
using Microsoft.Xna.Framework;
namespace Barotrauma
{
public static partial class GameAnalyticsManager
{
static partial void CreateConsentPrompt()
{
if (consentTextAvailable)
{
var background = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: "GUIBackgroundBlocker");
var frame = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.7f), background.RectTransform, Anchor.Center) { MaxSize = new Point(800, int.MaxValue) });
var content = new GUILayoutGroup(new RectTransform(new Vector2(0.95f), frame.RectTransform, Anchor.Center))
{
Stretch = true,
AbsoluteSpacing = GUI.IntScale(15)
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform), TextManager.Get("statisticsconsentheader"), font: GUI.SubHeadingFont, textColor: Color.White);
var mainText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform), TextManager.Get("statisticsconsenttext"), wrap: true, parseRichText: true);
foreach (var data in mainText.RichTextData)
{
mainText.ClickableAreas.Add(new GUITextBlock.ClickableArea()
{
Data = data,
OnClick = (GUITextBlock component, GUITextBlock.ClickableArea area) =>
{
GameMain.Instance.ShowOpenUrlInWebBrowserPrompt("https://gameanalytics.com/privacy/");
}
});
}
string privacyPolicyText = File.ReadAllText("daedalic_privacypolicy.txt");
var privacyPolicyBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.5f), content.RectTransform) { MaxSize = new Point(int.MaxValue, GUI.IntScale(200)) });
var privacyPolicy = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), privacyPolicyBox.Content.RectTransform), privacyPolicyText, wrap: true)
{
CanBeFocused = false
};
privacyPolicy.RectTransform.MinSize = new Point(0, (int)privacyPolicy.TextSize.Y);
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform), TextManager.Get("statisticsconsentstatement"), wrap: true);
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform), isHorizontal: true);
void buttonContainerSpacing(float width)
=> new GUIFrame(new RectTransform(new Vector2(width, 1.0f), buttonContainer.RectTransform), style: null);
buttonContainerSpacing(0.1f);
var yesBtn = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonContainer.RectTransform), TextManager.Get("Yes"));
yesBtn.OnClicked += (btn, userdata) =>
{
GUIMessageBox.MessageBoxes.Remove(background);
SetConsentInternal(Consent.Yes);
return true;
};
yesBtn.Enabled = false;
IEnumerable<CoroutineStatus> enableAfterTime(WaitForSeconds time, params GUIComponent[] components)
{
yield return time;
foreach (var c in components)
{
c.Enabled = true;
}
yield return CoroutineStatus.Success;
}
buttonContainerSpacing(0.2f);
var noBtn = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonContainer.RectTransform), TextManager.Get("No"));
noBtn.OnClicked += (btn, userdata) =>
{
GUIMessageBox.MessageBoxes.Remove(background);
SetConsent(Consent.No);
return true;
};
noBtn.Enabled = false;
CoroutineManager.StartCoroutine(enableAfterTime(new WaitForSeconds(0.3f), yesBtn, noBtn));
buttonContainerSpacing(0.1f);
buttonContainer.RectTransform.MinSize = new Point(0, yesBtn.RectTransform.MinSize.Y);
buttonContainer.RectTransform.MaxSize = new Point(int.MaxValue, yesBtn.RectTransform.MinSize.Y);
foreach (var child in content.Children)
{
if (child is GUITextBlock textBlock)
{
textBlock.RectTransform.MinSize = new Point(0, (int)textBlock.TextSize.Y);
textBlock.RectTransform.MaxSize = new Point(int.MaxValue, (int)textBlock.TextSize.Y + GUI.IntScale(15));
}
}
frame.RectTransform.MaxSize = new Point(
frame.RectTransform.MaxSize.X,
(int)(content.Children.Sum(c => c.RectTransform.MaxSize.Y + content.AbsoluteSpacing) / content.RectTransform.RelativeSize.Y));
GUIMessageBox.MessageBoxes.Add(background);
}
else
{
//user statistics disabled by default if the prompt cannot be shown in the user's language
SetConsent(Consent.Unknown);
}
}
}
}
@@ -11,7 +11,6 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using GameAnalyticsSDK.Net;
using Barotrauma.IO;
using System.Threading;
using Barotrauma.Tutorials;
@@ -384,51 +383,6 @@ namespace Barotrauma
loadingCoroutine = CoroutineManager.StartCoroutine(Load(canLoadInSeparateThread), "Load", canLoadInSeparateThread);
}
private void InitUserStats()
{
return;
if (GameSettings.ShowUserStatisticsPrompt)
{
if (TextManager.ContainsTag("statisticspromptheader") && TextManager.ContainsTag("statisticsprompttext"))
{
var userStatsPrompt = new GUIMessageBox(
TextManager.Get("statisticspromptheader"),
TextManager.Get("statisticsprompttext"),
new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
userStatsPrompt.Buttons[0].OnClicked += (btn, userdata) =>
{
GameSettings.ShowUserStatisticsPrompt = false;
GameSettings.SendUserStatistics = true;
GameAnalyticsManager.Init();
Config.SaveNewPlayerConfig();
return true;
};
userStatsPrompt.Buttons[0].OnClicked += userStatsPrompt.Close;
userStatsPrompt.Buttons[1].OnClicked += (btn, userdata) =>
{
GameSettings.ShowUserStatisticsPrompt = false;
GameSettings.SendUserStatistics = false;
Config.SaveNewPlayerConfig();
return true;
};
userStatsPrompt.Buttons[1].OnClicked += userStatsPrompt.Close;
}
else
{
//user statistics enabled by default if the prompt cannot be shown in the user's language
GameSettings.ShowUserStatisticsPrompt = false;
GameSettings.SendUserStatistics = true;
GameAnalyticsManager.Init();
Config.SaveNewPlayerConfig();
}
}
else if (GameSettings.SendUserStatistics)
{
GameAnalyticsManager.Init();
}
}
public class LoadingException : Exception
{
public LoadingException(Exception e) : base("Loading was interrupted due to an error.", innerException: e)
@@ -522,14 +476,9 @@ namespace Barotrauma
DebugConsole.Log("Selected content packages: " + string.Join(", ", Config.AllEnabledPackages.Select(cp => cp.Name)));
}
#if DEBUG
GameSettings.ShowUserStatisticsPrompt = false;
GameSettings.SendUserStatistics = false;
#endif
GameAnalyticsManager.InitIfConsented();
InitUserStats();
yield return CoroutineStatus.Running;
yield return CoroutineStatus.Running;
Debug.WriteLine("sounds");
@@ -841,6 +790,8 @@ namespace Barotrauma
}
#endif
NetworkMember?.Update((float)Timing.Step);
if (!hasLoaded && !CoroutineManager.IsCoroutineRunning(loadingCoroutine))
{
throw new LoadingException(loadingCoroutine.Exception);
@@ -915,6 +866,11 @@ namespace Barotrauma
{
gameSession.ToggleTabMenu();
}
else if (GUIMessageBox.VisibleBox as GUIMessageBox != null &&
GUIMessageBox.VisibleBox.UserData as string == "bugreporter")
{
((GUIMessageBox)GUIMessageBox.VisibleBox).Close();
}
else if (GUI.PauseMenuOpen)
{
GUI.TogglePauseMenu();
@@ -999,11 +955,11 @@ namespace Barotrauma
}
}
NetworkMember?.Update((float)Timing.Step);
GUI.Update((float)Timing.Step);
}
NetworkMember?.Update((float)Timing.Step);
CoroutineManager.Update((float)Timing.Step, Paused ? 0.0f : (float)Timing.Step);
SteamManager.Update((float)Timing.Step);
@@ -1123,6 +1079,10 @@ namespace Barotrauma
if (GameSession != null)
{
double roundDuration = Timing.TotalTime - GameSession.RoundStartTime;
GameAnalyticsManager.AddProgressionEvent(GameAnalyticsManager.ProgressionStatus.Fail,
GameSession.GameMode?.Name ?? "none",
roundDuration);
if (Tutorial.Initialized)
{
((TutorialMode)GameSession.GameMode).Tutorial?.Stop();
@@ -1131,6 +1091,7 @@ namespace Barotrauma
GUIMessageBox.CloseAll();
MainMenuScreen.Select();
GameSession = null;
}
public void ShowCampaignDisclaimer(Action onContinue = null)
@@ -1254,7 +1215,7 @@ namespace Barotrauma
DebugConsole.ThrowError("Error while cleaning unnecessary save files", e);
}
if (GameSettings.SendUserStatistics) { GameAnalytics.OnQuit(); }
if (GameAnalyticsManager.SendUserStatistics) { GameAnalyticsManager.ShutDown(); }
if (GameSettings.SaveDebugConsoleLogs || GameSettings.VerboseLogging) { DebugConsole.SaveLogs(); }
base.OnExiting(sender, args);
@@ -330,7 +330,7 @@ namespace Barotrauma
if (data == null) { return false; }
if (GameMain.NetworkMember?.ConnectedClients?.Find(c => c.Character == data) is Client client)
{
CreateModerationContextMenu(PlayerInput.MousePosition.ToPoint(), client);
NetLobbyScreen.CreateModerationContextMenu(client);
return true;
}
return false;
@@ -789,7 +789,7 @@ namespace Barotrauma
}
else if (orderGiver != null)
{
OrderChatMessage msg = new OrderChatMessage(order, option, priority, order?.TargetSpatialEntity ?? order?.TargetItemComponent?.Item as ISpatialEntity, character, orderGiver);
OrderChatMessage msg = new OrderChatMessage(order, option, priority, order?.TargetSpatialEntity ?? order?.TargetItemComponent?.Item, character, orderGiver);
GameMain.Client?.SendChatMessage(msg);
}
}
@@ -968,7 +968,8 @@ namespace Barotrauma
{
if (!CanIssueOrders) { return false; }
var orderInfo = (OrderInfo)userData;
SetCharacterOrder(character, orderInfo.Order, orderInfo.OrderOption, CharacterInfo.HighestManualOrderPriority, Character.Controlled);
int priority = GetManualOrderPriority(character, orderInfo.Order);
SetCharacterOrder(character, orderInfo.Order, orderInfo.OrderOption, priority, Character.Controlled);
return true;
},
OnSecondaryClicked = (button, userData) =>
@@ -1153,105 +1154,6 @@ namespace Barotrauma
}
}
#region Context Menu
public void CreateModerationContextMenu(Point mousePos, Client client)
{
if (GUIContextMenu.CurrentContextMenu != null) { return; }
if (IsSinglePlayer || client == null || ((!GameMain.Client?.PreviouslyConnectedClients?.Contains(client)) ?? true)) { return; }
bool hasSteam = client.SteamID > 0 && SteamManager.IsInitialized,
canKick = GameMain.Client.HasPermission(ClientPermissions.Kick),
canBan = GameMain.Client.HasPermission(ClientPermissions.Ban) && client.AllowKicking,
canPromo = GameMain.Client.HasPermission(ClientPermissions.ManagePermissions);
// Disable options if we are targeting ourselves
if (client.ID == GameMain.Client?.ID)
{
canKick = canBan = canPromo = false;
}
List<ContextMenuOption> options = new List<ContextMenuOption>();
options.Add(new ContextMenuOption("ViewSteamProfile", isEnabled: hasSteam, onSelected: delegate
{
Steamworks.SteamFriends.OpenWebOverlay($"https://steamcommunity.com/profiles/{client.SteamID}");
}));
options.Add(new ContextMenuOption("ModerationMenu.UserDetails", isEnabled: true, onSelected: delegate
{
GameMain.NetLobbyScreen?.SelectPlayer(client);
}));
// Creates sub context menu options for all the ranks
List<ContextMenuOption> permissionOptions = new List<ContextMenuOption>();
foreach (PermissionPreset rank in PermissionPreset.List)
{
permissionOptions.Add(new ContextMenuOption(rank.Name, isEnabled: true, onSelected: () =>
{
string label = TextManager.GetWithVariables(rank.Permissions == ClientPermissions.None ? "clearrankprompt" : "giverankprompt", new []{ "[user]", "[rank]" }, new []{ client.Name, rank.Name });
GUIMessageBox msgBox = new GUIMessageBox(string.Empty, label, new[] { TextManager.Get("Yes"), TextManager.Get("Cancel") });
msgBox.Buttons[0].OnClicked = delegate
{
client.SetPermissions(rank.Permissions, rank.PermittedCommands);
GameMain.Client.UpdateClientPermissions(client);
msgBox.Close();
return true;
};
msgBox.Buttons[1].OnClicked = delegate
{
msgBox.Close();
return true;
};
}) { Tooltip = rank.Description });
}
options.Add(new ContextMenuOption("Permissions", isEnabled: canPromo, options: permissionOptions.ToArray()));
Color clientColor = client.Character?.Info?.Job.Prefab.UIColor ?? Color.White;
if (GameMain.Client.ConnectedClients.Contains(client))
{
options.Add(new ContextMenuOption(client.MutedLocally ? "Unmute" : "Mute", isEnabled: client.ID != GameMain.Client?.ID, onSelected: delegate
{
client.MutedLocally = !client.MutedLocally;
}));
bool kickEnabled = client.ID != GameMain.Client?.ID && client.AllowKicking;
// if the user can kick create a kick option else create the votekick option
ContextMenuOption kickOption;
if (canKick)
{
kickOption = new ContextMenuOption("Kick", isEnabled: kickEnabled, onSelected: delegate
{
GameMain.Client?.CreateKickReasonPrompt(client.Name, false);
});
}
else
{
kickOption = new ContextMenuOption("VoteToKick", isEnabled: kickEnabled, onSelected: delegate
{
GameMain.Client?.VoteForKick(client);
});
}
options.Add(kickOption);
}
options.Add(new ContextMenuOption("Ban", isEnabled: canBan, onSelected: delegate
{
GameMain.Client?.CreateKickReasonPrompt(client.Name, true);
}));
GUIContextMenu.CreateContextMenu(null, client.Name, headerColor: clientColor, options.ToArray());
}
#endregion
public void AddToGUIUpdateList()
{
if (GUI.DisableHUD) { return; }
@@ -1902,7 +1804,7 @@ namespace Barotrauma
private Hull hullContext;
private WallSection wallContext;
private bool isContextual;
private readonly List<Order> contextualOrders = new List<Order>();
private readonly List<OrderInfo> contextualOrders = new List<OrderInfo>();
private Point shorcutCenterNodeOffset;
private const int maxShortcutNodeCount = 4;
@@ -2605,7 +2507,7 @@ namespace Barotrauma
{
order = orders[i];
disableNode = !CanCharacterBeHeard() ||
(order.MustSetTarget && (order.ItemComponentType != null || order.TargetItems.Length > 0) &&
(order.MustSetTarget && (order.ItemComponentType != null || order.GetTargetItems().Any() || order.RequireItems.Any()) &&
order.GetMatchingItems(true, interactableFor: characterContext ?? Character.Controlled).None());
optionNodes.Add(new Tuple<GUIComponent, Keys>(
CreateOrderNode(nodeSize, commandFrame.RectTransform, offsets[i].ToPoint(), order, (i + 1) % 10, disableNode: disableNode, checkIfOrderCanBeHeard: false),
@@ -2621,7 +2523,6 @@ namespace Barotrauma
if (contextualOrders.None())
{
string orderIdentifier;
// Check if targeting an item or a hull
if (itemContext != null && itemContext.IsPlayerTeamInteractable)
{
@@ -2630,84 +2531,89 @@ namespace Barotrauma
{
targetComponent = null;
if (p.UseController && itemContext.Components.None(c => c is Controller)) { continue; }
if ((p.TargetItems.Length > 0 && (p.TargetItems.Contains(itemContext.Prefab.Identifier) || itemContext.HasTag(p.TargetItems))) ||
p.TryGetTargetItemComponent(itemContext, out targetComponent))
if (p.HasOptionSpecificTargetItems)
{
contextualOrders.Add(p.HasOptions ? p : new Order(p, itemContext, targetComponent, Character.Controlled));
foreach (string option in p.Options)
{
if (p.TargetItemsMatchItem(itemContext, option))
{
contextualOrders.Add(new OrderInfo(new Order(p, itemContext, targetComponent, Character.Controlled), option));
}
}
}
else if (p.TargetItemsMatchItem(itemContext) || p.TryGetTargetItemComponent(itemContext, out targetComponent))
{
contextualOrders.Add(new OrderInfo(p.HasOptions ? p : new Order(p, itemContext, targetComponent, Character.Controlled), null));
}
}
// If targeting a periscope connected to a turret, show the 'operateweapons' order
orderIdentifier = "operateweapons";
var operateWeaponsPrefab = Order.GetPrefab(orderIdentifier);
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)) && itemContext.Components.Any(c => c is Controller))
if (contextualOrders.None(info => info.Order.Identifier.Equals(orderIdentifier)) && itemContext.Components.Any(c => c is Controller))
{
var turret = itemContext.GetConnectedComponents<Turret>().FirstOrDefault(c => c.Item.HasTag(operateWeaponsPrefab.TargetItems)) ??
itemContext.GetConnectedComponents<Turret>(recursive: true).FirstOrDefault(c => c.Item.HasTag(operateWeaponsPrefab.TargetItems));
if (turret != null) { contextualOrders.Add(new Order(operateWeaponsPrefab, turret.Item, turret, Character.Controlled)); }
var turret = itemContext.GetConnectedComponents<Turret>().FirstOrDefault(c => operateWeaponsPrefab.TargetItemsMatchItem(c.Item)) ??
itemContext.GetConnectedComponents<Turret>(recursive: true).FirstOrDefault(c => operateWeaponsPrefab.TargetItemsMatchItem(c.Item));
if (turret != null)
{
contextualOrders.Add(new OrderInfo(new Order(operateWeaponsPrefab, turret.Item, turret, Character.Controlled), null));
}
}
// If targeting a repairable item with condition below the repair threshold, show the 'repairsystems' order
orderIdentifier = "repairsystems";
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)) && itemContext.Repairables.Any(r => r.IsBelowRepairThreshold))
if (contextualOrders.None(info => info.Order.Identifier.Equals(orderIdentifier)) && itemContext.Repairables.Any(r => r.IsBelowRepairThreshold))
{
if (itemContext.Repairables.Any(r => r != null && r.requiredSkills.Any(s => s != null && s.Identifier.Equals("electrical"))))
{
contextualOrders.Add(new Order(Order.GetPrefab("repairelectrical"), itemContext, targetItem: null, Character.Controlled));
contextualOrders.Add(new OrderInfo(new Order(Order.GetPrefab("repairelectrical"), itemContext, targetItem: null, Character.Controlled), null));
}
else if (itemContext.Repairables.Any(r => r != null && r.requiredSkills.Any(s => s != null && s.Identifier.Equals("mechanical"))))
{
contextualOrders.Add(new Order(Order.GetPrefab("repairmechanical"), itemContext, targetItem: null, Character.Controlled));
contextualOrders.Add(new OrderInfo(new Order(Order.GetPrefab("repairmechanical"), itemContext, targetItem: null, Character.Controlled), null));
}
else
{
contextualOrders.Add(new Order(Order.GetPrefab(orderIdentifier), itemContext, targetItem: null, Character.Controlled));
contextualOrders.Add(new OrderInfo(new Order(Order.GetPrefab(orderIdentifier), itemContext, targetItem: null, Character.Controlled), null));
}
}
// Remove the 'pumpwater' order if the target pump is auto-controlled (as it will immediately overwrite the work done by the bot)
orderIdentifier = "pumpwater";
if (contextualOrders.FirstOrDefault(o => o.Identifier.Equals(orderIdentifier)) is Order o &&
itemContext.Components.FirstOrDefault(c => c.GetType() == o.ItemComponentType) is Pump pump)
if (contextualOrders.FirstOrDefault(info => info.Order.Identifier.Equals(orderIdentifier)) is OrderInfo pumpOrderInfo && pumpOrderInfo.Order is Order pumpOrder &&
itemContext.Components.FirstOrDefault(c => c.GetType() == pumpOrder.ItemComponentType) is Pump pump && pump.IsAutoControlled)
{
if (pump.IsAutoControlled) { contextualOrders.Remove(o); }
contextualOrders.Remove(pumpOrderInfo);
}
if (contextualOrders.None())
{
orderIdentifier = "cleanupitems";
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)))
if (contextualOrders.None(info => info.Order.Identifier.Equals(orderIdentifier)))
{
if (AIObjectiveCleanupItems.IsValidTarget(itemContext, Character.Controlled, checkInventory: false) || AIObjectiveCleanupItems.IsValidContainer(itemContext, Character.Controlled))
{
contextualOrders.Add(new Order(Order.GetPrefab(orderIdentifier), itemContext, targetItem: null, Character.Controlled));
contextualOrders.Add(new OrderInfo(new Order(Order.GetPrefab(orderIdentifier), itemContext, targetItem: null, Character.Controlled), null));
}
}
}
AddIgnoreOrder(itemContext);
}
else if (hullContext != null)
{
contextualOrders.Add(new Order(Order.GetPrefab("fixleaks"), hullContext, targetItem: null, Character.Controlled));
contextualOrders.Add(new OrderInfo(new Order(Order.GetPrefab("fixleaks"), hullContext, targetItem: null, Character.Controlled), null));
if (wallContext != null)
{
AddIgnoreOrder(wallContext);
}
}
void AddIgnoreOrder(IIgnorable target)
{
var orderIdentifier = "ignorethis";
if (!target.OrderedToBeIgnored && contextualOrders.None(o => o.Identifier == orderIdentifier))
if (!target.OrderedToBeIgnored && contextualOrders.None(info => info.Order.Identifier == orderIdentifier))
{
AddOrder();
}
else
{
orderIdentifier = "unignorethis";
if (target.OrderedToBeIgnored && contextualOrders.None(o => o.Identifier == orderIdentifier))
if (target.OrderedToBeIgnored && contextualOrders.None(info => info.Order.Identifier == orderIdentifier))
{
AddOrder();
}
@@ -2717,64 +2623,61 @@ namespace Barotrauma
{
if (target is WallSection ws)
{
contextualOrders.Add(new Order(Order.GetPrefab(orderIdentifier), ws.Wall, ws.Wall.Sections.IndexOf(ws), orderGiver: Character.Controlled));
contextualOrders.Add(new OrderInfo(new Order(Order.GetPrefab(orderIdentifier), ws.Wall, ws.Wall.Sections.IndexOf(ws), orderGiver: Character.Controlled), null));
}
else
{
contextualOrders.Add(new Order(Order.GetPrefab(orderIdentifier), target as Entity, null, Character.Controlled));
contextualOrders.Add(new OrderInfo(new Order(Order.GetPrefab(orderIdentifier), target as Entity, null, Character.Controlled), null));
}
}
}
orderIdentifier = "wait";
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)))
if (contextualOrders.None(info => info.Order.Identifier.Equals(orderIdentifier)))
{
Vector2 position = GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
Hull hull = Hull.FindHull(position, guess: Character.Controlled?.CurrentHull);
contextualOrders.Add(new Order(Order.GetPrefab(orderIdentifier), new OrderTarget(position, hull), Character.Controlled));
contextualOrders.Add(new OrderInfo(new Order(Order.GetPrefab(orderIdentifier), new OrderTarget(position, hull), Character.Controlled), null));
}
if (contextualOrders.None(o => o.Category != OrderCategory.Movement) && characters.Any(c => c != Character.Controlled))
if (contextualOrders.None(info => info.Order.Category != OrderCategory.Movement) && characters.Any(c => c != Character.Controlled))
{
orderIdentifier = "follow";
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)))
if (contextualOrders.None(info => info.Order.Identifier.Equals(orderIdentifier)))
{
contextualOrders.Add(Order.GetPrefab(orderIdentifier));
contextualOrders.Add(new OrderInfo(Order.GetPrefab(orderIdentifier), null));
}
}
// Show 'dismiss' order only when there are crew members with active orders
orderIdentifier = "dismissed";
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)) && characters.Any(c => !c.IsDismissed))
if (contextualOrders.None(info => info.Order.Identifier.Equals(orderIdentifier)) && characters.Any(c => !c.IsDismissed))
{
contextualOrders.Add(Order.GetPrefab(orderIdentifier));
contextualOrders.Add(new OrderInfo(Order.GetPrefab(orderIdentifier), null));
}
}
var offsets = MathUtils.GetPointsOnCircumference(Vector2.Zero, nodeDistance, contextualOrders.Count, MathHelper.ToRadians(90f + 180f / contextualOrders.Count));
bool disableNode = !CanCharacterBeHeard();
for (int i = 0; i < contextualOrders.Count; i++)
{
optionNodes.Add(new Tuple<GUIComponent, Keys>(
CreateOrderNode(nodeSize, commandFrame.RectTransform, offsets[i].ToPoint(), contextualOrders[i], (i + 1) % 10, disableNode: disableNode, checkIfOrderCanBeHeard: false),
!disableNode ? Keys.D0 + (i + 1) % 10 : Keys.None));
var info = contextualOrders[i];
int hotkey = (i + 1) % 10;
var component = string.IsNullOrEmpty(info.OrderOption) ?
CreateOrderNode(nodeSize, commandFrame.RectTransform, offsets[i].ToPoint(), info.Order, hotkey, disableNode: disableNode, checkIfOrderCanBeHeard: false) :
CreateOrderOptionNode(nodeSize, commandFrame.RectTransform, offsets[i].ToPoint(), info.Order, info.OrderOption, info.Order.Prefab.GetOptionName(info.OrderOption), hotkey);
optionNodes.Add(new Tuple<GUIComponent, Keys>(component, !disableNode ? Keys.D0 + (i + 1) % 10 : Keys.None));
}
}
// TODO: there's duplicate logic here and above -> would be better to refactor so that the conditions are only defined in one place
public static bool DoesItemHaveContextualOrders(Item item)
{
if (Order.PrefabList.Any(o => o.TargetItems.Length > 0 && o.TargetItems.Contains(item.Prefab.Identifier))) { return true; }
if (Order.PrefabList.Any(o => item.HasTag(o.TargetItems))) { return true; }
if (Order.PrefabList.Any(o => o.TargetItemsMatchItem(item))) { return true; }
if (Order.PrefabList.Any(o => o.TryGetTargetItemComponent(item, out _))) { return true; }
if (AIObjectiveCleanupItems.IsValidTarget(item, Character.Controlled, checkInventory: false)) { return true; }
if (AIObjectiveCleanupItems.IsValidContainer(item, Character.Controlled)) { return true; }
if (Order.GetPrefab("loaditems") is Order loadItemsPrefab && AIObjectiveLoadItems.IsValidTarget(item, Character.Controlled, targetContainerTags: loadItemsPrefab.GetTargetItems())) { return true; }
if (item.Repairables.Any(r => r.IsBelowRepairThreshold)) { return true; }
var operateWeaponsPrefab = Order.GetPrefab("operateweapons");
return item.Components.Any(c => c is Controller) &&
(item.GetConnectedComponents<Turret>().Any(c => c.Item.HasTag(operateWeaponsPrefab.TargetItems)) ||
item.GetConnectedComponents<Turret>(recursive: true).Any(c => c.Item.HasTag(operateWeaponsPrefab.TargetItems)));
return Order.GetPrefab("operateweapons") is Order operateWeaponsPrefab && item.Components.Any(c => c is Controller) &&
(item.GetConnectedComponents<Turret>().Any(c => operateWeaponsPrefab.TargetItemsMatchItem(c.Item)) ||
item.GetConnectedComponents<Turret>(recursive: true).Any(c => operateWeaponsPrefab.TargetItemsMatchItem(c.Item)));
}
/// <param name="hotkey">Use a negative value (e.g. -1) if there should be no hotkey associated with the node</param>
@@ -2831,7 +2734,8 @@ namespace Barotrauma
o = new Order(o.Prefab, orderTargetEntity, orderTargetEntity.Components.FirstOrDefault(ic => ic.GetType() == order.ItemComponentType), orderGiver: order.OrderGiver);
}
var character = !o.TargetAllCharacters ? characterContext ?? GetCharacterForQuickAssignment(o) : null;
SetCharacterOrder(character, o, null, CharacterInfo.HighestManualOrderPriority, Character.Controlled);
int priority = GetManualOrderPriority(character, o);
SetCharacterOrder(character, o, null, priority, Character.Controlled);
DisableCommandUI();
}
return true;
@@ -2943,7 +2847,9 @@ namespace Barotrauma
}
else
{
SetCharacterOrder(characterContext ?? GetCharacterForQuickAssignment(o.Item1), o.Item1, o.Item2, CharacterInfo.HighestManualOrderPriority, Character.Controlled);
var character = characterContext ?? GetCharacterForQuickAssignment(o.Item1);
int priority = GetManualOrderPriority(character, o.Item1);
SetCharacterOrder(character, o.Item1, o.Item2, priority, Character.Controlled);
DisableCommandUI();
}
return true;
@@ -3013,7 +2919,9 @@ namespace Barotrauma
}
else
{
SetCharacterOrder(characterContext ?? GetCharacterForQuickAssignment(o.Item1), o.Item1, o.Item2, CharacterInfo.HighestManualOrderPriority, Character.Controlled);
var character = characterContext ?? GetCharacterForQuickAssignment(o.Item1);
int priority = GetManualOrderPriority(character, o.Item1);
SetCharacterOrder(character, o.Item1, o.Item2, priority, Character.Controlled);
DisableCommandUI();
}
return true;
@@ -3218,7 +3126,9 @@ namespace Barotrauma
OnClicked = (_, userData) =>
{
if (!CanIssueOrders) { return false; }
SetCharacterOrder(userData as Character, order.Item1, order.Item2, CharacterInfo.HighestManualOrderPriority, Character.Controlled);
var character = userData as Character;
int priority = GetManualOrderPriority(character, order.Item1);
SetCharacterOrder(character, order.Item1, order.Item2, priority, Character.Controlled);
DisableCommandUI();
return true;
}
@@ -3496,6 +3406,11 @@ namespace Barotrauma
return order.Name;
}
private int GetManualOrderPriority(Character character, Order order)
{
return character?.Info?.GetManualOrderPriority(order) ?? CharacterInfo.HighestManualOrderPriority;
}
#region Crew Member Assignment Logic
private bool CanOpenManualAssignment(GUIComponent node)
{
@@ -65,7 +65,7 @@ namespace Barotrauma
public override void ShowStartMessage()
{
foreach (Mission mission in Missions)
foreach (Mission mission in Missions.ToList())
{
new GUIMessageBox(
mission.Prefab.IsSideObjective ? TextManager.AddPunctuation(':', TextManager.Get("sideobjective"), mission.Name) : mission.Name,
@@ -60,7 +60,7 @@ namespace Barotrauma
var newCampaignContainer = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.95f), campaignContainer.RectTransform, Anchor.Center), style: null);
var loadCampaignContainer = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.95f), campaignContainer.RectTransform, Anchor.Center), style: null);
GameMain.NetLobbyScreen.CampaignSetupUI = new MultiPlayerCampaignSetupUI(newCampaignContainer, loadCampaignContainer, null, saveFiles);
GameMain.NetLobbyScreen.CampaignSetupUI = new MultiPlayerCampaignSetupUI(newCampaignContainer, loadCampaignContainer, saveFiles);
var newCampaignButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), buttonContainer.RectTransform),
TextManager.Get("NewCampaign"), style: "GUITabButton")
@@ -475,12 +475,12 @@ namespace Barotrauma
ItemComponent targetItem = null;
if (orderPrefab.MustSetTarget)
{
targetEntity = orderPrefab.GetMatchingItems(true, interactableFor: Character.Controlled).FirstOrDefault();
targetEntity = orderPrefab.GetMatchingItems(true, interactableFor: Character.Controlled, orderOption: orderInfo.option).FirstOrDefault();
if (targetEntity == null) { return; }
targetItem = orderPrefab.GetTargetItemComponent(targetEntity);
}
var order = new Order(orderPrefab, targetEntity as Entity, targetItem, orderGiver: Character.Controlled);
GameMain.GameSession.CrewManager.SetCharacterOrder(Character.Controlled, order, orderInfo.option, CharacterInfo.HighestManualOrderPriority, Character.Controlled);
GameMain.GameSession?.CrewManager?.SetCharacterOrder(Character.Controlled, order, orderInfo.option, CharacterInfo.HighestManualOrderPriority, Character.Controlled);
});
}
@@ -635,9 +635,9 @@ namespace Barotrauma
}
else if (characterInfo.CauseOfDeath.Type == CauseOfDeathType.Affliction && characterInfo.CauseOfDeath.Affliction == null)
{
string errorMsg = "Character \"" + characterInfo.Name + "\" had an invalid cause of death (the type of the cause of death was Affliction, but affliction was not specified).";
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("RoundSummary:InvalidCauseOfDeath", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
string errorMsg = "Character \"[name]\" had an invalid cause of death (the type of the cause of death was Affliction, but affliction was not specified).";
DebugConsole.ThrowError(errorMsg.Replace("[name]", characterInfo.Name));
GameAnalyticsManager.AddErrorEventOnce("RoundSummary:InvalidCauseOfDeath", GameAnalyticsManager.ErrorSeverity.Error, errorMsg.Replace("[name]", characterInfo.SpeciesName));
statusText = TextManager.Get("CauseOfDeathDescription.Unknown");
statusColor = GUI.Style.Red;
}
@@ -1,12 +1,10 @@
using Barotrauma.Extensions;
using Barotrauma.Networking;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using OpenAL;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Xml.Linq;
@@ -365,6 +363,12 @@ namespace Barotrauma
TextManager.Get("Settings"), textAlignment: Alignment.TopLeft, font: GUI.LargeFont)
{ ForceUpperCase = true };
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), settingsTitle.RectTransform, Anchor.CenterRight, scaleBasis: ScaleBasis.Smallest), style: "GUIBugButton")
{
ToolTip = TextManager.Get("bugreportbutton") + $" (v{GameMain.Version})",
OnClicked = (btn, userdata) => { GameMain.Instance.ShowBugReporter(); return true; }
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), leftPanel.RectTransform), TextManager.Get("ContentPackages"), font: GUI.SubHeadingFont);
var corePackageDropdown = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.05f), leftPanel.RectTransform))
@@ -509,17 +513,53 @@ namespace Barotrauma
ApplySettings();
GameMain.Instance.Exit();
return true;
}; msgBox.Buttons[1].OnClicked += (btn, userdata) =>
};
msgBox.Buttons[1].OnClicked += (btn, userdata) =>
{
Language = prevLanguage;
languageDD.SelectItem(Language);
msgBox.Close();
return true;
};
return true;
};
var statisticsTickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.045f), leftPanel.RectTransform), TextManager.Get("statisticsconsenttickbox"))
{
OnSelected = (GUITickBox tickBox) =>
{
GameAnalyticsManager.SetConsent(
tickBox.Selected
? GameAnalyticsManager.Consent.Ask
: GameAnalyticsManager.Consent.No);
return false;
}
};
void updateGATickBoxToolTip()
=> statisticsTickBox.ToolTip = TextManager.Get($"GameAnalyticsStatus.{GameAnalyticsManager.UserConsented}");
updateGATickBoxToolTip();
var cachedConsent = GameAnalyticsManager.Consent.Unknown;
var statisticsTickBoxUpdater = new GUICustomComponent(
new RectTransform(Vector2.Zero, statisticsTickBox.RectTransform),
onUpdate: (deltaTime, component) =>
{
bool shouldTickBoxBeSelected = GameAnalyticsManager.UserConsented == GameAnalyticsManager.Consent.Yes;
bool shouldUpdateTickBoxState = cachedConsent != GameAnalyticsManager.UserConsented
|| statisticsTickBox.Selected != shouldTickBoxBeSelected;
if (!shouldUpdateTickBoxState) { return; }
updateGATickBoxToolTip();
cachedConsent = GameAnalyticsManager.UserConsented;
GUITickBox.OnSelectedHandler prevHandler = statisticsTickBox.OnSelected;
statisticsTickBox.OnSelected = null;
statisticsTickBox.Selected = shouldTickBoxBeSelected;
statisticsTickBox.OnSelected = prevHandler;
statisticsTickBox.Enabled = GameAnalyticsManager.UserConsented != GameAnalyticsManager.Consent.Error;
});
// right panel --------------------------------------
var rightPanel = new GUILayoutGroup(new RectTransform(new Vector2(0.99f - leftPanel.RectTransform.RelativeSize.X, leftPanel.RectTransform.RelativeSize.Y),
@@ -556,13 +596,6 @@ namespace Barotrauma
tabButtons[(int)tab].Text = ToolBox.LimitString(buttonText, tabButtons[(int)tab].Font, (int)(0.75f * tabWidth * tabButtonHolder.Rect.Width));
}
new GUIButton(new RectTransform(new Vector2(0.05f, 0.75f), tabButtonHolder.RectTransform, Anchor.BottomRight) { RelativeOffset = new Vector2(0.0f, 0.2f) }, style: "GUIBugButton")
{
ToolTip = TextManager.Get("bugreportbutton"),
OnClicked = (btn, userdata) => { GameMain.Instance.ShowBugReporter(); return true; }
};
/// Graphics tab --------------------------------------------------------------
var leftColumn = new GUILayoutGroup(new RectTransform(new Vector2(0.46f, 0.95f), tabs[(int)Tab.Graphics].RectTransform, Anchor.TopLeft)
@@ -1168,7 +1201,7 @@ namespace Barotrauma
catch (Exception e)
{
DebugConsole.ThrowError("Failed to set voice capture mode.", e);
GameAnalyticsManager.AddErrorEventOnce("SetVoiceCaptureMode", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, "Failed to set voice capture mode. " + e.Message + "\n" + e.StackTrace.CleanupStackTrace());
GameAnalyticsManager.AddErrorEventOnce("SetVoiceCaptureMode", GameAnalyticsManager.ErrorSeverity.Error, "Failed to set voice capture mode. " + e.Message + "\n" + e.StackTrace.CleanupStackTrace());
VoiceSetting = VoiceMode.Disabled;
}
@@ -406,7 +406,7 @@ namespace Barotrauma.Items.Components
DebugConsole.Log("Invalid sound volume (item " + item.Name + ", " + GetType().ToString() + "): " + newVolume);
GameAnalyticsManager.AddErrorEventOnce(
"ItemComponent.PlaySound:" + item.Name + GetType().ToString(),
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
GameAnalyticsManager.ErrorSeverity.Error,
"Invalid sound volume (item " + item.Name + ", " + GetType().ToString() + "): " + newVolume);
return 0.0f;
}
@@ -1,9 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
@@ -11,7 +8,7 @@ namespace Barotrauma.Items.Components
{
public float BackgroundSpriteDepth
{
get { return item.GetDrawDepth() + 0.1f; }
get { return item.GetDrawDepth() + 0.05f; }
}
public Vector2 DrawSize
@@ -672,36 +672,33 @@ namespace Barotrauma.Items.Components
return;
}
if (currentMode == MiniMapMode.HullStatus)
if (currentMode == MiniMapMode.HullStatus && item.Submarine != null)
{
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable);
spriteBatch.GraphicsDevice.ScissorRectangle = submarineContainer.Rect;
if (item.Submarine != null)
var sprite = GUI.Style.UIGlowSolidCircular?.Sprite;
float alpha = (MathF.Sin(blipState / maxBlipState * MathHelper.TwoPi) + 1.5f) * 0.5f;
if (sprite != null)
{
var sprite = GUI.Style.UIGlowSolidCircular?.Sprite;
float alpha = (MathF.Sin(blipState / maxBlipState * MathHelper.TwoPi) + 1.5f) * 0.5f;
if (sprite != null)
Vector2 spriteSize = sprite.size;
Rectangle worldBorders = item.Submarine.GetDockedBorders();
worldBorders.Location += item.Submarine.WorldPosition.ToPoint();
foreach (Gap gap in Gap.GapList)
{
Vector2 spriteSize = sprite.size;
Rectangle worldBorders = item.Submarine.GetDockedBorders();
worldBorders.Location += item.Submarine.WorldPosition.ToPoint();
foreach (Gap gap in Gap.GapList)
{
if (gap.IsRoomToRoom || gap.Submarine != item.Submarine || gap.ConnectedDoor != null || gap.HiddenInGame) { continue; }
RectangleF entityRect = ScaleRectToUI(gap, miniMapFrame.Rect, worldBorders);
if (gap.IsRoomToRoom || gap.linkedTo.Count == 0 || gap.Submarine != item.Submarine || gap.ConnectedDoor != null || gap.HiddenInGame) { continue; }
RectangleF entityRect = ScaleRectToUI(gap, miniMapFrame.Rect, worldBorders);
Vector2 scale = new Vector2(entityRect.Size.X / spriteSize.X, entityRect.Size.Y / spriteSize.Y) * 2.0f;
Vector2 scale = new Vector2(entityRect.Size.X / spriteSize.X, entityRect.Size.Y / spriteSize.Y) * 2.0f;
Color color = ToolBox.GradientLerp(gap.Open, GUI.Style.HealthBarColorMedium, GUI.Style.HealthBarColorLow) * alpha;
sprite.Draw(spriteBatch,
miniMapFrame.Rect.Location.ToVector2() + entityRect.Center,
color, origin: sprite.Origin, rotate: 0.0f, scale: scale);
}
Color color = ToolBox.GradientLerp(gap.Open, GUI.Style.HealthBarColorMedium, GUI.Style.HealthBarColorLow) * alpha;
sprite.Draw(spriteBatch,
miniMapFrame.Rect.Location.ToVector2() + entityRect.Center,
color, origin: sprite.Origin, rotate: 0.0f, scale: scale);
}
}
}
if (currentMode == MiniMapMode.HullStatus && hullStatusComponents != null)
{
@@ -991,8 +988,40 @@ namespace Barotrauma.Items.Components
continue;
}
hullData.HullOxygenAmount = RequireOxygenDetectors ? hullData.ReceivedOxygenAmount : hull.OxygenPercentage;
hullData.HullWaterAmount = RequireWaterDetectors ? hullData.ReceivedWaterAmount : Math.Min(hull.WaterVolume / hull.Volume, 1.0f);
if (RequireOxygenDetectors)
{
hullData.HullOxygenAmount = hullData.ReceivedOxygenAmount;
}
else if (hullData.LinkedHulls.Any())
{
hullData.HullOxygenAmount = 0.0f;
foreach (Hull linkedHull in hullData.LinkedHulls)
{
hullData.HullOxygenAmount += linkedHull.OxygenPercentage;
}
hullData.HullOxygenAmount /= hullData.LinkedHulls.Count;
}
else
{
hullData.HullOxygenAmount = hull.OxygenPercentage;
}
if (RequireWaterDetectors)
{
hullData.HullWaterAmount = hullData.ReceivedWaterAmount;
}
else if (hullData.LinkedHulls.Any())
{
hullData.HullWaterAmount = 0.0f;
foreach (Hull linkedHull in hullData.LinkedHulls)
{
hullData.HullWaterAmount += Math.Min(linkedHull.WaterVolume / linkedHull.Volume, 1.0f);
}
hullData.HullWaterAmount /= hullData.LinkedHulls.Count;
}
else
{
hullData.HullWaterAmount = Math.Min(hull.WaterVolume / hull.Volume, 1.0f);
}
float gapOpenSum = 0.0f;
@@ -1013,15 +1042,6 @@ namespace Barotrauma.Items.Components
float? oxygenAmount = hullData.HullOxygenAmount,
waterAmount = hullData.HullWaterAmount;
foreach (Hull linkedHull in hullData.LinkedHulls)
{
oxygenAmount += linkedHull.OxygenPercentage;
waterAmount += Math.Min(linkedHull.WaterVolume / linkedHull.Volume, 1.0f);
}
oxygenAmount /= (hullData.LinkedHulls.Count + 1);
waterAmount /= (hullData.LinkedHulls.Count + 1);
string line1 = gapOpenSum > 0.1f ? TextManager.Get("MiniMapHullBreach") : string.Empty;
Color line1Color = GUI.Style.Red;
@@ -1111,10 +1131,9 @@ namespace Barotrauma.Items.Components
private void DrawHUDBack(SpriteBatch spriteBatch, GUICustomComponent container)
{
if (item.Submarine != null)
{
DrawSubmarine(spriteBatch);
}
if (item.Submarine == null) { return; }
DrawSubmarine(spriteBatch);
if (Voltage < MinVoltage) { return; }
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
@@ -1155,7 +1174,8 @@ namespace Barotrauma.Items.Components
if (hullsVisible && hullData.HullWaterAmount is { } waterAmount)
{
if (hullFrame.Rect.Height * waterAmount > 3.0f)
if (!RequireWaterDetectors) { waterAmount = hull.WaterPercentage / 100.0f; }
if (hullFrame.Rect.Height * waterAmount > 1.0f)
{
RectangleF waterRect = new RectangleF(hullFrame.Rect.X, hullFrame.Rect.Y + hullFrame.Rect.Height * (1.0f - waterAmount), hullFrame.Rect.Width, hullFrame.Rect.Height * waterAmount);
@@ -1418,7 +1438,7 @@ namespace Barotrauma.Items.Components
{
if (linkedEntity is Hull linkedHull)
{
if (linkedHulls.Contains(linkedHull)) { continue; }
if (linkedHulls.Contains(linkedHull) || linkedHull.HiddenInGame) { continue; }
linkedHulls.Add(linkedHull);
GetLinkedHulls(linkedHull, linkedHulls);
}
@@ -1598,7 +1618,7 @@ namespace Barotrauma.Items.Components
bool IsPartofSub(MapEntity entity)
{
if (entity.Submarine != sub && !connectedSubs.Contains(entity.Submarine)) { return false; }
if (entity.Submarine != sub && !connectedSubs.Contains(entity.Submarine) || entity.HiddenInGame) { return false; }
return !settings.IgnoreOutposts || sub.IsEntityFoundOnThisSub(entity, true);
}
@@ -1623,6 +1623,11 @@ namespace Barotrauma.Items.Components
markerDistances.Add(targetIdentifier, cachedDistance);
dist = path.TotalLength;
}
else
{
var cachedDistance = new CachedDistance(transducerPosition, worldPosition, linearDist, Timing.TotalTime + Rand.Range(4.0f, 7.0f));
markerDistances.Add(targetIdentifier, cachedDistance);
}
}
Vector2 position = worldPosition - transducerPosition;
@@ -35,6 +35,13 @@ namespace Barotrauma.Items.Components
private FixActions requestStartFixAction;
private bool qteSuccess;
private float qteTimer;
private const float qteTime = 0.5f;
private float qteCooldown;
private const float qteCooldownTime = 0.5f;
public float FakeBrokenTimer;
[Serialize("", false, description: "An optional description of the needed repairs displayed in the repair interface.")]
@@ -55,16 +62,13 @@ namespace Barotrauma.Items.Components
if (!HasRequiredItems(character, false) || character.SelectedConstruction != item) { return false; }
if (character.IsTraitor && item.ConditionPercentage > MinSabotageCondition) { return true; }
float maxRepairConditionMultiplier = GetMaxRepairConditionMultiplier(character);
float defaultMaxCondition = item.MaxCondition / maxRepairConditionMultiplier;
float defaultMaxCondition = item.MaxCondition / item.MaxRepairConditionMultiplier;
if (MathUtils.Percentage(item.Condition, defaultMaxCondition) < RepairThreshold) { return true; }
if (CurrentFixer == character)
{
float condition = item.Condition / item.MaxRepairConditionMultiplier;
float maxCondition = item.MaxCondition / item.MaxRepairConditionMultiplier;
if (condition < maxCondition * maxRepairConditionMultiplier)
if (item.Condition < item.MaxCondition)
{
return true;
}
@@ -145,11 +149,14 @@ namespace Barotrauma.Items.Components
progressBar = new GUIProgressBar(new RectTransform(new Vector2(0.6f, 1.0f), progressBarHolder.RectTransform),
color: GUI.Style.Green, barSize: 0.0f, style: "DeviceProgressBar");
progressBarOverlayText = new GUITextBlock(new RectTransform(Vector2.One, progressBar.RectTransform), string.Empty, font: GUI.SubHeadingFont, textAlignment: Alignment.Center)
{
IgnoreLayoutGroups = true
};
qteTimer = qteTime;
repairButtonText = TextManager.Get("RepairButton");
repairingText = TextManager.Get("Repairing");
RepairButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1.0f), progressBarHolder.RectTransform, Anchor.TopCenter), repairButtonText)
@@ -159,6 +166,11 @@ namespace Barotrauma.Items.Components
requestStartFixAction = FixActions.Repair;
item.CreateClientEvent(this);
return true;
},
OnButtonDown = () =>
{
QTEAction();
return true;
}
};
RepairButton.TextBlock.AutoScaleHorizontal = true;
@@ -183,6 +195,11 @@ namespace Barotrauma.Items.Components
requestStartFixAction = FixActions.Sabotage;
item.CreateClientEvent(this);
return true;
},
OnButtonDown = () =>
{
QTEAction();
return true;
}
};
@@ -253,6 +270,21 @@ namespace Barotrauma.Items.Components
{
repairSoundChannel = SoundPlayer.PlaySound("repair", item.WorldPosition, hullGuess: item.CurrentHull);
}
if (qteCooldown > 0.0f)
{
qteCooldown -= deltaTime;
if (qteCooldown <= 0.0f)
{
qteTimer = qteTime;
}
}
else
{
qteTimer -= deltaTime * (qteTimer / qteTime);
if (qteTimer < 0.0f) qteTimer = qteTime;
}
}
else
{
@@ -270,6 +302,26 @@ namespace Barotrauma.Items.Components
progressBar.BarSize = item.Condition / defaultMaxCondition;
progressBar.Color = ToolBox.GradientLerp(progressBar.BarSize, GUI.Style.Red, GUI.Style.Orange, GUI.Style.Green);
Rectangle sliderRect = progressBar.GetSliderRect(1.0f);
Color qteSliderColor = Color.White;
if (qteCooldown > 0.0f)
{
qteSliderColor = qteSuccess ? GUI.Style.Green : GUI.Style.Red * 0.5f;
progressBar.Color = ToolBox.GradientLerp(qteCooldown / qteCooldownTime, progressBar.Color, qteSliderColor, Color.White);
}
else
{
if (qteTimer / qteTime <= item.Condition / item.MaxCondition)
{
qteSliderColor = Color.Lerp(qteSliderColor, GUI.Style.Green, 0.5f);
}
}
progressBar.Parent.Parent.Parent.DrawManually(spriteBatch, true);
GUI.DrawRectangle(spriteBatch,
new Rectangle(sliderRect.X + (int)((qteTimer / qteTime) * sliderRect.Width), sliderRect.Y - 5, 2, sliderRect.Height + 10),
qteSliderColor, true);
if (item.Condition > defaultMaxCondition)
{
float extraCondition = item.MaxCondition * (item.MaxRepairConditionMultiplier - 1.0f);
@@ -282,7 +334,7 @@ namespace Barotrauma.Items.Components
progressBarOverlayText.Visible = false;
}
RepairButton.Enabled = (currentFixerAction == FixActions.None || (CurrentFixer == character && currentFixerAction != FixActions.Repair)) && !item.IsFullCondition && IsBelowRepairThreshold;
RepairButton.Enabled = (currentFixerAction == FixActions.None || CurrentFixer == character) && !item.IsFullCondition;
RepairButton.Text = (currentFixerAction == FixActions.None || CurrentFixer != character || currentFixerAction != FixActions.Repair) ?
repairButtonText :
repairingText + new string('.', ((int)(Timing.TotalTime * 2.0f) % 3) + 1);
@@ -352,6 +404,29 @@ namespace Barotrauma.Items.Components
repairSoundChannel = null;
}
private void QTEAction()
{
if (currentFixerAction == FixActions.Repair)
{
qteSuccess = qteCooldown <= 0.0f && qteTimer / qteTime <= item.Condition / item.MaxCondition;
}
else
{
return;
}
if (!GameMain.IsMultiplayer) { RepairBoost(qteSuccess); }
SoundPlayer.PlayUISound(qteSuccess ? GUISoundType.IncreaseQuantity : GUISoundType.DecreaseQuantity);
//on failure during cooldown reset cursor to beginning
if (!qteSuccess && qteCooldown > 0.0f) { qteTimer = qteTime; }
qteCooldown = qteCooldownTime;
//this will be set on button down so we can reset it here
requestStartFixAction = FixActions.None;
item.CreateClientEvent(this);
}
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
deteriorationTimer = msg.ReadSingle();
@@ -363,11 +438,13 @@ namespace Barotrauma.Items.Components
currentFixerAction = (FixActions)msg.ReadRangedInteger(0, 2);
CurrentFixer = currentFixerID != 0 ? Entity.FindEntityByID(currentFixerID) as Character : null;
item.MaxRepairConditionMultiplier = GetMaxRepairConditionMultiplier(CurrentFixer);
repairBoost = msg.ReadSingle();
}
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
{
msg.WriteRangedInteger((int)requestStartFixAction, 0, 2);
msg.Write(qteSuccess);
}
}
}
@@ -26,12 +26,7 @@ namespace Barotrauma.Items.Components
AutoHideScrollBar = false
};
// Create fillerBlock to cover historyBox so new values appear at the bottom of historyBox
// This could be removed if GUIListBox supported aligning its children
fillerBlock = new GUITextBlock(new RectTransform(new Vector2(1, 1), historyBox.Content.RectTransform, anchor: Anchor.TopCenter), string.Empty)
{
CanBeFocused = false
};
CreateFillerBlock();
new GUIFrame(new RectTransform(new Vector2(0.9f, 0.01f), layoutGroup.RectTransform), style: "HorizontalLine");
@@ -55,6 +50,16 @@ namespace Barotrauma.Items.Components
};
}
// Create fillerBlock to cover historyBox so new values appear at the bottom of historyBox
// This could be removed if GUIListBox supported aligning its children
public void CreateFillerBlock()
{
fillerBlock = new GUITextBlock(new RectTransform(new Vector2(1, 1), historyBox.Content.RectTransform, anchor: Anchor.TopCenter), string.Empty)
{
CanBeFocused = false
};
}
private void SendOutput(string input)
{
if (input.Length > MaxMessageLength)
@@ -130,7 +135,12 @@ namespace Barotrauma.Items.Components
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
{
msg.Write((string)extraData[2]);
if (extraData is null) { return; }
if (extraData[2] is string str)
{
msg.Write(str);
}
}
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
@@ -160,7 +160,7 @@ namespace Barotrauma.Items.Components
{
errorMsg += "\nTrying to dock the submarine to itself.";
}
GameAnalyticsManager.AddErrorEventOnce("DockingPort.ClientRead:JointNotCreated", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("DockingPort.ClientRead:JointNotCreated", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
}
if (isLocked)
@@ -1445,7 +1445,7 @@ namespace Barotrauma
#else
if (GameSettings.VerboseLogging) { DebugConsole.ThrowError(errorMsg); }
#endif
GameAnalyticsManager.AddErrorEventOnce("Item.ClientReadPosition:nophysicsbody", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("Item.ClientReadPosition:nophysicsbody", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
return;
}
@@ -1586,7 +1586,7 @@ namespace Barotrauma
string errorMsg = "Failed to spawn item, prefab not found (name: " + (itemName ?? "null") + ", identifier: " + (itemIdentifier ?? "null") + ")";
errorMsg += "\n" + string.Join(", ", GameMain.Config.AllEnabledPackages.Select(cp => cp.Name));
GameAnalyticsManager.AddErrorEventOnce("Item.ReadSpawnData:PrefabNotFound" + (itemName ?? "null") + (itemIdentifier ?? "null"),
GameAnalyticsSDK.Net.EGAErrorSeverity.Critical,
GameAnalyticsManager.ErrorSeverity.Critical,
errorMsg);
DebugConsole.ThrowError(errorMsg);
return null;
@@ -1607,7 +1607,7 @@ namespace Barotrauma
string errorMsg =
$"Failed to spawn item \"{(itemIdentifier ?? "null")}\" in the inventory of \"{parentItem.prefab.Identifier} ({parentItem.ID})\" (component index out of range). Index: {itemContainerIndex}, components: {parentItem.components.Count}.";
GameAnalyticsManager.AddErrorEventOnce("Item.ReadSpawnData:ContainerIndexOutOfRange" + (itemName ?? "null") + (itemIdentifier ?? "null"),
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
GameAnalyticsManager.ErrorSeverity.Error,
errorMsg);
DebugConsole.ThrowError(errorMsg);
inventory = parentItem.GetComponent<ItemContainer>()?.Inventory;
@@ -98,7 +98,7 @@ namespace Barotrauma
private IEnumerable<CoroutineStatus> DimLight(LightSource light)
{
float currBrightness = 1.0f;
while (light.Color.A > 0.0f && flashDuration > 0.0f)
while (light.Color.A > 0.0f && flashDuration > 0.0f && currBrightness > 0.0f)
{
light.Color = new Color(light.Color.R, light.Color.G, light.Color.B, (byte)(currBrightness * 255));
currBrightness -= 1.0f / flashDuration * CoroutineManager.DeltaTime;
@@ -92,7 +92,7 @@ namespace Barotrauma
DebugConsole.ThrowError("Invalid left normal");
#endif
GameAnalyticsManager.AddErrorEventOnce("CaveGenerator.GenerateWallShapes:InvalidLeftNormal:" + level.Seed,
GameAnalyticsSDK.Net.EGAErrorSeverity.Warning,
GameAnalyticsManager.ErrorSeverity.Warning,
"Invalid left normal (leftedge: " + leftEdge + ", rightedge: " + rightEdge + ", normal: " + leftNormal + ", seed: " + level.Seed + ")");
if (cell.Body != null)
@@ -127,7 +127,7 @@ namespace Barotrauma
DebugConsole.ThrowError("Invalid right normal");
#endif
GameAnalyticsManager.AddErrorEventOnce("CaveGenerator.GenerateWallShapes:InvalidRightNormal:" + level.Seed,
GameAnalyticsSDK.Net.EGAErrorSeverity.Warning,
GameAnalyticsManager.ErrorSeverity.Warning,
"Invalid right normal (leftedge: " + leftEdge + ", rightedge: " + rightEdge + ", normal: " + rightNormal + ", seed: " + level.Seed + ")");
if (cell.Body != null)
@@ -497,11 +497,13 @@ namespace Barotrauma.Lights
return true;
}
private readonly Dictionary<Hull, Rectangle> visibleHulls = new Dictionary<Hull, Rectangle>();
private Dictionary<Hull, Rectangle> GetVisibleHulls(Camera cam)
{
Dictionary<Hull, Rectangle> visibleHulls = new Dictionary<Hull, Rectangle>();
visibleHulls.Clear();
foreach (Hull hull in Hull.hullList)
{
if (hull.HiddenInGame) { continue; }
var drawRect =
hull.Submarine == null ?
hull.Rect :
@@ -536,7 +536,7 @@ namespace Barotrauma
invalidMessage = true;
string errorMsg = $"Error while reading a network event for the structure \"{Name} ({ID})\". Section count does not match (server: {sectionCount} client: {Sections.Length})";
DebugConsole.NewMessage(errorMsg, Color.Red);
GameAnalyticsManager.AddErrorEventOnce("Structure.ClientRead:SectionCountMismatch", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("Structure.ClientRead:SectionCountMismatch", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
}
for (int i = 0; i < sectionCount; i++)
@@ -98,7 +98,7 @@ namespace Barotrauma
{
string errorMsg = "Error when loading round sound (" + element + ") - file path not set";
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("Submarine.LoadRoundSound:FilePathEmpty" + element.ToString(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace.CleanupStackTrace());
GameAnalyticsManager.AddErrorEventOnce("Submarine.LoadRoundSound:FilePathEmpty" + element.ToString(), GameAnalyticsManager.ErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace.CleanupStackTrace());
return null;
}
@@ -124,7 +124,7 @@ namespace Barotrauma
{
string errorMsg = "Failed to load sound file \"" + filename + "\".";
DebugConsole.ThrowError(errorMsg, e);
GameAnalyticsManager.AddErrorEventOnce("Submarine.LoadRoundSound:FileNotFound" + filename, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace.CleanupStackTrace());
GameAnalyticsManager.AddErrorEventOnce("Submarine.LoadRoundSound:FileNotFound" + filename, GameAnalyticsManager.ErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace.CleanupStackTrace());
return null;
}
}
@@ -148,7 +148,7 @@ namespace Barotrauma
{
string errorMsg = "Failed to load sound file \"" + roundSound.Filename + "\".";
DebugConsole.ThrowError(errorMsg, e);
GameAnalyticsManager.AddErrorEventOnce("Submarine.LoadRoundSound:FileNotFound" + roundSound.Filename, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace.CleanupStackTrace());
GameAnalyticsManager.AddErrorEventOnce("Submarine.LoadRoundSound:FileNotFound" + roundSound.Filename, GameAnalyticsManager.ErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace.CleanupStackTrace());
return;
}
}
@@ -183,13 +183,14 @@ namespace Barotrauma
visibleSubs.Clear();
foreach (Submarine sub in Loaded)
{
if (sub.WorldPosition.Y < Level.MaxEntityDepth) continue;
if (sub.WorldPosition.Y < Level.MaxEntityDepth) { continue; }
int margin = 500;
Rectangle worldBorders = new Rectangle(
sub.Borders.X + (int)sub.WorldPosition.X - 500,
sub.Borders.Y + (int)sub.WorldPosition.Y + 500,
sub.Borders.Width + 1000,
sub.Borders.Height + 1000);
sub.VisibleBorders.X + (int)sub.WorldPosition.X - margin,
sub.VisibleBorders.Y + (int)sub.WorldPosition.Y + margin,
sub.VisibleBorders.Width + margin * 2,
sub.VisibleBorders.Height + margin * 2);
if (RectsOverlap(worldBorders, cam.WorldView))
{
@@ -26,7 +26,7 @@ namespace Barotrauma
catch (Exception e)
{
DebugConsole.ThrowError("Loading the preview image of the submarine \"" + Name + "\" failed. The file may be corrupted.", e);
GameAnalyticsManager.AddErrorEventOnce("Submarine..ctor:PreviewImageLoadingFailed", GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
GameAnalyticsManager.AddErrorEventOnce("Submarine..ctor:PreviewImageLoadingFailed", GameAnalyticsManager.ErrorSeverity.Error,
"Loading the preview image of the submarine \"" + Name + "\" failed. The file may be corrupted.");
PreviewImage = null;
}
@@ -649,7 +649,7 @@ namespace Barotrauma.Networking
{
errorMsg += "\nInner exception: " + e.InnerException.Message + "\n" + e.InnerException.StackTrace.CleanupStackTrace();
}
GameAnalyticsManager.AddErrorEventOnce("GameClient.Update:CheckServerMessagesException" + e.TargetSite.ToString(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameClient.Update:CheckServerMessagesException" + e.TargetSite.ToString(), GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
DebugConsole.ThrowError("Error while reading a message from server.", e);
new GUIMessageBox(TextManager.Get("Error"), TextManager.GetWithVariables("MessageReadError", new string[2] { "[message]", "[targetsite]" }, new string[2] { e.Message, e.TargetSite.ToString() }));
Disconnect();
@@ -779,7 +779,7 @@ namespace Barotrauma.Networking
#if DEBUG
DebugConsole.ThrowError("Error while reading an ingame update message from server.", e);
#endif
GameAnalyticsManager.AddErrorEventOnce("GameClient.ReadDataMessage:ReadIngameUpdate", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameClient.ReadDataMessage:ReadIngameUpdate", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
throw;
}
break;
@@ -791,7 +791,7 @@ namespace Barotrauma.Networking
errorMsg += "\n" + Environment.StackTrace.CleanupStackTrace();
GameAnalyticsManager.AddErrorEventOnce(
"GameClient.ReadDataMessage:VoipClientNull",
GameMain.Client == null ? GameAnalyticsSDK.Net.EGAErrorSeverity.Error : GameAnalyticsSDK.Net.EGAErrorSeverity.Warning,
GameMain.Client == null ? GameAnalyticsManager.ErrorSeverity.Error : GameAnalyticsManager.ErrorSeverity.Warning,
errorMsg);
return;
}
@@ -989,7 +989,7 @@ namespace Barotrauma.Networking
{
string errorMsg = "Submarine equality check failed. The submarine loaded at your end doesn't match the one loaded by the server." +
" There may have been an error in receiving the up-to-date submarine file from the server.";
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:SubsDontMatch" + Level.Loaded.Seed, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:SubsDontMatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
throw new Exception(errorMsg);
}
@@ -1010,7 +1010,7 @@ namespace Barotrauma.Networking
if (!GameMain.GameSession.Missions.Select(m => m.Prefab.Identifier).OrderBy(id => id).SequenceEqual(serverMissionIdentifiers.OrderBy(id => id)))
{
string errorMsg = $"Mission equality check failed. The mission selected at your end doesn't match the one loaded by the server (server: {string.Join(", ", serverMissionIdentifiers)}, client: {string.Join(", ", GameMain.GameSession.Missions.Select(m => m.Prefab.Identifier))})";
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:MissionsDontMatch" + Level.Loaded.Seed, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:MissionsDontMatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
throw new Exception(errorMsg);
}
GameMain.GameSession.EnforceMissionOrder(serverMissionIdentifiers);
@@ -1031,7 +1031,7 @@ namespace Barotrauma.Networking
", seed: " + Level.Loaded.Seed +
", sub: " + Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash.ShortHash + ")" +
", mirrored: " + Level.Loaded.Mirrored + ").";
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + Level.Loaded.Seed, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
throw new Exception(errorMsg);
}
else
@@ -1047,7 +1047,7 @@ namespace Barotrauma.Networking
", seed: " + Level.Loaded.Seed +
", sub: " + Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash.ShortHash + ")" +
", mirrored: " + Level.Loaded.Mirrored + ").";
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + Level.Loaded.Seed, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
throw new Exception(errorMsg);
}
}
@@ -1117,8 +1117,8 @@ namespace Barotrauma.Networking
{
GameAnalyticsManager.AddErrorEventOnce(
"GameClient.HandleDisconnectMessage",
GameAnalyticsSDK.Net.EGAErrorSeverity.Debug,
"Client received a disconnect message. Reason: " + disconnectReason.ToString() + ", message: " + disconnectMsg);
GameAnalyticsManager.ErrorSeverity.Debug,
"Client received a disconnect message. Reason: " + disconnectReason.ToString());
}
if (disconnectReason == DisconnectReason.ServerFull)
@@ -1532,7 +1532,7 @@ namespace Barotrauma.Networking
gameStarted = true;
GameMain.NetLobbyScreen.Select();
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:FailedToSelectSub" + subName, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:FailedToSelectSub" + subName, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
roundInitStatus = RoundInitStatus.Interrupted;
yield return CoroutineStatus.Failure;
}
@@ -1544,7 +1544,7 @@ namespace Barotrauma.Networking
GameMain.NetLobbyScreen.Select();
string errorMsg = "Failed to select shuttle \"" + shuttleName + "\" (hash: " + shuttleHash + ").";
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:FailedToSelectShuttle" + shuttleName, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:FailedToSelectShuttle" + shuttleName, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
roundInitStatus = RoundInitStatus.Interrupted;
yield return CoroutineStatus.Failure;
}
@@ -2116,9 +2116,6 @@ namespace Barotrauma.Networking
bool autoRestartEnabled = inc.ReadBoolean();
float autoRestartTimer = autoRestartEnabled ? inc.ReadSingle() : 0.0f;
bool radiationEnabled = inc.ReadBoolean();
byte maxMissionCount = inc.ReadByte();
//ignore the message if we already a more up-to-date one
//or if we're still waiting for the initial update
if (NetIdUtils.IdMoreRecent(updateID, GameMain.NetLobbyScreen.LastUpdateID) &&
@@ -2168,22 +2165,15 @@ namespace Barotrauma.Networking
if (GameMain.NetLobbyScreen.CheckIfCampaignSubMatches(sub, "campaign"))
{
GameMain.NetLobbyScreen.CampaignSubmarines.Add(sub);
}
}
if (HasPermission(ClientPermissions.ManageCampaign) && !gameStarted && GameMain.NetLobbyScreen?.CampaignSetupUI != null)
{
GameMain.NetLobbyScreen.CampaignSetupUI.RefreshMultiplayerCampaignSubUI(GameMain.NetLobbyScreen.CampaignSubmarines);
}
}
}
GameMain.NetLobbyScreen.SetAllowSpectating(allowSpectating);
GameMain.NetLobbyScreen.LevelSeed = levelSeed;
GameMain.NetLobbyScreen.SetLevelDifficulty(levelDifficulty);
GameMain.NetLobbyScreen.SetRadiationEnabled(radiationEnabled);
GameMain.NetLobbyScreen.SetBotSpawnMode(botSpawnMode);
GameMain.NetLobbyScreen.SetBotCount(botCount);
GameMain.NetLobbyScreen.SetMaxMissionCount(maxMissionCount);
GameMain.NetLobbyScreen.SetAutoRestart(autoRestartEnabled, autoRestartTimer);
serverSettings.VoiceChatEnabled = voiceChatEnabled;
@@ -2355,7 +2345,7 @@ namespace Barotrauma.Networking
{
errorLines.Add("[" + DebugConsole.Messages[i].Time + "] " + DebugConsole.Messages[i].Text);
}
GameAnalyticsManager.AddErrorEventOnce("GameClient.ReadInGameUpdate", GameAnalyticsSDK.Net.EGAErrorSeverity.Critical, string.Join("\n", errorLines));
GameAnalyticsManager.AddErrorEventOnce("GameClient.ReadInGameUpdate", GameAnalyticsManager.ErrorSeverity.Critical, string.Join("\n", errorLines));
DebugConsole.ThrowError("Writing object data to \"networkerror_data.log\", please send this file to us at http://github.com/Regalis11/Barotrauma/issues");
@@ -2591,29 +2581,29 @@ namespace Barotrauma.Networking
subElement.ToolTip = newSub.Description;
}
if (GameMain.NetLobbyScreen.FailedSelectedSub != null &&
GameMain.NetLobbyScreen.FailedSelectedSub.First == newSub.Name &&
GameMain.NetLobbyScreen.FailedSelectedSub.Second == newSub.MD5Hash.Hash)
if (GameMain.NetLobbyScreen.FailedSelectedSub.HasValue &&
GameMain.NetLobbyScreen.FailedSelectedSub.Value.Name == newSub.Name &&
GameMain.NetLobbyScreen.FailedSelectedSub.Value.Hash == newSub.MD5Hash.Hash)
{
GameMain.NetLobbyScreen.TrySelectSub(newSub.Name, newSub.MD5Hash.Hash, GameMain.NetLobbyScreen.SubList);
}
if (GameMain.NetLobbyScreen.FailedSelectedShuttle != null &&
GameMain.NetLobbyScreen.FailedSelectedShuttle.First == newSub.Name &&
GameMain.NetLobbyScreen.FailedSelectedShuttle.Second == newSub.MD5Hash.Hash)
if (GameMain.NetLobbyScreen.FailedSelectedShuttle.HasValue &&
GameMain.NetLobbyScreen.FailedSelectedShuttle.Value.Name == newSub.Name &&
GameMain.NetLobbyScreen.FailedSelectedShuttle.Value.Hash == newSub.MD5Hash.Hash)
{
GameMain.NetLobbyScreen.TrySelectSub(newSub.Name, newSub.MD5Hash.Hash, GameMain.NetLobbyScreen.ShuttleList.ListBox);
}
Pair<string, string> failedCampaignSub = GameMain.NetLobbyScreen.FailedCampaignSubs.Find(s => s.First == newSub.Name && s.Second == newSub.MD5Hash.Hash);
if (failedCampaignSub != null)
NetLobbyScreen.FailedSubInfo failedCampaignSub = GameMain.NetLobbyScreen.FailedCampaignSubs.Find(s => s.Name == newSub.Name && s.Hash == newSub.MD5Hash.Hash);
if (failedCampaignSub != default)
{
GameMain.NetLobbyScreen.CampaignSubmarines.Add(newSub);
GameMain.NetLobbyScreen.FailedCampaignSubs.Remove(failedCampaignSub);
}
Pair<string, string> failedOwnedSub = GameMain.NetLobbyScreen.FailedOwnedSubs.Find(s => s.First == newSub.Name && s.Second == newSub.MD5Hash.Hash);
if (failedOwnedSub != null)
NetLobbyScreen.FailedSubInfo failedOwnedSub = GameMain.NetLobbyScreen.FailedOwnedSubs.Find(s => s.Name == newSub.Name && s.Hash == newSub.MD5Hash.Hash);
if (failedOwnedSub != default)
{
GameMain.NetLobbyScreen.ServerOwnedSubmarines.Add(newSub);
GameMain.NetLobbyScreen.FailedOwnedSubs.Remove(failedOwnedSub);
@@ -2946,7 +2936,6 @@ namespace Barotrauma.Networking
IWriteMessage msg = new WriteOnlyMessage();
msg.Write((byte)ClientPacketHeader.SERVER_COMMAND);
msg.Write((UInt16)ClientPermissions.SelectSub);
msg.Write(false);
msg.Write(isShuttle); msg.WritePadBits();
msg.Write((UInt16)subIndex);
msg.Write((byte)ServerNetObject.END_OF_MESSAGE);
@@ -2954,23 +2943,6 @@ namespace Barotrauma.Networking
clientPeer.Send(msg, DeliveryMethod.Reliable);
}
/// <summary>
/// Tell the server to add / remove a purchasable submarine (permission required)
/// </summary>
public void RequestCampaignSub(SubmarineInfo sub, bool add)
{
if (!HasPermission(ClientPermissions.SelectSub) || sub == null) return;
IWriteMessage msg = new WriteOnlyMessage();
msg.Write((byte)ClientPacketHeader.SERVER_COMMAND);
msg.Write((UInt16)ClientPermissions.SelectSub);
msg.Write(true);
msg.Write(sub.EqualityCheckVal);
msg.Write(add);
msg.Write((byte)ServerNetObject.END_OF_MESSAGE);
clientPeer.Send(msg, DeliveryMethod.Reliable);
}
/// <summary>
/// Tell the server to select a mode (permission required)
/// </summary>
@@ -233,7 +233,7 @@ namespace Barotrauma.Networking
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("ClientEntityEventManager.Read:BitPosMismatch", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("ClientEntityEventManager.Read:BitPosMismatch", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
//TODO: force the BitPosition to correct place? Having some entity in a potentially incorrect state is not as bad as a desync kick
//msg.BitPosition = (int)(msgPosition + msgLength * 8);
@@ -252,7 +252,7 @@ namespace Barotrauma.Networking
DebugConsole.ThrowError("Failed to read event for entity \"" + entity.ToString() + "\"!", e);
GameAnalyticsManager.AddErrorEventOnce("ClientEntityEventManager.Read:ReadFailed" + entity.ToString(),
GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
msg.BitPosition = (int)(msgPosition + msgLength * 8);
msg.ReadPadBits();
}
@@ -115,13 +115,11 @@ namespace Barotrauma.Networking
{
if (!isActive) { return; }
byte incByte = inc.ReadByte();
bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
bool isConnectionInitializationStep = (incByte & (byte)PacketHeader.IsConnectionInitializationStep) != 0;
PacketHeader packetHeader = (PacketHeader)inc.ReadByte();
//Console.WriteLine(isCompressed + " " + isConnectionInitializationStep + " " + (int)incByte);
if (isConnectionInitializationStep && initializationStep != ConnectionInitialization.Success)
if (packetHeader.IsConnectionInitializationStep() && initializationStep != ConnectionInitialization.Success)
{
ReadConnectionInitializationStep(new ReadWriteMessage(inc.Data, (int)inc.Position, inc.LengthBits, false));
}
@@ -133,7 +131,7 @@ namespace Barotrauma.Networking
initializationStep = ConnectionInitialization.Success;
}
UInt16 length = inc.ReadUInt16();
IReadMessage msg = new ReadOnlyMessage(inc.Data, isCompressed, inc.PositionInBytes, length, ServerConnection);
IReadMessage msg = new ReadOnlyMessage(inc.Data, packetHeader.IsCompressed(), inc.PositionInBytes, length, ServerConnection);
OnMessageReceived?.Invoke(msg);
}
}
@@ -112,33 +112,28 @@ namespace Barotrauma.Networking
NetworkConnection.TimeoutThresholdInGame :
NetworkConnection.TimeoutThreshold;
byte incByte = data[0];
bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
bool isConnectionInitializationStep = (incByte & (byte)PacketHeader.IsConnectionInitializationStep) != 0;
bool isDisconnectMessage = (incByte & (byte)PacketHeader.IsDisconnectMessage) != 0;
bool isServerMessage = (incByte & (byte)PacketHeader.IsServerMessage) != 0;
bool isHeartbeatMessage = (incByte & (byte)PacketHeader.IsHeartbeatMessage) != 0;
PacketHeader packetHeader = (PacketHeader)data[0];
if (!isServerMessage) { return; }
if (!packetHeader.IsServerMessage()) { return; }
if (isConnectionInitializationStep)
if (packetHeader.IsConnectionInitializationStep())
{
ulong low = Lidgren.Network.NetBitWriter.ReadUInt32(data, 32, 8);
ulong high = Lidgren.Network.NetBitWriter.ReadUInt32(data, 32, 8 + 32);
ulong lobbyId = low + (high << 32);
Steam.SteamManager.JoinLobby(lobbyId, false);
IReadMessage inc = new ReadOnlyMessage(data, false, 1 + 8, dataLength - 9, ServerConnection);
IReadMessage inc = new ReadOnlyMessage(data, false, 1 + 8, dataLength - (1 + 8), ServerConnection);
if (initializationStep != ConnectionInitialization.Success)
{
incomingInitializationMessages.Add(inc);
}
}
else if (isHeartbeatMessage)
else if (packetHeader.IsHeartbeatMessage())
{
return; //TODO: implement heartbeats
}
else if (isDisconnectMessage)
else if (packetHeader.IsDisconnectMessage())
{
IReadMessage inc = new ReadOnlyMessage(data, false, 1, dataLength - 1, ServerConnection);
string msg = inc.ReadString();
@@ -147,10 +142,9 @@ namespace Barotrauma.Networking
}
else
{
UInt16 length = data[1];
length |= (UInt16)(((UInt32)data[2]) << 8);
UInt16 length = Lidgren.Network.NetBitWriter.ReadUInt16(data, 16, 8);
IReadMessage inc = new ReadOnlyMessage(data, isCompressed, 3, length, ServerConnection);
IReadMessage inc = new ReadOnlyMessage(data, packetHeader.IsCompressed(), 3, length, ServerConnection);
incomingDataMessages.Add(inc);
}
}
@@ -147,18 +147,13 @@ namespace Barotrauma.Networking
DeliveryMethod deliveryMethod = (DeliveryMethod)data[0];
byte incByte = data[1];
bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
bool isConnectionInitializationStep = (incByte & (byte)PacketHeader.IsConnectionInitializationStep) != 0;
bool isDisconnectMessage = (incByte & (byte)PacketHeader.IsDisconnectMessage) != 0;
bool isServerMessage = (incByte & (byte)PacketHeader.IsServerMessage) != 0;
bool isHeartbeatMessage = (incByte & (byte)PacketHeader.IsHeartbeatMessage) != 0;
PacketHeader packetHeader = (PacketHeader)data[1];
if (!remotePeer.Authenticated & !remotePeer.Authenticating && isConnectionInitializationStep)
if (!remotePeer.Authenticated & !remotePeer.Authenticating && packetHeader.IsConnectionInitializationStep())
{
remotePeer.DisconnectTime = null;
IReadMessage authMsg = new ReadOnlyMessage(data, isCompressed, 2, dataLength - 2, null);
IReadMessage authMsg = new ReadOnlyMessage(data, packetHeader.IsCompressed(), 2, dataLength - 2, null);
ConnectionInitialization initializationStep = (ConnectionInitialization)authMsg.ReadByte();
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion)
{
@@ -242,17 +237,11 @@ namespace Barotrauma.Networking
int p2pDataStart = inc.BytePosition;
byte incByte = inc.ReadByte();
bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
bool isConnectionInitializationStep = (incByte & (byte)PacketHeader.IsConnectionInitializationStep) != 0;
bool isDisconnectMessage = (incByte & (byte)PacketHeader.IsDisconnectMessage) != 0;
bool isServerMessage = (incByte & (byte)PacketHeader.IsServerMessage) != 0;
bool isHeartbeatMessage = (incByte & (byte)PacketHeader.IsHeartbeatMessage) != 0;
PacketHeader packetHeader = (PacketHeader)inc.ReadByte();
if (recipientSteamId != selfSteamID)
{
if (!isServerMessage)
if (!packetHeader.IsServerMessage())
{
DebugConsole.ThrowError("Received non-server message meant for remote peer");
return;
@@ -262,7 +251,7 @@ namespace Barotrauma.Networking
if (peer == null) { return; }
if (isDisconnectMessage)
if (packetHeader.IsDisconnectMessage())
{
DisconnectPeer(peer, inc.ReadString());
return;
@@ -273,8 +262,8 @@ namespace Barotrauma.Networking
{
case DeliveryMethod.Reliable:
case DeliveryMethod.ReliableOrdered:
//the documentation seems to suggest that the Reliable send type
//enforces packet order (TODO: verify)
//the documentation seems to suggest that the
//Reliable send type enforces packet order
sendType = Steamworks.P2PSend.Reliable;
break;
default:
@@ -284,17 +273,31 @@ namespace Barotrauma.Networking
byte[] p2pData;
if (isConnectionInitializationStep)
if (packetHeader.IsConnectionInitializationStep())
{
p2pData = new byte[inc.LengthBytes - p2pDataStart + 8];
p2pData[0] = inc.Buffer[p2pDataStart];
Lidgren.Network.NetBitWriter.WriteUInt64(SteamManager.CurrentLobbyID, 64, p2pData, 8);
Array.Copy(inc.Buffer, p2pDataStart+1, p2pData, 9, inc.LengthBytes - p2pDataStart - 1);
Lidgren.Network.NetBitWriter.WriteUInt64(SteamManager.CurrentLobbyID, 8 * 8, p2pData, 1 * 8);
Array.Copy(inc.Buffer, p2pDataStart+1, p2pData, 1 + 8, inc.LengthBytes - p2pDataStart - 1);
}
else
{
p2pData = new byte[inc.LengthBytes - p2pDataStart];
Array.Copy(inc.Buffer, p2pDataStart, p2pData, 0, p2pData.Length);
if (!packetHeader.IsHeartbeatMessage() && !packetHeader.IsDisconnectMessage())
{
UInt16 length = Lidgren.Network.NetBitWriter.ReadUInt16(p2pData, 16, 8);
if (length > p2pData.Length - 2)
{
string errorMsg = $"Length written in message to send to client is larger than buffer size ({length} > {p2pData.Length - 2})";
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce(
"SteamP2POwnerPeerLengthValidationFail",
GameAnalyticsManager.ErrorSeverity.Error,
errorMsg);
}
}
}
if (p2pData.Length + 4 >= MsgConstants.MTU)
@@ -323,21 +326,21 @@ namespace Barotrauma.Networking
}
else
{
if (isDisconnectMessage)
if (packetHeader.IsDisconnectMessage())
{
DebugConsole.ThrowError("Received disconnect message from owned server");
return;
}
if (!isServerMessage)
if (!packetHeader.IsServerMessage())
{
DebugConsole.ThrowError("Received non-server message from owned server");
return;
}
if (isHeartbeatMessage)
if (packetHeader.IsHeartbeatMessage())
{
return; //timeout is handled by Lidgren, ignore this message
return; //no timeout since we're using pipes, ignore this message
}
if (isConnectionInitializationStep)
if (packetHeader.IsConnectionInitializationStep())
{
IWriteMessage outMsg = new WriteOnlyMessage();
outMsg.Write(selfSteamID);
@@ -358,7 +361,7 @@ namespace Barotrauma.Networking
initializationStep = ConnectionInitialization.Success;
}
UInt16 length = inc.ReadUInt16();
IReadMessage msg = new ReadOnlyMessage(inc.Buffer, isCompressed, inc.BytePosition, length, ServerConnection);
IReadMessage msg = new ReadOnlyMessage(inc.Buffer, packetHeader.IsCompressed(), inc.BytePosition, length, ServerConnection);
OnMessageReceived?.Invoke(msg);
return;
@@ -242,7 +242,8 @@ namespace Barotrauma.Networking
textBlock.ClickableAreas.Add(new GUITextBlock.ClickableArea()
{
Data = data,
OnClick = GameMain.NetLobbyScreen.SelectPlayer
OnClick = GameMain.NetLobbyScreen.SelectPlayer,
OnSecondaryClick = GameMain.NetLobbyScreen.ShowPlayerContextMenu
});
}
}
@@ -92,8 +92,9 @@ namespace Barotrauma.Networking
}
}
public void ClientAdminRead(IReadMessage incMsg)
public void ClientAdminRead(IReadMessage incMsg, NetFlags requiredFlags)
{
if (!requiredFlags.HasFlag(NetFlags.Properties)) { return; }
int count = incMsg.ReadUInt16();
for (int i = 0; i < count; i++)
{
@@ -128,8 +129,18 @@ namespace Barotrauma.Networking
{
cachedServerListInfo = null;
ServerName = incMsg.ReadString();
ServerMessageText = incMsg.ReadString();
NetFlags requiredFlags = (NetFlags)incMsg.ReadByte();
if (requiredFlags.HasFlag(NetFlags.Name))
{
ServerName = incMsg.ReadString();
}
if (requiredFlags.HasFlag(NetFlags.Message))
{
ServerMessageText = incMsg.ReadString();
}
PlayStyle = (PlayStyle)incMsg.ReadByte();
MaxPlayers = incMsg.ReadByte();
HasPassword = incMsg.ReadBoolean();
IsPublic = incMsg.ReadBoolean();
@@ -139,23 +150,23 @@ namespace Barotrauma.Networking
TickRate = incMsg.ReadRangedInteger(1, 60);
GameMain.NetworkMember.TickRate = TickRate;
ReadExtraCargo(incMsg);
if (requiredFlags.HasFlag(NetFlags.Properties))
{
ReadExtraCargo(incMsg);
}
ReadHiddenSubs(incMsg);
GameMain.NetLobbyScreen.UpdateSubVisibility();
Voting.ClientRead(incMsg);
bool isAdmin = incMsg.ReadBoolean();
incMsg.ReadPadBits();
if (isAdmin)
{
ClientAdminRead(incMsg);
ClientAdminRead(incMsg, requiredFlags);
}
}
public void ClientAdminWrite(NetFlags dataToSend, int? missionTypeOr = null, int? missionTypeAnd = null, float? levelDifficulty = null, bool? autoRestart = null, int traitorSetting = 0, int botCount = 0, int botSpawnMode = 0, bool? radiationEnabled = null, bool? useRespawnShuttle = null, int maxMissionCount = 0)
public void ClientAdminWrite(NetFlags dataToSend, int? missionTypeOr = null, int? missionTypeAnd = null, float? levelDifficulty = null, bool? autoRestart = null, int traitorSetting = 0, int botCount = 0, int botSpawnMode = 0, bool? useRespawnShuttle = null)
{
if (!GameMain.Client.HasPermission(Networking.ClientPermissions.ManageSettings)) return;
@@ -225,8 +236,6 @@ namespace Barotrauma.Networking
outMsg.Write(autoRestart != null);
outMsg.Write(autoRestart ?? false);
outMsg.Write(radiationEnabled ?? RadiationEnabled);
outMsg.Write((byte)maxMissionCount + 1);
outMsg.WritePadBits();
}
@@ -711,7 +720,6 @@ namespace Barotrauma.Networking
RelativeSpacing = 0.05f
};
if (ip.InventoryIcon != null || ip.sprite != null)
{
GUIImage img = new GUIImage(new RectTransform(new Point(itemFrame.Rect.Height), itemFrame.RectTransform),
@@ -734,7 +742,7 @@ namespace Barotrauma.Networking
GUINumberInput.NumberType.Int, textAlignment: Alignment.CenterLeft)
{
MinValueInt = 0,
MaxValueInt = 100,
MaxValueInt = MaxExtraCargoItemsOfType,
IntValue = cargoVal
};
amountInput.OnValueChanged += (numberInput) =>
@@ -742,16 +750,26 @@ namespace Barotrauma.Networking
if (ExtraCargo.ContainsKey(ip))
{
ExtraCargo[ip] = numberInput.IntValue;
if (numberInput.IntValue <= 0) ExtraCargo.Remove(ip);
if (numberInput.IntValue <= 0) { ExtraCargo.Remove(ip); }
}
else
else if (ExtraCargo.Keys.Count() < MaxExtraCargoItemTypes)
{
ExtraCargo.Add(ip, numberInput.IntValue);
}
numberInput.IntValue = ExtraCargo.ContainsKey(ip) ? ExtraCargo[ip] : 0;
CoroutineManager.Invoke(() =>
{
foreach (var child in cargoFrame.Content.GetAllChildren())
{
if (child.GetChild<GUINumberInput>() is GUINumberInput otherNumberInput)
{
otherNumberInput.PlusButton.Enabled = ExtraCargo.Keys.Count() < MaxExtraCargoItemTypes && otherNumberInput.IntValue < otherNumberInput.MaxValueInt;
}
}
}, 0.0f);
};
}
//--------------------------------------------------------------------------------
// antigriefing
//--------------------------------------------------------------------------------
@@ -913,6 +931,7 @@ namespace Barotrauma.Networking
//--------------------------------------------------------------------------------
Whitelist.CreateWhiteListFrame(settingsTabs[(int)SettingsTab.Whitelist]);
Whitelist.localEnabled = Whitelist.Enabled;
}
private void CreateLabeledSlider(GUIComponent parent, string labelTag, out GUIScrollBar slider, out GUITextBlock label)
@@ -147,7 +147,14 @@ namespace Barotrauma.Steam
if (currentLobby == null)
{
DebugConsole.ThrowError("Failed to create Steam lobby");
DebugConsole.ThrowError("Failed to create Steam lobby: returned lobby was null");
lobbyState = LobbyState.NotConnected;
return;
}
if (currentLobby.Value.Result != Steamworks.Result.OK)
{
DebugConsole.ThrowError($"Failed to create Steam lobby: result was {currentLobby.Value.Result}");
lobbyState = LobbyState.NotConnected;
return;
}
@@ -525,18 +532,6 @@ namespace Barotrauma.Steam
}
#region Connecting to servers
private static Steamworks.AuthTicket currentTicket = null;
public static Steamworks.AuthTicket GetAuthSessionTicket()
{
if (!isInitialized)
{
return null;
}
currentTicket?.Cancel();
currentTicket = Steamworks.SteamUser.GetAuthSessionTicket();
return currentTicket;
}
public static Steamworks.BeginAuthResult StartAuthSession(byte[] authTicketData, ulong clientSteamID)
{
@@ -884,9 +879,9 @@ namespace Barotrauma.Steam
catch (Exception e)
{
string errorMsg = "Failed to save workshop item preview image to \"" + previewImagePath + "\" when creating workshop item staging folder.";
string errorMsg = "Failed to save workshop item preview image when creating workshop item staging folder.";
GameAnalyticsManager.AddErrorEventOnce("SteamManager.CreateWorkshopItemStaging:WriteAllBytesFailed" + previewImagePath,
GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + "\n" + e.Message);
GameAnalyticsManager.ErrorSeverity.Error, errorMsg + "\n" + e.Message);
}
return true;
@@ -1434,8 +1429,8 @@ namespace Barotrauma.Steam
"\" not found. Could not combine path (" + (item.Directory ?? "directory name empty") + ").";
DebugConsole.ThrowError(errorMessage);
GameAnalyticsManager.AddErrorEventOnce("SteamManager.CheckWorkshopItemInstalled:PathCombineException" + item.Title,
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
errorMessage);
GameAnalyticsManager.ErrorSeverity.Error,
"Metadata file for a Workshop item not found. Could not combine path.");
return false;
}
@@ -1567,8 +1562,8 @@ namespace Barotrauma.Steam
}
GameAnalyticsManager.AddErrorEventOnce(
"SteamManager.AutoUpdateWorkshopItems:" + e.Message,
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Failed to autoupdate workshop item \"" + item.Title + "\". " + e.Message + "\n" + e.StackTrace.CleanupStackTrace());
GameAnalyticsManager.ErrorSeverity.Error,
"Failed to autoupdate workshop item. " + e.Message + "\n" + e.StackTrace.CleanupStackTrace());
});
}
}
@@ -113,7 +113,7 @@ namespace Barotrauma.Networking
UserData = "capturedevicenotfound"
};
}
GameAnalyticsManager.AddErrorEventOnce("Alc.CaptureDeviceOpenFailed", GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
GameAnalyticsManager.AddErrorEventOnce("Alc.CaptureDeviceOpenFailed", GameAnalyticsManager.ErrorSeverity.Error,
"Alc.CaptureDeviceOpen(" + deviceName + ") failed. Error code: " + errorCode);
GameMain.Config.VoiceSetting = GameSettings.VoiceMode.Disabled;
Instance?.Dispose();
@@ -56,17 +56,12 @@ namespace Barotrauma.Networking
{
nameBox.Enabled = box.Selected;
ipBox.Enabled = box.Selected;
addNewButton.Enabled = box.Selected;
addNewButton.Enabled = box.Selected && !string.IsNullOrEmpty(ipBox.Text) && !string.IsNullOrEmpty(nameBox.Text);
localEnabled = box.Selected;
return true;
}
};
localEnabled = Enabled;
var listBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.7f), whitelistFrame.RectTransform));
foreach (WhiteListedPlayer wlp in whitelistedPlayers)
{
@@ -136,7 +136,7 @@ namespace Barotrauma.Particles
Prefab = prefab;
}
public void Emit(float deltaTime, Vector2 position, Hull hullGuess = null, float angle = 0.0f, float particleRotation = 0.0f, float velocityMultiplier = 1.0f, float sizeMultiplier = 1.0f, float amountMultiplier = 1.0f, Color? colorMultiplier = null, ParticlePrefab overrideParticle = null, Tuple<Vector2, Vector2> tracerPoints = null)
public void Emit(float deltaTime, Vector2 position, Hull hullGuess = null, float angle = 0.0f, float particleRotation = 0.0f, float velocityMultiplier = 1.0f, float sizeMultiplier = 1.0f, float amountMultiplier = 1.0f, Color? colorMultiplier = null, ParticlePrefab overrideParticle = null, bool mirrorAngle = false, Tuple<Vector2, Vector2> tracerPoints = null)
{
if (GameMain.Client?.MidRoundSyncing ?? false) { return; }
@@ -159,7 +159,7 @@ namespace Barotrauma.Particles
for (float z = 0.0f; z < dist; z += Prefab.Properties.EmitAcrossRayInterval)
{
Vector2 pos = tracerPoints.Item1 + dir * z;
Emit(pos, hullGuess, angle, particleRotation, velocityMultiplier, sizeMultiplier, colorMultiplier, overrideParticle, tracerPoints: null);
Emit(pos, hullGuess, angle, particleRotation, velocityMultiplier, sizeMultiplier, colorMultiplier, overrideParticle, mirrorAngle, tracerPoints: null);
}
}
}
@@ -169,7 +169,7 @@ namespace Barotrauma.Particles
float emitInterval = 1.0f / Prefab.Properties.ParticlesPerSecond;
while (emitTimer > emitInterval)
{
Emit(position, hullGuess, angle, particleRotation, velocityMultiplier, sizeMultiplier, colorMultiplier, overrideParticle, tracerPoints: tracerPoints);
Emit(position, hullGuess, angle, particleRotation, velocityMultiplier, sizeMultiplier, colorMultiplier, overrideParticle, mirrorAngle, tracerPoints: tracerPoints);
emitTimer -= emitInterval;
}
}
@@ -183,7 +183,7 @@ namespace Barotrauma.Particles
}
}
private void Emit(Vector2 position, Hull hullGuess, float angle, float particleRotation, float velocityMultiplier, float sizeMultiplier, Color? colorMultiplier = null, ParticlePrefab overrideParticle = null, Tuple<Vector2, Vector2> tracerPoints = null)
private void Emit(Vector2 position, Hull hullGuess, float angle, float particleRotation, float velocityMultiplier, float sizeMultiplier, Color? colorMultiplier = null, ParticlePrefab overrideParticle = null, bool mirrorAngle = false, Tuple<Vector2, Vector2> tracerPoints = null)
{
var particlePrefab = overrideParticle ?? Prefab.ParticlePrefab;
if (particlePrefab == null) { return; }
@@ -191,7 +191,7 @@ namespace Barotrauma.Particles
Vector2 velocity = Vector2.Zero;
if (!MathUtils.NearlyEqual(Prefab.Properties.VelocityMax * velocityMultiplier, 0.0f) || !MathUtils.NearlyEqual(Prefab.Properties.DistanceMax, 0.0f))
{
angle += Rand.Range(Prefab.Properties.AngleMinRad, Prefab.Properties.AngleMaxRad);
angle += Rand.Range(Prefab.Properties.AngleMinRad, Prefab.Properties.AngleMaxRad) * (mirrorAngle ? -1 : 1);
Vector2 dir = new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle));
velocity = dir * Rand.Range(Prefab.Properties.VelocityMin, Prefab.Properties.VelocityMax) * velocityMultiplier;
position += dir * Rand.Range(Prefab.Properties.DistanceMin, Prefab.Properties.DistanceMax);
@@ -201,7 +201,7 @@ namespace Barotrauma
DebugConsole.ThrowError(errorMsg);
#endif
GameAnalyticsManager.AddErrorEventOnce("PhysicsBody.ClientRead:InvalidData" + parentDebugName,
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
GameAnalyticsManager.ErrorSeverity.Error,
errorMsg);
return null;
}
@@ -1,11 +1,9 @@
#region Using Statements
using System;
using System.Collections.Generic;
using Barotrauma.IO;
using System.Linq;
using System.Text;
using GameAnalyticsSDK.Net;
using Barotrauma.Steam;
using System.Diagnostics;
using System.Runtime.InteropServices;
@@ -245,6 +243,13 @@ namespace Barotrauma
}
}
if (GameAnalyticsManager.SendUserStatistics)
{
//send crash report before appending debug console messages (which may contain non-anonymous information)
GameAnalyticsManager.AddErrorEvent(GameAnalyticsManager.ErrorSeverity.Critical, sb.ToString());
GameAnalyticsManager.ShutDown();
}
sb.AppendLine("Last debug messages:");
for (int i = DebugConsole.Messages.Count - 1; i >= 0; i--)
{
@@ -257,11 +262,9 @@ namespace Barotrauma
if (GameSettings.SaveDebugConsoleLogs || GameSettings.VerboseLogging) { DebugConsole.SaveLogs(); }
if (GameSettings.SendUserStatistics)
if (GameAnalyticsManager.SendUserStatistics)
{
CrashMessageBox("A crash report (\"" + filePath + "\") was saved in the root folder of the game and sent to the developers.", filePath);
GameAnalytics.AddErrorEvent(EGAErrorSeverity.Critical, crashReport);
GameAnalytics.OnQuit();
}
else
{
@@ -7,14 +7,10 @@ namespace Barotrauma
{
protected readonly GUIComponent newGameContainer, loadGameContainer;
protected GUIListBox subList;
protected GUIListBox saveList;
protected List<GUITickBox> subTickBoxes;
protected GUITextBox saveNameBox, seedBox;
protected GUILayoutGroup subPreviewContainer;
protected GUIButton loadGameButton;
public Action<SubmarineInfo, string, string, CampaignSettings> StartNewGame;
@@ -7,6 +7,7 @@ using System.Linq;
using System.Xml.Linq;
using System.Globalization;
using Barotrauma.Extensions;
using Barotrauma.Networking;
namespace Barotrauma
{
@@ -14,55 +15,79 @@ namespace Barotrauma
{
private GUIButton deleteMpSaveButton;
public MultiPlayerCampaignSetupUI(GUIComponent newGameContainer, GUIComponent loadGameContainer, IEnumerable<SubmarineInfo> submarines, IEnumerable<string> saveFiles = null)
public MultiPlayerCampaignSetupUI(GUIComponent newGameContainer, GUIComponent loadGameContainer, IEnumerable<string> saveFiles = null)
: base(newGameContainer, loadGameContainer)
{
var columnContainer = new GUILayoutGroup(new RectTransform(Vector2.One, newGameContainer.RectTransform), isHorizontal: true)
var verticalLayout = new GUILayoutGroup(new RectTransform(Vector2.One, newGameContainer.RectTransform), isHorizontal: false)
{
Stretch = true,
RelativeSpacing = 0.0f
};
var leftColumn = new GUILayoutGroup(new RectTransform(Vector2.One, columnContainer.RectTransform))
{
Stretch = true,
RelativeSpacing = 0.015f
};
var rightColumn = new GUILayoutGroup(new RectTransform(Vector2.Zero, columnContainer.RectTransform))
{
Stretch = true,
RelativeSpacing = 0.015f
};
columnContainer.Recalculate();
// New game left side
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, TextManager.Get("SaveName"), font: GUI.SubHeadingFont);
saveNameBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, string.Empty)
// New game
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.03f), verticalLayout.RectTransform) { MinSize = new Point(0, 20) }, TextManager.Get("SaveName"), font: GUI.SubHeadingFont, textAlignment: Alignment.BottomLeft);
saveNameBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.03f), verticalLayout.RectTransform) { MinSize = new Point(0, 20) }, string.Empty)
{
textFilterFunction = (string str) => { return ToolBox.RemoveInvalidFileNameChars(str); }
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, TextManager.Get("MapSeed"), font: GUI.SubHeadingFont);
seedBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, ToolBox.RandomSeed(8));
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.03f), verticalLayout.RectTransform) { MinSize = new Point(0, 20) }, TextManager.Get("MapSeed"), font: GUI.SubHeadingFont, textAlignment: Alignment.BottomLeft);
seedBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.03f), verticalLayout.RectTransform) { MinSize = new Point(0, 20) }, ToolBox.RandomSeed(8));
// Spacing to fix the multiplayer campaign setup layout
CreateMultiplayerCampaignSubList(leftColumn.RectTransform);
//spacing
//new GUIFrame(new RectTransform(new Vector2(1.0f, 0.25f), leftColumn.RectTransform), style: null);
// New game right side
subPreviewContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), rightColumn.RectTransform))
GUIFrame radiationBoxContainer
= new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), verticalLayout.RectTransform), style: null);
GUITickBox radiationEnabledTickBox = null;
if (MapGenerationParams.Instance.RadiationParams != null)
{
Stretch = true
radiationEnabledTickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.5f), radiationBoxContainer.RectTransform, Anchor.Center), TextManager.Get("CampaignOption.EnableRadiation"), font: GUI.Style.Font)
{
Selected = true,
OnSelected = box => true
};
}
var maxMissionCountSettingHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), verticalLayout.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft) { Stretch = true };
var maxMissionCountDescription = new GUITextBlock(new RectTransform(new Vector2(0.7f, 0.0f), maxMissionCountSettingHolder.RectTransform), TextManager.Get("maxmissioncount", fallBackTag: "missions"), wrap: true)
{
ToolTip = TextManager.Get("maxmissioncounttooltip")
};
int maxMissionCount = GameMain.NetworkMember.ServerSettings.MaxMissionCount;
var maxMissionCountContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), maxMissionCountSettingHolder.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft) { RelativeSpacing = 0.05f, Stretch = true };
var maxMissionCountButtons = new GUIButton[2];
maxMissionCountButtons[0]
= new GUIButton(new RectTransform(new Vector2(0.15f, 1.0f), maxMissionCountContainer.RectTransform),
style: "GUIButtonToggleLeft");
var maxMissionCountText = new GUITextBlock(new RectTransform(new Vector2(0.7f, 1.0f), maxMissionCountContainer.RectTransform), "0", textAlignment: Alignment.Center, style: "GUITextBox");
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.12f),
leftColumn.RectTransform) { MaxSize = new Point(int.MaxValue, 60) }, childAnchor: Anchor.BottomRight, isHorizontal: true);
void updateMissionCountText()
{
maxMissionCount = MathHelper.Clamp(maxMissionCount,
CampaignSettings.MinMissionCountLimit,
CampaignSettings.MaxMissionCountLimit);
maxMissionCountText.Text = maxMissionCount.ToString(CultureInfo.InvariantCulture);
}
maxMissionCountButtons[1]
= new GUIButton(new RectTransform(new Vector2(0.15f, 1.0f), maxMissionCountContainer.RectTransform),
style: "GUIButtonToggleRight");
maxMissionCountButtons[0].OnClicked = (button, o) =>
{
maxMissionCount--;
updateMissionCountText();
return false;
};
maxMissionCountButtons[1].OnClicked = (button, o) =>
{
maxMissionCount++;
updateMissionCountText();
return false;
};
updateMissionCountText();
maxMissionCountSettingHolder.Children.ForEach(c => c.ToolTip = maxMissionCountSettingHolder.ToolTip);
StartButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1f), buttonContainer.RectTransform, Anchor.BottomRight) { MaxSize = new Point(350, 60) }, TextManager.Get("StartCampaignButton"))
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.04f),
verticalLayout.RectTransform) { MaxSize = new Point(int.MaxValue, 60) }, childAnchor: Anchor.BottomRight, isHorizontal: true);
StartButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1f), buttonContainer.RectTransform, Anchor.BottomRight), TextManager.Get("StartCampaignButton"))
{
OnClicked = (GUIButton btn, object userData) =>
{
@@ -85,20 +110,19 @@ namespace Barotrauma
if (string.IsNullOrEmpty(selectedSub.MD5Hash.Hash))
{
((GUITextBlock)subList.SelectedComponent).TextColor = Color.DarkRed * 0.8f;
subList.SelectedComponent.CanBeFocused = false;
subList.Deselect();
new GUIMessageBox(TextManager.Get("error"), TextManager.Get("nohashsubmarineselected"));
return false;
}
string savePath = SaveUtil.CreateSavePath(SaveUtil.SaveType.Multiplayer, saveNameBox.Text);
bool hasRequiredContentPackages = selectedSub.RequiredContentPackagesInstalled;
CampaignSettings settings = new CampaignSettings();
CampaignSettings settings = new CampaignSettings
{
RadiationEnabled = radiationEnabledTickBox?.Selected ?? GameMain.NetworkMember.ServerSettings.RadiationEnabled,
MaxMissionCount = maxMissionCount
};
settings.RadiationEnabled = GameMain.NetLobbyScreen.IsRadiationEnabled();
settings.MaxMissionCount = GameMain.NetLobbyScreen.GetMaxMissionCount();
if (selectedSub.HasTag(SubmarineTag.Shuttle) || !hasRequiredContentPackages)
{
if (!hasRequiredContentPackages)
@@ -148,7 +172,9 @@ namespace Barotrauma
return true;
}
};
StartButton.RectTransform.MaxSize = RectTransform.MaxPoint;
StartButton.Children.ForEach(c => c.RectTransform.MaxSize = RectTransform.MaxPoint);
InitialMoneyText = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1f), buttonContainer.RectTransform), "", font: GUI.Style.SmallFont, textColor: GUI.Style.Green)
{
TextGetter = () =>
@@ -163,114 +189,11 @@ namespace Barotrauma
}
};
columnContainer.Recalculate();
leftColumn.Recalculate();
rightColumn.Recalculate();
verticalLayout.Recalculate();
if (submarines != null) { UpdateSubList(submarines); }
UpdateLoadMenu(saveFiles);
}
private void CreateMultiplayerCampaignSubList(RectTransform parent)
{
GUILayoutGroup subHolder = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.725f), parent))
{
RelativeSpacing = 0.005f,
Stretch = true
};
var subLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.055f), subHolder.RectTransform) { MinSize = new Point(0, 25) }, TextManager.Get("purchasablesubmarines", fallBackTag: "workshoplabelsubmarines"), font: GUI.SubHeadingFont);
var filterContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), subHolder.RectTransform), isHorizontal: true)
{
Stretch = true
};
var searchTitle = new GUITextBlock(new RectTransform(new Vector2(0.001f, 1.0f), filterContainer.RectTransform), TextManager.Get("serverlog.filter"), textAlignment: Alignment.CenterLeft, font: GUI.Font);
var searchBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 1.0f), filterContainer.RectTransform, Anchor.CenterRight), font: GUI.Font, createClearButton: true);
filterContainer.RectTransform.MinSize = searchBox.RectTransform.MinSize;
searchBox.OnSelected += (sender, userdata) => { searchTitle.Visible = false; };
searchBox.OnDeselected += (sender, userdata) => { searchTitle.Visible = true; };
searchBox.OnTextChanged += (textBox, text) =>
{
foreach (GUIComponent child in subList.Content.Children)
{
if (!(child.UserData is SubmarineInfo sub)) { continue; }
child.Visible = string.IsNullOrEmpty(text) ? true : sub.DisplayName.ToLower().Contains(text.ToLower());
}
return true;
};
subList = new GUIListBox(new RectTransform(Vector2.One, subHolder.RectTransform));
subTickBoxes = new List<GUITickBox>();
for (int i = 0; i < GameMain.Client.ServerSubmarines.Count; i++)
{
SubmarineInfo sub = GameMain.Client.ServerSubmarines[i];
if (!sub.IsCampaignCompatible) continue;
var frame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.2f), subList.Content.RectTransform) { MinSize = new Point(0, 20) },
style: "ListBoxElement")
{
ToolTip = sub.Description,
UserData = sub
};
int buttonSize = (int)(frame.Rect.Height * 0.8f);
GUITickBox tickBox = new GUITickBox(new RectTransform(new Vector2(0.8f, 1.0f), frame.RectTransform, Anchor.CenterLeft), ToolBox.LimitString(sub.DisplayName, GUI.Font, subList.Content.Rect.Width - 65))
{
UserData = sub,
OnSelected = (GUITickBox box) =>
{
GameMain.Client.RequestCampaignSub(box.UserData as SubmarineInfo, box.Selected);
return true;
}
};
subTickBoxes.Add(tickBox);
tickBox.Selected = GameMain.NetLobbyScreen.CampaignSubmarines.Contains(sub);
frame.RectTransform.MinSize = new Point(0, tickBox.RectTransform.MinSize.Y);
var subTextBlock = tickBox.TextBlock;
var matchingSub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == sub.Name && s.MD5Hash?.Hash == sub.MD5Hash?.Hash);
if (matchingSub == null) matchingSub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == sub.Name);
if (matchingSub == null)
{
subTextBlock.TextColor = new Color(subTextBlock.TextColor, 0.5f);
frame.ToolTip = TextManager.Get("SubNotFound");
}
else if (matchingSub?.MD5Hash == null || matchingSub.MD5Hash?.Hash != sub.MD5Hash?.Hash)
{
subTextBlock.TextColor = new Color(subTextBlock.TextColor, 0.5f);
frame.ToolTip = TextManager.Get("SubDoesntMatch");
}
if (!sub.RequiredContentPackagesInstalled)
{
subTextBlock.TextColor = Color.Lerp(subTextBlock.TextColor, Color.DarkRed, 0.5f);
frame.ToolTip = TextManager.Get("ContentPackageMismatch") + "\n\n" + frame.RawToolTip;
}
var classText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), frame.RectTransform, Anchor.CenterRight),
TextManager.Get($"submarineclass.{sub.SubmarineClass}"), textAlignment: Alignment.CenterRight, font: GUI.SmallFont)
{
TextColor = subTextBlock.TextColor * 0.8f,
ToolTip = subTextBlock.RawToolTip
};
}
}
public void RefreshMultiplayerCampaignSubUI(List<SubmarineInfo> campaignSubs)
{
for (int i = 0; i < subTickBoxes.Count; i++)
{
subTickBoxes[i].Selected = campaignSubs.Contains(subTickBoxes[i].UserData as SubmarineInfo);
}
}
private IEnumerable<CoroutineStatus> WaitForCampaignSetup()
{
GUI.SetCursorWaiting();
@@ -298,64 +221,6 @@ namespace Barotrauma
yield return CoroutineStatus.Success;
}
public void UpdateSubList(IEnumerable<SubmarineInfo> submarines)
{
List<SubmarineInfo> subsToShow;
string downloadFolder = Path.GetFullPath(SaveUtil.SubmarineDownloadFolder);
subsToShow = submarines.Where(s => s.IsCampaignCompatibleIgnoreClass && Path.GetDirectoryName(Path.GetFullPath(s.FilePath)) != downloadFolder).ToList();
subsToShow.Sort((s1, s2) =>
{
int p1 = s1.Price > CampaignMode.InitialMoney ? 10 : 0;
int p2 = s2.Price > CampaignMode.InitialMoney ? 10 : 0;
return p1.CompareTo(p2) * 100 + s1.Name.CompareTo(s2.Name);
});
subList.ClearChildren();
foreach (SubmarineInfo sub in subsToShow)
{
var textBlock = new GUITextBlock(
new RectTransform(new Vector2(1, 0.1f), subList.Content.RectTransform) { MinSize = new Point(0, 30) },
ToolBox.LimitString(sub.DisplayName, GUI.Font, subList.Rect.Width - 65), style: "ListBoxElement")
{
ToolTip = sub.Description,
UserData = sub
};
if (!sub.RequiredContentPackagesInstalled)
{
textBlock.TextColor = Color.Lerp(textBlock.TextColor, Color.DarkRed, .5f);
textBlock.ToolTip = TextManager.Get("ContentPackageMismatch") + "\n\n" + textBlock.RawToolTip;
}
var priceText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), textBlock.RectTransform, Anchor.CenterRight),
TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", sub.Price)), textAlignment: Alignment.CenterRight, font: GUI.SmallFont)
{
TextColor = sub.Price > CampaignMode.InitialMoney ? GUI.Style.Red : textBlock.TextColor * 0.8f,
ToolTip = textBlock.ToolTip
};
#if !DEBUG
if (!GameMain.DebugDraw)
{
if (sub.Price > CampaignMode.InitialMoney || !sub.IsCampaignCompatible)
{
textBlock.CanBeFocused = false;
textBlock.TextColor *= 0.5f;
}
}
#endif
}
if (SubmarineInfo.SavedSubmarines.Any())
{
var validSubs = subsToShow.Where(s => s.IsCampaignCompatible && s.Price <= CampaignMode.InitialMoney).ToList();
if (validSubs.Count > 0)
{
subList.Select(validSubs[Rand.Int(validSubs.Count)]);
}
}
}
private List<string> prevSaveFiles;
public void UpdateLoadMenu(IEnumerable<string> saveFiles = null)
{
@@ -12,6 +12,10 @@ namespace Barotrauma
{
class SinglePlayerCampaignSetupUI : CampaignSetupUI
{
private GUIListBox subList;
protected GUILayoutGroup subPreviewContainer;
public CharacterInfo.AppearanceCustomizationMenu[] CharacterMenus { get; private set; }
private GUIButton nextButton;
@@ -38,7 +42,7 @@ namespace Barotrauma
pageContainer.BarScroll = targetScroll;
}
for (int i=0; i<CharacterMenus.Length; i++)
for (int i = 0; i < CharacterMenus.Length; i++)
{
CharacterMenus[i]?.Update();
}
@@ -77,6 +81,7 @@ namespace Barotrauma
{
ScrollBarEnabled = false,
ScrollBarVisible = false,
AllowArrowKeyScroll = false,
HoverCursor = CursorState.Default
};
@@ -705,7 +705,7 @@ namespace Barotrauma.CharacterEditor
{
string errorMsg = "Attempted to modify the state of the physics simulation while a time step was running.";
DebugConsole.ThrowError(errorMsg, e);
GameAnalyticsManager.AddErrorEventOnce("CharacterEditorScreen.Update:WorldLockedException" + e.Message, GameAnalyticsSDK.Net.EGAErrorSeverity.Critical, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("CharacterEditorScreen.Update:WorldLockedException" + e.Message, GameAnalyticsManager.ErrorSeverity.Critical, errorMsg);
}
}
// Camera
@@ -732,9 +732,7 @@ namespace Barotrauma
if (!string.IsNullOrEmpty(subName))
{
DebugConsole.NewMessage($"Loading the predefined quick start sub \"{subName}\"", Color.White);
selectedSub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s =>
s.Name.ToLower() == subName.ToLower());
selectedSub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name.ToLowerInvariant() == subName.ToLowerInvariant());
if (selectedSub == null)
{
DebugConsole.NewMessage($"Cannot find a sub that matches the name \"{subName}\".", Color.Red);
@@ -1055,17 +1053,23 @@ namespace Barotrauma
GUI.Draw(Cam, spriteBatch);
#if !UNSTABLE
string versionString = "Barotrauma v" + GameMain.Version + " (" + AssemblyInfo.BuildString + ", branch " + AssemblyInfo.GitBranch + ", revision " + AssemblyInfo.GitRevision + ")";
GUI.SmallFont.DrawString(spriteBatch, versionString, new Vector2(HUDLayoutSettings.Padding, GameMain.GraphicsHeight - GUI.SmallFont.MeasureString(versionString).Y - HUDLayoutSettings.Padding * 0.75f), Color.White * 0.7f);
#endif
if (selectedTab != Tab.Credits)
{
#if !UNSTABLE
string versionString = "Barotrauma v" + GameMain.Version + " (" + AssemblyInfo.BuildString + ", branch " + AssemblyInfo.GitBranch + ", revision " + AssemblyInfo.GitRevision + ")";
GUI.SmallFont.DrawString(spriteBatch, versionString, new Vector2(HUDLayoutSettings.Padding, GameMain.GraphicsHeight - GUI.SmallFont.MeasureString(versionString).Y - HUDLayoutSettings.Padding * 0.75f), Color.White * 0.7f);
#endif
string gameAnalyticsStatus = TextManager.Get($"GameAnalyticsStatus.{GameAnalyticsManager.UserConsented}");
Vector2 textSize = GUI.SmallFont.MeasureString(gameAnalyticsStatus).ToPoint().ToVector2();
GUI.SmallFont.DrawString(spriteBatch, gameAnalyticsStatus, new Vector2(HUDLayoutSettings.Padding, GameMain.GraphicsHeight - GUI.SmallFont.LineHeight * 2 - HUDLayoutSettings.Padding * 0.75f), Color.White * 0.7f);
Vector2 textPos = new Vector2(GameMain.GraphicsWidth - HUDLayoutSettings.Padding, GameMain.GraphicsHeight - HUDLayoutSettings.Padding * 0.75f);
for (int i = legalCrap.Length - 1; i >= 0; i--)
{
Vector2 textSize = GUI.SmallFont.MeasureString(legalCrap[i]);
textSize = new Vector2((int)textSize.X, (int)textSize.Y);
textSize = GUI.SmallFont.MeasureString(legalCrap[i])
.ToPoint().ToVector2();
bool mouseOn = i == 0 &&
PlayerInput.MousePosition.X > textPos.X - textSize.X && PlayerInput.MousePosition.X < textPos.X &&
PlayerInput.MousePosition.Y > textPos.Y - textSize.Y && PlayerInput.MousePosition.Y < textPos.Y;
@@ -1121,8 +1125,8 @@ namespace Barotrauma
DebugConsole.ThrowError("Copying the file \"" + selectedSub.FilePath + "\" failed. The file may have been deleted or in use by another process. Try again or select another submarine.", e);
GameAnalyticsManager.AddErrorEventOnce(
"MainMenuScreen.StartGame:IOException" + selectedSub.Name,
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Copying the file \"" + selectedSub.FilePath + "\" failed.\n" + e.Message + "\n" + Environment.StackTrace.CleanupStackTrace());
GameAnalyticsManager.ErrorSeverity.Error,
"Copying a submarine file failed. " + e.Message + "\n" + Environment.StackTrace.CleanupStackTrace());
return;
}
@@ -1446,7 +1450,7 @@ namespace Barotrauma
#if DEBUG
DebugConsole.ThrowError("Fetching remote content to the main menu failed.", e);
#endif
GameAnalyticsManager.AddErrorEventOnce("MainMenuScreen.FetchRemoteContent:Exception", GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
GameAnalyticsManager.AddErrorEventOnce("MainMenuScreen.FetchRemoteContent:Exception", GameAnalyticsManager.ErrorSeverity.Error,
"Fetching remote content to the main menu failed. " + e.Message);
return;
}
@@ -1489,7 +1493,7 @@ namespace Barotrauma
#if DEBUG
DebugConsole.ThrowError("Reading received remote main menu content failed.", e);
#endif
GameAnalyticsManager.AddErrorEventOnce("MainMenuScreen.WairForRemoteContentReceived:Exception", GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
GameAnalyticsManager.AddErrorEventOnce("MainMenuScreen.WairForRemoteContentReceived:Exception", GameAnalyticsManager.ErrorSeverity.Error,
"Reading received remote main menu content failed. " + e.Message);
}
}
@@ -7,6 +7,7 @@ using System.Collections.Generic;
using Barotrauma.IO;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.Steam;
namespace Barotrauma
{
@@ -40,12 +41,6 @@ namespace Barotrauma
private readonly GUIScrollBar levelDifficultyScrollBar;
private readonly GUITickBox radiationEnabledTickBox;
private readonly GUIButton[] maxMissionCountButtons;
private readonly GUITextBlock maxMissionCountText;
private readonly GUITextBlock maxMissionCountDescription;
private readonly GUIButton[] traitorProbabilityButtons;
private readonly GUITextBlock traitorProbabilityText;
@@ -192,6 +187,9 @@ namespace Barotrauma
}
}
public IReadOnlyList<SubmarineInfo> GetSubList()
=> SubList.Content.Children.Select(c => c.UserData as SubmarineInfo).ToArray();
public readonly GUIListBox PlayerList;
public GUITextBox CharacterNameBox
@@ -1185,45 +1183,6 @@ namespace Barotrauma
}
};
if (MapGenerationParams.Instance.RadiationParams != null)
{
radiationEnabledTickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.1f), settingsContent.RectTransform), TextManager.Get("CampaignOption.EnableRadiation"), font: GUI.Style.Font)
{
Selected = true,
OnSelected = box =>
{
GameMain.Client.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, radiationEnabled: box.Selected);
return true;
}
};
}
var maxMissionCountSettingHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), settingsContent.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft) { Stretch = true };
maxMissionCountDescription = new GUITextBlock(new RectTransform(new Vector2(0.7f, 0.0f), maxMissionCountSettingHolder.RectTransform), TextManager.Get("maxmissioncount", fallBackTag: "missions"), wrap: true)
{
ToolTip = TextManager.Get("maxmissioncounttooltip")
};
var maxMissionCountContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), maxMissionCountSettingHolder.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft) { RelativeSpacing = 0.05f, Stretch = true };
maxMissionCountButtons = new GUIButton[2];
maxMissionCountButtons[0] = new GUIButton(new RectTransform(new Vector2(0.15f, 1.0f), maxMissionCountContainer.RectTransform), style: "GUIButtonToggleLeft")
{
OnClicked = (button, obj) =>
{
GameMain.Client.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, maxMissionCount: -1);
return true;
}
};
maxMissionCountText = new GUITextBlock(new RectTransform(new Vector2(0.7f, 1.0f), maxMissionCountContainer.RectTransform), "0", textAlignment: Alignment.Center, style: "GUITextBox");
maxMissionCountButtons[1] = new GUIButton(new RectTransform(new Vector2(0.15f, 1.0f), maxMissionCountContainer.RectTransform), style: "GUIButtonToggleRight")
{
OnClicked = (button, obj) =>
{
GameMain.Client.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, maxMissionCount: 1);
return true;
}
};
maxMissionCountSettingHolder.Children.ForEach(c => c.ToolTip = maxMissionCountSettingHolder.ToolTip);
List<GUIComponent> settingsElements = settingsContent.Children.ToList();
for (int i = 0; i < settingsElements.Count; i++)
{
@@ -1372,16 +1331,6 @@ namespace Barotrauma
}
SeedBox.Enabled = !CampaignFrame.Visible && !CampaignSetupFrame.Visible && GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
levelDifficultyScrollBar.Enabled = !CampaignFrame.Visible && !CampaignSetupFrame.Visible && GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
if (radiationEnabledTickBox != null)
{
radiationEnabledTickBox.Enabled = CampaignSetupFrame.Visible && GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
}
maxMissionCountDescription.Enabled = CampaignSetupFrame.Visible && GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
maxMissionCountText.Enabled = CampaignSetupFrame.Visible && GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
foreach (var button in maxMissionCountButtons)
{
button.Enabled = CampaignSetupFrame.Visible && GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
}
traitorProbabilityButtons[0].Enabled = traitorProbabilityButtons[1].Enabled = traitorProbabilityText.Enabled =
!CampaignFrame.Visible && !CampaignSetupFrame.Visible && GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
@@ -2163,17 +2112,126 @@ namespace Barotrauma
if (child != null) { PlayerList.RemoveChild(child); }
}
private Client ExtractClientFromClickableArea(GUITextBlock.ClickableArea area)
{
if (!UInt64.TryParse(area.Data.Metadata, out UInt64 id)) { return null; }
Client client = GameMain.Client.ConnectedClients.Find(c => c.SteamID == id)
?? GameMain.Client.ConnectedClients.Find(c => c.ID == id)
?? GameMain.Client.PreviouslyConnectedClients.FirstOrDefault(c => c.SteamID == id)
?? GameMain.Client.PreviouslyConnectedClients.FirstOrDefault(c => c.ID == id);
return client;
}
public void SelectPlayer(GUITextBlock component, GUITextBlock.ClickableArea area)
{
if (!UInt64.TryParse(area.Data.Metadata, out UInt64 id)) { return; }
Client client = GameMain.Client.ConnectedClients.Find(c => c.SteamID == id)
?? GameMain.Client.ConnectedClients.Find(c => c.ID == id)
?? GameMain.Client.PreviouslyConnectedClients.FirstOrDefault(c => c.SteamID == id)
?? GameMain.Client.PreviouslyConnectedClients.FirstOrDefault(c => c.ID == id);
if (client == null) { return; }
var client = ExtractClientFromClickableArea(area);
if (client is null) { return; }
GameMain.NetLobbyScreen.SelectPlayer(client);
}
public void ShowPlayerContextMenu(GUITextBlock component, GUITextBlock.ClickableArea area)
{
var client = ExtractClientFromClickableArea(area);
if (client is null) { return; }
CreateModerationContextMenu(client);
}
#region Context Menu
public static void CreateModerationContextMenu(Client client)
{
if (GUIContextMenu.CurrentContextMenu != null) { return; }
if (GameMain.IsSingleplayer || client == null || ((!GameMain.Client?.PreviouslyConnectedClients?.Contains(client)) ?? true)) { return; }
bool hasSteam = client.SteamID > 0 && SteamManager.IsInitialized,
canKick = GameMain.Client.HasPermission(ClientPermissions.Kick),
canBan = GameMain.Client.HasPermission(ClientPermissions.Ban) && client.AllowKicking,
canPromo = GameMain.Client.HasPermission(ClientPermissions.ManagePermissions);
// Disable options if we are targeting ourselves
if (client.ID == GameMain.Client?.ID)
{
canKick = canBan = canPromo = false;
}
List<ContextMenuOption> options = new List<ContextMenuOption>();
options.Add(new ContextMenuOption("ViewSteamProfile", isEnabled: hasSteam, onSelected: delegate
{
Steamworks.SteamFriends.OpenWebOverlay($"https://steamcommunity.com/profiles/{client.SteamID}");
}));
options.Add(new ContextMenuOption("ModerationMenu.UserDetails", isEnabled: true, onSelected: delegate
{
GameMain.NetLobbyScreen?.SelectPlayer(client);
}));
// Creates sub context menu options for all the ranks
List<ContextMenuOption> permissionOptions = new List<ContextMenuOption>();
foreach (PermissionPreset rank in PermissionPreset.List)
{
permissionOptions.Add(new ContextMenuOption(rank.Name, isEnabled: true, onSelected: () =>
{
string label = TextManager.GetWithVariables(rank.Permissions == ClientPermissions.None ? "clearrankprompt" : "giverankprompt", new []{ "[user]", "[rank]" }, new []{ client.Name, rank.Name });
GUIMessageBox msgBox = new GUIMessageBox(string.Empty, label, new[] { TextManager.Get("Yes"), TextManager.Get("Cancel") });
msgBox.Buttons[0].OnClicked = delegate
{
client.SetPermissions(rank.Permissions, rank.PermittedCommands);
GameMain.Client.UpdateClientPermissions(client);
msgBox.Close();
return true;
};
msgBox.Buttons[1].OnClicked = delegate
{
msgBox.Close();
return true;
};
}) { Tooltip = rank.Description });
}
options.Add(new ContextMenuOption("Permissions", isEnabled: canPromo, options: permissionOptions.ToArray()));
Color clientColor = client.Character?.Info?.Job.Prefab.UIColor ?? Color.White;
if (GameMain.Client.ConnectedClients.Contains(client))
{
options.Add(new ContextMenuOption(client.MutedLocally ? "Unmute" : "Mute", isEnabled: client.ID != GameMain.Client?.ID, onSelected: delegate
{
client.MutedLocally = !client.MutedLocally;
}));
bool kickEnabled = client.ID != GameMain.Client?.ID && client.AllowKicking;
// if the user can kick create a kick option else create the votekick option
ContextMenuOption kickOption;
if (canKick)
{
kickOption = new ContextMenuOption("Kick", isEnabled: kickEnabled, onSelected: delegate
{
GameMain.Client?.CreateKickReasonPrompt(client.Name, false);
});
}
else
{
kickOption = new ContextMenuOption("VoteToKick", isEnabled: kickEnabled, onSelected: delegate
{
GameMain.Client?.VoteForKick(client);
});
}
options.Add(kickOption);
}
options.Add(new ContextMenuOption("Ban", isEnabled: canBan, onSelected: delegate
{
GameMain.Client?.CreateKickReasonPrompt(client.Name, true);
}));
GUIContextMenu.CreateContextMenu(null, client.Name, headerColor: clientColor, options.ToArray());
}
#endregion
public bool SelectPlayer(Client selectedClient)
{
bool myClient = selectedClient.ID == GameMain.Client.ID;
@@ -2763,7 +2821,8 @@ namespace Barotrauma
msg.ClickableAreas.Add(new GUITextBlock.ClickableArea()
{
Data = data,
OnClick = GameMain.NetLobbyScreen.SelectPlayer
OnClick = GameMain.NetLobbyScreen.SelectPlayer,
OnSecondaryClick = GameMain.NetLobbyScreen.ShowPlayerContextMenu
});
}
}
@@ -3221,6 +3280,7 @@ namespace Barotrauma
{
CreateSubPreview(submarine);
}
UpdateSubVisibility();
}
private bool ViewJobInfo(GUIButton button, object obj)
@@ -3369,14 +3429,28 @@ namespace Barotrauma
return btn;
}
public Pair<string, string> FailedSelectedSub;
public Pair<string, string> FailedSelectedShuttle;
public readonly struct FailedSubInfo
{
public readonly string Name;
public readonly string Hash;
public FailedSubInfo(string name, string hash) { Name = name; Hash = hash; }
public void Deconstruct(out string name, out string hash) { name = Name; hash = Hash; }
public static bool operator ==(FailedSubInfo a, FailedSubInfo b)
=> a.Name.Equals(b.Name, StringComparison.OrdinalIgnoreCase)
&& a.Hash.Equals(b.Hash, StringComparison.OrdinalIgnoreCase);
public static bool operator !=(FailedSubInfo a, FailedSubInfo b)
=> !(a == b);
}
public List<Pair<string, string>> FailedCampaignSubs = new List<Pair<string, string>>();
public List<Pair<string, string>> FailedOwnedSubs = new List<Pair<string, string>>();
public FailedSubInfo? FailedSelectedSub;
public FailedSubInfo? FailedSelectedShuttle;
public List<FailedSubInfo> FailedCampaignSubs = new List<FailedSubInfo>();
public List<FailedSubInfo> FailedOwnedSubs = new List<FailedSubInfo>();
public bool TrySelectSub(string subName, string md5Hash, GUIListBox subList)
{
UpdateSubVisibility();
if (GameMain.Client == null) { return false; }
//already downloading the selected sub file
@@ -3441,9 +3515,13 @@ namespace Barotrauma
//if we get to this point, a matching sub was not found or it has an incorrect MD5 hash
if (subList == SubList)
FailedSelectedSub = new Pair<string, string>(subName, md5Hash);
{
FailedSelectedSub = new FailedSubInfo(subName, md5Hash);
}
else
FailedSelectedShuttle = new Pair<string, string>(subName, md5Hash);
{
FailedSelectedShuttle = new FailedSubInfo(subName, md5Hash);
}
string errorMsg = "";
if (sub == null || !SubmarineInfo.SavedSubmarines.Contains(sub))
@@ -3542,22 +3620,22 @@ namespace Barotrauma
{
UserData = "request" + serverSubmarine.Name
};
requestFileBox.Buttons[0].UserData = new string[] { serverSubmarine.Name, serverSubmarine.MD5Hash.Hash };
requestFileBox.Buttons[0].UserData = new FailedSubInfo(serverSubmarine.Name, serverSubmarine.MD5Hash.Hash);
requestFileBox.Buttons[0].OnClicked += requestFileBox.Close;
requestFileBox.Buttons[0].OnClicked += (GUIButton button, object userdata) =>
{
string[] fileInfo = (string[])userdata;
FailedSubInfo fileInfo = (FailedSubInfo)userdata;
if (deliveryData == "owned")
if (deliveryData == "owned") //owned!!!!
{
FailedOwnedSubs.Add(new Pair<string, string>(fileInfo[0], fileInfo[1]));
FailedOwnedSubs.Add(fileInfo);
}
else if (deliveryData == "campaign")
{
FailedCampaignSubs.Add(new Pair<string, string>(fileInfo[0], fileInfo[1]));
FailedCampaignSubs.Add(fileInfo);
}
GameMain.Client?.RequestFile(FileTransferType.Submarine, fileInfo[0], fileInfo[1]);
GameMain.Client?.RequestFile(FileTransferType.Submarine, fileInfo.Name, fileInfo.Hash);
return true;
};
requestFileBox.Buttons[1].OnClicked += requestFileBox.Close;
@@ -3691,7 +3769,7 @@ namespace Barotrauma
};
var subName = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), frameContent.RectTransform),
text: sub.Name)
text: sub.DisplayName)
{
CanBeFocused = false
};
@@ -3823,7 +3901,9 @@ namespace Barotrauma
foreach (GUIComponent child in SubList.Content.Children)
{
if (!(child.UserData is SubmarineInfo sub)) { continue; }
child.Visible = !GameMain.Client.ServerSettings.HiddenSubs.Contains(sub.Name)
child.Visible =
(!GameMain.Client.ServerSettings.HiddenSubs.Contains(sub.Name)
|| (GameMain.GameSession?.SubmarineInfo != null && GameMain.GameSession.SubmarineInfo.Name.Equals(sub.Name, StringComparison.OrdinalIgnoreCase)))
&& (string.IsNullOrEmpty(subSearchBox.Text) || sub.DisplayName.Contains(subSearchBox.Text, StringComparison.OrdinalIgnoreCase));
}
}
@@ -2376,10 +2376,9 @@ namespace Barotrauma
}
catch (Exception ex)
{
string errorMsg = "Failed to ping a server (" + ip + ") - " + (ex?.InnerException?.Message ?? ex.Message);
GameAnalyticsManager.AddErrorEventOnce("ServerListScreen.PingServer:PingException" + ip, GameAnalyticsSDK.Net.EGAErrorSeverity.Warning, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("ServerListScreen.PingServer:PingException" + ip, GameAnalyticsManager.ErrorSeverity.Warning, "Failed to ping a server - " + (ex?.InnerException?.Message ?? ex.Message));
#if DEBUG
DebugConsole.NewMessage(errorMsg, Color.Red);
DebugConsole.NewMessage("Failed to ping a server (" + ip + ") - " + (ex?.InnerException?.Message ?? ex.Message), Color.Red);
#endif
}
}
@@ -824,9 +824,8 @@ namespace Barotrauma
}
catch (Exception e)
{
string errorMsg = "Failed to save workshop item preview image to \"" + previewImagePath + "\".";
GameAnalyticsManager.AddErrorEventOnce("SteamWorkshopScreen.OnItemPreviewDownloaded:WriteAllBytesFailed" + previewImagePath,
GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + "\n" + e.Message);
GameAnalyticsManager.ErrorSeverity.Error, "Failed to save workshop item preview image.\n" + e.Message);
return;
}
}
@@ -1195,7 +1194,7 @@ namespace Barotrauma
{
string errorMsg = "Failed to edit workshop item (content package null)\n" + Environment.StackTrace.CleanupStackTrace();
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("SteamWorkshopScreen.ShowCreateItemFrame:ContentPackageNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("SteamWorkshopScreen.ShowCreateItemFrame:ContentPackageNull", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
return;
}
@@ -358,7 +358,7 @@ namespace Barotrauma
}
else
{
displayName = TextManager.Get(fallbackTag, true);
displayName = TextManager.Get(fallbackTag, true) ?? TextManager.Get($"sp.{fallbackTag}.name", true);
}
}
@@ -228,7 +228,7 @@ namespace Barotrauma.Sounds
uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex);
float effectiveGain = gain;
if (category != null) effectiveGain *= Sound.Owner.GetCategoryGainMultiplier(category);
if (category != null) { effectiveGain *= Sound.Owner.GetCategoryGainMultiplier(category); }
Al.Sourcef(alSource, Al.Gain, effectiveGain);
int alError = Al.GetError();
@@ -470,14 +470,14 @@ namespace Barotrauma
{
string errorMsg = "Failed to update water ambience volume - submarine's movement value invalid (" + movementSoundVolume + ", sub velocity: " + sub.Velocity + ")";
DebugConsole.Log(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("SoundPlayer.UpdateWaterAmbience:InvalidVolume", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("SoundPlayer.UpdateWaterAmbience:InvalidVolume", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
movementSoundVolume = 0.0f;
}
if (!MathUtils.IsValid(insideSubFactor))
{
string errorMsg = "Failed to update water ambience volume - inside sub value invalid (" + insideSubFactor + ")";
DebugConsole.Log(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("SoundPlayer.UpdateWaterAmbience:InvalidVolume", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("SoundPlayer.UpdateWaterAmbience:InvalidVolume", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
insideSubFactor = 0.0f;
}
}
@@ -609,7 +609,7 @@ namespace Barotrauma
flowSoundChannels[i] = FlowSounds[i].Play(1.0f, FlowSoundRange, soundPos);
flowSoundChannels[i].Looping = true;
}
flowSoundChannels[i].Gain = Math.Max(flowVolumeRight[i], flowVolumeLeft[i]);
flowSoundChannels[i].Gain = Math.Min(Math.Max(flowVolumeRight[i], flowVolumeLeft[i]), 1.0f);
flowSoundChannels[i].Position = new Vector3(soundPos, 0.0f);
}
}
@@ -790,7 +790,7 @@ namespace Barotrauma
if (sound == null)
{
string errorMsg = "Error in SoundPlayer.PlaySound (sound was null)\n" + Environment.StackTrace.CleanupStackTrace();
GameAnalyticsManager.AddErrorEventOnce("SoundPlayer.PlaySound:SoundNull" + Environment.StackTrace.CleanupStackTrace(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("SoundPlayer.PlaySound:SoundNull" + Environment.StackTrace.CleanupStackTrace(), GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
return null;
}
@@ -64,6 +64,7 @@ namespace Barotrauma
{
float angle = 0.0f;
float particleRotation = 0.0f;
bool mirrorAngle = false;
if (emitter.Prefab.Properties.CopyEntityAngle)
{
Limb targetLimb = null;
@@ -71,7 +72,11 @@ namespace Barotrauma
{
angle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
particleRotation = -item.body.Rotation;
if (item.body.Dir < 0.0f) { particleRotation += MathHelper.Pi; }
if (item.body.Dir < 0.0f)
{
particleRotation += MathHelper.Pi;
mirrorAngle = true;
}
}
else if (entity is Character c && !c.Removed && targetLimbs?.FirstOrDefault(l => l != LimbType.None) is LimbType l)
{
@@ -85,11 +90,15 @@ namespace Barotrauma
{
angle = targetLimb.body.Rotation + ((targetLimb.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
particleRotation = -targetLimb.body.Rotation;
if (targetLimb.body.Dir < 0.0f) { particleRotation += MathHelper.Pi; }
if (targetLimb.body.Dir < 0.0f)
{
particleRotation += MathHelper.Pi;
mirrorAngle = true;
}
}
}
emitter.Emit(deltaTime, worldPosition, hull, angle: angle, particleRotation: particleRotation);
emitter.Emit(deltaTime, worldPosition, hull, angle: angle, particleRotation: particleRotation, mirrorAngle: mirrorAngle);
}
}
@@ -108,7 +117,7 @@ namespace Barotrauma
if (sound?.Sound == null)
{
string errorMsg = $"Error in StatusEffect.ApplyProjSpecific1 (sound \"{sound?.Filename ?? "unknown"}\" was null)\n" + Environment.StackTrace.CleanupStackTrace();
GameAnalyticsManager.AddErrorEventOnce("StatusEffect.ApplyProjSpecific:SoundNull1" + Environment.StackTrace.CleanupStackTrace(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("StatusEffect.ApplyProjSpecific:SoundNull1" + Environment.StackTrace.CleanupStackTrace(), GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
return;
}
soundChannel = SoundPlayer.PlaySound(sound.Sound, worldPosition, sound.Volume, sound.Range, hullGuess: hull, ignoreMuffling: sound.IgnoreMuffling);
@@ -135,7 +144,7 @@ namespace Barotrauma
if (selectedSound?.Sound == null)
{
string errorMsg = $"Error in StatusEffect.ApplyProjSpecific2 (sound \"{selectedSound?.Filename ?? "unknown"}\" was null)\n" + Environment.StackTrace.CleanupStackTrace();
GameAnalyticsManager.AddErrorEventOnce("StatusEffect.ApplyProjSpecific:SoundNull2" + Environment.StackTrace.CleanupStackTrace(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("StatusEffect.ApplyProjSpecific:SoundNull2" + Environment.StackTrace.CleanupStackTrace(), GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
return;
}
if (selectedSound.Sound.Disposed)
@@ -421,7 +421,7 @@ namespace Barotrauma
#if DEBUG
DebugConsole.ThrowError("Empty color array passed to the GradientLerp method.\n" + Environment.StackTrace.CleanupStackTrace());
#endif
GameAnalyticsManager.AddErrorEventOnce("ToolBox.GradientLerp:EmptyColorArray", GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
GameAnalyticsManager.AddErrorEventOnce("ToolBox.GradientLerp:EmptyColorArray", GameAnalyticsManager.ErrorSeverity.Error,
"Empty color array passed to the GradientLerp method.\n" + Environment.StackTrace.CleanupStackTrace());
return Color.Black;
}
@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>0.15.15.0</Version>
<Version>0.15.17.0</Version>
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName>
@@ -55,6 +55,7 @@
<ItemGroup>
<Content Include="..\BarotraumaShared\**\*" CopyToOutputDirectory="PreserveNewest" />
<Content Remove="..\BarotraumaShared\**\*.cs" />
<Content Remove="..\BarotraumaShared\**\*.props" />
<Compile Include="..\BarotraumaShared\**\*.cs" />
</ItemGroup>
@@ -99,7 +100,6 @@
<ProjectReference Include="..\..\Libraries\Concentus\CSharp\Concentus\Concentus.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\Facepunch.Steamworks\Facepunch.Steamworks.Posix.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\Farseer Physics Engine 3.5\Farseer.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\GameAnalytics\GA_SDK_NETSTANDARD\GA_SDK_NETSTANDARD.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\Hyper.ComponentModel\Hyper.ComponentModel.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\Lidgren.Network\Lidgren.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\MonoGame.Framework\Src\MonoGame.Framework\MonoGame.Framework.Linux.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
@@ -109,7 +109,6 @@
<ProjectReference Include="..\..\Libraries\Concentus\CSharp\Concentus\Concentus.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\Facepunch.Steamworks\Facepunch.Steamworks.Posix.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\Farseer Physics Engine 3.5\Farseer.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\GameAnalytics\GA_SDK_NETSTANDARD\GA_SDK_NETSTANDARD.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\Hyper.ComponentModel\Hyper.ComponentModel.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\Lidgren.Network\Lidgren.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\MonoGame.Framework\Src\MonoGame.Framework\MonoGame.Framework.Linux.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
@@ -189,4 +188,9 @@
<WriteCodeFragment Language="C#" OutputFile="$(CustomAssemblyInfoFile)" AssemblyAttributes="@(AssemblyAttributes)" />
</Target>
<PropertyGroup>
<GARuntime>linux-x64</GARuntime>
</PropertyGroup>
<Import Project="../BarotraumaShared/DeployGameAnalytics.props" />
</Project>
+7 -3
View File
@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>0.15.15.0</Version>
<Version>0.15.17.0</Version>
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName>
@@ -58,6 +58,7 @@
<ItemGroup>
<Content Include="..\BarotraumaShared\**\*" CopyToOutputDirectory="PreserveNewest" />
<Content Remove="..\BarotraumaShared\**\*.cs" />
<Content Remove="..\BarotraumaShared\**\*.props" />
<Compile Include="..\BarotraumaShared\**\*.cs" />
<Content Remove="..\BarotraumaShared\libsteam_api64.dylib" />
<Content Remove="..\BarotraumaShared\libsteam_api64.so" />
@@ -100,7 +101,6 @@
<ProjectReference Include="..\..\Libraries\Concentus\CSharp\Concentus\Concentus.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\Facepunch.Steamworks\Facepunch.Steamworks.Posix.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\Farseer Physics Engine 3.5\Farseer.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\GameAnalytics\GA_SDK_NETSTANDARD\GA_SDK_NETSTANDARD.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\Hyper.ComponentModel\Hyper.ComponentModel.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\Lidgren.Network\Lidgren.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\SharpFont\Source\SharpFont\SharpFont.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
@@ -110,7 +110,6 @@
<ProjectReference Include="..\..\Libraries\Concentus\CSharp\Concentus\Concentus.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\Facepunch.Steamworks\Facepunch.Steamworks.Posix.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\Farseer Physics Engine 3.5\Farseer.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\GameAnalytics\GA_SDK_NETSTANDARD\GA_SDK_NETSTANDARD.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\Hyper.ComponentModel\Hyper.ComponentModel.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\Lidgren.Network\Lidgren.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\SharpFont\Source\SharpFont\SharpFont.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
@@ -201,4 +200,9 @@
<WriteCodeFragment Language="C#" OutputFile="$(CustomAssemblyInfoFile)" AssemblyAttributes="@(AssemblyAttributes)" />
</Target>
<PropertyGroup>
<GARuntime>osx-x64</GARuntime>
</PropertyGroup>
<Import Project="../BarotraumaShared/DeployGameAnalytics.props" />
</Project>
@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>0.15.15.0</Version>
<Version>0.15.17.0</Version>
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName>
@@ -63,6 +63,7 @@
<ItemGroup>
<Content Include="..\BarotraumaShared\**\*" CopyToOutputDirectory="PreserveNewest" />
<Content Remove="..\BarotraumaShared\**\*.cs" />
<Content Remove="..\BarotraumaShared\**\*.props" />
<Compile Include="..\BarotraumaShared\**\*.cs" />
</ItemGroup>
@@ -103,7 +104,6 @@
<ProjectReference Include="..\..\Libraries\Concentus\CSharp\Concentus\Concentus.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\Facepunch.Steamworks\Facepunch.Steamworks.Win64.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\Farseer Physics Engine 3.5\Farseer.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\GameAnalytics\GA_SDK_NETSTANDARD\GA_SDK_NETSTANDARD.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\Hyper.ComponentModel\Hyper.ComponentModel.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\Lidgren.Network\Lidgren.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\MonoGame.Framework\Src\MonoGame.Framework\MonoGame.Framework.Windows.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
@@ -113,7 +113,6 @@
<ProjectReference Include="..\..\Libraries\Concentus\CSharp\Concentus\Concentus.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\Facepunch.Steamworks\Facepunch.Steamworks.Win64.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\Farseer Physics Engine 3.5\Farseer.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\GameAnalytics\GA_SDK_NETSTANDARD\GA_SDK_NETSTANDARD.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\Hyper.ComponentModel\Hyper.ComponentModel.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\Lidgren.Network\Lidgren.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\MonoGame.Framework\Src\MonoGame.Framework\MonoGame.Framework.Windows.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
@@ -220,4 +219,9 @@
<WriteCodeFragment Language="C#" OutputFile="$(CustomAssemblyInfoFile)" AssemblyAttributes="@(AssemblyAttributes)" />
</Target>
<PropertyGroup>
<GARuntime>win-x64</GARuntime>
</PropertyGroup>
<Import Project="../BarotraumaShared/DeployGameAnalytics.props" />
</Project>
+62 -62
View File
@@ -1,62 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on
and is designed to work with. Uncomment the appropriate elements
and Windows will automatically select the most compatible environment. -->
<!-- Windows Vista -->
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<!-- Indicates that the application is DPI-aware and will not be automatically scaled by Windows at higher
DPIs. Windows Presentation Foundation (WPF) applications are automatically DPI-aware and do not need
to opt in. Windows Forms applications targeting .NET Framework 4.6 that opt into this setting, should
also set the 'EnableWindowsFormsHighDpiAutoResizing' setting to 'true' in their app.config. -->
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
</windowsSettings>
</application>
<!-- Enable themes for Windows common controls and dialogs (Windows XP and later) -->
<!--
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
-->
</assembly>
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on
and is designed to work with. Uncomment the appropriate elements
and Windows will automatically select the most compatible environment. -->
<!-- Windows Vista -->
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<!-- Indicates that the application is DPI-aware and will not be automatically scaled by Windows at higher
DPIs. Windows Presentation Foundation (WPF) applications are automatically DPI-aware and do not need
to opt in. Windows Forms applications targeting .NET Framework 4.6 that opt into this setting, should
also set the 'EnableWindowsFormsHighDpiAutoResizing' setting to 'true' in their app.config. -->
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
</windowsSettings>
</application>
<!-- Enable themes for Windows common controls and dialogs (Windows XP and later) -->
<!--
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
-->
</assembly>