(bcb06cc5c) Unstable v0.9.9.0

This commit is contained in:
Juan Pablo Arce
2020-03-27 15:22:59 -03:00
parent c81486a993
commit b143329701
326 changed files with 9692 additions and 4364 deletions

View File

@@ -1,6 +1,9 @@
---
name: Bug report
about: Found a bug? Help us squash it by making a bug report!
title: ''
labels: ''
assignees: ''
---

View File

@@ -0,0 +1,33 @@
---
name: Release checklist
about: A checklist that should be gone through when releasing a hotfix/patch/update
title: v0.0.0.0
labels: Code, CM
assignees: ''
---
**Code:**
- [ ] Build and upload dedicated server
- [ ] Verify that Vanilla content package hashes match between Windows/Mac/Linux
- [ ] Run "checkmissingloca" command to make sure localization files are up-to-date.
- [ ] Install Trick or Trauma and check you can start a round with no obvious issues/errors (to make sure we didn't unintentionally break compatibility with older mods).
- [ ] Prepare new main menu content (changelog)
- [ ] Prepare public github repo for pushing the new changes
**CM:**
- [ ] Prepare Steam announcement
- [ ] Prepare Discord announcement (if needed)
- [ ] Prepare blog post (if needed)
**Code (when everything above is ready):**
- [ ] Publish
- [ ] Upload new main menu content
- [ ] Update public github repo
- [ ] Merge release to master and active branches
**CM (after the update is live):**
- [ ] Post Steam announcement
- [ ] Post Discord announcement (if needed)
- [ ] Blog post (if needed)
- [ ] Clean up Trello

View File

@@ -335,7 +335,8 @@ namespace Barotrauma
//an ad-hoc way of allowing the players to have roughly the same maximum view distance regardless of the resolution,
//while still keeping the zoom around 1.0 when not looking further away (because otherwise we'd always be downsampling
//on lower resolutions, which doesn't look that good)
float newZoom = MathHelper.Lerp(unscaledZoom, scaledZoom, (float)Math.Sqrt(zoomOutAmount));
float newZoom = MathHelper.Lerp(unscaledZoom, scaledZoom,
(GameMain.Config == null || GameMain.Config.EnableMouseLook) ? (float)Math.Sqrt(zoomOutAmount) : 0.3f);
Zoom += (newZoom - zoom) / ZoomSmoothness;

View File

@@ -9,7 +9,7 @@ namespace Barotrauma
public void Draw(SpriteBatch spriteBatch)
{
if (!ShowAITargets) return;
if (!ShowAITargets) { return; }
var pos = new Vector2(WorldPosition.X, -WorldPosition.Y);
if (soundRange > 0.0f)
{
@@ -43,8 +43,8 @@ namespace Barotrauma
}
else
{
color = Color.WhiteSmoke;
// disable the indicators for structures, because they clutter the debug view
//color = Color.WhiteSmoke;
// disable the indicators for structures and hulls, because they clutter the debug view
return;
}
ShapeExtensions.DrawCircle(spriteBatch, pos, SightRange, 100, color, thickness: 1 / Screen.Selected.Cam.Zoom);

View File

@@ -17,7 +17,7 @@ namespace Barotrauma
if (State == AIState.Idle && PreviousState == AIState.Attack)
{
var target = _selectedAiTarget ?? _lastAiTarget;
if (target != null)
if (target != null && target.Entity != null)
{
var memory = GetTargetMemory(target);
Vector2 targetPos = memory.Location;

View File

@@ -16,11 +16,6 @@ namespace Barotrauma
}*/
}
partial void SetOrderProjSpecific(Order order, string option)
{
GameMain.GameSession.CrewManager.DisplayCharacterOrder(Character, order, option);
}
public override void DebugDraw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
{
Vector2 pos = Character.WorldPosition;
@@ -40,7 +35,7 @@ namespace Barotrauma
var currentOrder = ObjectiveManager.CurrentOrder;
if (currentOrder != null)
{
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 20), $"ORDER: {currentOrder.DebugTag} ({currentOrder.GetPriority().FormatZeroDecimal()})", Color.White, Color.Black);
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 20), $"ORDER: {currentOrder.DebugTag} ({currentOrder.Priority.FormatZeroDecimal()})", Color.White, Color.Black);
}
else if (ObjectiveManager.WaitTimer > 0)
{
@@ -51,17 +46,17 @@ namespace Barotrauma
{
if (currentOrder == null)
{
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 20), $"MAIN OBJECTIVE: {currentObjective.DebugTag} ({currentObjective.GetPriority().FormatZeroDecimal()})", Color.White, Color.Black);
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 20), $"MAIN OBJECTIVE: {currentObjective.DebugTag} ({currentObjective.Priority.FormatZeroDecimal()})", Color.White, Color.Black);
}
var subObjective = currentObjective.SubObjectives.FirstOrDefault();
var subObjective = currentObjective.CurrentSubObjective;
if (subObjective != null)
{
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 40), $"SUBOBJECTIVE: {subObjective.DebugTag} ({subObjective.GetPriority().FormatZeroDecimal()})", Color.White, Color.Black);
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 40), $"SUBOBJECTIVE: {subObjective.DebugTag} ({subObjective.Priority.FormatZeroDecimal()})", Color.White, Color.Black);
}
var activeObjective = ObjectiveManager.GetActiveObjective();
if (activeObjective != null)
{
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 60), $"ACTIVE OBJECTIVE: {activeObjective.DebugTag} ({activeObjective.GetPriority().FormatZeroDecimal()})", Color.White, Color.Black);
GUI.DrawString(spriteBatch, pos + textOffset + new Vector2(0, 60), $"ACTIVE OBJECTIVE: {activeObjective.DebugTag} ({activeObjective.Priority.FormatZeroDecimal()})", Color.White, Color.Black);
}
}
}

View File

@@ -286,7 +286,7 @@ namespace Barotrauma
{
bool inWater = limb.inWater;
if (character.CurrentHull != null &&
character.CurrentHull.Surface > character.CurrentHull.Rect.Y - character.CurrentHull.Rect.Height &&
character.CurrentHull.Surface > character.CurrentHull.Rect.Y - character.CurrentHull.Rect.Height + 5.0f &&
limb.SimPosition.Y < ConvertUnits.ToSimUnits(character.CurrentHull.Rect.Y - character.CurrentHull.Rect.Height) + limb.body.GetMaxExtent())
{
inWater = true;
@@ -370,6 +370,7 @@ namespace Barotrauma
foreach (var deformation in SpriteDeformations)
{
if (character.IsDead && deformation.Params.StopWhenHostIsDead) { continue; }
if (!character.AnimController.InWater && deformation.Params.OnlyInWater) { continue; }
if (deformation.Params.UseMovementSine)
{
if (this is AnimController animator)

View File

@@ -365,7 +365,7 @@ namespace Barotrauma
}
}
partial void KillProjSpecific(CauseOfDeathType causeOfDeath, Affliction causeOfDeathAffliction)
partial void KillProjSpecific(CauseOfDeathType causeOfDeath, Affliction causeOfDeathAffliction, bool log)
{
if (GameMain.NetworkMember != null && controlled == this)
{
@@ -466,7 +466,7 @@ namespace Barotrauma
//modify the distance based on the size of the trigger (preferring smaller items)
distanceToItem *= MathHelper.Lerp(0.05f, 2.0f, (transformedTrigger.Width + transformedTrigger.Height) / 250.0f);
}
else
else if (!item.Prefab.RequireCursorInsideTrigger)
{
Rectangle itemDisplayRect = new Rectangle(item.InteractionRect.X, item.InteractionRect.Y - item.InteractionRect.Height, item.InteractionRect.Width, item.InteractionRect.Height);
@@ -551,7 +551,7 @@ namespace Barotrauma
{
if (!enabled) { return; }
if (!IsDead && !IsUnconscious)
if (!IsDead && !IsIncapacitated)
{
if (soundTimer > 0)
{
@@ -603,6 +603,11 @@ namespace Barotrauma
}
}
partial void SetOrderProjSpecific(Order order, string orderOption)
{
GameMain.GameSession?.CrewManager?.DisplayCharacterOrder(this, order, orderOption);
}
public static void AddAllToGUIUpdateList()
{
for (int i = 0; i < CharacterList.Count; i++)
@@ -638,8 +643,7 @@ namespace Barotrauma
public void Draw(SpriteBatch spriteBatch, Camera cam)
{
if (!Enabled) return;
if (!Enabled) { return; }
AnimController.Draw(spriteBatch, cam);
}
@@ -656,8 +660,6 @@ namespace Barotrauma
if (GameMain.DebugDraw)
{
AnimController.DebugDraw(spriteBatch);
if (aiTarget != null) aiTarget.Draw(spriteBatch);
}
if (GUI.DisableHUD) return;

View File

@@ -61,7 +61,7 @@ namespace Barotrauma
{
if (GUI.DisableHUD) return;
if (!character.IsUnconscious && character.Stun <= 0.0f)
if (!character.IsIncapacitated && character.Stun <= 0.0f)
{
if (character.Inventory != null)
{
@@ -90,9 +90,9 @@ namespace Barotrauma
{
if (GUI.DisableHUD) { return; }
if (!character.IsUnconscious && character.Stun <= 0.0f)
if (!character.IsIncapacitated && character.Stun <= 0.0f)
{
if (character.Info != null && !character.ShouldLockHud())
if (character.Info != null && !character.ShouldLockHud() && character.SelectedCharacter == null)
{
bool mouseOnPortrait = HUDLayoutSettings.BottomRightInfoArea.Contains(PlayerInput.MousePosition) && GUI.MouseOn == null;
if (mouseOnPortrait && PlayerInput.PrimaryMouseButtonClicked())
@@ -154,6 +154,7 @@ namespace Barotrauma
brokenItemsCheckTimer = 1.0f;
foreach (Item item in Item.ItemList)
{
if (item.Submarine == null || item.Submarine.TeamID != character.TeamID || item.Submarine.Info.IsWreck) { continue; }
if (!item.Repairables.Any(r => item.ConditionPercentage <= r.AIRepairThreshold)) { continue; }
if (Submarine.VisibleEntities != null && !Submarine.VisibleEntities.Contains(item)) { continue; }
@@ -201,7 +202,7 @@ namespace Barotrauma
Color.Lerp(GUI.Style.Red, GUI.Style.Orange * 0.5f, brokenItem.Condition / brokenItem.MaxCondition) * alpha);
}
if (!character.IsUnconscious && character.Stun <= 0.0f)
if (!character.IsIncapacitated && character.Stun <= 0.0f)
{
if (character.FocusedCharacter != null && character.FocusedCharacter.CanBeSelected)
{
@@ -309,7 +310,7 @@ namespace Barotrauma
(int)(HUDLayoutSettings.BottomRightInfoArea.Y + HUDLayoutSettings.BottomRightInfoArea.Height * 0.1f),
(int)(HUDLayoutSettings.BottomRightInfoArea.Width / 2),
(int)(HUDLayoutSettings.BottomRightInfoArea.Height * 0.7f)));
character.Info.DrawPortrait(spriteBatch, HUDLayoutSettings.PortraitArea.Location.ToVector2(), new Vector2((int)(-4 * GUI.Scale), (int)(2 * GUI.Scale)), targetWidth: HUDLayoutSettings.PortraitArea.Width, true);
character.Info.DrawPortrait(spriteBatch, HUDLayoutSettings.PortraitArea.Location.ToVector2(), new Vector2(-12 * GUI.Scale, 4 * GUI.Scale), targetWidth: HUDLayoutSettings.PortraitArea.Width, true);
}
mouseOnPortrait = HUDLayoutSettings.BottomRightInfoArea.Contains(PlayerInput.MousePosition) && !character.ShouldLockHud();
if (mouseOnPortrait)
@@ -327,7 +328,7 @@ namespace Barotrauma
}
}
if (!character.IsUnconscious && character.Stun <= 0.0f)
if (!character.IsIncapacitated && character.Stun <= 0.0f)
{
if (character.IsHumanoid && character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null)
{

View File

@@ -10,12 +10,12 @@ namespace Barotrauma
{
partial class CharacterInfo
{
public const float BgScale = 1.2f;
private static Sprite infoAreaPortraitBG;
public static void Init()
{
infoAreaPortraitBG = new Sprite("Content/UI/InventoryUIAtlas.png", new Rectangle(833, 298, 142, 98), null, 0);
infoAreaPortraitBG = GUI.Style.GetComponentStyle("InfoAreaPortraitBG")?.Sprites[GUIComponent.ComponentState.None][0].Sprite;
new Sprite("Content/UI/InventoryUIAtlas.png", new Rectangle(833, 298, 142, 98), null, 0);
}
@@ -171,6 +171,7 @@ namespace Barotrauma
public void DrawBackground(SpriteBatch spriteBatch)
{
if (infoAreaPortraitBG == null) { return; }
infoAreaPortraitBG.Draw(spriteBatch, HUDLayoutSettings.BottomRightInfoArea.Location.ToVector2(), Color.White, Vector2.Zero, 0.0f,
scale: new Vector2(
HUDLayoutSettings.BottomRightInfoArea.Width / (float)infoAreaPortraitBG.SourceRect.Width,

View File

@@ -1,4 +1,5 @@
using Barotrauma.Networking;
using Barotrauma.Extensions;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System;
using System.Linq;
@@ -384,6 +385,37 @@ namespace Barotrauma
character = Create(speciesName, position, seed, info, GameMain.Client.ID != ownerId, hasAi);
character.ID = id;
character.TeamID = (TeamType)teamID;
// Check if the character has a current order
if (inc.ReadBoolean())
{
int orderPrefabIndex = inc.ReadByte();
Entity targetEntity = FindEntityByID(inc.ReadUInt16());
Character orderGiver = inc.ReadBoolean() ? FindEntityByID(inc.ReadUInt16()) as Character : null;
int orderOptionIndex = inc.ReadByte();
if (orderPrefabIndex >= 0 && orderPrefabIndex < Order.PrefabList.Count)
{
var orderPrefab = Order.PrefabList[orderPrefabIndex];
if ((orderPrefab.ItemComponentType == null && orderPrefab.ItemIdentifiers.None()) ||
(targetEntity != null && (targetEntity as Item).Components.Any(c => c?.GetType() == orderPrefab.ItemComponentType)))
{
character.SetOrder(
new Order(orderPrefab, targetEntity, (targetEntity as Item)?.Components.FirstOrDefault(c => c?.GetType() == orderPrefab.ItemComponentType), orderGiver: orderGiver),
orderOptionIndex >= 0 && orderOptionIndex < orderPrefab.Options.Length ? orderPrefab.Options[orderOptionIndex] : null,
orderGiver, speak: false);
}
else
{
DebugConsole.ThrowError("Could not set order \"" + orderPrefab.Identifier + "\" for character \"" + character.Name + "\" because required target entity was not found.");
}
}
else
{
DebugConsole.ThrowError("Invalid order prefab index - index (" + orderPrefabIndex + ") out of bounds.");
}
}
bool containsStatusData = inc.ReadBoolean();
if (containsStatusData)
{

View File

@@ -14,8 +14,8 @@ namespace Barotrauma
public SoundType Type => Params.State;
public Gender Gender => Params.Gender;
public float Volume => roundSound.Volume;
public float Range => roundSound.Range;
public float Volume => roundSound == null ? 0.0f : roundSound.Volume;
public float Range => roundSound == null ? 0.0f : roundSound.Range;
public Sound Sound => roundSound?.Sound;
public CharacterSound(CharacterParams.SoundParams soundParams)

View File

@@ -8,26 +8,25 @@ namespace Barotrauma
{
partial class AfflictionHusk : Affliction
{
partial void UpdateMessages(float prevStrength, Character character)
partial void UpdateMessages()
{
if (Strength < Prefab.MaxStrength * 0.5f)
{
if (prevStrength % 10.0f > 0.05f && Strength % 10.0f < 0.05f)
switch (State)
{
case InfectionState.Dormant:
GUI.AddMessage(TextManager.Get("HuskDormant"), GUI.Style.Red);
}
}
else if (Strength < Prefab.MaxStrength)
{
if (state == InfectionState.Dormant && Character.Controlled == character)
{
break;
case InfectionState.Transition:
GUI.AddMessage(TextManager.Get("HuskCantSpeak"), GUI.Style.Red);
}
}
else if (state != InfectionState.Active && Character.Controlled == character)
break;
case InfectionState.Active:
if (character.Params.UseHuskAppendage)
{
GUI.AddMessage(TextManager.GetWithVariable("HuskActivate", "[Attack]", GameMain.Config.KeyBindText(InputType.Attack)),
GUI.Style.Red);
GUI.AddMessage(TextManager.GetWithVariable("HuskActivate", "[Attack]", GameMain.Config.KeyBindText(InputType.Attack)), GUI.Style.Red);
}
break;
case InfectionState.Final:
default:
break;
}
}
}

View File

@@ -132,7 +132,7 @@ namespace Barotrauma
private List<HeartratePosition> heartratePositions;
private float currentHeartrateTime;
private float heartbeatTimer;
private Texture2D heartrateFade;
private static Texture2D heartrateFade;
private readonly HeartratePosition[] heartbeatPattern =
{
@@ -246,11 +246,13 @@ namespace Barotrauma
}
private GUIFrame healthBarHolder;
private Point healthBarOffset
{
get
{
return new Point(5 - (int)Math.Ceiling(1 - 1 * GUI.Scale), (int)Math.Min(Math.Ceiling(17 * GUI.Scale), 20));
// 0.38775510204f = percentage of offset before reaching the healthbar portion of the graphic going from bottom upwards
return new Point(2, (int)(HUDLayoutSettings.HealthBarArea.Size.Y * 0.38775510204f));
}
}
@@ -258,7 +260,7 @@ namespace Barotrauma
{
get
{
return new Point(healthBarHolder.Rect.Width - (int)Math.Ceiling(Math.Min(46 * GUI.Scale, 53)), (int)(healthBarHolder.Rect.Height - Math.Min(23 * GUI.Scale, 25)) / 2);
return new Point((int)Math.Ceiling(HUDLayoutSettings.HealthBarArea.Size.X - 45 * GUI.Scale), (int)(healthBarHolder.Rect.Height - Math.Min(23 * GUI.Scale, 25)) / 2);
}
}
@@ -303,7 +305,7 @@ namespace Barotrauma
healthShadowSize = 1.0f;
healthBar = new GUIProgressBar(new RectTransform(healthBarSize, healthBarHolder.RectTransform, Anchor.BottomRight),
barSize: 1.0f, color: GUIColorSettings.HealthBarColorHigh, style: horizontal ? "CharacterHealthBarSlider" : "GUIProgressBarVertical", showFrame: false)
barSize: 1.0f, color: GUI.Style.HealthBarColorHigh, style: horizontal ? "CharacterHealthBarSlider" : "GUIProgressBarVertical", showFrame: false)
{
HoverCursor = CursorState.Hand,
Enabled = true,
@@ -478,7 +480,7 @@ namespace Barotrauma
cprFrame = new GUIFrame(new RectTransform(new Vector2(0.7f, 1.0f), cprLayout.RectTransform), style: "GUIFrameListBox");
heartrateFade = TextureLoader.FromFile("Content/UI/Health/HeartrateFade.png");
heartrateFade ??= TextureLoader.FromFile("Content/UI/Health/HeartrateFade.png");
new GUICustomComponent(new RectTransform(Vector2.One * 0.95f, cprFrame.RectTransform, Anchor.Center), DrawHeartrate, UpdateHeartrate);
@@ -520,8 +522,10 @@ namespace Barotrauma
UpdateAlignment();
suicideButton = new GUIButton(new RectTransform(new Vector2(0.06f, 0.02f), GUI.Canvas, Anchor.TopCenter)
{ MinSize = new Point(150, 20), RelativeOffset = new Vector2(0.0f, 0.01f) },
suicideButton = new GUIButton(new RectTransform(new Vector2(0.1f, 0.02f), GUI.Canvas, Anchor.TopCenter)
{
MinSize = new Point(150, 20), RelativeOffset = new Vector2(0.0f, 0.01f)
},
TextManager.Get("GiveInButton"), style: "GUIButtonLarge")
{
ToolTip = TextManager.Get(GameMain.NetworkMember == null ? "GiveInHelpSingleplayer" : "GiveInHelpMultiplayer"),
@@ -816,9 +820,7 @@ namespace Barotrauma
if (highlightedLimbIndex < 0 && selectedLimbIndex < 0)
{
// If no limb is selected or highlighted, select the one with the most critical afflictions.
var affliction = GetAllAfflictions(a => a.Prefab.IndicatorLimb != LimbType.None)
.OrderByDescending(a => a.DamagePerSecond)
.ThenByDescending(a => a.Strength).FirstOrDefault();
var affliction = SortAfflictionsBySeverity(GetAllAfflictions(a => a.Prefab.IndicatorLimb != LimbType.None)).FirstOrDefault();
if (affliction.DamagePerSecond > 0 || affliction.Strength > 0)
{
var limbHealth = GetMatchingLimbHealth(affliction);
@@ -849,7 +851,7 @@ namespace Barotrauma
}
else
{
healthBar.Color = healthWindowHealthBar.Color = ToolBox.GradientLerp(DisplayedVitality / MaxVitality, GUIColorSettings.HealthBarColorLow, GUIColorSettings.HealthBarColorMedium, GUIColorSettings.HealthBarColorHigh);
healthBar.Color = healthWindowHealthBar.Color = ToolBox.GradientLerp(DisplayedVitality / MaxVitality, GUI.Style.HealthBarColorLow, GUI.Style.HealthBarColorMedium, GUI.Style.HealthBarColorHigh);
healthBar.HoverColor = healthWindowHealthBar.HoverColor = healthBar.Color * 2.0f;
healthBar.BarSize = healthWindowHealthBar.BarSize =
(DisplayedVitality > 0.0f) ?
@@ -936,7 +938,7 @@ namespace Barotrauma
healthBar.State = GUIComponent.ComponentState.None;
}
suicideButton.Visible = Character == Character.Controlled && Character.IsUnconscious && !Character.IsDead;
suicideButton.Visible = Character == Character.Controlled && !Character.IsDead && Character.IsIncapacitated;
cprButton.Visible =
Character == Character.Controlled?.SelectedCharacter
@@ -1134,11 +1136,11 @@ namespace Barotrauma
{
if (prefab.IsBuff)
{
return ToolBox.GradientLerp(affliction.Strength / prefab.MaxStrength, GUIColorSettings.BuffColorLow, GUIColorSettings.BuffColorMedium, GUIColorSettings.BuffColorHigh);
return ToolBox.GradientLerp(affliction.Strength / prefab.MaxStrength, GUI.Style.BuffColorLow, GUI.Style.BuffColorMedium, GUI.Style.BuffColorHigh);
}
else
{
return ToolBox.GradientLerp(affliction.Strength / prefab.MaxStrength, GUIColorSettings.DebuffColorLow, GUIColorSettings.DebuffColorMedium, GUIColorSettings.DebuffColorHigh);
return ToolBox.GradientLerp(affliction.Strength / prefab.MaxStrength, GUI.Style.DebuffColorLow, GUI.Style.DebuffColorMedium, GUI.Style.DebuffColorHigh);
}
}
else
@@ -1185,7 +1187,8 @@ namespace Barotrauma
Dictionary<string, float> treatmentSuitability = new Dictionary<string, float>();
GetSuitableTreatments(treatmentSuitability, normalize: true, randomization: randomVariance);
Affliction mostSevereAffliction = afflictions.FirstOrDefault(a => !a.Prefab.IsBuff && !afflictions.Any(a2 => !a2.Prefab.IsBuff && a2.Strength > a.Strength)) ?? afflictions.FirstOrDefault();
//Affliction mostSevereAffliction = afflictions.FirstOrDefault(a => !a.Prefab.IsBuff && !afflictions.Any(a2 => !a2.Prefab.IsBuff && a2.Strength > a.Strength)) ?? afflictions.FirstOrDefault();
Affliction mostSevereAffliction = SortAfflictionsBySeverity(afflictions).FirstOrDefault();
GUIButton buttonToSelect = null;
foreach (Affliction affliction in afflictions)
@@ -1811,8 +1814,8 @@ namespace Barotrauma
float iconScale = 0.25f * scale;
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 = thisAfflictions.FirstOrDefault(a => !a.Prefab.IsBuff && !thisAfflictions.Any(a2 => !a2.Prefab.IsBuff && a2.Strength > a.Strength)) ?? thisAfflictions.FirstOrDefault();
Affliction mostSevereAffliction = SortAfflictionsBySeverity(thisAfflictions).FirstOrDefault();
if (mostSevereAffliction != null) { DrawLimbAfflictionIcon(spriteBatch, mostSevereAffliction, iconScale, ref iconPos); }
if (thisAfflictions.Count() > 1)
@@ -1871,10 +1874,11 @@ namespace Barotrauma
healthBarHolder.Visible = value;
}
private readonly List<Pair<AfflictionPrefab, float>> newAfflictions = new List<Pair<AfflictionPrefab, float>>();
private readonly List<Triplet<LimbHealth, AfflictionPrefab, float>> newLimbAfflictions = new List<Triplet<LimbHealth, AfflictionPrefab, float>>();
public void ClientRead(IReadMessage inc)
{
List<Pair<AfflictionPrefab, float>> newAfflictions = new List<Pair<AfflictionPrefab, float>>();
newAfflictions.Clear();
byte afflictionCount = inc.ReadByte();
for (int i = 0; i < afflictionCount; i++)
{
@@ -1914,7 +1918,7 @@ namespace Barotrauma
}
}
List<Triplet<LimbHealth, AfflictionPrefab, float>> newLimbAfflictions = new List<Triplet<LimbHealth, AfflictionPrefab, float>>();
newLimbAfflictions.Clear();
byte limbAfflictionCount = inc.ReadByte();
for (int i = 0; i < limbAfflictionCount; i++)
{
@@ -1992,6 +1996,9 @@ namespace Barotrauma
}
}
medUIExtra?.Remove();
medUIExtra = null;
limbIndicatorOverlay?.Remove();
limbIndicatorOverlay = null;
}

View File

@@ -83,22 +83,22 @@ namespace Barotrauma
// pos.Y = -pos.Y;
// ShapeExtensions.DrawPoint(spriteBatch, pos, GUI.Style.Red, size: 5);
//}
return;
// A debug visualisation on the bezier curve between limbs.
var start = LimbA.WorldPosition;
/*var start = LimbA.WorldPosition;
var end = LimbB.WorldPosition;
var jointAPos = ConvertUnits.ToDisplayUnits(LocalAnchorA);
var control = start + Vector2.Transform(jointAPos, Matrix.CreateRotationZ(LimbA.Rotation));
start.Y = -start.Y;
end.Y = -end.Y;
control.Y = -control.Y;
//GUI.DrawRectangle(spriteBatch, start, Vector2.One * 5, Color.White, true);
//GUI.DrawRectangle(spriteBatch, end, Vector2.One * 5, Color.Black, true);
//GUI.DrawRectangle(spriteBatch, control, Vector2.One * 5, Color.Black, true);
//GUI.DrawLine(spriteBatch, start, end, Color.White);
//GUI.DrawLine(spriteBatch, start, control, Color.Black);
//GUI.DrawLine(spriteBatch, control, end, Color.Black);
GUI.DrawBezierWithDots(spriteBatch, start, end, control, 1000, GUI.Style.Red);
GUI.DrawRectangle(spriteBatch, start, Vector2.One * 5, Color.White, true);
GUI.DrawRectangle(spriteBatch, end, Vector2.One * 5, Color.Black, true);
GUI.DrawRectangle(spriteBatch, control, Vector2.One * 5, Color.Black, true);
GUI.DrawLine(spriteBatch, start, end, Color.White);
GUI.DrawLine(spriteBatch, start, control, Color.Black);
GUI.DrawLine(spriteBatch, control, end, Color.Black);
GUI.DrawBezierWithDots(spriteBatch, start, end, control, 1000, GUI.Style.Red);*/
}
}
@@ -220,9 +220,18 @@ namespace Barotrauma
}
set
{
if (HuskSprite != null && value != enableHuskSprite)
if (enableHuskSprite == value) { return; }
enableHuskSprite = value;
if (enableHuskSprite)
{
if (value)
if (HuskSprite == null)
{
LoadHuskSprite();
}
}
if (HuskSprite != null)
{
if (enableHuskSprite)
{
List<WearableSprite> otherWearablesWithHusk = new List<WearableSprite>() { HuskSprite };
otherWearablesWithHusk.AddRange(OtherWearables);
@@ -235,7 +244,6 @@ namespace Barotrauma
UpdateWearableTypesToHide();
}
}
enableHuskSprite = value;
}
}

View File

@@ -195,6 +195,34 @@ namespace Barotrauma
}
}
private static bool IsCommandPermitted(string command, GameClient client)
{
switch (command)
{
case "kick":
return client.HasPermission(ClientPermissions.Kick);
case "ban":
case "banip":
case "banendpoint":
return client.HasPermission(ClientPermissions.Ban);
case "unban":
case "unbanip":
return client.HasPermission(ClientPermissions.Unban);
case "netstats":
case "help":
case "dumpids":
case "admin":
case "entitylist":
case "togglehud":
case "toggleupperhud":
case "togglecharacternames":
case "fpscounter":
return true;
default:
return client.HasConsoleCommandPermission(command);
}
}
public static void DequeueMessages()
{
while (queuedMessages.Count > 0)
@@ -367,6 +395,7 @@ namespace Barotrauma
NewMessage("Steam achievements have been disabled during this play session.", Color.Red);
#endif
}));
AssignRelayToServer("enablecheats", true);
commands.Add(new Command("mainmenu|menu", "mainmenu/menu: Go to the main menu.", (string[] args) =>
{
@@ -394,7 +423,8 @@ namespace Barotrauma
{
if (args.Length > 0)
{
Submarine.Load(string.Join(" ", args), true);
var subInfo = new SubmarineInfo(string.Join(" ", args));
Submarine.MainSub = Submarine.Load(subInfo, true);
}
GameMain.SubEditorScreen.Select();
}, isCheat: true));
@@ -440,6 +470,7 @@ namespace Barotrauma
AssignRelayToServer("ban", false);
AssignRelayToServer("banid", false);
AssignRelayToServer("dumpids", false);
AssignRelayToServer("dumptofile", false);
AssignRelayToServer("findentityids", false);
AssignRelayToServer("campaigninfo", false);
AssignRelayToServer("help", false);
@@ -805,7 +836,7 @@ namespace Barotrauma
return;
}
if (Submarine.SaveCurrent(System.IO.Path.Combine(Submarine.SavePath, fileName + ".sub")))
if (Submarine.MainSub.SaveAs(System.IO.Path.Combine(SubmarineInfo.SavePath, fileName + ".sub")))
{
NewMessage("Sub saved", Color.Green);
}
@@ -814,7 +845,8 @@ namespace Barotrauma
commands.Add(new Command("load|loadsub", "load [submarine name]: Load a submarine.", (string[] args) =>
{
if (args.Length == 0) return;
Submarine.Load(string.Join(" ", args), true);
SubmarineInfo subInfo = new SubmarineInfo(string.Join(" ", args));
Submarine.Load(subInfo, true);
}));
commands.Add(new Command("cleansub", "", (string[] args) =>
@@ -1057,23 +1089,69 @@ namespace Barotrauma
if (args.Length != 2 || Screen.Selected != GameMain.SubEditorScreen) { return; }
foreach (MapEntity me in MapEntity.SelectedList)
{
if (me is ISerializableEntity serializableEntity)
bool propertyFound = false;
if (!(me is ISerializableEntity serializableEntity)) { continue; }
if (serializableEntity.SerializableProperties == null) { continue; }
if (serializableEntity.SerializableProperties.TryGetValue(args[0].ToLowerInvariant(), out SerializableProperty property))
{
if (serializableEntity.SerializableProperties == null)
propertyFound = true;
object prevValue = property.GetValue(me);
if (property.TrySetValue(me, args[1]))
{
continue;
NewMessage($"Changed the value \"{args[0]}\" from {(prevValue?.ToString() ?? null)} to {args[1]} on entity \"{me.ToString()}\".", Color.LightGreen);
}
if (!serializableEntity.SerializableProperties.TryGetValue(args[0].ToLowerInvariant(), out SerializableProperty property))
else
{
NewMessage("Property \"" + args[0] + "\" not found in the entity \"" + me.ToString() + "\".", Color.Orange);
continue;
NewMessage($"Failed to set the value of \"{args[0]}\" to \"{args[1]}\" on the entity \"{me.ToString()}\".", Color.Orange);
}
if (!property.TrySetValue(me, args[1]))
}
if (me is Item item)
{
NewMessage("Failed to set the value of \"" + args[0] + "\" to \"" + args[1] + "\" on the entity \"" + me.ToString() + "\".", Color.Orange);
foreach (ItemComponent ic in item.Components)
{
ic.SerializableProperties.TryGetValue(args[0].ToLowerInvariant(), out SerializableProperty componentProperty);
if (componentProperty == null) { continue; }
propertyFound = true;
object prevValue = componentProperty.GetValue(ic);
if (componentProperty.TrySetValue(ic, args[1]))
{
NewMessage($"Changed the value \"{args[0]}\" from {prevValue} to {args[1]} on item \"{me.ToString()}\", component \"{ic.GetType().Name}\".", Color.LightGreen);
}
else
{
NewMessage($"Failed to set the value of \"{args[0]}\" to \"{args[1]}\" on the item \"{me.ToString()}\", component \"{ic.GetType().Name}\".", Color.Orange);
}
}
}
if (!propertyFound)
{
NewMessage($"Property \"{args[0]}\" not found in the entity \"{me.ToString()}\".", Color.Orange);
}
}
},
() =>
{
List<string> propertyList = new List<string>();
foreach (MapEntity me in MapEntity.SelectedList)
{
if (!(me is ISerializableEntity serializableEntity)) { continue; }
if (serializableEntity.SerializableProperties == null) { continue; }
propertyList.AddRange(serializableEntity.SerializableProperties.Select(p => p.Key));
if (me is Item item)
{
foreach (ItemComponent ic in item.Components)
{
propertyList.AddRange(ic.SerializableProperties.Select(p => p.Key));
}
}
}
return new string[][]
{
propertyList.Distinct().ToArray(),
new string[0]
};
}));
commands.Add(new Command("checkmissingloca", "", (string[] args) =>
@@ -1106,7 +1184,7 @@ namespace Barotrauma
}
}
foreach (Submarine sub in Submarine.SavedSubmarines)
foreach (SubmarineInfo sub in SubmarineInfo.SavedSubmarines)
{
string nameIdentifier = "submarine.name." + sub.Name.ToLowerInvariant();
if (!tags[language].Contains(nameIdentifier))
@@ -2113,6 +2191,11 @@ namespace Barotrauma
commands.Add(new Command("flipx", "flipx: mirror the main submarine horizontally", (string[] args) =>
{
if (GameMain.NetworkMember != null)
{
ThrowError("Cannot use the flipx command while playing online.");
return;
}
Submarine.MainSub?.FlipX();
}, isCheat: true));
@@ -2235,7 +2318,8 @@ namespace Barotrauma
}
try
{
Submarine spawnedSub = Submarine.Load(args[0], false);
SubmarineInfo subInfo = new SubmarineInfo(args[0]);
Submarine spawnedSub = Submarine.Load(subInfo, false);
spawnedSub.SetPosition(GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition));
}
catch (Exception e)
@@ -2313,7 +2397,7 @@ namespace Barotrauma
switch (firstArg)
{
case "name":
var sprites = Sprite.LoadedSprites.Where(s => s.Name?.ToLowerInvariant() == secondArg.ToLowerInvariant());
var sprites = Sprite.LoadedSprites.Where(s => s.Name != null && s.Name.Equals(secondArg, StringComparison.OrdinalIgnoreCase));
if (sprites.Any())
{
foreach (var s in sprites)
@@ -2329,7 +2413,7 @@ namespace Barotrauma
}
case "identifier":
case "id":
sprites = Sprite.LoadedSprites.Where(s => s.EntityID?.ToLowerInvariant() == secondArg.ToLowerInvariant());
sprites = Sprite.LoadedSprites.Where(s => s.EntityID != null && s.EntityID.Equals(secondArg, StringComparison.OrdinalIgnoreCase));
if (sprites.Any())
{
foreach (var s in sprites)

View File

@@ -24,7 +24,7 @@ namespace Barotrauma
{
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() != "icon") { continue; }
if (!subElement.Name.ToString().Equals("icon", StringComparison.OrdinalIgnoreCase)) { continue; }
Icon = new Sprite(subElement);
IconColor = subElement.GetAttributeColor("color", Color.White);
}

View File

@@ -6,12 +6,25 @@ namespace Barotrauma
partial class SalvageMission : Mission
{
public override void ClientReadInitial(IReadMessage msg)
{
bool usedExistingItem = msg.ReadBoolean();
if (usedExistingItem)
{
ushort id = msg.ReadUInt16();
item = Entity.FindEntityByID(id) as Item;
if (item == null)
{
throw new System.Exception("Error in SalvageMission.ClientReadInitial: failed to find item " + id + " (mission: " + Prefab.Identifier + ")");
}
}
else
{
item = Item.ReadSpawnData(msg);
if (item == null)
{
throw new System.Exception("Error in SalvageMission.ClientReadInitial: spawned item was null (mission: " + Prefab.Identifier + ")");
}
}
item.body.FarseerBody.BodyType = BodyType.Kinematic;
}

View File

@@ -135,31 +135,33 @@ namespace Barotrauma
}
}
Color textColor = textBox.Color;
switch (command)
{
case "r":
case "radio":
textBox.TextColor = ChatMessage.MessageColor[(int)ChatMessageType.Radio];
textColor = ChatMessage.MessageColor[(int)ChatMessageType.Radio];
break;
case "d":
case "dead":
textBox.TextColor = ChatMessage.MessageColor[(int)ChatMessageType.Dead];
textColor = ChatMessage.MessageColor[(int)ChatMessageType.Dead];
break;
default:
if (Character.Controlled != null && (Character.Controlled.IsDead || Character.Controlled.SpeechImpediment >= 100.0f))
{
textBox.TextColor = ChatMessage.MessageColor[(int)ChatMessageType.Dead];
textColor = ChatMessage.MessageColor[(int)ChatMessageType.Dead];
}
else if (command != "") //PMing
{
textBox.TextColor = ChatMessage.MessageColor[(int)ChatMessageType.Private];
textColor = ChatMessage.MessageColor[(int)ChatMessageType.Private];
}
else
{
textBox.TextColor = ChatMessage.MessageColor[(int)ChatMessageType.Default];
textColor = ChatMessage.MessageColor[(int)ChatMessageType.Default];
}
break;
}
textBox.TextColor = textBox.TextBlock.SelectedTextColor = textColor;
return true;
}
@@ -252,21 +254,29 @@ namespace Barotrauma
Visible = false,
CanBeFocused = false
};
var senderText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), popupMsg.RectTransform, Anchor.TopRight),
senderName, textColor: senderColor, font: GUI.SmallFont, textAlignment: Alignment.TopRight)
var content = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), popupMsg.RectTransform, Anchor.Center));
Vector2 senderTextSize = Vector2.Zero;
if (!string.IsNullOrEmpty(senderName))
{
var senderText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform),
senderName, textColor: senderColor, style: null, font: GUI.SmallFont)
{
CanBeFocused = false
};
var msgPopupText = new GUITextBlock(new RectTransform(new Vector2(0.8f, 0.0f), popupMsg.RectTransform, Anchor.TopRight)
{ AbsoluteOffset = new Point(0, senderText.Rect.Height) },
displayedText, textColor: message.Color, font: GUI.SmallFont, textAlignment: Alignment.TopRight, style: null, wrap: true)
senderTextSize = senderText.Font.MeasureString(senderText.WrappedText);
senderText.RectTransform.MinSize = new Point(0, senderText.Rect.Height);
}
var msgPopupText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform),
displayedText, textColor: message.Color, font: GUI.SmallFont, textAlignment: Alignment.BottomLeft, style: null, wrap: true)
{
CanBeFocused = false
};
int textWidth = (int)Math.Max(
msgPopupText.Font.MeasureString(msgPopupText.WrappedText).X,
senderText.Font.MeasureString(senderText.WrappedText).X);
popupMsg.RectTransform.Resize(new Point(textWidth + 20, msgPopupText.Rect.Bottom - senderText.Rect.Y), resizeChildren: false);
msgPopupText.RectTransform.MinSize = new Point(0, msgPopupText.Rect.Height);
Vector2 msgSize = msgPopupText.Font.MeasureString(msgPopupText.WrappedText);
int textWidth = (int)Math.Max(msgSize.X + msgPopupText.Padding.X + msgPopupText.Padding.Z, senderTextSize.X) + 10;
popupMsg.RectTransform.Resize(new Point((int)(textWidth / content.RectTransform.RelativeSize.X) , (int)((senderTextSize.Y + msgSize.Y) / content.RectTransform.RelativeSize.Y)), resizeChildren: true);
popupMsg.RectTransform.IsFixedSize = true;
content.Recalculate();
popupMessages.Enqueue(popupMsg);
}

View File

@@ -5,16 +5,6 @@ using System.Xml.Linq;
namespace Barotrauma
{
public enum TransitionMode
{
Linear,
Smooth,
Smoother,
EaseIn,
EaseOut,
Exponential
}
public enum SpriteFallBackState
{
None,
@@ -159,7 +149,7 @@ namespace Barotrauma
Point size = new Point(0, 0);
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() != "size") { continue; }
if (!subElement.Name.ToString().Equals("size", StringComparison.OrdinalIgnoreCase)) { continue; }
Point maxResolution = subElement.GetAttributePoint("maxresolution", new Point(int.MaxValue, int.MaxValue));
if (GameMain.GraphicsWidth <= maxResolution.X && GameMain.GraphicsHeight <= maxResolution.Y)
{

View File

@@ -26,7 +26,8 @@ namespace Barotrauma
Click,
PickItem,
PickItemFail,
DropItem
DropItem,
PopupMenu
}
public enum CursorState
@@ -242,6 +243,7 @@ namespace Barotrauma
sounds[(int)GUISoundType.RadioMessage] = GameMain.SoundManager.LoadSound("Content/Sounds/UI/RadioMsg.ogg", false);
sounds[(int)GUISoundType.DeadMessage] = GameMain.SoundManager.LoadSound("Content/Sounds/UI/DeadMsg.ogg", false);
sounds[(int)GUISoundType.Click] = GameMain.SoundManager.LoadSound("Content/Sounds/UI/Click.ogg", false);
sounds[(int)GUISoundType.PopupMenu] = GameMain.SoundManager.LoadSound("Content/Sounds/UI/PopupMenu.ogg", false);
sounds[(int)GUISoundType.PickItem] = GameMain.SoundManager.LoadSound("Content/Sounds/PickItem.ogg", false);
sounds[(int)GUISoundType.PickItemFail] = GameMain.SoundManager.LoadSound("Content/Sounds/PickItemFail.ogg", false);
@@ -1922,6 +1924,19 @@ namespace Barotrauma
return true;
};
}
else if (GameMain.GameSession.GameMode is SubTestMode)
{
button = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), text: TextManager.Get("PauseMenuReturnToEditor"))
{
OnClicked = (btn, userdata) =>
{
GameMain.GameSession.GameMode.End("");
return true;
}
};
button.OnClicked += TogglePauseMenu;
}
else if (!GameMain.GameSession.GameMode.IsSinglePlayer && GameMain.Client != null && GameMain.Client.HasPermission(ClientPermissions.ManageRound))
{
new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), text: TextManager.Get("EndRound"))

View File

@@ -524,23 +524,9 @@ namespace Barotrauma
};
}
private float GetEasing(TransitionMode easing, float t)
{
return easing switch
{
TransitionMode.Smooth => MathUtils.SmoothStep(t),
TransitionMode.Smoother => MathUtils.SmootherStep(t),
TransitionMode.EaseIn => MathUtils.EaseIn(t),
TransitionMode.EaseOut => MathUtils.EaseOut(t),
TransitionMode.Exponential => t * t,
TransitionMode.Linear => t,
_ => t,
};
}
protected Color GetBlendedColor(Color targetColor, ref Color blendedColor)
{
blendedColor = ColorCrossFadeTime > 0 ? Color.Lerp(blendedColor, targetColor, MathUtils.InverseLerp(ColorCrossFadeTime, 0, GetEasing(ColorTransition, colorFadeTimer))) : targetColor;
blendedColor = ColorCrossFadeTime > 0 ? Color.Lerp(blendedColor, targetColor, MathUtils.InverseLerp(ColorCrossFadeTime, 0, ToolBox.GetEasing(ColorTransition, colorFadeTimer))) : targetColor;
return blendedColor;
}
@@ -598,7 +584,7 @@ namespace Barotrauma
foreach (UISprite uiSprite in previousSprites)
{
float alphaMultiplier = SpriteCrossFadeTime > 0 && (uiSprite.CrossFadeOut || currentSprites != null && currentSprites.Any(s => s.CrossFadeIn))
? MathUtils.InverseLerp(0, SpriteCrossFadeTime, GetEasing(uiSprite.TransitionMode, spriteFadeTimer)) : 0;
? MathUtils.InverseLerp(0, SpriteCrossFadeTime, ToolBox.GetEasing(uiSprite.TransitionMode, spriteFadeTimer)) : 0;
if (alphaMultiplier > 0)
{
uiSprite.Draw(spriteBatch, rect, previousColor * alphaMultiplier, SpriteEffects);
@@ -612,7 +598,7 @@ namespace Barotrauma
foreach (UISprite uiSprite in currentSprites)
{
float alphaMultiplier = SpriteCrossFadeTime > 0 && (uiSprite.CrossFadeIn || previousSprites != null && previousSprites.Any(s => s.CrossFadeOut))
? MathUtils.InverseLerp(SpriteCrossFadeTime, 0, GetEasing(uiSprite.TransitionMode, spriteFadeTimer)) : (_currentColor.A / 255.0f);
? MathUtils.InverseLerp(SpriteCrossFadeTime, 0, ToolBox.GetEasing(uiSprite.TransitionMode, spriteFadeTimer)) : (_currentColor.A / 255.0f);
if (alphaMultiplier > 0)
{
uiSprite.Draw(spriteBatch, rect, _currentColor * alphaMultiplier, SpriteEffects);
@@ -801,8 +787,7 @@ namespace Barotrauma
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() == "conditional" &&
!CheckConditional(subElement))
if (subElement.Name.ToString().Equals("conditional", StringComparison.OrdinalIgnoreCase) && !CheckConditional(subElement))
{
return null;
}
@@ -851,7 +836,7 @@ namespace Barotrauma
{
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() == "conditional") { continue; }
if (subElement.Name.ToString().Equals("conditional", StringComparison.OrdinalIgnoreCase)) { continue; }
FromXML(subElement, component is GUIListBox listBox ? listBox.Content.RectTransform : component.RectTransform);
}
@@ -1019,7 +1004,7 @@ namespace Barotrauma
private static GUIFrame LoadGUIFrame(XElement element, RectTransform parent)
{
string style = element.GetAttributeString("style", element.Name.ToString().ToLowerInvariant() == "spacing" ? null : "");
string style = element.GetAttributeString("style", element.Name.ToString().Equals("spacing", StringComparison.OrdinalIgnoreCase) ? null : "");
if (style == "null") { style = null; }
return new GUIFrame(RectTransform.Load(element, parent), style: style);
}

View File

@@ -95,6 +95,15 @@ namespace Barotrauma
set { button.TextColor = value; }
}
public override ScalableFont Font
{
get { return button?.Font ?? base.Font; }
set
{
if (button != null) { button.Font = value; }
}
}
public void ReceiveTextInput(char inputChar)
{
GUI.KeyboardDispatcher.Subscriber = null;
@@ -168,12 +177,11 @@ namespace Barotrauma
Anchor listAnchor = dropAbove ? Anchor.TopCenter : Anchor.BottomCenter;
Pivot listPivot = dropAbove ? Pivot.BottomCenter : Pivot.TopCenter;
listBox = new GUIListBox(new RectTransform(new Point(Rect.Width, Rect.Height * MathHelper.Clamp(elementCount, 2, 10)), rectT, listAnchor, listPivot)
{ IsFixedSize = false }, style: null)
{
Enabled = !selectMultiple,
OnSelected = SelectItem
Enabled = !selectMultiple
};
if (!selectMultiple) { listBox.OnSelected = SelectItem; }
GUI.Style.Apply(listBox, "GUIListBox", this);
GUI.Style.Apply(listBox.ContentBackground, "GUIListBox", this);
@@ -245,7 +253,7 @@ namespace Barotrauma
ToolTip = toolTip
};
new GUITickBox(new RectTransform(new Point((int)(button.Rect.Height * 0.8f)), frame.RectTransform, anchor: Anchor.CenterLeft), text)
new GUITickBox(new RectTransform(new Vector2(1.0f, 0.8f), frame.RectTransform, anchor: Anchor.CenterLeft) { MaxSize = new Point(int.MaxValue, (int)(button.Rect.Height * 0.8f)) }, text)
{
UserData = userData,
ToolTip = toolTip,

View File

@@ -59,11 +59,36 @@ namespace Barotrauma
/// </summary>
public Color Blue { get; private set; } = Color.Blue;
public Color ColorInventoryEmpty { get; private set; } = Color.Red;
public Color ColorInventoryHalf { get; private set; } = Color.Orange;
public Color ColorInventoryFull { get; private set; } = Color.LightGreen;
public Color ColorInventoryBackground { get; private set; } = Color.Gray;
public Color TextColor { get; private set; } = Color.White * 0.8f;
public Color TextColorBright { get; private set; } = Color.White * 0.9f;
public Color TextColorDark { get; private set; } = Color.Black * 0.9f;
public Color TextColorDim { get; private set; } = Color.White * 0.6f;
// Inventory
public Color EquipmentSlotIconColor { get; private set; } = new Color(99, 70, 64);
// Health HUD
public Color BuffColorLow { get; private set; } = Color.LightGreen;
public Color BuffColorMedium { get; private set; } = Color.Green;
public Color BuffColorHigh { get; private set; } = Color.DarkGreen;
public Color DebuffColorLow { get; private set; } = Color.DarkSalmon;
public Color DebuffColorMedium { get; private set; } = Color.Red;
public Color DebuffColorHigh { get; private set; } = Color.DarkRed;
public Color HealthBarColorLow { get; private set; } = Color.Red;
public Color HealthBarColorMedium { get; private set; } = Color.Orange;
public Color HealthBarColorHigh { get; private set; } = new Color(78, 114, 88);
public Color EquipmentIndicatorNotEquipped { get; private set; } = Color.Gray;
public Color EquipmentIndicatorEquipped { get; private set; } = new Color(105, 202, 125);
public Color EquipmentIndicatorRunningOut { get; private set; } = new Color(202, 105, 105);
public static Point ItemFrameMargin => new Point(50, 56).Multiply(GUI.SlicedSpriteScale);
public static Point ItemFrameOffset => new Point(0, 3).Multiply(GUI.SlicedSpriteScale);
@@ -103,10 +128,22 @@ namespace Barotrauma
case "blue":
Blue = subElement.GetAttributeColor("color", Blue);
break;
case "colorinventoryempty":
ColorInventoryEmpty = subElement.GetAttributeColor("color", ColorInventoryEmpty);
break;
case "colorinventoryhalf":
ColorInventoryHalf = subElement.GetAttributeColor("color", ColorInventoryHalf);
break;
case "colorinventoryfull":
ColorInventoryFull = subElement.GetAttributeColor("color", ColorInventoryFull);
break;
case "colorinventorybackground":
ColorInventoryBackground = subElement.GetAttributeColor("color", ColorInventoryBackground);
break;
case "textcolordark":
TextColorDark = subElement.GetAttributeColor("color", TextColorDark);
break;
case "TextColorBright":
case "textcolorbright":
TextColorBright = subElement.GetAttributeColor("color", TextColorBright);
break;
case "textcolordim":
@@ -116,6 +153,45 @@ namespace Barotrauma
case "textcolor":
TextColor = subElement.GetAttributeColor("color", TextColor);
break;
case "equipmentsloticoncolor":
EquipmentSlotIconColor = subElement.GetAttributeColor("color", EquipmentSlotIconColor);
break;
case "buffcolorlow":
BuffColorLow = subElement.GetAttributeColor("color", BuffColorLow);
break;
case "buffcolormedium":
BuffColorMedium = subElement.GetAttributeColor("color", BuffColorMedium);
break;
case "buffcolorhigh":
BuffColorHigh = subElement.GetAttributeColor("color", BuffColorHigh);
break;
case "debuffcolorlow":
DebuffColorLow = subElement.GetAttributeColor("color", DebuffColorLow);
break;
case "debuffcolormedium":
DebuffColorMedium = subElement.GetAttributeColor("color", DebuffColorMedium);
break;
case "debuffcolorhigh":
DebuffColorHigh = subElement.GetAttributeColor("color", DebuffColorHigh);
break;
case "healthbarcolorlow":
HealthBarColorLow = subElement.GetAttributeColor("color", HealthBarColorLow);
break;
case "healthbarcolormedium":
HealthBarColorMedium = subElement.GetAttributeColor("color", HealthBarColorMedium);
break;
case "healthbarcolorhigh":
HealthBarColorHigh = subElement.GetAttributeColor("color", HealthBarColorHigh);
break;
case "equipmentindicatornotequipped":
EquipmentIndicatorNotEquipped = subElement.GetAttributeColor("color", EquipmentIndicatorNotEquipped);
break;
case "equipmentindicatorequipped":
EquipmentIndicatorEquipped = subElement.GetAttributeColor("color", EquipmentIndicatorEquipped);
break;
case "equipmentindicatorrunningout":
EquipmentIndicatorRunningOut = subElement.GetAttributeColor("color", EquipmentIndicatorRunningOut);
break;
case "uiglow":
UIGlow = new UISprite(subElement);
break;
@@ -250,9 +326,8 @@ namespace Barotrauma
//check if any of the language override fonts want to override the font size as well
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() != "override") { continue; }
string language = subElement.GetAttributeString("language", "").ToLowerInvariant();
if (GameMain.Config.Language.ToLowerInvariant() == language)
if (!subElement.Name.ToString().Equals("override", StringComparison.OrdinalIgnoreCase)) { continue; }
if (GameMain.Config.Language.Equals(subElement.GetAttributeString("language", ""), StringComparison.OrdinalIgnoreCase))
{
uint overrideFontSize = GetFontSize(subElement, 0);
if (overrideFontSize > 0) { return overrideFontSize; }
@@ -261,7 +336,7 @@ namespace Barotrauma
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() != "size") { continue; }
if (!subElement.Name.ToString().Equals("size", StringComparison.OrdinalIgnoreCase)) { continue; }
Point maxResolution = subElement.GetAttributePoint("maxresolution", new Point(int.MaxValue, int.MaxValue));
if (GameMain.GraphicsWidth <= maxResolution.X && GameMain.GraphicsHeight <= maxResolution.Y)
{
@@ -275,9 +350,8 @@ namespace Barotrauma
{
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() != "override") { continue; }
string language = subElement.GetAttributeString("language", "").ToLowerInvariant();
if (GameMain.Config.Language.ToLowerInvariant() == language)
if (!subElement.Name.ToString().Equals("override", StringComparison.OrdinalIgnoreCase)) { continue; }
if (GameMain.Config.Language.Equals(subElement.GetAttributeString("language", ""), StringComparison.OrdinalIgnoreCase))
{
return subElement.GetAttributeString("file", "");
}
@@ -289,9 +363,8 @@ namespace Barotrauma
{
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() != "override") { continue; }
string language = subElement.GetAttributeString("language", "").ToLowerInvariant();
if (GameMain.Config.Language.ToLowerInvariant() == language)
if (!subElement.Name.ToString().Equals("override", StringComparison.OrdinalIgnoreCase)) { continue; }
if (GameMain.Config.Language.Equals(subElement.GetAttributeString("language", ""), StringComparison.OrdinalIgnoreCase))
{
return subElement.GetAttributeBool("dynamicloading", false);
}
@@ -303,9 +376,8 @@ namespace Barotrauma
{
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() != "override") { continue; }
string language = subElement.GetAttributeString("language", "").ToLowerInvariant();
if (GameMain.Config.Language.ToLowerInvariant() == language)
if (!subElement.Name.ToString().Equals("override", StringComparison.OrdinalIgnoreCase)) { continue; }
if (GameMain.Config.Language.Equals(subElement.GetAttributeString("language", ""), StringComparison.OrdinalIgnoreCase))
{
return subElement.GetAttributeBool("iscjk", false);
}

View File

@@ -328,11 +328,7 @@ namespace Barotrauma
{
if (text == null) { return; }
censoredText = "";
for (int i = 0; i < text.Length; i++)
{
censoredText += "\u2022";
}
censoredText = string.IsNullOrEmpty(text) ? "" : new string('\u2022', text.Length);
var rect = Rect;
@@ -446,9 +442,10 @@ namespace Barotrauma
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
if (overflowClipActive)
{
spriteBatch.End();
Rectangle scissorRect = new Rectangle(rect.X + (int)padding.X, rect.Y, rect.Width - (int)padding.X - (int)padding.Z, rect.Height);
spriteBatch.GraphicsDevice.ScissorRectangle = scissorRect;
if (!scissorRect.Intersects(prevScissorRect)) { return; }
spriteBatch.End();
spriteBatch.GraphicsDevice.ScissorRectangle = Rectangle.Intersect(prevScissorRect, scissorRect);
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable);
}

View File

@@ -69,6 +69,11 @@ namespace Barotrauma
private readonly Memento<string> memento = new Memento<string>();
public GUIFrame Frame
{
get { return frame; }
}
public GUITextBlock.TextGetterHandler TextGetter
{
get { return textBlock.TextGetter; }

View File

@@ -112,16 +112,16 @@ namespace Barotrauma
//slice from the top of the screen for misc buttons (info, end round, server controls)
ButtonAreaTop = new Rectangle(Padding, Padding, GameMain.GraphicsWidth - Padding * 2, (int)(50 * GUI.Scale));
int infoAreaWidth = (int)(142 * GUI.Scale * CharacterInfo.BgScale);
int infoAreaHeight = (int)(98 * GUI.Scale * CharacterInfo.BgScale);
int portraitSize = (int)(125 * GUI.Scale);
int infoAreaWidth = (int)(142 * GUI.Scale);
int infoAreaHeight = (int)(98 * GUI.Scale);
int portraitSize = (int)(infoAreaHeight * 0.95f);
BottomRightInfoArea = new Rectangle(GameMain.GraphicsWidth - Padding * 2 - infoAreaWidth, GameMain.GraphicsHeight - Padding * 2 - infoAreaHeight, infoAreaWidth, infoAreaHeight);
PortraitArea = new Rectangle(GameMain.GraphicsWidth - Padding - portraitSize, GameMain.GraphicsHeight - Padding - portraitSize, portraitSize, portraitSize);
PortraitArea = new Rectangle(GameMain.GraphicsWidth - portraitSize, BottomRightInfoArea.Bottom - portraitSize + Padding / 2, portraitSize, portraitSize);
//horizontal slices at the corners of the screen for health bar and affliction icons
int afflictionAreaHeight = (int)(50 * GUI.Scale);
int healthBarWidth = (int)((BottomRightInfoArea.Width + CharacterInventory.SlotSize.X + CharacterInventory.Spacing) * 1.1f);
int healthBarHeight = (int)Math.Max(50f * GUI.Scale, 25f);
int healthBarWidth = BottomRightInfoArea.Width + CharacterInventory.SlotSize.X + CharacterInventory.Spacing * 2 + CharacterInventory.HideButtonWidth;
int healthBarHeight = (int)(50f * GUI.Scale);
HealthBarArea = new Rectangle(BottomRightInfoArea.X - (healthBarWidth - BottomRightInfoArea.Width) + (int)(2 * GUI.Scale), BottomRightInfoArea.Y - healthBarHeight + (int)(10 * GUI.Scale), healthBarWidth, healthBarHeight);
AfflictionAreaLeft = new Rectangle(HealthBarArea.X, HealthBarArea.Y - Padding - afflictionAreaHeight, HealthBarArea.Width, afflictionAreaHeight);

View File

@@ -66,7 +66,7 @@ namespace Barotrauma
if (vanillaContent == null)
{
// TODO: Dynamic method for defining and finding the vanilla content package.
vanillaContent = ContentPackage.List.SingleOrDefault(cp => Path.GetFileName(cp.Path).ToLowerInvariant() == "vanilla 0.9.xml");
vanillaContent = ContentPackage.List.SingleOrDefault(cp => Path.GetFileName(cp.Path).Equals("vanilla 0.9.xml", StringComparison.OrdinalIgnoreCase));
}
return vanillaContent;
}
@@ -189,6 +189,11 @@ namespace Barotrauma
Instance = this;
if (!Directory.Exists(Content.RootDirectory))
{
throw new Exception("Content folder not found. If you are trying to compile the game from the source code and own a legal copy of the game, you can copy the Content folder from the game's files to BarotraumaShared/Content.");
}
Config = new GameSettings();
Md5Hash.LoadCache();
@@ -380,6 +385,13 @@ namespace Barotrauma
}
}
public class LoadingException : Exception
{
public LoadingException(Exception e) : base("Loading was interrupted due to an error.", innerException: e)
{
}
}
private IEnumerable<object> Load(bool isSeparateThread)
{
if (GameSettings.VerboseLogging)
@@ -397,7 +409,7 @@ namespace Barotrauma
SoundManager.SetCategoryGainMultiplier("ui", Config.SoundVolume, 0);
SoundManager.SetCategoryGainMultiplier("waterambience", Config.SoundVolume, 0);
SoundManager.SetCategoryGainMultiplier("music", Config.MusicVolume, 0);
SoundManager.SetCategoryGainMultiplier("voip", Config.VoiceChatVolume * 20.0f, 0);
SoundManager.SetCategoryGainMultiplier("voip", Config.VoiceChatVolume, 0);
if (Config.EnableSplashScreen && !ConsoleArguments.Contains("-skipintro"))
{
@@ -421,17 +433,27 @@ namespace Barotrauma
GUI.Init(Window, Config.SelectedContentPackages, GraphicsDevice);
DebugConsole.Init();
CrossThread.RequestExecutionOnMainThread(() =>
{
if (Config.AutoUpdateWorkshopItems)
{
if (SteamManager.AutoUpdateWorkshopItems())
bool waitingForWorkshopUpdates = true;
bool result = false;
TaskPool.Add(SteamManager.AutoUpdateWorkshopItemsAsync(), (task) =>
{
result = task.Result;
waitingForWorkshopUpdates = false;
});
while (waitingForWorkshopUpdates) { yield return CoroutineStatus.Running; }
if (result)
{
CrossThread.RequestExecutionOnMainThread(() =>
{
ContentPackage.LoadAll();
Config.ReloadContentPackages();
}
}
});
}
}
if (SelectedPackages.None())
@@ -488,6 +510,7 @@ namespace Barotrauma
Tutorials.Tutorial.Init();
MapGenerationParams.Init();
LevelGenerationParams.LoadPresets();
WreckAIConfig.LoadAll();
ScriptedEventSet.LoadPrefabs();
AfflictionPrefab.LoadAll(GetFilesOfType(ContentType.Afflictions));
SkillSettings.Load(GetFilesOfType(ContentType.SkillSettings));
@@ -503,6 +526,7 @@ namespace Barotrauma
yield return CoroutineStatus.Running;
JobPrefab.LoadAll(GetFilesOfType(ContentType.Jobs));
CorpsePrefab.LoadAll(GetFilesOfType(ContentType.Corpses));
NPCConversation.LoadAll(GetFilesOfType(ContentType.NPCConversations));
@@ -512,7 +536,7 @@ namespace Barotrauma
GameModePreset.Init();
Submarine.RefreshSavedSubs();
SubmarineInfo.RefreshSavedSubs();
TitleScreen.LoadState = 65.0f;
yield return CoroutineStatus.Running;
@@ -649,6 +673,8 @@ namespace Barotrauma
{
#if DEBUG
DebugConsole.ThrowError($"Failed to parse a Steam friend's connect invitation command ({connectCommand})", e);
#else
DebugConsole.Log($"Failed to parse a Steam friend's connect invitation command ({connectCommand})\n" + e.StackTrace);
#endif
ConnectName = null;
ConnectEndpoint = null;
@@ -741,12 +767,7 @@ namespace Barotrauma
if (!hasLoaded && !CoroutineManager.IsCoroutineRunning(loadingCoroutine))
{
string errMsg = "Loading was interrupted due to an error";
if (loadingCoroutine.Exception != null)
{
errMsg += ": " + loadingCoroutine.Exception.Message + "\n" + loadingCoroutine.Exception.StackTrace;
}
throw new Exception(errMsg);
throw new LoadingException(loadingCoroutine.Exception);
}
}
else if (hasLoaded)
@@ -1086,7 +1107,10 @@ namespace Barotrauma
UserData = "https://steamcommunity.com/app/602960/discussions/1/",
OnClicked = (btn, userdata) =>
{
SteamManager.OverlayCustomURL(userdata as string);
if (!SteamManager.OverlayCustomURL(userdata as string))
{
ShowOpenUrlInWebBrowserPrompt(userdata as string);
}
msgBox.Close();
return true;
}

View File

@@ -34,6 +34,7 @@ namespace Barotrauma
private GUIButton commandButton, toggleCrewButton;
private float crewListOpenState;
private bool toggleCrewListOpen = true;
private Point crewListEntrySize;
/// <summary>
/// Present only in single player games. In multiplayer. The chatbox is found from GameSession.Client.
@@ -51,7 +52,6 @@ namespace Barotrauma
{
if (toggleCrewListOpen == value) { return; }
toggleCrewListOpen = GameMain.Config.CrewMenuOpen = value;
toggleCrewButton.Children.ForEach(c => c.SpriteEffects = toggleCrewListOpen ? SpriteEffects.None : SpriteEffects.FlipHorizontally);
}
}
@@ -70,13 +70,13 @@ namespace Barotrauma
{
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() != "character") continue;
if (!subElement.Name.ToString().Equals("character", StringComparison.OrdinalIgnoreCase)) { continue; }
var characterInfo = new CharacterInfo(subElement);
characterInfos.Add(characterInfo);
foreach (XElement invElement in subElement.Elements())
{
if (invElement.Name.ToString().ToLowerInvariant() != "inventory") continue;
if (!invElement.Name.ToString().Equals("inventory", StringComparison.OrdinalIgnoreCase)) { continue; }
characterInfo.InventoryData = invElement;
break;
}
@@ -90,6 +90,8 @@ namespace Barotrauma
CanBeFocused = false
};
#region Crew Area
var crewAreaWithButtons = new GUIFrame(
HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.CrewArea, guiFrame.RectTransform),
style: null,
@@ -98,11 +100,13 @@ namespace Barotrauma
CanBeFocused = false
};
var buttonHeight = (int)(GUI.Scale * 40);
var commandButtonHeight = (int)(GUI.Scale * 40);
var buttonSize = new Point((int)(182f / 99f * commandButtonHeight), commandButtonHeight);
var crewListToggleButtonHeight = (int)(64f * buttonSize.X / 175f);
crewArea = new GUIFrame(
new RectTransform(
new Point(crewAreaWithButtons.Rect.Width, crewAreaWithButtons.Rect.Height - (int)(1.5f * buttonHeight) - 2 * HUDLayoutSettings.Padding),
new Point(crewAreaWithButtons.Rect.Width, crewAreaWithButtons.Rect.Height - commandButtonHeight - crewListToggleButtonHeight - 2 * HUDLayoutSettings.Padding),
crewAreaWithButtons.RectTransform,
Anchor.BottomLeft),
style: null,
@@ -111,7 +115,6 @@ namespace Barotrauma
CanBeFocused = false
};
var buttonSize = new Point((int)(182.0f / 99.0f * buttonHeight), buttonHeight);
commandButton = new GUIButton(
new RectTransform(buttonSize, parent: crewAreaWithButtons.RectTransform),
style: "CommandButton")
@@ -139,14 +142,13 @@ namespace Barotrauma
Spacing = (int)(GUI.Scale * 10)
};
buttonSize.Y = crewListToggleButtonHeight;
toggleCrewButton = new GUIButton(
new RectTransform(
new Point(buttonSize.X, (int)(0.5f * buttonHeight)),
parent: crewAreaWithButtons.RectTransform)
new RectTransform(buttonSize, parent: crewAreaWithButtons.RectTransform)
{
AbsoluteOffset = new Point(0, buttonHeight + HUDLayoutSettings.Padding)
AbsoluteOffset = new Point(0, commandButtonHeight + HUDLayoutSettings.Padding)
},
style: "UIToggleButton")
style: "CrewListToggleButton")
{
OnClicked = (GUIButton btn, object userdata) =>
{
@@ -159,6 +161,17 @@ namespace Barotrauma
previousOrderArrow = new Sprite("Content/UI/CommandUIAtlas.png", new Rectangle(128, 512, 128, 128));
cancelIcon = new Sprite("Content/UI/CommandUIAtlas.png", new Rectangle(512, 384, 128, 128));
// Calculate and store crew list entry size so it doesn't have to be calculated for every entry
crewListEntrySize = new Point(crewList.Content.Rect.Width - HUDLayoutSettings.Padding, 0);
int crewListEntryMinHeight = 32;
crewListEntrySize.Y = Math.Max(crewListEntryMinHeight, (int)(crewListEntrySize.X / 8f));
float charactersPerView = crewList.Content.Rect.Height / (float)(crewListEntrySize.Y + crewList.Spacing);
int adjustedHeight = (int)Math.Ceiling(crewList.Content.Rect.Height / Math.Round(charactersPerView)) - crewList.Spacing;
if (adjustedHeight < crewListEntryMinHeight) { adjustedHeight = (int)Math.Ceiling(crewList.Content.Rect.Height / Math.Floor(charactersPerView)) - crewList.Spacing; }
crewListEntrySize.Y = adjustedHeight;
#endregion
#region Chatbox
if (IsSinglePlayer)
@@ -212,7 +225,7 @@ namespace Barotrauma
var chatBox = ChatBox ?? GameMain.Client?.ChatBox;
if (chatBox != null)
{
chatBox.ToggleButton = new GUIButton(new RectTransform(new Point((int)(182f * GUI.Scale * 0.4f), (int)(99f * GUI.Scale * 0.4f)), guiFrame.RectTransform), style: "ChatToggleButton");
chatBox.ToggleButton = new GUIButton(new RectTransform(new Point((int)(182f * GUI.Scale * 0.4f), (int)(99f * GUI.Scale * 0.4f)), chatBox.GUIFrame.Parent.RectTransform), style: "ChatToggleButton");
chatBox.ToggleButton.RectTransform.AbsoluteOffset = new Point(0, HUDLayoutSettings.ChatBoxArea.Height - chatBox.ToggleButton.Rect.Height);
chatBox.ToggleButton.OnClicked += (GUIButton btn, object userdata) =>
{
@@ -248,6 +261,8 @@ namespace Barotrauma
OnClicked = (GUIButton button, object userData) =>
{
if (!CanIssueOrders) { return false; }
var sub = Character.Controlled.Submarine;
if (sub == null || sub.TeamID != Character.Controlled.TeamID || sub.Info.IsWreck) { return false; }
SetCharacterOrder(null, order, null, Character.Controlled);
var visibleHulls = new List<Hull>(Character.Controlled.GetVisibleHulls());
foreach (var hull in visibleHulls)
@@ -330,17 +345,7 @@ namespace Barotrauma
}
AddCharacterToCrewList(character);
if (character is AICharacter)
{
var ai = character.AIController as HumanAIController;
if (ai == null)
{
DebugConsole.ThrowError("Error in crewmanager - attempted to give orders to a character with no HumanAIController");
return;
}
character.SetOrder(ai.CurrentOrder, "", null, false);
}
DisplayCharacterOrder(character, character.CurrentOrder, character.CurrentOrderOption);
}
public void AddCharacterInfo(CharacterInfo characterInfo)
@@ -383,16 +388,14 @@ namespace Barotrauma
{
if (character == null) { return; }
int width = crewList.Content.Rect.Width - HUDLayoutSettings.Padding;
int height = Math.Max(32, (int)((1.0f / 8.0f) * width));
var background = new GUIFrame(
new RectTransform(new Point(width, height), parent: crewList.Content.RectTransform, anchor: Anchor.TopRight),
new RectTransform(crewListEntrySize, parent: crewList.Content.RectTransform, anchor: Anchor.TopRight),
style: "CrewListBackground")
{
UserData = character
};
var iconRelativeWidth = (float)height / background.Rect.Width;
var iconRelativeWidth = (float)crewListEntrySize.Y / background.Rect.Width;
var layoutGroup = new GUILayoutGroup(
new RectTransform(Vector2.One, parent: background.RectTransform),
@@ -788,11 +791,11 @@ namespace Barotrauma
characterFrame.SetAsFirstChild();
}
private void DisplayPreviousCharacterOrder(Character character, GUILayoutGroup characterComponent, OrderInfo currentOrderInfo)
private void DisplayPreviousCharacterOrder(Character character, GUILayoutGroup characterComponent, OrderInfo orderInfo)
{
if (currentOrderInfo.Order == null || currentOrderInfo.Order.Identifier == dismissedOrderPrefab.Identifier) { return; }
if (orderInfo.Order == null || orderInfo.Order.Identifier == dismissedOrderPrefab.Identifier) { return; }
var previousOrderInfo = new OrderInfo(currentOrderInfo);
var previousOrderInfo = new OrderInfo(orderInfo);
var prevOrderFrame = new GUIButton(
new RectTransform(
characterComponent.GetChildByUserData("job").RectTransform.RelativeSize,
@@ -835,12 +838,12 @@ namespace Barotrauma
private GUIComponent GetCurrentOrderComponent(GUILayoutGroup characterComponent)
{
return characterComponent.FindChild(c => c.UserData is OrderInfo orderInfo && orderInfo.ComponentIdentifier == "currentorder");
return characterComponent?.FindChild(c => c?.UserData is OrderInfo orderInfo && orderInfo.ComponentIdentifier == "currentorder");
}
private GUIComponent GetPreviousOrderComponent(GUILayoutGroup characterComponent)
{
return characterComponent.FindChild(c => c.UserData is OrderInfo orderInfo && orderInfo.ComponentIdentifier == "previousorder");
return characterComponent?.FindChild(c => c?.UserData is OrderInfo orderInfo && orderInfo.ComponentIdentifier == "previousorder");
}
private struct OrderInfo
@@ -910,7 +913,11 @@ namespace Barotrauma
{
if (!(c.UserData is Character character) || character.IsDead || character.Removed) { continue; }
AddCharacter(character);
DisplayCharacterOrder(character, character.CurrentOrder, (character.AIController as HumanAIController)?.CurrentOrderOption);
if (GetPreviousOrderComponent(c.GetChild<GUILayoutGroup>())?.UserData is OrderInfo prevInfo &&
crewList.Content.Children.FirstOrDefault(c => c?.UserData == character)?.GetChild<GUILayoutGroup>() is GUILayoutGroup newLayoutGroup)
{
DisplayPreviousCharacterOrder(character, newLayoutGroup, prevInfo);
}
}
}
@@ -944,6 +951,7 @@ namespace Barotrauma
{
Character.Controlled.AIController.ObjectiveManager.WaitTimer = CharacterWaitOnSwitch;
}
DisableCommandUI();
Character.Controlled = character;
}
@@ -988,6 +996,7 @@ namespace Barotrauma
commandFrame == null && !clicklessSelectionActive && CanIssueOrders)
{
CreateCommandUI(HUDLayoutSettings.PortraitArea.Contains(PlayerInput.MousePosition) ? Character.Controlled : GUI.MouseOn?.UserData as Character);
GUI.PlayUISound(GUISoundType.PopupMenu);
clicklessSelectionActive = isOpeningClick = true;
}
@@ -1175,6 +1184,8 @@ namespace Barotrauma
}
if (PlayerInput.KeyHit(InputType.RadioChat) && !ChatBox.InputBox.Selected)
{
if (Character.Controlled == null || Character.Controlled.SpeechImpediment < 100)
{
ChatBox.InputBox.AddToGUIUpdateList();
ChatBox.GUIFrame.Flash(Color.YellowGreen, 0.5f);
@@ -1192,6 +1203,7 @@ namespace Barotrauma
}
}
}
}
crewArea.Visible = characters.Count > 0 && CharacterHealth.OpenHealthWindow == null;
@@ -1234,6 +1246,7 @@ namespace Barotrauma
if (GUI.KeyboardDispatcher.Subscriber == null && PlayerInput.KeyHit(InputType.CrewOrders))
{
GUI.PlayUISound(GUISoundType.PopupMenu);
ToggleCrewListOpen = !ToggleCrewListOpen;
}
@@ -1293,13 +1306,21 @@ namespace Barotrauma
{
get
{
#if DEBUG
return Character.Controlled == null || Character.Controlled.Info != null && Character.Controlled.SpeechImpediment < 100.0f;
#else
return Character.Controlled != null && Character.Controlled.SpeechImpediment < 100.0f;
#endif
}
}
private bool CanSomeoneHearCharacter()
{
#if DEBUG
return true;
#else
return Character.Controlled != null && characters.Any(c => c != Character.Controlled && c.CanHearCharacter(Character.Controlled));
#endif
}
private void CreateCommandUI(Character characterContext = null)
@@ -1505,17 +1526,7 @@ namespace Barotrauma
shortcutCenterNode = null;
}
CreateNodes(userData);
if (returnNode != null && returnNode.Visible)
{
var hotkey = optionNodes.Count + 1;
if (expandNode != null && expandNode.Visible) { hotkey += 1; }
CreateHotkeyIcon(returnNode.RectTransform, hotkey % 10, true);
returnNodeHotkey = Keys.D0 + hotkey % 10;
}
else
{
returnNodeHotkey = Keys.None;
}
CreateReturnNodeHotkey();
return true;
}
@@ -1539,10 +1550,20 @@ namespace Barotrauma
returnNode = null;
}
CreateNodes(userData);
CreateReturnNodeHotkey();
return true;
}
private void CreateReturnNodeHotkey()
{
if (returnNode != null && returnNode.Visible)
{
var hotkey = optionNodes.Count + 1;
var hotkey = 1;
if (targetFrame == null || !targetFrame.Visible)
{
hotkey = optionNodes.Count + 1;
if (expandNode != null && expandNode.Visible) { hotkey += 1; }
}
CreateHotkeyIcon(returnNode.RectTransform, hotkey % 10, true);
returnNodeHotkey = Keys.D0 + hotkey % 10;
}
@@ -1550,7 +1571,6 @@ namespace Barotrauma
{
returnNodeHotkey = Keys.None;
}
return true;
}
private void SetCenterNode(GUIButton node)
@@ -1822,7 +1842,7 @@ namespace Barotrauma
Item.ItemList.FindAll(it => it.Components.Any(ic => ic.GetType() == order.ItemComponentType));
matchingItems.RemoveAll(it => it.Submarine != submarine && !submarine.DockedTo.Contains(it.Submarine));
matchingItems.RemoveAll(it => it.Submarine != null && it.Submarine.IsOutpost);
matchingItems.RemoveAll(it => it.Submarine != null && it.Submarine.Info.Type != SubmarineInfo.SubmarineType.Player);
}
//more than one target item -> create a minimap-like selection with a pic of the sub
@@ -2148,7 +2168,11 @@ namespace Barotrauma
ToolTip = character.Info.DisplayName + " (" + character.Info.Job.Name + ")"
};
#if DEBUG
bool canHear = true;
#else
bool canHear = character.CanHearCharacter(Character.Controlled);
#endif
if (!canHear)
{
node.CanBeFocused = icon.CanBeFocused = false;
@@ -2271,8 +2295,14 @@ namespace Barotrauma
private Character GetBestCharacterForOrder(Order order)
{
#if !DEBUG
if (Character.Controlled == null) { return null; }
return characters.FindAll(c => c != Character.Controlled && c.TeamID == Character.Controlled.TeamID)
#endif
if (order.Category == OrderCategory.Operate && HumanAIController.IsItemOperatedByAnother(null, order.TargetItemComponent, out Character operatingCharacter))
{
return operatingCharacter;
}
return characters.FindAll(c => Character.Controlled == null || (c != Character.Controlled && c.TeamID == Character.Controlled.TeamID))
.OrderByDescending(c => c.CurrentOrder == null || c.CurrentOrder.Identifier == dismissedOrderPrefab.Identifier)
.ThenByDescending(c => order.HasAppropriateJob(c))
.ThenBy(c => c.CurrentOrder?.Weight)
@@ -2281,16 +2311,18 @@ namespace Barotrauma
private List<Character> GetCharactersSortedForOrder(Order order)
{
#if !DEBUG
if (Character.Controlled == null) { return new List<Character>(); }
#endif
if (order.Identifier == "follow")
{
return characters.FindAll(c => c != Character.Controlled && c.TeamID == Character.Controlled.TeamID)
return characters.FindAll(c => Character.Controlled == null || (c != Character.Controlled && c.TeamID == Character.Controlled.TeamID))
.OrderByDescending(c => c.CurrentOrder == null || c.CurrentOrder.Identifier == dismissedOrderPrefab.Identifier)
.ToList();
}
else
{
return characters.FindAll(c => c.TeamID == Character.Controlled.TeamID)
return characters.FindAll(c => Character.Controlled == null || c.TeamID == Character.Controlled.TeamID)
.OrderByDescending(c => c.CurrentOrder == null || c.CurrentOrder.Identifier == dismissedOrderPrefab.Identifier)
.ThenByDescending(c => order.HasAppropriateJob(c))
.ThenBy(c => c.CurrentOrder?.Weight)
@@ -2411,12 +2443,15 @@ namespace Barotrauma
var reportButtonParent = ChatBox ?? GameMain.Client?.ChatBox;
if (reportButtonParent == null) { return; }
var sub = Character.Controlled.Submarine;
if (sub == null || sub.TeamID != Character.Controlled.TeamID || sub.Info.IsWreck) { return; }
ReportButtonFrame.RectTransform.AbsoluteOffset = new Point(reportButtonParent.GUIFrame.Rect.Right + (int)(10 * GUI.Scale), reportButtonParent.GUIFrame.Rect.Y);
bool hasFires = Character.Controlled.CurrentHull.FireSources.Count > 0;
ToggleReportButton("reportfire", hasFires);
bool hasLeaks = Character.Controlled.CurrentHull.Submarine != null && Character.Controlled.CurrentHull.ConnectedGaps.Any(g => !g.IsRoomToRoom && g.Open > 0.0f);
bool hasLeaks = Character.Controlled.CurrentHull.ConnectedGaps.Any(g => !g.IsRoomToRoom && g.Open > 0.0f);
ToggleReportButton("reportbreach", hasLeaks);
bool hasIntruders = Character.CharacterList.Any(c => c.CurrentHull == Character.Controlled.CurrentHull && AIObjectiveFightIntruders.IsValidTarget(c, Character.Controlled));

View File

@@ -91,7 +91,7 @@ namespace Barotrauma
if (Character.Controlled.Submarine != outpost) { return null; }
//if there's a sub docked to the outpost, we can leave the level
if (outpost.DockedTo.Count > 0)
if (outpost.DockedTo.Any())
{
var dockedSub = outpost.DockedTo.FirstOrDefault();
return dockedSub.DockedTo.Contains(Submarine.MainSub) ? Submarine.MainSub : dockedSub;
@@ -277,6 +277,9 @@ namespace Barotrauma
c.Info.InventoryData = inventoryElement;
c.Inventory?.DeleteAllItems();
}
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(GameMain.GameSession.Submarine);
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
}

View File

@@ -0,0 +1,80 @@
using Barotrauma.Tutorials;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma
{
class SubTestMode : GameMode
{
public SubTestMode(GameModePreset preset, object param)
: base(preset, param)
{
foreach (JobPrefab jobPrefab in JobPrefab.Prefabs)
{
for (int i = 0; i < jobPrefab.InitialCount; i++)
{
var variant = Rand.Range(0, jobPrefab.Variants);
CrewManager.AddCharacterInfo(new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobPrefab: jobPrefab, variant: variant));
}
}
}
public override void Start()
{
base.Start();
isRunning = true;
CrewManager.InitSinglePlayerRound();
Submarine.MainSub.SetPosition(Vector2.Zero);
}
public override void Draw(SpriteBatch spriteBatch)
{
if (!isRunning|| GUI.DisableHUD || GUI.DisableUpperHUD) return;
if (Submarine.MainSub == null) return;
}
public override void AddToGUIUpdateList()
{
if (!isRunning) return;
base.AddToGUIUpdateList();
CrewManager.AddToGUIUpdateList();
}
public override void Update(float deltaTime)
{
if (!isRunning) { return; }
base.Update(deltaTime);
}
public override void End(string endMessage = "")
{
isRunning = false;
GameMain.GameSession.EndRound("");
CrewManager.EndRound();
Submarine.Unload();
GameMain.SubEditorScreen.Select();
}
private bool EndRound(Submarine leavingSub)
{
isRunning = false;
End("");
return true;
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.Items.Components;
using Barotrauma.Networking;
@@ -221,7 +222,7 @@ namespace Barotrauma.Tutorials
{
//captain_navConsoleCustomInterface.HighlightElement(0, uiHighlightColor, duration: 1.0f, pulsateAmount: 0.0f);
yield return new WaitForSeconds(1.0f, false);
} while (Submarine.MainSub.DockedTo.Count > 0);
} while (Submarine.MainSub.DockedTo.Any());
RemoveCompletedObjective(segments[4]);
yield return new WaitForSeconds(2f, false);
TriggerTutorialSegment(5); // Navigate to destination
@@ -245,7 +246,7 @@ namespace Barotrauma.Tutorials
{
//captain_navConsoleCustomInterface.HighlightElement(0, uiHighlightColor, duration: 1.0f, pulsateAmount: 0.0f);
yield return new WaitForSeconds(1.0f, false);
} while (!Submarine.MainSub.AtEndPosition || Submarine.MainSub.DockedTo.Count == 0);
} while (!Submarine.MainSub.AtEndPosition || Submarine.MainSub.DockedTo.Any());
RemoveCompletedObjective(segments[6]);
yield return new WaitForSeconds(3f, false);
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.GetWithVariable("Captain.Radio.Complete", "[OUTPOSTNAME]", GameMain.GameSession.EndLocation.Name), ChatMessageType.Radio, null);

View File

@@ -21,8 +21,8 @@ namespace Barotrauma.Tutorials
private string levelSeed;
private string levelParams;
private Submarine startOutpost = null;
private Submarine endOutpost = null;
private SubmarineInfo startOutpost = null;
private SubmarineInfo endOutpost = null;
private bool currentTutorialCompleted = false;
private float fadeOutTime = 3f;
protected float waitBeforeFade = 4f;
@@ -56,13 +56,13 @@ namespace Barotrauma.Tutorials
private IEnumerable<object> Loading()
{
Submarine.MainSub = Submarine.Load(submarinePath, "", true);
SubmarineInfo subInfo = new SubmarineInfo(submarinePath);
LevelGenerationParams generationParams = LevelGenerationParams.LevelParams.Find(p => p.Name == levelParams);
yield return CoroutineStatus.Running;
GameMain.GameSession = new GameSession(Submarine.MainSub, "",
GameMain.GameSession = new GameSession(subInfo, "",
GameModePreset.List.Find(g => g.Identifier == "tutorial"));
(GameMain.GameSession.GameMode as TutorialMode).Tutorial = this;
@@ -72,12 +72,12 @@ namespace Barotrauma.Tutorials
if (startOutpostPath != string.Empty)
{
startOutpost = Submarine.Load(startOutpostPath, "", false);
startOutpost = new SubmarineInfo(startOutpostPath);
}
if (endOutpostPath != string.Empty)
{
endOutpost = Submarine.Load(endOutpostPath, "", false);
endOutpost = new SubmarineInfo(endOutpostPath);
}
Level tutorialLevel = new Level(levelSeed, 0, 0, generationParams, biome, startOutpost, endOutpost);
@@ -160,11 +160,11 @@ namespace Barotrauma.Tutorials
switch (this.spawnSub)
{
case "startoutpost":
spawnSub = startOutpost;
spawnSub = Level.Loaded.StartOutpost;
break;
case "endoutpost":
spawnSub = endOutpost;
spawnSub = Level.Loaded.EndOutpost;
break;
default:

View File

@@ -13,6 +13,7 @@ namespace Barotrauma
private GUIFrame infoFrameContent;
public RoundSummary RoundSummary { get; private set; }
public static bool IsInfoFrameOpen => GameMain.GameSession?.infoFrame != null;
private bool ToggleInfoFrame()
{

View File

@@ -24,7 +24,7 @@ namespace Barotrauma
public GUIFrame CreateSummaryFrame(string endMessage)
{
bool singleplayer = GameMain.NetworkMember == null;
bool gameOver = gameSession.CrewManager.GetCharacters().All(c => c.IsDead || c.IsUnconscious);
bool gameOver = gameSession.CrewManager.GetCharacters().All(c => c.IsDead || c.IsIncapacitated);
bool progress = Submarine.MainSub.AtEndPosition;
if (!singleplayer)
{
@@ -55,7 +55,7 @@ namespace Barotrauma
string summaryText = TextManager.GetWithVariables(gameOver ? "RoundSummaryGameOver" :
(progress ? "RoundSummaryProgress" : "RoundSummaryReturn"), new string[2] { "[sub]", "[location]" },
new string[2] { Submarine.MainSub.Name, progress ? GameMain.GameSession.EndLocation.Name : GameMain.GameSession.StartLocation.Name });
new string[2] { Submarine.MainSub.Info.Name, progress ? GameMain.GameSession.EndLocation.Name : GameMain.GameSession.StartLocation.Name });
var infoText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform),
summaryText, wrap: true);

View File

@@ -47,7 +47,7 @@ namespace Barotrauma
{
keyMapping = new KeyOrMouse[Enum.GetNames(typeof(InputType)).Length];
keyMapping[(int)InputType.Run] = new KeyOrMouse(Keys.LeftShift);
keyMapping[(int)InputType.Attack] = new KeyOrMouse(MouseButton.MiddleMouse);
keyMapping[(int)InputType.Attack] = new KeyOrMouse(Keys.R);
keyMapping[(int)InputType.Crouch] = new KeyOrMouse(Keys.LeftControl);
keyMapping[(int)InputType.Grab] = new KeyOrMouse(Keys.G);
keyMapping[(int)InputType.Health] = new KeyOrMouse(Keys.H);
@@ -1182,7 +1182,7 @@ namespace Barotrauma
{ RelativeOffset = new Vector2(0.02f, 0.02f) })
{ RelativeSpacing = 0.01f };
var automaticQuickStartTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.18f, debugTickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), "Enable automatic quickstart", style: "GUITickBox");
var automaticQuickStartTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.18f, debugTickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), "Automatic quickstart enabled", style: "GUITickBox");
automaticQuickStartTickBox.Selected = AutomaticQuickStartEnabled;
automaticQuickStartTickBox.ToolTip = "Will the game automatically move on to Quickstart when the game is launched";
automaticQuickStartTickBox.OnSelected = (tickBox) =>
@@ -1192,7 +1192,7 @@ namespace Barotrauma
return true;
};
var showSplashScreenTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.18f, debugTickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), "Show splash screen", style: "GUITickBox");
var showSplashScreenTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.18f, debugTickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), "Splash screen enabled", style: "GUITickBox");
showSplashScreenTickBox.Selected = EnableSplashScreen;
showSplashScreenTickBox.ToolTip = "Are the splash screens shown when the game is launched";
showSplashScreenTickBox.OnSelected = (tickBox) =>
@@ -1202,7 +1202,7 @@ namespace Barotrauma
return true;
};
var verboseLoggingTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.18f, debugTickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), "Enable verbose logging", style: "GUITickBox");
var verboseLoggingTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.18f, debugTickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), "Verbose logging enabled", style: "GUITickBox");
verboseLoggingTickBox.Selected = VerboseLogging;
verboseLoggingTickBox.ToolTip = "Should verbose logging be used";
verboseLoggingTickBox.OnSelected = (tickBox) =>
@@ -1211,6 +1211,16 @@ namespace Barotrauma
UnsavedSettings = true;
return true;
};
var textManagerDebugModeTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.18f, debugTickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), "TextManager debug mode enabled", style: "GUITickBox");
textManagerDebugModeTickBox.Selected = TextManagerDebugModeEnabled;
textManagerDebugModeTickBox.ToolTip = "Does the TextManager return the text tags for debug purposes?";
textManagerDebugModeTickBox.OnSelected = (tickBox) =>
{
TextManagerDebugModeEnabled = tickBox.Selected;
UnsavedSettings = true;
return true;
};
#endif
UnsavedSettings = false; // Reset unsaved settings to false once the UI has been created
@@ -1279,7 +1289,7 @@ namespace Barotrauma
string[] prefixes = { "OpenAL Soft on " };
foreach (string prefix in prefixes)
{
if (name.StartsWith(prefix, StringComparison.InvariantCulture))
if (name.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
{
return name.Remove(0, prefix.Length);
}

View File

@@ -43,6 +43,7 @@ namespace Barotrauma
public Vector2[] SlotPositions;
public static Point SlotSize;
public static int Spacing;
public static int HideButtonWidth;
private Layout layout;
public Layout CurrentLayout
@@ -72,21 +73,43 @@ namespace Barotrauma
get { return personalSlotArea; }
}
private GUIImage[] indicators = new GUIImage[5];
private int[] indicatorIndexes = new int[5];
private Vector2 indicatorSpriteSize;
private GUILayoutGroup indicatorGroup;
partial void InitProjSpecific(XElement element)
{
Hidden = true;
hideButton = new GUIButton(new RectTransform(new Point((int)(30 * GUI.Scale), (int)(60 * GUI.Scale)), GUI.Canvas)
hideButton = new GUIButton(new RectTransform(new Point((int)(31f * (HUDLayoutSettings.BottomRightInfoArea.Height / 100f)), HUDLayoutSettings.BottomRightInfoArea.Height), GUI.Canvas)
{ AbsoluteOffset = HUDLayoutSettings.CrewArea.Location },
"", style: "UIToggleButton");
hideButton.Children.ForEach(c => c.SpriteEffects = SpriteEffects.FlipHorizontally);
"", style: "EquipmentToggleButton");
indicatorGroup = new GUILayoutGroup(new RectTransform(Point.Zero, hideButton.RectTransform)) { IsHorizontal = false };
indicatorGroup.ChildAnchor = Anchor.TopCenter;
indicatorSpriteSize = GUI.Style.GetComponentStyle("EquipmentIndicatorDivingSuit").Sprites[GUIComponent.ComponentState.None][0].Sprite.size;
indicators[0] = new GUIImage(new RectTransform(Point.Zero, indicatorGroup.RectTransform), "EquipmentIndicatorDivingSuit");
indicators[1] = new GUIImage(new RectTransform(Point.Zero, indicatorGroup.RectTransform), "EquipmentIndicatorID");
indicators[2] = new GUIImage(new RectTransform(Point.Zero, indicatorGroup.RectTransform), "EquipmentIndicatorOutfit");
indicators[3] = new GUIImage(new RectTransform(Point.Zero, indicatorGroup.RectTransform), "EquipmentIndicatorHeadwear");
indicators[4] = new GUIImage(new RectTransform(Point.Zero, indicatorGroup.RectTransform), "EquipmentIndicatorHeadphones");
indicatorIndexes[0] = FindLimbSlot(InvSlotType.OuterClothes);
indicatorIndexes[1] = FindLimbSlot(InvSlotType.Card);
indicatorIndexes[2] = FindLimbSlot(InvSlotType.InnerClothes);
indicatorIndexes[3] = FindLimbSlot(InvSlotType.Head);
indicatorIndexes[4] = FindLimbSlot(InvSlotType.Headset);
for (int i = 0; i < indicators.Length; i++)
{
indicators[i].CanBeFocused = false;
}
hideButton.OnClicked += (GUIButton btn, object userdata) =>
{
hidePersonalSlots = !hidePersonalSlots;
foreach (GUIComponent child in btn.Children)
{
child.SpriteEffects = hidePersonalSlots ? SpriteEffects.None : SpriteEffects.FlipHorizontally;
}
return true;
};
@@ -245,6 +268,26 @@ namespace Barotrauma
return false;
}
private void SetIndicatorSizes()
{
indicatorGroup.RectTransform.AbsoluteOffset = new Point((int)Math.Round(4 * GUI.Scale), (int)Math.Round(7 * GUI.Scale));
indicatorGroup.RectTransform.NonScaledSize = new Point(hideButton.Rect.Width - indicatorGroup.RectTransform.AbsoluteOffset.X * 2, hideButton.Rect.Height - indicatorGroup.RectTransform.AbsoluteOffset.Y * 2);
indicatorGroup.AbsoluteSpacing = (int)Math.Ceiling(2 * GUI.Scale);
int indicatorHeight = (indicatorGroup.RectTransform.NonScaledSize.Y - indicatorGroup.AbsoluteSpacing * (indicators.Length - 1)) / indicators.Length;
int indicatorWidth = (int)(indicatorSpriteSize.X / (indicatorSpriteSize.Y / indicatorHeight));
if (HideButtonWidth % 2 != indicatorWidth % 2) indicatorWidth++;
Point indicatorSize = new Point(indicatorWidth, indicatorHeight);
for (int i = 0; i < indicators.Length; i++)
{
indicators[i].RectTransform.NonScaledSize = indicatorSize;
}
}
private void SetSlotPositions(Layout layout)
{
bool isFourByThree = GUI.IsFourByThree();
@@ -257,6 +300,8 @@ namespace Barotrauma
Spacing = (int)(8 * UIScale);
}
HideButtonWidth = (int)(31f * (HUDLayoutSettings.BottomRightInfoArea.Height / 100f));
SlotSize = !isFourByThree ? (SlotSpriteSmall.size * UIScale).ToPoint() : (SlotSpriteSmall.size * UIScale * .925f).ToPoint();
int bottomOffset = SlotSize.Y + Spacing * 2 + ContainedIndicatorHeight;
@@ -272,8 +317,7 @@ namespace Barotrauma
int normalSlotCount = SlotTypes.Count(s => !PersonalSlots.HasFlag(s));
int x = GameMain.GraphicsWidth / 2 - normalSlotCount * (SlotSize.X + Spacing) / 2;
int upperX = HUDLayoutSettings.BottomRightInfoArea.X - Spacing * 2 - SlotSize.X - SlotSize.X / 2;
//int upperX = GameMain.GraphicsWidth - personalSlotCount * (slotSize.X + spacing) + (int)(11 * GUI.Scale) + spacing;
int upperX = HUDLayoutSettings.BottomRightInfoArea.X - SlotSize.X - Spacing * 4 - HideButtonWidth;
//make sure the rightmost normal slot doesn't overlap with the personal slots
x -= Math.Max((x + normalSlotCount * (SlotSize.X + Spacing)) - (upperX - personalSlotCount * (SlotSize.X + Spacing)), 0);
@@ -300,11 +344,13 @@ namespace Barotrauma
if (hideButtonSlotIndex > -1)
{
hideButton.RectTransform.SetPosition(Anchor.TopLeft, Pivot.TopLeft);
hideButton.RectTransform.NonScaledSize = new Point(SlotSize.X / 2, HUDLayoutSettings.BottomRightInfoArea.Height);
hideButton.RectTransform.NonScaledSize = new Point(HideButtonWidth, HUDLayoutSettings.BottomRightInfoArea.Height);
hideButton.RectTransform.AbsoluteOffset = new Point(
personalSlotArea.Right + Spacing,
personalSlotArea.Right + Spacing * 2,
HUDLayoutSettings.BottomRightInfoArea.Y);
hideButton.Visible = true;
SetIndicatorSizes();
}
}
break;
@@ -458,6 +504,7 @@ namespace Barotrauma
Math.Min(hidePersonalSlotsState + deltaTime * 5.0f, 1.0f) :
Math.Max(hidePersonalSlotsState - deltaTime * 5.0f, 0.0f);
bool personalSlotsMoving = hidePersonalSlotsState > 0 && hidePersonalSlotsState < 1f;
for (int i = 0; i < slots.Length; i++)
{
if (!PersonalSlots.HasFlag(SlotTypes[i])) { continue; }
@@ -466,6 +513,7 @@ namespace Barotrauma
if (selectedSlot?.Slot == slots[i]) { selectedSlot = null; }
highlightedSubInventorySlots.RemoveWhere(s => s.Slot == slots[i]);
}
slots[i].IsMoving = personalSlotsMoving;
slots[i].DrawOffset = Vector2.Lerp(Vector2.Zero, new Vector2(personalSlotArea.Width, 0.0f), hidePersonalSlotsState);
}
}
@@ -551,6 +599,8 @@ namespace Barotrauma
if (character == Character.Controlled && character.SelectedCharacter == null) // Permanently open subinventories only available when the default UI layout is in use -> not when grabbing characters
{
UpdateEquipmentIndicators();
//remove the highlighted slots of other characters' inventories when not grabbing anyone
highlightedSubInventorySlots.RemoveWhere(s => s.ParentInventory != this && s.ParentInventory?.Owner is Character);
@@ -652,6 +702,39 @@ namespace Barotrauma
}
}
private void UpdateEquipmentIndicators()
{
for (int i = 0; i < indicators.Length; i++)
{
Item item = Items[indicatorIndexes[i]];
if (item != null)
{
Wearable wearable = item.GetComponent<Wearable>();
if (wearable != null && wearable.DisplayContainedStatus)
{
float conditionPercentage = item.GetContainedItemConditionPercentage();
if (conditionPercentage != -1)
{
indicators[i].Color = ToolBox.GradientLerp(conditionPercentage, GUI.Style.EquipmentIndicatorRunningOut, GUI.Style.EquipmentIndicatorEquipped);
}
else
{
indicators[i].Color = GUI.Style.EquipmentIndicatorRunningOut;
}
}
else
{
indicators[i].Color = GUI.Style.EquipmentIndicatorEquipped;
}
}
else
{
indicators[i].Color = GUI.Style.EquipmentIndicatorNotEquipped;
}
}
}
private void ShowSubInventory(SlotReference slotRef, float deltaTime, Camera cam, List<SlotReference> hideSubInventories, bool isEquippedSubInventory)
{
Rectangle hoverArea = GetSubInventoryHoverArea(slotRef);
@@ -964,7 +1047,7 @@ namespace Barotrauma
if (limbSlotIcons.ContainsKey(SlotTypes[i]))
{
var icon = limbSlotIcons[SlotTypes[i]];
icon.Draw(spriteBatch, slots[i].Rect.Center.ToVector2() + slots[i].DrawOffset, GUIColorSettings.EquipmentSlotIconColor, origin: icon.size / 2, scale: slots[i].Rect.Width / icon.size.X);
icon.Draw(spriteBatch, slots[i].Rect.Center.ToVector2() + slots[i].DrawOffset, GUI.Style.EquipmentSlotIconColor, origin: icon.size / 2, scale: slots[i].Rect.Width / icon.size.X);
}
continue;
}

View File

@@ -52,10 +52,14 @@ namespace Barotrauma.Items.Components
get { return sounds.Count > 0; }
}
private bool[] hasSoundsOfType;
private Dictionary<ActionType, List<ItemSound>> sounds;
private readonly bool[] hasSoundsOfType;
private readonly Dictionary<ActionType, List<ItemSound>> sounds;
private Dictionary<ActionType, SoundSelectionMode> soundSelectionModes;
protected float correctionTimer;
public float IsActiveTimer;
public GUILayoutSettings DefaultLayout { get; protected set; }
public GUILayoutSettings AlternativeLayout { get; protected set; }
@@ -230,20 +234,23 @@ namespace Barotrauma.Items.Components
if (loopingSound != null)
{
float targetGain = 0.0f;
if (Vector3.DistanceSquared(GameMain.SoundManager.ListenerPosition, new Vector3(item.WorldPosition, 0.0f)) > loopingSound.Range * loopingSound.Range ||
(targetGain = GetSoundVolume(loopingSound)) <= 0.0001f)
(GetSoundVolume(loopingSound)) <= 0.0001f)
{
if (loopingSoundChannel != null)
{
loopingSoundChannel.FadeOutAndDispose(); loopingSoundChannel = null;
loopingSoundChannel.FadeOutAndDispose();
loopingSoundChannel = null;
loopingSound = null;
}
return;
}
if (loopingSoundChannel != null && loopingSoundChannel.Sound != loopingSound.RoundSound.Sound)
{
loopingSoundChannel.FadeOutAndDispose(); loopingSoundChannel = null;
loopingSoundChannel.FadeOutAndDispose();
loopingSoundChannel = null;
loopingSound = null;
}
if (loopingSoundChannel == null || !loopingSoundChannel.IsPlaying)
{
@@ -259,7 +266,6 @@ namespace Barotrauma.Items.Components
return;
}
ItemSound itemSound = null;
var matchingSounds = sounds[type];
if (loopingSoundChannel == null || !loopingSoundChannel.IsPlaying)
{
@@ -277,7 +283,7 @@ namespace Barotrauma.Items.Components
{
foreach (ItemSound sound in matchingSounds)
{
PlaySound(sound, item.WorldPosition, user);
PlaySound(sound, item.WorldPosition);
}
return;
}
@@ -286,13 +292,12 @@ namespace Barotrauma.Items.Components
index = Rand.Int(matchingSounds.Count);
}
itemSound = matchingSounds[index];
PlaySound(matchingSounds[index], item.WorldPosition, user);
PlaySound(matchingSounds[index], item.WorldPosition);
}
}
private void PlaySound(ItemSound itemSound, Vector2 position, Character user = null)
private void PlaySound(ItemSound itemSound, Vector2 position)
{
if (Vector2.DistanceSquared(new Vector2(GameMain.SoundManager.ListenerPosition.X, GameMain.SoundManager.ListenerPosition.Y), position) > itemSound.Range * itemSound.Range)
{
@@ -301,8 +306,7 @@ namespace Barotrauma.Items.Components
if (itemSound.Loop)
{
loopingSound = itemSound;
if (loopingSoundChannel != null && loopingSoundChannel.Sound != loopingSound.RoundSound.Sound)
if (loopingSoundChannel != null && loopingSoundChannel.Sound != itemSound.RoundSound.Sound)
{
loopingSoundChannel.FadeOutAndDispose(); loopingSoundChannel = null;
}
@@ -310,6 +314,7 @@ namespace Barotrauma.Items.Components
{
float volume = GetSoundVolume(itemSound);
if (volume <= 0.0001f) { return; }
loopingSound = itemSound;
loopingSoundChannel = loopingSound.RoundSound.Sound.Play(
new Vector3(position.X, position.Y, 0.0f),
0.01f,

View File

@@ -3,11 +3,17 @@ using Barotrauma.Lights;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Collections.Generic;
namespace Barotrauma.Items.Components
{
partial class LightComponent : Powered, IServerSerializable, IDrawableComponent
{
private bool? lastReceivedState;
private CoroutineHandle resetPredictionCoroutine;
private float resetPredictionTimer;
public Vector2 DrawSize
{
get { return new Vector2(light.Range * 2, light.Range * 2); }
@@ -32,6 +38,12 @@ namespace Barotrauma.Items.Components
light.Color = LightColor.Multiply(brightness);
}
public override void OnItemLoaded()
{
base.OnItemLoaded();
SetLightSourceState(IsActive, lightBrightness);
}
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
{
if (light.LightSprite != null && (item.body == null || item.body.Enabled) && lightBrightness > 0.0f && IsOn)
@@ -49,9 +61,36 @@ namespace Barotrauma.Items.Components
}
}
partial void OnStateChanged()
{
if (GameMain.Client == null || !lastReceivedState.HasValue) { return; }
//reset to last known server state after the state hasn't changed in 1.0 seconds client-side
resetPredictionTimer = 1.0f;
if (resetPredictionCoroutine == null || !CoroutineManager.IsCoroutineRunning(resetPredictionCoroutine))
{
resetPredictionCoroutine = CoroutineManager.StartCoroutine(ResetPredictionAfterDelay());
}
}
/// <summary>
/// Reset client-side prediction of the light's state to the last known state sent by the server after resetPredictionTimer runs out
/// </summary>
private IEnumerable<object> ResetPredictionAfterDelay()
{
while (resetPredictionTimer > 0.0f)
{
resetPredictionTimer -= CoroutineManager.DeltaTime;
yield return CoroutineStatus.Running;
}
if (lastReceivedState.HasValue) { IsActive = lastReceivedState.Value; }
resetPredictionCoroutine = null;
yield return CoroutineStatus.Success;
}
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
IsOn = msg.ReadBoolean();
IsActive = msg.ReadBoolean();
lastReceivedState = IsActive;
}
protected override void RemoveComponentSpecific()

View File

@@ -140,11 +140,11 @@ namespace Barotrauma.Items.Components
var inputArea = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 1f), bottomFrame.RectTransform, Anchor.BottomCenter), isHorizontal: true, childAnchor: Anchor.BottomLeft);
// === INPUT SLOTS === //
inputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(0.8f, 1f), inputArea.RectTransform), style: null);
inputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(0.7f, 1f), inputArea.RectTransform), style: null);
new GUICustomComponent(new RectTransform(Vector2.One, inputInventoryHolder.RectTransform), DrawInputOverLay) { CanBeFocused = false };
// === ACTIVATE BUTTON === //
var buttonFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.2f, 0.8f), inputArea.RectTransform), childAnchor: Anchor.CenterRight);
var buttonFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.3f, 0.8f), inputArea.RectTransform), childAnchor: Anchor.CenterRight);
activateButton = new GUIButton(new RectTransform(new Vector2(1f, 0.6f), buttonFrame.RectTransform),
TextManager.Get("FabricatorCreate"), style: "DeviceButton")
{
@@ -154,7 +154,7 @@ namespace Barotrauma.Items.Components
};
// === POWER WARNING === //
inSufficientPowerWarning = new GUITextBlock(new RectTransform(Vector2.One, activateButton.RectTransform),
TextManager.Get("FabricatorNoPower"), textColor: GUI.Style.Orange, textAlignment: Alignment.Center, color: Color.Black, style: "OuterGlow")
TextManager.Get("FabricatorNoPower"), textColor: GUI.Style.Orange, textAlignment: Alignment.Center, color: Color.Black, style: "OuterGlow", wrap: true)
{
HoverColor = Color.Black,
IgnoreLayoutGroups = true,
@@ -357,6 +357,8 @@ namespace Barotrauma.Items.Components
{
overlayComponent.RectTransform.SetAsLastChild();
if (outputContainer.Inventory.Items.First() != null) { return; }
FabricationRecipe targetItem = fabricatedItem ?? selectedItem;
if (targetItem != null)
{
@@ -584,15 +586,20 @@ namespace Barotrauma.Items.Components
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
FabricatorState newState = (FabricatorState)msg.ReadByte();
float newTimeUntilReady = msg.ReadSingle();
int itemIndex = msg.ReadRangedInteger(-1, fabricationRecipes.Count - 1);
UInt16 userID = msg.ReadUInt16();
Character user = Entity.FindEntityByID(userID) as Character;
if (itemIndex == -1 || user == null)
State = newState;
timeUntilReady = newTimeUntilReady;
if (newState == FabricatorState.Stopped || itemIndex == -1 || user == null)
{
CancelFabricating();
}
else
else if (newState == FabricatorState.Active || newState == FabricatorState.Paused)
{
//if already fabricating the selected item, return
if (fabricatedItem != null && fabricationRecipes.IndexOf(fabricatedItem) == itemIndex) { return; }

View File

@@ -129,8 +129,8 @@ namespace Barotrauma.Items.Components
{
if (child.UserData is Hull hull)
{
if (hull.Submarine == null || !hull.Submarine.IsOutpost) { continue; }
string text = TextManager.GetWithVariable("MiniMapOutpostDockingInfo", "[outpost]", hull.Submarine.Name);
if (hull.Submarine == null || !hull.Submarine.Info.IsOutpost) { continue; }
string text = TextManager.GetWithVariable("MiniMapOutpostDockingInfo", "[outpost]", hull.Submarine.Info.Name);
Vector2 textSize = GUI.Font.MeasureString(text);
Vector2 textPos = child.Center;
if (textPos.X + textSize.X / 2 > submarineContainer.Rect.Right)

View File

@@ -99,6 +99,10 @@ namespace Barotrauma.Items.Components
Step = 0.05f,
OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
{
if (pumpSpeedLockTimer <= 0.0f)
{
targetLevel = null;
}
float newValue = barScroll * 200.0f - 100.0f;
if (Math.Abs(newValue - FlowPercentage) < 0.1f) { return false; }

View File

@@ -490,7 +490,7 @@ namespace Barotrauma.Items.Components
disruptedDirections.Clear();
foreach (AITarget t in AITarget.List)
{
if (t.SoundRange <= 0.0f || !t.Enabled || float.IsNaN(t.SoundRange) || float.IsInfinity(t.SoundRange)) { continue; }
if (t.SoundRange <= 0.0f || float.IsNaN(t.SoundRange) || float.IsInfinity(t.SoundRange)) { continue; }
float distSqr = Vector2.DistanceSquared(t.WorldPosition, transducerCenter);
if (distSqr > t.SoundRange * t.SoundRange * 2) { continue; }
@@ -647,6 +647,8 @@ namespace Barotrauma.Items.Components
if (GameMain.GameSession == null) { return; }
if (Level.Loaded == null) { return; }
DrawMarker(spriteBatch,
GameMain.GameSession.StartLocation.Name,
"outpost",
@@ -699,8 +701,8 @@ namespace Barotrauma.Items.Components
if (sub.WorldPosition.Y > Level.Loaded.Size.Y) { continue; }
DrawMarker(spriteBatch,
sub.Name,
sub.HasTag(SubmarineTag.Shuttle) ? "shuttle" : "submarine",
sub.Info.Name,
sub.Info.HasTag(SubmarineTag.Shuttle) ? "shuttle" : "submarine",
sub.WorldPosition - transducerCenter,
displayScale, center, DisplayRadius * 0.95f);
}

View File

@@ -46,6 +46,8 @@ namespace Barotrauma.Items.Components
private float checkConnectedPortsTimer;
private const float CheckConnectedPortsInterval = 1.0f;
public DockingPort ActiveDockingSource, DockingTarget;
private Vector2 keyboardInput = Vector2.Zero;
private float inputCumulation;
@@ -665,7 +667,7 @@ namespace Barotrauma.Items.Components
if (Vector2.DistanceSquared(PlayerInput.MousePosition, steerArea.Rect.Center.ToVector2()) < steerRadius * steerRadius)
{
if (PlayerInput.PrimaryMouseButtonHeld() && !CrewManager.IsCommandInterfaceOpen)
if (PlayerInput.PrimaryMouseButtonHeld() && !CrewManager.IsCommandInterfaceOpen && !GameSession.IsInfoFrameOpen)
{
Vector2 displaySubPos = (-sonar.DisplayOffset * sonar.Zoom) / sonar.Range * sonar.DisplayRadius * sonar.Zoom;
displaySubPos.Y = -displaySubPos.Y;

View File

@@ -106,11 +106,10 @@ namespace Barotrauma.Items.Components
{
if (indicatorSize.X <= 1.0f || indicatorSize.Y <= 1.0f) { return; }
GUI.DrawRectangle(spriteBatch,
new Vector2(
item.DrawPosition.X - item.Sprite.SourceRect.Width / 2 * item.Scale + indicatorPosition.X * item.Scale,
-item.DrawPosition.Y - item.Sprite.SourceRect.Height / 2 * item.Scale + indicatorPosition.Y * item.Scale),
indicatorSize * item.Scale, Color.Black, depth: item.SpriteDepth - 0.00001f);
Vector2 itemSize = new Vector2(item.Sprite.SourceRect.Width, item.Sprite.SourceRect.Height) * item.Scale;
Vector2 indicatorPos = -itemSize / 2 + indicatorPosition * item.Scale;
if (item.FlippedX && item.Prefab.CanSpriteFlipX) { indicatorPos.X = -indicatorPos.X - indicatorSize.X * item.Scale; }
if (item.FlippedY && item.Prefab.CanSpriteFlipY) { indicatorPos.Y = -indicatorPos.Y - indicatorSize.Y * item.Scale; }
if (charge > 0)
{
@@ -118,23 +117,21 @@ namespace Barotrauma.Items.Components
if (!isHorizontal)
{
GUI.DrawRectangle(spriteBatch,
new Vector2(
item.DrawPosition.X - item.Sprite.SourceRect.Width / 2 * item.Scale + indicatorPosition.X * item.Scale + 1,
-item.DrawPosition.Y - item.Sprite.SourceRect.Height / 2 * item.Scale + indicatorPosition.Y * item.Scale + 1 + ((indicatorSize.Y * item.Scale) * (1.0f - charge / capacity))),
new Vector2(indicatorSize.X * item.Scale - 2, (indicatorSize.Y * item.Scale - 2) * (charge / capacity)), indicatorColor, true,
new Vector2(item.DrawPosition.X, -item.DrawPosition.Y + ((indicatorSize.Y * item.Scale) * (1.0f - charge / capacity))) + indicatorPos,
new Vector2(indicatorSize.X * item.Scale, (indicatorSize.Y * item.Scale) * (charge / capacity)), indicatorColor, true,
depth: item.SpriteDepth - 0.00001f);
}
else
{
GUI.DrawRectangle(spriteBatch,
new Vector2(
item.DrawPosition.X - item.Sprite.SourceRect.Width / 2 * item.Scale + indicatorPosition.X * item.Scale + 1 ,
-item.DrawPosition.Y - item.Sprite.SourceRect.Height / 2 * item.Scale + indicatorPosition.Y * item.Scale + 1),
new Vector2((indicatorSize.X * item.Scale - 2) * (charge / capacity), indicatorSize.Y * item.Scale - 2), indicatorColor, true,
new Vector2(item.DrawPosition.X, -item.DrawPosition.Y) + indicatorPos,
new Vector2((indicatorSize.X * item.Scale) * (charge / capacity), indicatorSize.Y * item.Scale), indicatorColor, true,
depth: item.SpriteDepth - 0.00001f);
}
}
GUI.DrawRectangle(spriteBatch,
new Vector2(item.DrawPosition.X, -item.DrawPosition.Y) + indicatorPos,
indicatorSize * item.Scale, Color.Black, depth: item.SpriteDepth - 0.00001f);
}
public void ClientWrite(IWriteMessage msg, object[] extraData)

View File

@@ -0,0 +1,66 @@
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
partial class Projectile : ItemComponent
{
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
bool isStuck = msg.ReadBoolean();
if (isStuck)
{
Vector2 simPosition = new Vector2(
msg.ReadSingle(),
msg.ReadSingle());
Vector2 axis = new Vector2(
msg.ReadSingle(),
msg.ReadSingle());
UInt16 entityID = msg.ReadUInt16();
Entity entity = Entity.FindEntityByID(entityID);
item.body.SetTransform(simPosition, item.body.Rotation);
if (entity is Character character)
{
byte limbIndex = msg.ReadByte();
if (limbIndex >= character.AnimController.Limbs.Length)
{
DebugConsole.ThrowError($"Failed to read a projectile update from the server. Limb index out of bounds ({limbIndex}, character: {character.ToString()})");
return;
}
var limb = character.AnimController.Limbs[limbIndex];
StickToTarget(limb.body.FarseerBody, axis);
}
else if (entity is Structure structure)
{
byte bodyIndex = msg.ReadByte();
if (bodyIndex >= structure.Bodies.Count)
{
DebugConsole.ThrowError($"Failed to read a projectile update from the server. Structure body index out of bounds ({bodyIndex}, structure: {structure.ToString()})");
return;
}
var body = structure.Bodies[bodyIndex];
StickToTarget(body, axis);
}
else if (entity is Item item)
{
StickToTarget(item.body.FarseerBody, axis);
}
else if (entity is Submarine sub)
{
StickToTarget(sub.PhysicsBody.FarseerBody, axis);
}
else
{
DebugConsole.ThrowError($"Failed to read a projectile update from the server. Invalid stick target ({entity?.ToString() ?? "null"}, {entityID})");
}
}
else
{
Unstick();
}
}
}
}

View File

@@ -236,15 +236,7 @@ namespace Barotrauma.Items.Components
DeteriorateAlways = msg.ReadBoolean();
ushort currentFixerID = msg.ReadUInt16();
currentFixerAction = (FixActions)msg.ReadRangedInteger(0, 2);
if (currentFixerID == 0)
{
CurrentFixer = null;
}
else
{
CurrentFixer = Entity.FindEntityByID(currentFixerID) as Character;
}
CurrentFixer = currentFixerID != 0 ? Entity.FindEntityByID(currentFixerID) as Character : null;
}
public void ClientWrite(IWriteMessage msg, object[] extraData = null)

View File

@@ -0,0 +1,163 @@
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
partial class Rope : ItemComponent, IDrawableComponent
{
private Sprite sprite, startSprite, endSprite;
[Serialize(5, false)]
public int SpriteWidth
{
get;
set;
}
[Serialize("255,255,255,255", false)]
public Color SpriteColor
{
get;
set;
}
[Serialize(false, false)]
public bool Tile
{
get;
set;
}
public Vector2 DrawSize
{
get
{
if (target == null || source == null) { return Vector2.Zero; }
return new Vector2(
Math.Abs(target.DrawPosition.X - source.DrawPosition.X),
Math.Abs(target.DrawPosition.Y - source.DrawPosition.Y)) * 1.5f;
}
}
partial void InitProjSpecific(XElement element)
{
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "sprite":
sprite = new Sprite(subElement);
break;
case "startsprite":
startSprite = new Sprite(subElement);
break;
case "endsprite":
endSprite = new Sprite(subElement);
break;
}
}
}
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
{
if (target == null) { return; }
Vector2 startPos = new Vector2(source.DrawPosition.X, -source.DrawPosition.Y);
Vector2 endPos = new Vector2(target.DrawPosition.X, -target.DrawPosition.Y);
if (Snapped)
{
float snapState = 1.0f - snapTimer / SnapAnimDuration;
Vector2 diff = target.DrawPosition - source.DrawPosition;
diff.Y = -diff.Y;
int width = (int)(SpriteWidth * snapState);
if (width > 0.0f)
{
DrawRope(spriteBatch, endPos - diff * snapState * 0.5f, endPos, width);
DrawRope(spriteBatch, startPos, startPos + diff * snapState * 0.5f, width);
}
}
else
{
DrawRope(spriteBatch, startPos, endPos, SpriteWidth);
}
if (startSprite != null || endSprite != null)
{
Vector2 dir = endPos - startPos;
float angle = (float)Math.Atan2(dir.Y, dir.X);
if (startSprite != null)
{
float depth = Math.Min(item.GetDrawDepth() + (startSprite.Depth - item.Sprite.Depth), 0.999f);
startSprite?.Draw(spriteBatch, startPos, SpriteColor, angle, depth: depth);
}
if (endSprite != null)
{
float depth = Math.Min(item.GetDrawDepth() + (endSprite.Depth - item.Sprite.Depth), 0.999f);
endSprite?.Draw(spriteBatch, endPos, SpriteColor, angle, depth: depth);
}
}
}
private void DrawRope(SpriteBatch spriteBatch, Vector2 startPos, Vector2 endPos, int width)
{
float depth = sprite == null ?
item.Sprite.Depth + 0.001f :
Math.Min(item.GetDrawDepth() + (sprite.Depth - item.Sprite.Depth), 0.999f);
if (sprite?.Texture == null)
{
GUI.DrawLine(spriteBatch,
startPos,
endPos,
SpriteColor, depth: depth, width: width);
return;
}
if (Tile)
{
float length = Vector2.Distance(startPos, endPos);
Vector2 dir = (endPos - startPos) / length;
float x;
for (x = 0.0f; x <= length - sprite.size.X; x += sprite.size.X)
{
GUI.DrawLine(spriteBatch, sprite,
startPos + dir * (x - 5.0f),
startPos + dir * (x + sprite.size.X),
SpriteColor, depth: depth, width: width);
}
float leftOver = length - x;
if (leftOver > 0.0f)
{
GUI.DrawLine(spriteBatch, sprite,
startPos + dir * (x - 5.0f),
endPos,
SpriteColor, depth: depth, width: width);
}
}
else
{
GUI.DrawLine(spriteBatch, sprite,
startPos,
endPos,
SpriteColor, depth: depth, width: width);
}
}
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
snapped = msg.ReadBoolean();
}
protected override void RemoveComponentSpecific()
{
sprite?.Remove(); sprite = null;
startSprite?.Remove(); startSprite = null;
endSprite?.Remove(); endSprite = null;
}
}
}

View File

@@ -45,13 +45,48 @@ namespace Barotrauma.Items.Components
float elementSize = Math.Min(1.0f / visibleElements.Count(), 1);
foreach (CustomInterfaceElement ciElement in visibleElements)
{
if (ciElement.ContinuousSignal)
if (!string.IsNullOrEmpty(ciElement.PropertyName))
{
var layoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, elementSize), uiElementContainer.RectTransform), isHorizontal: true)
{
RelativeSpacing = 0.02f,
UserData = ciElement
};
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), layoutGroup.RectTransform),
TextManager.Get(ciElement.Label, returnNull: true) ?? ciElement.Label);
var textBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), layoutGroup.RectTransform), "", style: "GUITextBoxNoIcon")
{
OverflowClip = true,
UserData = ciElement
};
//reset size restrictions set by the Style to make sure the elements can fit the interface
textBox.RectTransform.MinSize = textBox.Frame.RectTransform.MinSize = new Point(0, 0);
textBox.RectTransform.MaxSize = textBox.Frame.RectTransform.MaxSize = new Point(int.MaxValue, int.MaxValue);
textBox.OnDeselected += (tb, key) =>
{
if (GameMain.Client == null)
{
TextChanged(tb.UserData as CustomInterfaceElement, textBox.Text);
}
else
{
item.CreateClientEvent(this);
}
};
textBox.OnEnterPressed += (tb, text) =>
{
tb.Deselect();
return true;
};
uiElements.Add(textBox);
}
else if (ciElement.ContinuousSignal)
{
var tickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, elementSize), uiElementContainer.RectTransform)
{
MaxSize = ElementMaxSize
},
TextManager.Get(ciElement.Label, returnNull: true) ?? ciElement.Label)
}, TextManager.Get(ciElement.Label, returnNull: true) ?? ciElement.Label)
{
UserData = ciElement
};
@@ -148,7 +183,7 @@ namespace Barotrauma.Items.Components
foreach (var uiElement in uiElements)
{
if (!(uiElement.UserData is CustomInterfaceElement element)) { continue; }
bool visible = Screen.Selected == GameMain.SubEditorScreen || element.StatusEffects.Any() || (element.Connection != null && element.Connection.Wires.Any(w => w != null));
bool visible = Screen.Selected == GameMain.SubEditorScreen || element.StatusEffects.Any() || !string.IsNullOrEmpty(element.PropertyName) || (element.Connection != null && element.Connection.Wires.Any(w => w != null));
if (visible) { visibleElementCount++; }
if (uiElement.Visible != visible)
{
@@ -188,6 +223,22 @@ namespace Barotrauma.Items.Components
customInterfaceElementList[i].Label;
tickBox.TextBlock.Wrap = tickBox.Text.Contains(' ');
}
if (uiElements[i] is GUITextBox textBox)
{
var textBlock = textBox.Parent.GetChild<GUITextBlock>();
textBlock.Text = string.IsNullOrWhiteSpace(customInterfaceElementList[i].Label) ?
TextManager.GetWithVariable("connection.signaloutx", "[num]", (i + 1).ToString()) :
customInterfaceElementList[i].Label;
textBlock.Wrap = textBlock.Text.Contains(' ');
foreach (ISerializableEntity e in item.AllPropertyObjects)
{
if (e.SerializableProperties.ContainsKey(customInterfaceElementList[i].PropertyName))
{
textBox.Text = e.SerializableProperties[customInterfaceElementList[i].PropertyName].GetValue(e) as string;
}
}
}
}
uiElementContainer.Recalculate();
@@ -206,6 +257,10 @@ namespace Barotrauma.Items.Components
{
textBlocks.Add(tickBox.TextBlock);
}
else if (element is GUILayoutGroup)
{
textBlocks.Add(element.GetChild<GUITextBlock>());
}
}
uiElementContainer.Recalculate();
GUITextBlock.AutoScaleAndNormalize(textBlocks);
@@ -216,7 +271,11 @@ namespace Barotrauma.Items.Components
//extradata contains an array of buttons clicked by the player (or nothing if the player didn't click anything)
for (int i = 0; i < customInterfaceElementList.Count; i++)
{
if (customInterfaceElementList[i].ContinuousSignal)
if (!string.IsNullOrEmpty(customInterfaceElementList[i].PropertyName))
{
msg.Write(((GUITextBox)uiElements[i]).Text);
}
else if (customInterfaceElementList[i].ContinuousSignal)
{
msg.Write(((GUITickBox)uiElements[i]).Selected);
}
@@ -230,6 +289,12 @@ namespace Barotrauma.Items.Components
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
for (int i = 0; i < customInterfaceElementList.Count; i++)
{
if (!string.IsNullOrEmpty(customInterfaceElementList[i].PropertyName))
{
TextChanged(customInterfaceElementList[i], msg.ReadString());
}
else
{
bool elementState = msg.ReadBoolean();
if (customInterfaceElementList[i].ContinuousSignal)
@@ -243,6 +308,7 @@ namespace Barotrauma.Items.Components
}
}
}
}
protected override void RemoveComponentSpecific()
{

View File

@@ -20,10 +20,10 @@ namespace Barotrauma.Items.Components
public void Draw(SpriteBatch spriteBatch, Wire wire, Color color, Vector2 offset, float depth, float width = 0.3f)
{
spriteBatch.Draw(wire.wireSprite.Texture,
new Vector2(start.X + offset.X, -(start.Y + offset.Y)), null, color,
new Vector2(start.X + offset.X, -(start.Y + offset.Y)), wire.wireSprite.SourceRect, color,
-angle,
new Vector2(0.0f, wire.wireSprite.size.Y / 2.0f),
new Vector2(length / wire.wireSprite.Texture.Width, width),
new Vector2(length / wire.wireSprite.size.X, width),
SpriteEffects.None,
depth);
}
@@ -34,10 +34,10 @@ namespace Barotrauma.Items.Components
end.Y = -end.Y;
spriteBatch.Draw(wire.wireSprite.Texture,
start, null, color,
start, wire.wireSprite.SourceRect, color,
MathUtils.VectorToAngle(end - start),
new Vector2(0.0f, wire.wireSprite.size.Y / 2.0f),
new Vector2((Vector2.Distance(start, end)) / wire.wireSprite.Texture.Width, width),
new Vector2((Vector2.Distance(start, end)) / wire.wireSprite.size.X, width),
SpriteEffects.None,
depth);
}
@@ -50,6 +50,13 @@ namespace Barotrauma.Items.Components
private static int? selectedNodeIndex;
private static int? highlightedNodeIndex;
[Serialize(0.3f, false)]
public float Width
{
get;
set;
}
public Vector2 DrawSize
{
get { return sectionExtents; }
@@ -72,7 +79,7 @@ namespace Barotrauma.Items.Components
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() == "wiresprite")
if (subElement.Name.ToString().Equals("wiresprite", StringComparison.OrdinalIgnoreCase))
{
overrideSprite = new Sprite(subElement);
break;
@@ -109,20 +116,20 @@ namespace Barotrauma.Items.Components
{
foreach (WireSection section in sections)
{
section.Draw(spriteBatch, this, Screen.Selected == GameMain.GameScreen ? higlightColor : editorHighlightColor, drawOffset, depth + 0.00001f, 0.7f);
section.Draw(spriteBatch, this, Screen.Selected == GameMain.GameScreen ? higlightColor : editorHighlightColor, drawOffset, depth + 0.00001f, Width * 2.0f);
}
}
else if (item.IsSelected)
{
foreach (WireSection section in sections)
{
section.Draw(spriteBatch, this, editorSelectedColor, drawOffset, depth + 0.00001f, 0.7f);
section.Draw(spriteBatch, this, editorSelectedColor, drawOffset, depth + 0.00001f, Width * 2.0f);
}
}
foreach (WireSection section in sections)
{
section.Draw(spriteBatch, this, item.Color, drawOffset, depth, 0.3f);
section.Draw(spriteBatch, this, item.Color, drawOffset, depth, Width);
}
if (nodes.Count > 0)
@@ -167,13 +174,13 @@ namespace Barotrauma.Items.Components
spriteBatch, this,
new Vector2(nodes[nodes.Count - 1].X, nodes[nodes.Count - 1].Y) + drawOffset,
new Vector2(newNodePos.X, newNodePos.Y) + drawOffset,
item.Color, 0.0f, 0.3f);
item.Color, 0.0f, Width);
WireSection.Draw(
spriteBatch, this,
new Vector2(newNodePos.X, newNodePos.Y) + drawOffset,
item.DrawPosition,
item.Color, itemDepth, 0.3f);
item.Color, itemDepth, Width);
GUI.DrawRectangle(spriteBatch, new Vector2(newNodePos.X + drawOffset.X, -(newNodePos.Y + drawOffset.Y)) - Vector2.One * 3, Vector2.One * 6, item.Color);
}
@@ -183,7 +190,7 @@ namespace Barotrauma.Items.Components
spriteBatch, this,
new Vector2(nodes[nodes.Count - 1].X, nodes[nodes.Count - 1].Y) + drawOffset,
item.DrawPosition,
item.Color, 0.0f, 0.3f);
item.Color, 0.0f, Width);
}
}
}

View File

@@ -142,7 +142,7 @@ namespace Barotrauma.Items.Components
private void DrawCharacterInfo(SpriteBatch spriteBatch, Character target, float alpha = 1.0f)
{
Vector2 hudPos = GameMain.GameScreen.Cam.WorldToScreen(target.WorldPosition);
Vector2 hudPos = GameMain.GameScreen.Cam.WorldToScreen(target.DrawPosition);
hudPos += Vector2.UnitX * 50.0f;
List<string> texts = new List<string>();

View File

@@ -223,11 +223,14 @@ namespace Barotrauma.Items.Components
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
{
Vector2 drawPos = new Vector2(item.Rect.X + transformedBarrelPos.X, item.Rect.Y - transformedBarrelPos.Y);
if (item.Submarine != null) drawPos += item.Submarine.DrawPosition;
if (item.Submarine != null)
{
drawPos += item.Submarine.DrawPosition;
}
drawPos.Y = -drawPos.Y;
float recoilOffset = 0.0f;
if (RecoilDistance > 0.0f && recoilTimer > 0.0f)
if (Math.Abs(RecoilDistance) > 0.0f && recoilTimer > 0.0f)
{
//move the barrel backwards 0.1 seconds after launching
if (recoilTimer >= Math.Max(Reload, 0.1f) - 0.1f)
@@ -376,6 +379,19 @@ namespace Barotrauma.Items.Components
return widget;
}
private void GetAvailablePower(out float availableCharge, out float availableCapacity)
{
var batteries = item.GetConnectedComponents<PowerContainer>();
availableCharge = 0.0f;
availableCapacity = 0.0f;
foreach (PowerContainer battery in batteries)
{
availableCharge += battery.Charge;
availableCapacity += battery.Capacity;
}
}
/// <summary>
/// Returns correct angle between -2PI and +2PI
/// </summary>
@@ -488,11 +504,17 @@ namespace Barotrauma.Items.Components
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
UInt16 projectileID = msg.ReadUInt16();
//projectile removed, do nothing
if (projectileID == 0) return;
float newTargetRotation = msg.ReadRangedSingle(minRotation, maxRotation, 8);
Item projectile = Entity.FindEntityByID(projectileID) as Item;
if (projectile == null)
if (Character.Controlled == null || user != Character.Controlled)
{
targetRotation = newTargetRotation;
}
//projectile removed, do nothing
if (projectileID == 0) { return; }
if (!(Entity.FindEntityByID(projectileID) is Item projectile))
{
DebugConsole.ThrowError("Failed to launch a projectile - item with the ID \"" + projectileID + " not found");
return;

View File

@@ -150,9 +150,9 @@ namespace Barotrauma.Items.Components
if (joint == null)
{
string errorMsg = "Error while reading a docking port network event (Dock method did not create a joint between the ports)." +
" Submarine: " + (item.Submarine?.Name ?? "null") +
", target submarine: " + (DockingTarget.item.Submarine?.Name ?? "null");
if (item.Submarine?.DockedTo.Contains(DockingTarget.item.Submarine) ?? false)
" Submarine: " + (item.Submarine?.Info.Name ?? "null") +
", target submarine: " + (DockingTarget.item.Submarine?.Info.Name ?? "null");
if (item.Submarine?.ConnectedDockingPorts.ContainsKey(DockingTarget.item.Submarine) ?? false)
{
errorMsg += "\nAlready docked.";
}

View File

@@ -45,12 +45,17 @@ namespace Barotrauma
public float QuickUseTimer;
public string QuickUseButtonToolTip;
public bool IsMoving = false;
private static Rectangle offScreenRect = new Rectangle(new Point(-1000, 0), Point.Zero);
public GUIComponent.ComponentState EquipButtonState;
public Rectangle EquipButtonRect
{
get
{
// Returns a point off-screen, Rectangle.Empty places buttons in the top left of the screen
if (IsMoving) return offScreenRect;
int buttonDir = Math.Sign(SubInventoryDir);
float sizeY = Inventory.UnequippedIndicator.size.Y * Inventory.UIScale * Inventory.IndicatorScaleAdjustment;
@@ -284,6 +289,7 @@ namespace Barotrauma
}
protected static HashSet<SlotReference> highlightedSubInventorySlots = new HashSet<SlotReference>();
private static List<SlotReference> subInventorySlotsToDraw = new List<SlotReference>();
protected static SlotReference selectedSlot;
@@ -1048,11 +1054,14 @@ namespace Barotrauma
return hoverArea;
}
public static void DrawFront(SpriteBatch spriteBatch)
{
if (GUI.PauseMenuOpen || GUI.SettingsMenuOpen) return;
if (GUI.PauseMenuOpen || GUI.SettingsMenuOpen) { return; }
foreach (var slot in highlightedSubInventorySlots)
subInventorySlotsToDraw.Clear();
subInventorySlotsToDraw.AddRange(highlightedSubInventorySlots);
foreach (var slot in subInventorySlotsToDraw)
{
int slotIndex = Array.IndexOf(slot.ParentInventory.slots, slot.Slot);
if (slotIndex > -1 && slotIndex < slot.ParentInventory.slots.Length)
@@ -1136,11 +1145,11 @@ namespace Barotrauma
/*if (inventory != null && (CharacterInventory.PersonalSlots.HasFlag(type) || (inventory.isSubInventory && (inventory.Owner as Item) != null
&& (inventory.Owner as Item).AllowedSlots.Any(a => CharacterInventory.PersonalSlots.HasFlag(a)))))
{
slotColor = slot.IsHighlighted ? GUIColorSettings.EquipmentSlotColor : GUIColorSettings.EquipmentSlotColor * 0.8f;
slotColor = slot.IsHighlighted ? GUI.Style.EquipmentSlotColor : GUI.Style.EquipmentSlotColor * 0.8f;
}
else
{
slotColor = slot.IsHighlighted ? GUIColorSettings.InventorySlotColor : GUIColorSettings.InventorySlotColor * 0.8f;
slotColor = slot.IsHighlighted ? GUI.Style.InventorySlotColor : GUI.Style.InventorySlotColor * 0.8f;
}*/
if (inventory != null && inventory.Locked) { slotColor = Color.Gray * 0.5f; }
@@ -1199,13 +1208,15 @@ namespace Barotrauma
dir < 0 ? rect.Bottom + HUDLayoutSettings.Padding / 2 : rect.Y - HUDLayoutSettings.Padding / 2 - ContainedIndicatorHeight, rect.Width, ContainedIndicatorHeight);
containedIndicatorArea.Inflate(-4, 0);
Color backgroundColor = GUI.Style.ColorInventoryBackground;
if (itemContainer.ContainedStateIndicator?.Texture == null)
{
containedIndicatorArea.Inflate(0, -2);
GUI.DrawRectangle(spriteBatch, containedIndicatorArea, Color.Gray * 0.9f, true);
GUI.DrawRectangle(spriteBatch, containedIndicatorArea, backgroundColor, true);
GUI.DrawRectangle(spriteBatch,
new Rectangle(containedIndicatorArea.X, containedIndicatorArea.Y, (int)(containedIndicatorArea.Width * containedState), containedIndicatorArea.Height),
ToolBox.GradientLerp(containedState, Color.Red, Color.Orange, Color.LightGreen) * 0.8f, true);
ToolBox.GradientLerp(containedState, GUI.Style.ColorInventoryEmpty, GUI.Style.ColorInventoryHalf, GUI.Style.ColorInventoryFull) * 0.8f, true);
GUI.DrawLine(spriteBatch,
new Vector2(containedIndicatorArea.X + (int)(containedIndicatorArea.Width * containedState), containedIndicatorArea.Y),
new Vector2(containedIndicatorArea.X + (int)(containedIndicatorArea.Width * containedState), containedIndicatorArea.Bottom),
@@ -1224,12 +1235,12 @@ namespace Barotrauma
}
indicatorSprite.Draw(spriteBatch, containedIndicatorArea.Center.ToVector2(),
(inventory != null && inventory.Locked) ? Color.Gray * 0.5f : Color.Gray * 0.9f,
(inventory != null && inventory.Locked) ? backgroundColor * 0.5f : backgroundColor,
origin: indicatorSprite.size / 2,
rotate: 0.0f,
scale: indicatorScale);
Color indicatorColor = ToolBox.GradientLerp(containedState, Color.Red, Color.Orange, Color.LightGreen);
Color indicatorColor = ToolBox.GradientLerp(containedState, GUI.Style.ColorInventoryEmpty, GUI.Style.ColorInventoryHalf, GUI.Style.ColorInventoryFull);
if (inventory != null && inventory.Locked) { indicatorColor *= 0.5f; }
spriteBatch.Draw(indicatorSprite.Texture, containedIndicatorArea.Center.ToVector2(),

View File

@@ -29,14 +29,8 @@ namespace Barotrauma
private bool editingHUDRefreshPending;
private float editingHUDRefreshTimer;
class SpriteState
{
public float RotationState;
public float OffsetState;
public bool IsActive = true;
}
private Dictionary<DecorativeSprite, SpriteState> spriteAnimState = new Dictionary<DecorativeSprite, SpriteState>();
private readonly Dictionary<DecorativeSprite, DecorativeSprite.State> spriteAnimState = new Dictionary<DecorativeSprite, DecorativeSprite.State>();
private Sprite activeSprite;
public override Sprite Sprite
@@ -160,7 +154,7 @@ namespace Barotrauma
foreach (var decorativeSprite in ((ItemPrefab)prefab).DecorativeSprites)
{
decorativeSprite.Sprite.EnsureLazyLoaded();
spriteAnimState.Add(decorativeSprite, new SpriteState());
spriteAnimState.Add(decorativeSprite, new DecorativeSprite.State());
}
}
@@ -197,8 +191,8 @@ namespace Barotrauma
public override void Draw(SpriteBatch spriteBatch, bool editing, bool back = true)
{
if (!Visible || (!editing && HiddenInGame)) return;
if (editing && !ShowItems) return;
if (!Visible || (!editing && HiddenInGame)) { return; }
if (editing && !ShowItems) { return; }
Color color = IsHighlighted && !GUI.DisableItemHighlights && Screen.Selected != GameMain.GameScreen ? GUI.Style.Orange : GetSpriteColor();
//if (IsSelected && editing) color = Color.Lerp(color, Color.Gold, 0.5f);
@@ -333,15 +327,6 @@ namespace Barotrauma
if (GameMain.DebugDraw)
{
aiTarget?.Draw(spriteBatch);
var containedItems = ContainedItems;
if (containedItems != null)
{
foreach (Item item in containedItems)
{
item.AiTarget?.Draw(spriteBatch);
}
}
if (body != null)
{
body.DebugDraw(spriteBatch, Color.White);
@@ -407,46 +392,7 @@ namespace Barotrauma
public void UpdateSpriteStates(float deltaTime)
{
foreach (int spriteGroup in Prefab.DecorativeSpriteGroups.Keys)
{
for (int i = 0; i < Prefab.DecorativeSpriteGroups[spriteGroup].Count; i++)
{
var decorativeSprite = Prefab.DecorativeSpriteGroups[spriteGroup][i];
if (decorativeSprite == null) { continue; }
if (spriteGroup > 0)
{
int activeSpriteIndex = ID % Prefab.DecorativeSpriteGroups[spriteGroup].Count;
if (i != activeSpriteIndex)
{
spriteAnimState[decorativeSprite].IsActive = false;
continue;
}
}
//check if the sprite is active (whether it should be drawn or not)
var spriteState = spriteAnimState[decorativeSprite];
spriteState.IsActive = true;
foreach (PropertyConditional conditional in decorativeSprite.IsActiveConditionals)
{
if (!ConditionalMatches(conditional))
{
spriteState.IsActive = false;
break;
}
}
if (!spriteState.IsActive) { continue; }
//check if the sprite should be animated
bool animate = true;
foreach (PropertyConditional conditional in decorativeSprite.AnimationConditionals)
{
if (!ConditionalMatches(conditional)) { animate = false; break; }
}
if (!animate) { continue; }
spriteState.OffsetState += deltaTime;
spriteState.RotationState += deltaTime;
}
}
DecorativeSprite.UpdateSpriteStates(Prefab.DecorativeSpriteGroups, spriteAnimState, ID, deltaTime, ConditionalMatches);
}
public override void UpdateEditing(Camera cam)
@@ -1227,6 +1173,8 @@ namespace Barotrauma
}
}
byte bodyType = msg.ReadByte();
byte teamID = msg.ReadByte();
bool tagsChanged = msg.ReadBoolean();
string tags = "";
@@ -1284,6 +1232,11 @@ namespace Barotrauma
ID = itemId
};
if (item.body != null)
{
item.body.BodyType = (BodyType)bodyType;
}
foreach (WifiComponent wifiComponent in item.GetComponents<WifiComponent>())
{
wifiComponent.TeamID = (Character.TeamType)teamID;

View File

@@ -24,7 +24,7 @@ namespace Barotrauma
public override void Draw(SpriteBatch sb, bool editing, bool back = true)
{
if (GameMain.DebugDraw)
if (!GameMain.DebugDraw && Screen.Selected.Cam.Zoom > 0.1f)
{
Vector2 center = new Vector2(WorldRect.X + rect.Width / 2.0f, -(WorldRect.Y - rect.Height / 2.0f));
GUI.DrawLine(sb, center, center + new Vector2(flowForce.X, -flowForce.Y) / 10.0f, GUI.Style.Red);
@@ -41,7 +41,7 @@ namespace Barotrauma
}
}
if (!editing || !ShowGaps) return;
if (!editing || !ShowGaps) { return; }
Color clr = (open == 0.0f) ? GUI.Style.Red : Color.Cyan;
if (IsHighlighted) clr = Color.Gold;
@@ -76,6 +76,8 @@ namespace Barotrauma
clr * 0.6f, width: lineWidth);
}
if (linkedTo.Count != 2 || linkedTo[0] != linkedTo[1])
{
for (int i = 0; i < linkedTo.Count; i++)
{
Vector2 dir = IsHorizontal ?
@@ -103,6 +105,7 @@ namespace Barotrauma
new Vector2(Math.Min(rect.Width, arrowWidth) / GUI.Arrow.size.X, arrowSize / GUI.Arrow.size.Y),
SpriteEffects.None, depth);
}
}
if (IsSelected)
{

View File

@@ -246,9 +246,7 @@ namespace Barotrauma
if (!ShowHulls && !GameMain.DebugDraw) return;
if (!editing && !GameMain.DebugDraw) return;
if (aiTarget != null) aiTarget.Draw(spriteBatch);
if (!editing && (!GameMain.DebugDraw || Screen.Selected.Cam.Zoom < 0.1f)) return;
Rectangle drawRect =
Submarine == null ? rect : new Rectangle((int)(Submarine.DrawPosition.X + rect.X), (int)(Submarine.DrawPosition.Y + rect.Y), rect.Width, rect.Height);
@@ -271,7 +269,8 @@ namespace Barotrauma
GUI.DrawRectangle(spriteBatch, new Rectangle(drawRect.Center.X, -drawRect.Y + drawRect.Height / 2, 10, (int)(100 * Math.Min(waterVolume / Volume, 1.0f))), Color.Cyan, true);
if (WaterVolume > Volume)
{
GUI.DrawRectangle(spriteBatch, new Rectangle(drawRect.Center.X, -drawRect.Y + drawRect.Height / 2, 10, (int)(100 * (waterVolume - Volume) / MaxCompress)), GUI.Style.Red, true);
float maxExcessWater = Volume * MaxCompress;
GUI.DrawRectangle(spriteBatch, new Rectangle(drawRect.Center.X, -drawRect.Y + drawRect.Height / 2, 10, (int)(100 * (waterVolume - Volume) / maxExcessWater)), GUI.Style.Red, true);
}
GUI.DrawRectangle(spriteBatch, new Rectangle(drawRect.Center.X, -drawRect.Y + drawRect.Height / 2, 10, 100), Color.Black);

View File

@@ -39,7 +39,7 @@ namespace Barotrauma
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() != "sprite") continue;
if (!subElement.Name.ToString().Equals("sprite", System.StringComparison.OrdinalIgnoreCase)) { continue; }
Sprite = new Sprite(subElement, lazyLoad: true);
break;

View File

@@ -1,7 +1,7 @@
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using FarseerPhysics.Dynamics;
using System;
using System.Linq;
using System.Collections.Generic;
using FarseerPhysics;
@@ -54,7 +54,7 @@ namespace Barotrauma
if (renderer == null) return;
renderer.Draw(spriteBatch, cam);
if (GameMain.DebugDraw)
if (GameMain.DebugDraw && Screen.Selected.Cam.Zoom > 0.1f)
{
foreach (InterestingPosition pos in positionsOfInterest)
{
@@ -78,6 +78,35 @@ namespace Barotrauma
GUI.DrawRectangle(spriteBatch, ruinArea, Color.DarkSlateBlue, false, 0, 5);
}
foreach (var positions in wreckPositions.Values)
{
for (int i = 0; i < positions.Count; i++)
{
float t = (i + 1) / (float)positions.Count;
float multiplier = MathHelper.Lerp(0, 1, t);
Color color = Color.Red * multiplier;
var pos = positions[i];
pos.Y = -pos.Y;
var size = new Vector2(100);
GUI.DrawRectangle(spriteBatch, pos - size / 2, size, color, thickness: 10);
if (i < positions.Count - 1)
{
var nextPos = positions[i + 1];
nextPos.Y = -nextPos.Y;
GUI.DrawLine(spriteBatch, pos, nextPos, color, width: 10);
}
}
}
foreach (var rects in blockedRects.Values)
{
foreach (var rect in rects)
{
Rectangle newRect = rect;
newRect.Y = -newRect.Y;
GUI.DrawRectangle(spriteBatch, newRect, Color.Red, thickness: 5);
}
}
}
}

View File

@@ -126,7 +126,7 @@ namespace Barotrauma
int j = 0;
foreach (XElement subElement in Prefab.Config.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() != "deformablesprite") continue;
if (!subElement.Name.ToString().Equals("deformablesprite", StringComparison.OrdinalIgnoreCase)) { continue; }
foreach (XElement animationElement in subElement.Elements())
{
var newDeformation = SpriteDeformation.Load(animationElement, Prefab.Name);

View File

@@ -4,6 +4,7 @@ using Barotrauma.SpriteDeformations;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma
@@ -120,7 +121,7 @@ namespace Barotrauma
SerializableProperty.SerializeProperties(this, element);
foreach (XElement subElement in element.Elements())
foreach (XElement subElement in element.Elements().ToList())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
@@ -160,7 +161,7 @@ namespace Barotrauma
bool elementFound = false;
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() == "overridecommonness"
if (subElement.Name.ToString().Equals("overridecommonness", System.StringComparison.OrdinalIgnoreCase)
&& subElement.GetAttributeString("leveltype", "") == overrideCommonness.Key)
{
subElement.Attribute("commonness").Value = overrideCommonness.Value.ToString("G", CultureInfo.InvariantCulture);

View File

@@ -228,7 +228,7 @@ namespace Barotrauma
public void Draw(SpriteBatch spriteBatch, Camera cam)
{
if (GameMain.DebugDraw && cam.Zoom > 0.05f)
if (GameMain.DebugDraw && cam.Zoom > 0.1f)
{
var cells = level.GetCells(cam.WorldViewCenter, 2);
foreach (VoronoiCell cell in cells)

View File

@@ -977,7 +977,7 @@ namespace Barotrauma.Lights
origin, -Rotation, SpriteScale, LightSpriteEffect);
}
if (GameMain.DebugDraw)
if (GameMain.DebugDraw && Screen.Selected.Cam.Zoom > 0.1f)
{
Vector2 drawPos = position;
if (ParentSub != null) { drawPos += ParentSub.DrawPosition; }

View File

@@ -12,10 +12,10 @@ namespace Barotrauma
{
public override void Draw(SpriteBatch spriteBatch, bool editing, bool back = true)
{
if (!editing || wallVertices == null) return;
if (!editing || wallVertices == null) { return; }
Color color = (IsHighlighted) ? GUI.Style.Orange : GUI.Style.Green;
if (IsSelected) color = GUI.Style.Red;
Color color = IsHighlighted ? GUI.Style.Orange : GUI.Style.Green;
if (IsSelected) { color = GUI.Style.Red; }
Vector2 pos = Position;
@@ -37,11 +37,7 @@ namespace Barotrauma
GUI.DrawLine(spriteBatch, pos + Vector2.UnitY * 50.0f, pos - Vector2.UnitY * 50.0f, color, 0.0f, 5);
GUI.DrawLine(spriteBatch, pos + Vector2.UnitX * 50.0f, pos - Vector2.UnitX * 50.0f, color, 0.0f, 5);
Rectangle drawRect = rect;
drawRect.Y = -rect.Y;
GUI.DrawRectangle(spriteBatch, drawRect, GUI.Style.Red, true);
if (!Item.ShowLinks) return;
if (!Item.ShowLinks) { return; }
foreach (MapEntity e in linkedTo)
{
@@ -135,7 +131,7 @@ namespace Barotrauma
return false;
}
XDocument doc = Submarine.OpenFile(pathBox.Text);
XDocument doc = SubmarineInfo.OpenFile(pathBox.Text);
if (doc == null || doc.Root == null) return false;
pathBox.Flash(GUI.Style.Green);

View File

@@ -18,6 +18,11 @@ namespace Barotrauma
public static Vector2 StartMovingPos => startMovingPos;
// Quick undo/redo for size and movement only. TODO: Remove if we do a more general implementation.
private Memento<Rectangle> rectMemento;
public event Action<Rectangle> Resized;
private static bool resizing;
private int resizeDirX, resizeDirY;
@@ -589,6 +594,14 @@ namespace Barotrauma
if (structure.FlippedX && structure.Prefab.CanSpriteFlipX) spriteEffects ^= SpriteEffects.FlipHorizontally;
if (structure.flippedY && structure.Prefab.CanSpriteFlipY) spriteEffects ^= SpriteEffects.FlipVertically;
}
else if (e is WayPoint wayPoint)
{
Vector2 drawPos = e.WorldPosition;
drawPos.Y = -drawPos.Y;
drawPos += moveAmount;
wayPoint.Draw(spriteBatch, drawPos);
continue;
}
e.prefab?.DrawPlacing(spriteBatch,
new Rectangle(e.WorldRect.Location + new Point((int)moveAmount.X, (int)-moveAmount.Y), e.WorldRect.Size), e.Scale, spriteEffects);
GUI.DrawRectangle(spriteBatch,

View File

@@ -18,11 +18,13 @@ namespace Barotrauma
private List<ConvexHull> convexHulls;
private readonly Dictionary<DecorativeSprite, DecorativeSprite.State> spriteAnimState = new Dictionary<DecorativeSprite, DecorativeSprite.State>();
public override bool SelectableInEditor
{
get
{
return HasBody ? ShowWalls : ShowStructures;;
return HasBody ? ShowWalls : ShowStructures;
}
}
@@ -38,6 +40,12 @@ namespace Barotrauma
{
Prefab.sprite?.EnsureLazyLoaded();
Prefab.BackgroundSprite?.EnsureLazyLoaded();
foreach (var decorativeSprite in Prefab.DecorativeSprites)
{
decorativeSprite.Sprite.EnsureLazyLoaded();
spriteAnimState.Add(decorativeSprite, new DecorativeSprite.State());
}
}
partial void CreateConvexHull(Vector2 position, Vector2 size, float rotation)
@@ -156,19 +164,19 @@ namespace Barotrauma
{
Rectangle worldRect = WorldRect;
if (worldRect.X > worldView.Right || worldRect.Right < worldView.X) return false;
if (worldRect.Y < worldView.Y - worldView.Height || worldRect.Y - worldRect.Height > worldView.Y) return false;
if (worldRect.X > worldView.Right || worldRect.Right < worldView.X) { return false; }
if (worldRect.Y < worldView.Y - worldView.Height || worldRect.Y - worldRect.Height > worldView.Y) { return false; }
return true;
}
public override void Draw(SpriteBatch spriteBatch, bool editing, bool back = true)
{
if (prefab.sprite == null) return;
if (prefab.sprite == null) { return; }
if (editing)
{
if (!HasBody && !ShowStructures) return;
if (HasBody && !ShowWalls) return;
if (!HasBody && !ShowStructures) { return; }
if (HasBody && !ShowWalls) { return; }
}
Draw(spriteBatch, editing, back, null);
@@ -188,12 +196,13 @@ namespace Barotrauma
private void Draw(SpriteBatch spriteBatch, bool editing, bool back = true, Effect damageEffect = null)
{
if (prefab.sprite == null) return;
if (prefab.sprite == null) { return; }
if (editing)
{
if (!HasBody && !ShowStructures) return;
if (HasBody && !ShowWalls) return;
if (!HasBody && !ShowStructures) { return; }
if (HasBody && !ShowWalls) { return; }
}
else if (HiddenInGame) { return; }
Color color = IsHighlighted ? GUI.Style.Orange : spriteColor;
if (IsSelected && editing)
@@ -254,7 +263,7 @@ namespace Barotrauma
spriteBatch,
new Vector2(rect.X + drawOffset.X, -(rect.Y + drawOffset.Y)),
new Vector2(rect.Width, rect.Height),
color: color,
color: Prefab.BackgroundSpriteColor,
textureScale: TextureScale * Scale,
startOffset: backGroundOffset,
depth: Math.Max(Prefab.BackgroundSprite.Depth + (ID % 255) * 0.000001f, depth + 0.000001f));
@@ -318,10 +327,20 @@ namespace Barotrauma
depth: depth,
textureScale: TextureScale * Scale);
}
foreach (var decorativeSprite in Prefab.DecorativeSprites)
{
if (!spriteAnimState[decorativeSprite].IsActive) { continue; }
float rotation = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState);
Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState) * Scale;
decorativeSprite.Sprite.Draw(spriteBatch, new Vector2(DrawPosition.X + offset.X, -(DrawPosition.Y + offset.Y)), color,
rotation, Scale, prefab.sprite.effects,
depth: Math.Min(depth + (decorativeSprite.Sprite.Depth - prefab.sprite.Depth), 0.999f));
}
prefab.sprite.effects = oldEffects;
}
if (GameMain.DebugDraw)
if (GameMain.DebugDraw && Screen.Selected.Cam.Zoom > 0.5f)
{
if (Bodies != null)
{
@@ -350,11 +369,67 @@ namespace Barotrauma
}
}
}
AiTarget?.Draw(spriteBatch);
}
}
public void UpdateSpriteStates(float deltaTime)
{
DecorativeSprite.UpdateSpriteStates(Prefab.DecorativeSpriteGroups, spriteAnimState, ID, deltaTime, ConditionalMatches);
foreach (int spriteGroup in Prefab.DecorativeSpriteGroups.Keys)
{
for (int i = 0; i < Prefab.DecorativeSpriteGroups[spriteGroup].Count; i++)
{
var decorativeSprite = Prefab.DecorativeSpriteGroups[spriteGroup][i];
if (decorativeSprite == null) { continue; }
if (spriteGroup > 0)
{
int activeSpriteIndex = ID % Prefab.DecorativeSpriteGroups[spriteGroup].Count;
if (i != activeSpriteIndex)
{
spriteAnimState[decorativeSprite].IsActive = false;
continue;
}
}
//check if the sprite is active (whether it should be drawn or not)
var spriteState = spriteAnimState[decorativeSprite];
spriteState.IsActive = true;
foreach (PropertyConditional conditional in decorativeSprite.IsActiveConditionals)
{
if (!ConditionalMatches(conditional))
{
spriteState.IsActive = false;
break;
}
}
if (!spriteState.IsActive) { continue; }
//check if the sprite should be animated
bool animate = true;
foreach (PropertyConditional conditional in decorativeSprite.AnimationConditionals)
{
if (!ConditionalMatches(conditional)) { animate = false; break; }
}
if (!animate) { continue; }
spriteState.OffsetState += deltaTime;
spriteState.RotationState += deltaTime;
}
}
}
private bool ConditionalMatches(PropertyConditional conditional)
{
if (!string.IsNullOrEmpty(conditional.TargetItemComponentName))
{
return false;
}
else
{
if (!conditional.Matches(this)) { return false; }
}
return true;
}
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
byte sectionCount = msg.ReadByte();

View File

@@ -1,11 +1,21 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
namespace Barotrauma
{
partial class StructurePrefab : MapEntityPrefab
{
public Color BackgroundSpriteColor
{
get;
private set;
}
public List<DecorativeSprite> DecorativeSprites = new List<DecorativeSprite>();
public Dictionary<int, List<DecorativeSprite>> DecorativeSpriteGroups = new Dictionary<int, List<DecorativeSprite>>();
public override void UpdatePlacing(Camera cam)
{
Vector2 position = Submarine.MouseToWorldGrid(cam, Submarine.MainSub);
@@ -40,7 +50,7 @@ namespace Barotrauma
if (PlayerInput.PrimaryMouseButtonReleased())
{
newRect.Location -= MathUtils.ToPoint(Submarine.MainSub.Position);
var structure = new Structure(newRect, this, Submarine.MainSub)
new Structure(newRect, this, Submarine.MainSub)
{
Submarine = Submarine.MainSub
};

View File

@@ -35,7 +35,6 @@ namespace Barotrauma
partial class Submarine : Entity, IServerSerializable
{
public Sprite PreviewImage;
public static Vector2 MouseToWorldGrid(Camera cam, Submarine sub)
{
Vector2 position = PlayerInput.MousePosition;
@@ -56,6 +55,8 @@ namespace Barotrauma
private static List<RoundSound> roundSounds = null;
public static RoundSound LoadRoundSound(XElement element, bool stream = false)
{
if (GameMain.SoundManager?.Disabled ?? true) { return null; }
string filename = element.GetAttributeString("file", "");
if (string.IsNullOrEmpty(filename)) filename = element.GetAttributeString("sound", "");
@@ -222,7 +223,7 @@ namespace Barotrauma
GUI.DrawRectangle(spriteBatch, worldBorders, Color.White, false, 0, 5);
if (sub.subBody.PositionBuffer.Count < 2) continue;
if (sub.subBody == null || sub.subBody.PositionBuffer.Count < 2) continue;
Vector2 prevPos = ConvertUnits.ToDisplayUnits(sub.subBody.PositionBuffer[0].Position);
prevPos.Y = -prevPos.Y;
@@ -329,125 +330,6 @@ namespace Barotrauma
}
}
public static bool SaveCurrent(string filePath, MemoryStream previewImage = null)
{
if (MainSub == null)
{
MainSub = new Submarine(filePath);
}
MainSub.filePath = filePath;
return MainSub.SaveAs(filePath, previewImage);
}
public void CreatePreviewWindow(GUIComponent parent)
{
var content = new GUIFrame(new RectTransform(Vector2.One, parent.RectTransform), style: null);
if (PreviewImage == null)
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), content.RectTransform), TextManager.Get(SavedSubmarines.Contains(this) ? "SubPreviewImageNotFound" : "SubNotDownloaded"));
}
else
{
var submarinePreviewBackground = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.5f), content.RectTransform), style: null) { Color = Color.Black };
new GUIImage(new RectTransform(new Vector2(0.98f), submarinePreviewBackground.RectTransform, Anchor.Center), PreviewImage, scaleToFit: true);
new GUIFrame(new RectTransform(Vector2.One, submarinePreviewBackground.RectTransform), "InnerGlow", color: Color.Black);
}
var descriptionBox = new GUIListBox(new RectTransform(new Vector2(1, 0.5f), content.RectTransform, Anchor.BottomCenter))
{
UserData = "descriptionbox",
ScrollBarVisible = true,
Spacing = 5
};
//space
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.03f), descriptionBox.Content.RectTransform), style: null);
new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionBox.Content.RectTransform), TextManager.Get("submarine.name." + Name, true) ?? Name, font: GUI.LargeFont, wrap: true) { ForceUpperCase = true, CanBeFocused = false };
float leftPanelWidth = 0.6f;
float rightPanelWidth = 0.4f / leftPanelWidth;
ScalableFont font = descriptionBox.Rect.Width < 350 ? GUI.SmallFont : GUI.Font;
Vector2 realWorldDimensions = Dimensions * Physics.DisplayToRealWorldRatio;
if (realWorldDimensions != Vector2.Zero)
{
string dimensionsStr = TextManager.GetWithVariables("DimensionsFormat", new string[2] { "[width]", "[height]" }, new string[2] { ((int)realWorldDimensions.X).ToString(), ((int)realWorldDimensions.Y).ToString() });
var dimensionsText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), descriptionBox.Content.RectTransform),
TextManager.Get("Dimensions"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
{ CanBeFocused = false };
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), dimensionsText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
dimensionsStr, textAlignment: Alignment.TopLeft, font: font, wrap: true)
{ CanBeFocused = false };
dimensionsText.RectTransform.MinSize = new Point(0, dimensionsText.Children.First().Rect.Height);
}
if (RecommendedCrewSizeMax > 0)
{
var crewSizeText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), descriptionBox.Content.RectTransform),
TextManager.Get("RecommendedCrewSize"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
{ CanBeFocused = false };
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), crewSizeText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
RecommendedCrewSizeMin + " - " + RecommendedCrewSizeMax, textAlignment: Alignment.TopLeft, font: font, wrap: true)
{ CanBeFocused = false };
crewSizeText.RectTransform.MinSize = new Point(0, crewSizeText.Children.First().Rect.Height);
}
if (!string.IsNullOrEmpty(RecommendedCrewExperience))
{
var crewExperienceText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), descriptionBox.Content.RectTransform),
TextManager.Get("RecommendedCrewExperience"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
{ CanBeFocused = false };
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), crewExperienceText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
TextManager.Get(RecommendedCrewExperience), textAlignment: Alignment.TopLeft, font: font, wrap: true)
{ CanBeFocused = false };
crewExperienceText.RectTransform.MinSize = new Point(0, crewExperienceText.Children.First().Rect.Height);
}
if (RequiredContentPackages.Any())
{
var contentPackagesText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), descriptionBox.Content.RectTransform),
TextManager.Get("RequiredContentPackages"), textAlignment: Alignment.TopLeft, font: font)
{ CanBeFocused = false };
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), contentPackagesText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
string.Join(", ", RequiredContentPackages), textAlignment: Alignment.TopLeft, font: font, wrap: true)
{ CanBeFocused = false };
contentPackagesText.RectTransform.MinSize = new Point(0, contentPackagesText.Children.First().Rect.Height);
}
// show what game version the submarine was created on
if (!IsVanillaSubmarine() && GameVersion != null)
{
var versionText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), descriptionBox.Content.RectTransform),
TextManager.Get("serverlistversion"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
{ CanBeFocused = false };
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), versionText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
GameVersion.ToString(), textAlignment: Alignment.TopLeft, font: font, wrap: true)
{ CanBeFocused = false };
versionText.RectTransform.MinSize = new Point(0, versionText.Children.First().Rect.Height);
}
GUITextBlock.AutoScaleAndNormalize(descriptionBox.Content.Children.Where(c => c is GUITextBlock).Cast<GUITextBlock>());
//space
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), descriptionBox.Content.RectTransform), style: null);
if (!string.IsNullOrEmpty(Description))
{
new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionBox.Content.RectTransform),
TextManager.Get("SaveSubDialogDescription", fallBackTag: "WorkshopItemDescription"), font: GUI.Font, wrap: true) { CanBeFocused = false, ForceUpperCase = true };
}
new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionBox.Content.RectTransform), Description, font: font, wrap: true)
{
CanBeFocused = false
};
}
public void CreateMiniMap(GUIComponent parent, IEnumerable<Entity> pointsOfInterest = null)
{
Rectangle worldBorders = GetDockedBorders();
@@ -496,21 +378,6 @@ namespace Barotrauma
}
}
public bool IsVanillaSubmarine()
{
var vanilla = GameMain.VanillaContent;
if (vanilla != null)
{
var vanillaSubs = vanilla.GetFilesOfType(ContentType.Submarine);
string pathToCompare = filePath.Replace(@"\", @"/").ToLowerInvariant();
if (vanillaSubs.Any(sub => sub.Replace(@"\", @"/").ToLowerInvariant() == pathToCompare))
{
return true;
}
}
return false;
}
public void CheckForErrors()
{
List<string> errorMsgs = new List<string>();
@@ -531,6 +398,11 @@ namespace Barotrauma
}
}
if (!WayPoint.WayPointList.Any(wp => wp.ShouldBeSaved && wp.SpawnType == SpawnType.Human))
{
errorMsgs.Add(TextManager.Get("NoHumanSpawnpointWarning"));
}
if (!WayPoint.WayPointList.Any(wp => wp.ShouldBeSaved && wp.SpawnType == SpawnType.Path))
{
errorMsgs.Add(TextManager.Get("NoWaypointsWarning"));
@@ -605,7 +477,7 @@ namespace Barotrauma
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
var posInfo = PhysicsBody.ClientRead(type, msg, sendingTime, parentDebugName: Name);
var posInfo = PhysicsBody.ClientRead(type, msg, sendingTime, parentDebugName: Info.Name);
msg.ReadPadBits();
if (posInfo != null)

View File

@@ -0,0 +1,149 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Linq;
namespace Barotrauma
{
partial class SubmarineInfo : IDisposable
{
public Sprite PreviewImage;
partial void InitProjectSpecific()
{
string previewImageData = SubmarineElement.GetAttributeString("previewimage", "");
if (!string.IsNullOrEmpty(previewImageData))
{
try
{
using (MemoryStream mem = new MemoryStream(Convert.FromBase64String(previewImageData)))
{
var texture = TextureLoader.FromStream(mem, path: FilePath);
if (texture == null) { throw new Exception("PreviewImage texture returned null"); }
PreviewImage = new Sprite(texture, null, null);
}
}
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,
"Loading the preview image of the submarine \"" + Name + "\" failed. The file may be corrupted.");
PreviewImage = null;
}
}
}
public void CreatePreviewWindow(GUIComponent parent)
{
var content = new GUIFrame(new RectTransform(Vector2.One, parent.RectTransform), style: null);
if (PreviewImage == null)
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), content.RectTransform), TextManager.Get(SavedSubmarines.Contains(this) ? "SubPreviewImageNotFound" : "SubNotDownloaded"));
}
else
{
var submarinePreviewBackground = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.5f), content.RectTransform), style: null) { Color = Color.Black };
new GUIImage(new RectTransform(new Vector2(0.98f), submarinePreviewBackground.RectTransform, Anchor.Center), PreviewImage, scaleToFit: true);
new GUIFrame(new RectTransform(Vector2.One, submarinePreviewBackground.RectTransform), "InnerGlow", color: Color.Black);
}
var descriptionBox = new GUIListBox(new RectTransform(new Vector2(1, 0.5f), content.RectTransform, Anchor.BottomCenter))
{
UserData = "descriptionbox",
ScrollBarVisible = true,
Spacing = 5
};
//space
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.03f), descriptionBox.Content.RectTransform), style: null);
new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionBox.Content.RectTransform), TextManager.Get("submarine.name." + Name, true) ?? Name, font: GUI.LargeFont, wrap: true) { ForceUpperCase = true, CanBeFocused = false };
float leftPanelWidth = 0.6f;
float rightPanelWidth = 0.4f / leftPanelWidth;
ScalableFont font = descriptionBox.Rect.Width < 350 ? GUI.SmallFont : GUI.Font;
Vector2 realWorldDimensions = Dimensions * Physics.DisplayToRealWorldRatio;
if (realWorldDimensions != Vector2.Zero)
{
string dimensionsStr = TextManager.GetWithVariables("DimensionsFormat", new string[2] { "[width]", "[height]" }, new string[2] { ((int)realWorldDimensions.X).ToString(), ((int)realWorldDimensions.Y).ToString() });
var dimensionsText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), descriptionBox.Content.RectTransform),
TextManager.Get("Dimensions"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
{ CanBeFocused = false };
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), dimensionsText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
dimensionsStr, textAlignment: Alignment.TopLeft, font: font, wrap: true)
{ CanBeFocused = false };
dimensionsText.RectTransform.MinSize = new Point(0, dimensionsText.Children.First().Rect.Height);
}
if (RecommendedCrewSizeMax > 0)
{
var crewSizeText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), descriptionBox.Content.RectTransform),
TextManager.Get("RecommendedCrewSize"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
{ CanBeFocused = false };
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), crewSizeText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
RecommendedCrewSizeMin + " - " + RecommendedCrewSizeMax, textAlignment: Alignment.TopLeft, font: font, wrap: true)
{ CanBeFocused = false };
crewSizeText.RectTransform.MinSize = new Point(0, crewSizeText.Children.First().Rect.Height);
}
if (!string.IsNullOrEmpty(RecommendedCrewExperience))
{
var crewExperienceText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), descriptionBox.Content.RectTransform),
TextManager.Get("RecommendedCrewExperience"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
{ CanBeFocused = false };
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), crewExperienceText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
TextManager.Get(RecommendedCrewExperience), textAlignment: Alignment.TopLeft, font: font, wrap: true)
{ CanBeFocused = false };
crewExperienceText.RectTransform.MinSize = new Point(0, crewExperienceText.Children.First().Rect.Height);
}
if (RequiredContentPackages.Any())
{
var contentPackagesText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), descriptionBox.Content.RectTransform),
TextManager.Get("RequiredContentPackages"), textAlignment: Alignment.TopLeft, font: font)
{ CanBeFocused = false };
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), contentPackagesText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
string.Join(", ", RequiredContentPackages), textAlignment: Alignment.TopLeft, font: font, wrap: true)
{ CanBeFocused = false };
contentPackagesText.RectTransform.MinSize = new Point(0, contentPackagesText.Children.First().Rect.Height);
}
// show what game version the submarine was created on
if (!IsVanillaSubmarine() && GameVersion != null)
{
var versionText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), descriptionBox.Content.RectTransform),
TextManager.Get("serverlistversion"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
{ CanBeFocused = false };
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), versionText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
GameVersion.ToString(), textAlignment: Alignment.TopLeft, font: font, wrap: true)
{ CanBeFocused = false };
versionText.RectTransform.MinSize = new Point(0, versionText.Children.First().Rect.Height);
}
GUITextBlock.AutoScaleAndNormalize(descriptionBox.Content.Children.Where(c => c is GUITextBlock).Cast<GUITextBlock>());
//space
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), descriptionBox.Content.RectTransform), style: null);
if (!string.IsNullOrEmpty(Description))
{
new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionBox.Content.RectTransform),
TextManager.Get("SaveSubDialogDescription", fallBackTag: "WorkshopItemDescription"), font: GUI.Font, wrap: true)
{ CanBeFocused = false, ForceUpperCase = true };
}
new GUITextBlock(new RectTransform(new Vector2(1, 0), descriptionBox.Content.RectTransform), Description, font: font, wrap: true)
{
CanBeFocused = false
};
}
}
}

View File

@@ -1,17 +1,15 @@
using Microsoft.Xna.Framework;
using Barotrauma.Items.Components;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using Barotrauma.Items.Components;
using System.Linq;
namespace Barotrauma
{
partial class WayPoint : MapEntity
{
private static Texture2D iconTexture;
private const int IconSize = 32;
private static int[] iconIndices = { 3, 0, 1, 2 };
private static Dictionary<SpawnType, Sprite> iconSprites;
private const int WaypointSize = 12, SpawnPointSize = 32;
public override bool IsVisible(Rectangle worldView)
{
@@ -23,58 +21,58 @@ namespace Barotrauma
get { return !IsHidden(); }
}
public override void Draw(SpriteBatch spriteBatch, bool editing, bool back = true)
{
if (!editing && !GameMain.DebugDraw) { return; }
if (!editing && (!GameMain.DebugDraw || Screen.Selected.Cam.Zoom < 0.1f)) { return; }
if (IsHidden()) { return; }
//Rectangle drawRect =
// Submarine == null ? rect : new Rectangle((int)(Submarine.DrawPosition.X + rect.X), (int)(Submarine.DrawPosition.Y + rect.Y), rect.Width, rect.Height);
Vector2 drawPos = Position;
if (Submarine != null) drawPos += Submarine.DrawPosition;
if (Submarine != null) { drawPos += Submarine.DrawPosition; }
drawPos.Y = -drawPos.Y;
Color clr = currentHull == null ? Color.Blue : Color.White;
Draw(spriteBatch, drawPos);
}
public void Draw(SpriteBatch spriteBatch, Vector2 drawPos)
{
Color clr = currentHull == null ? Color.CadetBlue : GUI.Style.Green;
if (spawnType != SpawnType.Path) { clr = Color.Gray; }
if (isObstructed)
{
clr = Color.Black;
}
if (IsSelected) clr = GUI.Style.Red;
if (IsHighlighted) clr = Color.DarkRed;
if (IsHighlighted || IsHighlighted) { clr = Color.Lerp(clr, Color.White, 0.8f); }
int iconX = iconIndices[(int)spawnType] * IconSize % iconTexture.Width;
int iconY = (int)(Math.Floor(iconIndices[(int)spawnType] * IconSize / (float)iconTexture.Width)) * IconSize;
int iconSize = spawnType == SpawnType.Path ? WaypointSize : SpawnPointSize;
if (ConnectedGap != null || Ladders != null || Stairs != null || SpawnType != SpawnType.Path) { iconSize = (int)(iconSize * 1.5f); }
int iconSize = IconSize;
if (ConnectedGap != null)
if (IsSelected || IsHighlighted)
{
iconSize = (int)(iconSize * 1.5f);
}
if (Ladders != null)
{
iconSize = (int)(iconSize * 1.5f);
}
if (Stairs != null)
{
iconSize = (int)(iconSize * 1.5f);
int glowSize = (int)(iconSize * 1.5f);
GUI.Style.UIGlowCircular.Draw(spriteBatch,
new Rectangle((int)(drawPos.X - glowSize / 2), (int)(drawPos.Y - glowSize / 2), glowSize, glowSize),
Color.White);
}
spriteBatch.Draw(iconTexture,
new Rectangle((int)(drawPos.X - iconSize / 2), (int)(drawPos.Y - iconSize / 2), iconSize, iconSize),
new Rectangle(iconX, iconY, IconSize, IconSize), clr);
//GUI.DrawRectangle(spriteBatch, new Rectangle(drawRect.X, -drawRect.Y, rect.Width, rect.Height), clr, true);
//GUI.SmallFont.DrawString(spriteBatch, Position.ToString(), new Vector2(Position.X, -Position.Y), Color.White);
Sprite sprite = iconSprites[SpawnType];
if (spawnType == SpawnType.Human && AssignedJob?.Icon != null)
{
sprite = iconSprites[SpawnType.Path];
}
sprite.Draw(spriteBatch, drawPos, clr, scale: iconSize / (float)sprite.SourceRect.Width, depth: 0.001f);
sprite.RelativeOrigin = Vector2.One * 0.5f;
if (spawnType == SpawnType.Human && AssignedJob?.Icon != null)
{
AssignedJob.Icon.Draw(spriteBatch, drawPos, AssignedJob.UIColor, scale: iconSize / (float)AssignedJob.Icon.SourceRect.Width * 0.8f, depth: 0.0f);
}
foreach (MapEntity e in linkedTo)
{
GUI.DrawLine(spriteBatch,
drawPos,
new Vector2(e.DrawPosition.X, -e.DrawPosition.Y),
isObstructed ? Color.Gray : GUI.Style.Green, width: 5);
(isObstructed ? Color.Gray : GUI.Style.Green) * 0.7f, width: 5, depth: 0.002f);
}
GUI.SmallFont.DrawString(spriteBatch,
@@ -83,6 +81,14 @@ namespace Barotrauma
Color.WhiteSmoke);
}
public override bool IsMouseOn(Vector2 position)
{
if (IsHidden()) { return false; }
float dist = Vector2.DistanceSquared(position, WorldPosition);
float radius = (SpawnType == SpawnType.Path ? WaypointSize : SpawnPointSize) * 0.6f;
return dist < radius * radius;
}
private bool IsHidden()
{
if (spawnType == SpawnType.Path)
@@ -178,14 +184,19 @@ namespace Barotrauma
private bool ChangeSpawnType(GUIButton button, object obj)
{
GUITextBlock spawnTypeText = button.Parent.GetChildByUserData("spawntypetext") as GUITextBlock;
spawnType += (int)button.UserData;
if (spawnType > SpawnType.Cargo) spawnType = SpawnType.Human;
if (spawnType < SpawnType.Human) spawnType = SpawnType.Cargo;
var values = Enum.GetValues(typeof(SpawnType));
int firstIndex = 1;
int lastIndex = values.Length - 1;
if ((int)spawnType > lastIndex)
{
spawnType = (SpawnType)firstIndex;
}
if ((int)spawnType < firstIndex)
{
spawnType = (SpawnType)values.GetValue(lastIndex);
}
spawnTypeText.Text = spawnType.ToString();
return true;
}

View File

@@ -15,6 +15,7 @@ namespace Barotrauma.Networking
public byte ID;
public UInt16 CharacterID;
public bool Muted;
public bool InGame;
public bool AllowKicking;
}
@@ -71,6 +72,7 @@ namespace Barotrauma.Networking
else
{
VoipSound.SetPosition(null);
VoipSound.Gain = 1.0f;
}
}

View File

@@ -8,6 +8,7 @@ using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Barotrauma.Networking
{
@@ -60,11 +61,24 @@ namespace Barotrauma.Networking
private bool connected;
private enum RoundInitStatus
{
NotStarted,
Starting,
WaitingForStartGameFinalize,
Started,
TimedOut,
Error,
Interrupted
}
private RoundInitStatus roundInitStatus = RoundInitStatus.NotStarted;
private byte myID;
private List<Client> otherClients;
private readonly List<Submarine> serverSubmarines = new List<Submarine>();
private readonly List<SubmarineInfo> serverSubmarines = new List<SubmarineInfo>();
private string serverIP, serverName;
@@ -148,6 +162,8 @@ namespace Barotrauma.Networking
this.ownerKey = ownerKey;
this.steamP2POwner = steamP2POwner;
roundInitStatus = RoundInitStatus.NotStarted;
allowReconnect = true;
netStats = new NetStats();
@@ -472,13 +488,17 @@ namespace Barotrauma.Networking
var msgBox = new GUIMessageBox(pwMsg, "", new string[] { TextManager.Get("OK"), TextManager.Get("Cancel") },
relativeSize: new Vector2(0.25f, 0.1f), minSize: new Point(400, 170));
var passwordHolder = new GUILayoutGroup(new RectTransform(Vector2.One, msgBox.Content.RectTransform), childAnchor: Anchor.TopCenter);
var passwordHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), msgBox.Content.RectTransform), childAnchor: Anchor.TopCenter);
var passwordBox = new GUITextBox(new RectTransform(new Vector2(0.8f, 1f), passwordHolder.RectTransform) { MinSize = new Point(0, 20) })
{
UserData = "password",
Censor = true
};
msgBox.Content.Recalculate();
msgBox.Content.RectTransform.MinSize = new Point(0, msgBox.Content.RectTransform.Children.Sum(c => c.Rect.Height));
msgBox.Content.Parent.RectTransform.MinSize = new Point(0, (int)(msgBox.Content.RectTransform.MinSize.Y / msgBox.Content.RectTransform.RelativeSize.Y));
var okButton = msgBox.Buttons[0];
var cancelButton = msgBox.Buttons[1];
@@ -524,6 +544,7 @@ namespace Barotrauma.Networking
foreach (Client c in ConnectedClients)
{
if (c.Character != null && c.Character.Removed) { c.Character = null; }
c.UpdateSoundPosition();
}
@@ -558,6 +579,13 @@ namespace Barotrauma.Networking
try
{
incomingMessagesToProcess.Clear();
incomingMessagesToProcess.AddRange(pendingIncomingMessages);
foreach (var inc in incomingMessagesToProcess)
{
ReadDataMessage(inc);
}
pendingIncomingMessages.Clear();
clientPeer?.Update(deltaTime);
}
catch (Exception e)
@@ -632,11 +660,23 @@ namespace Barotrauma.Networking
}
}
private CoroutineHandle startGameCoroutine;
private readonly List<IReadMessage> pendingIncomingMessages = new List<IReadMessage>();
private readonly List<IReadMessage> incomingMessagesToProcess = new List<IReadMessage>();
private void ReadDataMessage(IReadMessage inc)
{
ServerPacketHeader header = (ServerPacketHeader)inc.ReadByte();
if (header != ServerPacketHeader.STARTGAMEFINALIZE &&
header != ServerPacketHeader.ENDGAME &&
roundInitStatus == RoundInitStatus.WaitingForStartGameFinalize)
{
//rewind the header byte we just read
inc.BitPosition -= 8;
pendingIncomingMessages.Add(inc);
return;
}
switch (header)
{
case ServerPacketHeader.UPDATE_LOBBY:
@@ -714,7 +754,13 @@ namespace Barotrauma.Networking
}
break;
case ServerPacketHeader.STARTGAME:
startGameCoroutine = GameMain.Instance.ShowLoading(StartGame(inc), false);
GameMain.Instance.ShowLoading(StartGame(inc), false);
break;
case ServerPacketHeader.STARTGAMEFINALIZE:
if (roundInitStatus == RoundInitStatus.WaitingForStartGameFinalize)
{
ReadStartGameFinalize(inc);
}
break;
case ServerPacketHeader.ENDGAME:
string endMessage = inc.ReadString();
@@ -725,6 +771,8 @@ namespace Barotrauma.Networking
GameMain.GameSession.WinningTeam = winningTeam;
GameMain.GameSession.Mission.Completed = true;
}
roundInitStatus = RoundInitStatus.Interrupted;
CoroutineManager.StartCoroutine(EndGame(endMessage), "EndGame");
break;
case ServerPacketHeader.CAMPAIGN_SETUP_INFO:
@@ -776,6 +824,36 @@ namespace Barotrauma.Networking
}
}
private void ReadStartGameFinalize(IReadMessage inc)
{
ushort contentToPreloadCount = inc.ReadUInt16();
List<ContentFile> contentToPreload = new List<ContentFile>();
for (int i = 0; i < contentToPreloadCount; i++)
{
ContentType contentType = (ContentType)inc.ReadByte();
string filePath = inc.ReadString();
contentToPreload.Add(new ContentFile(filePath, contentType));
}
GameMain.GameSession.EventManager.PreloadContent(contentToPreload);
int levelEqualityCheckVal = inc.ReadInt32();
if (Level.Loaded.EqualityCheckVal != levelEqualityCheckVal)
{
string errorMsg = "Level equality check failed. The level generated at your end doesn't match the level generated by the server (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);
throw new Exception(errorMsg);
}
GameMain.GameSession.Mission?.ClientReadInitial(inc);
roundInitStatus = RoundInitStatus.Started;
}
private void OnDisconnect()
{
if (SteamManager.IsInitialized)
@@ -884,6 +962,7 @@ namespace Barotrauma.Networking
}
else
{
connected = false;
connectCancelled = true;
string msg = "";
@@ -1108,6 +1187,7 @@ namespace Barotrauma.Networking
if (Character != null) Character.Remove();
HasSpawned = false;
eventErrorWritten = false;
GameMain.NetLobbyScreen.StopWaitingForStartRound();
while (CoroutineManager.IsCoroutineRunning("EndGame"))
{
@@ -1126,9 +1206,11 @@ namespace Barotrauma.Networking
EndVoteTickBox.Selected = false;
roundInitStatus = RoundInitStatus.Starting;
int seed = inc.ReadInt32();
string levelSeed = inc.ReadString();
int levelEqualityCheckVal = inc.ReadInt32();
//int levelEqualityCheckVal = inc.ReadInt32();
float levelDifficulty = inc.ReadSingle();
byte losMode = inc.ReadByte();
@@ -1146,24 +1228,16 @@ namespace Barotrauma.Networking
int missionIndex = inc.ReadInt16();
bool respawnAllowed = inc.ReadBoolean();
bool loadSecondSub = inc.ReadBoolean();
bool disguisesAllowed = inc.ReadBoolean();
bool rewiringAllowed = inc.ReadBoolean();
bool allowRagdollButton = inc.ReadBoolean();
ushort contentToPreloadCount = inc.ReadUInt16();
List<ContentFile> contentToPreload = new List<ContentFile>();
for (int i = 0; i < contentToPreloadCount; i++)
{
ContentType contentType = (ContentType)inc.ReadByte();
string filePath = inc.ReadString();
contentToPreload.Add(new ContentFile(filePath, contentType));
}
serverSettings.ReadMonsterEnabled(inc);
bool includesFinalize = inc.ReadBoolean(); inc.ReadPadBits();
GameModePreset gameMode = GameModePreset.List.Find(gm => gm.Identifier == modeIdentifier);
MultiPlayerCampaign campaign =
GameMain.NetLobbyScreen.SelectedMode == GameMain.GameSession?.GameMode.Preset && gameMode == GameMain.NetLobbyScreen.SelectedMode ?
@@ -1237,31 +1311,114 @@ namespace Barotrauma.Networking
yield return CoroutineStatus.Failure;
}
MissionPrefab missionPrefab = missionIndex < 0 ? null : MissionPrefab.List[missionIndex];
GameMain.GameSession = missionIndex < 0 ?
new GameSession(GameMain.NetLobbyScreen.SelectedSub, "", gameMode, MissionType.None) :
new GameSession(GameMain.NetLobbyScreen.SelectedSub, "", gameMode, MissionPrefab.List[missionIndex]);
GameMain.GameSession.StartRound(levelSeed, levelDifficulty, loadSecondSub);
new GameSession(GameMain.NetLobbyScreen.SelectedSub, "", gameMode, missionPrefab);
//startRoundTask = Task.Run(async () => { await Task.Yield(); GameMain.GameSession.StartRound(levelSeed, levelDifficulty); });
GameMain.GameSession.StartRound(levelSeed, levelDifficulty);
}
else
{
if (GameMain.GameSession?.CrewManager != null) GameMain.GameSession.CrewManager.Reset();
/*startRoundTask = Task.Run(async () =>
{
await Task.Yield();
GameMain.GameSession.StartRound(campaign.Map.SelectedConnection.Level,
reloadSub: true,
loadSecondSub: false,
mirrorLevel: campaign.Map.CurrentLocation != campaign.Map.SelectedConnection.Locations[0]);
});*/
GameMain.GameSession.StartRound(campaign.Map.SelectedConnection.Level,
mirrorLevel: campaign.Map.CurrentLocation != campaign.Map.SelectedConnection.Locations[0]);
}
GameMain.GameSession.Mission?.ClientReadInitial(inc);
roundInitStatus = RoundInitStatus.WaitingForStartGameFinalize;
if (GameMain.GameSession.Submarine.IsFileCorrupted)
DateTime? timeOut = null;
DateTime requestFinalizeTime = DateTime.Now;
TimeSpan requestFinalizeInterval = new TimeSpan(0, 0, 2);
while (true)
{
DebugConsole.ThrowError($"Failed to start a round. Could not load the submarine \"{GameMain.GameSession.Submarine.Name}\".");
try
{
if (timeOut.HasValue)
{
if (DateTime.Now > requestFinalizeTime)
{
IWriteMessage msg = new WriteOnlyMessage();
msg.Write((byte)ClientPacketHeader.REQUEST_STARTGAMEFINALIZE);
clientPeer.Send(msg, DeliveryMethod.Unreliable);
requestFinalizeTime = DateTime.Now + requestFinalizeInterval;
}
if (DateTime.Now > timeOut)
{
DebugConsole.ThrowError("Error while starting the round (did not receive STARTGAMEFINALIZE message from the server). Stopping the round...");
roundInitStatus = RoundInitStatus.TimedOut;
break;
}
}
else
{
if (includesFinalize)
{
ReadStartGameFinalize(inc);
break;
}
//wait for up to 30 seconds for the server to send the STARTGAMEFINALIZE message
timeOut = DateTime.Now + new TimeSpan(0, 0, seconds: 30);
}
if (!connected)
{
roundInitStatus = RoundInitStatus.Interrupted;
break;
}
if (roundInitStatus != RoundInitStatus.WaitingForStartGameFinalize)
{
break;
}
clientPeer.Update((float)Timing.Step);
}
catch (Exception e)
{
DebugConsole.ThrowError("There was an error initializing the round.", e, true);
roundInitStatus = RoundInitStatus.Error;
break;
}
//waiting for a STARTGAMEFINALIZE message
yield return CoroutineStatus.Running;
}
if (roundInitStatus != RoundInitStatus.Started)
{
if (roundInitStatus != RoundInitStatus.Interrupted)
{
DebugConsole.ThrowError(roundInitStatus.ToString());
CoroutineManager.StartCoroutine(EndGame(""));
yield return CoroutineStatus.Failure;
}
else
{
yield return CoroutineStatus.Success;
}
}
if (GameMain.GameSession.Submarine.Info.IsFileCorrupted)
{
DebugConsole.ThrowError($"Failed to start a round. Could not load the submarine \"{GameMain.GameSession.Submarine.Info.Name}\".");
yield return CoroutineStatus.Failure;
}
for (int i = 0; i < Submarine.MainSubs.Length; i++)
{
if (!loadSecondSub && i > 0) { break; }
if (Submarine.MainSubs[i] == null) { break; }
var teamID = i == 0 ? Character.TeamType.Team1 : Character.TeamType.Team2;
Submarine.MainSubs[i].TeamID = teamID;
@@ -1271,23 +1428,10 @@ namespace Barotrauma.Networking
}
}
if (Level.Loaded.EqualityCheckVal != levelEqualityCheckVal)
{
string errorMsg = "Level equality check failed. The level generated at your end doesn't match the level generated by the server (seed: " + Level.Loaded.Seed +
", sub: " + Submarine.MainSub.Name + " (" + Submarine.MainSub.MD5Hash.ShortHash + ")" +
", mirrored: " + Level.Loaded.Mirrored + ").";
DebugConsole.ThrowError(errorMsg, createMessageBox: true);
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + levelSeed, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
CoroutineManager.StartCoroutine(EndGame(""));
yield return CoroutineStatus.Failure;
}
if (respawnAllowed) { respawnManager = new RespawnManager(this, GameMain.NetLobbyScreen.UsingShuttle ? GameMain.NetLobbyScreen.SelectedShuttle : null); }
GameMain.GameSession.EventManager.PreloadContent(contentToPreload);
ServerSettings.ServerDetailsChanged = true;
gameStarted = true;
ServerSettings.ServerDetailsChanged = true;
GameMain.GameScreen.Select();
@@ -1358,8 +1502,8 @@ namespace Barotrauma.Networking
bool requiredContentPackagesInstalled = inc.ReadBoolean();
var matchingSub =
Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == subName && s.MD5Hash.Hash == subHash) ??
new Submarine(Path.Combine(Submarine.SavePath, subName) + ".sub", subHash, false);
SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == subName && s.MD5Hash.Hash == subHash) ??
new SubmarineInfo(Path.Combine(SubmarineInfo.SavePath, subName) + ".sub", subHash);
matchingSub.RequiredContentPackagesInstalled = requiredContentPackagesInstalled;
serverSubmarines.Add(matchingSub);
@@ -1394,6 +1538,7 @@ namespace Barotrauma.Networking
string preferredJob = inc.ReadString();
UInt16 characterID = inc.ReadUInt16();
bool muted = inc.ReadBoolean();
bool inGame = inc.ReadBoolean();
bool allowKicking = inc.ReadBoolean();
inc.ReadPadBits();
@@ -1406,6 +1551,7 @@ namespace Barotrauma.Networking
PreferredJob = preferredJob,
CharacterID = characterID,
Muted = muted,
InGame = inGame,
AllowKicking = allowKicking
});
}
@@ -1424,6 +1570,7 @@ namespace Barotrauma.Networking
{
SteamID = tc.SteamID,
Muted = tc.Muted,
InGame = tc.InGame,
AllowKicking = tc.AllowKicking
};
ConnectedClients.Add(existingClient);
@@ -1433,15 +1580,12 @@ namespace Barotrauma.Networking
existingClient.PreferredJob = tc.PreferredJob;
existingClient.Character = null;
existingClient.Muted = tc.Muted;
existingClient.InGame = tc.InGame;
existingClient.AllowKicking = tc.AllowKicking;
GameMain.NetLobbyScreen.SetPlayerNameAndJobPreference(existingClient);
if (tc.CharacterID > 0)
if (Screen.Selected != GameMain.NetLobbyScreen && tc.CharacterID > 0)
{
existingClient.Character = Entity.FindEntityByID(tc.CharacterID) as Character;
if (existingClient.Character == null)
{
updateClientListId = false;
}
existingClient.CharacterID = tc.CharacterID;
}
if (existingClient.ID == myID)
{
@@ -1888,15 +2032,15 @@ namespace Barotrauma.Networking
{
case FileTransferType.Submarine:
new GUIMessageBox(TextManager.Get("ServerDownloadFinished"), TextManager.GetWithVariable("FileDownloadedNotification", "[filename]", transfer.FileName));
var newSub = new Submarine(transfer.FilePath);
var newSub = new SubmarineInfo(transfer.FilePath);
if (newSub.IsFileCorrupted) { return; }
var existingSubs = Submarine.SavedSubmarines.Where(s => s.Name == newSub.Name && s.MD5Hash.Hash == newSub.MD5Hash.Hash).ToList();
foreach (Submarine existingSub in existingSubs)
var existingSubs = SubmarineInfo.SavedSubmarines.Where(s => s.Name == newSub.Name && s.MD5Hash.Hash == newSub.MD5Hash.Hash).ToList();
foreach (SubmarineInfo existingSub in existingSubs)
{
existingSub.Dispose();
}
Submarine.AddToSavedSubs(newSub);
SubmarineInfo.AddToSavedSubs(newSub);
for (int i = 0; i < 2; i++)
{
@@ -1905,8 +2049,8 @@ namespace Barotrauma.Networking
GameMain.NetLobbyScreen.SubList.Content.Children;
var subElement = subListChildren.FirstOrDefault(c =>
((Submarine)c.UserData).Name == newSub.Name &&
((Submarine)c.UserData).MD5Hash.Hash == newSub.MD5Hash.Hash);
((SubmarineInfo)c.UserData).Name == newSub.Name &&
((SubmarineInfo)c.UserData).MD5Hash.Hash == newSub.MD5Hash.Hash);
if (subElement == null) continue;
subElement.GetChild<GUITextBlock>().TextColor = new Color(subElement.GetChild<GUITextBlock>().TextColor, 1.0f);
@@ -1934,17 +2078,17 @@ namespace Barotrauma.Networking
if (campaign == null) { return; }
GameMain.GameSession.SavePath = transfer.FilePath;
if (GameMain.GameSession.Submarine == null)
if (GameMain.GameSession.SubmarineInfo == null)
{
var gameSessionDoc = SaveUtil.LoadGameSessionDoc(GameMain.GameSession.SavePath);
string subPath = Path.Combine(SaveUtil.TempPath, gameSessionDoc.Root.GetAttributeString("submarine", "")) + ".sub";
GameMain.GameSession.Submarine = new Submarine(subPath, "");
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(subPath, "");
}
SaveUtil.LoadGame(GameMain.GameSession.SavePath, GameMain.GameSession);
GameMain.GameSession?.Submarine?.CheckSubsLeftBehind();
if (GameMain.GameSession?.Submarine?.Name != null)
if (GameMain.GameSession?.SubmarineInfo?.Name != null)
{
GameMain.NetLobbyScreen.TryDisplayCampaignSubmarine(GameMain.GameSession.Submarine);
GameMain.NetLobbyScreen.TryDisplayCampaignSubmarine(GameMain.GameSession.SubmarineInfo);
}
campaign.LastSaveID = campaign.PendingSaveID;
@@ -1979,8 +2123,7 @@ namespace Barotrauma.Networking
{
if (!permissions.HasFlag(ClientPermissions.ConsoleCommands)) { return false; }
commandName = commandName.ToLowerInvariant();
if (permittedConsoleCommands.Any(c => c.ToLowerInvariant() == commandName)) { return true; }
if (permittedConsoleCommands.Any(c => c.Equals(commandName, StringComparison.OrdinalIgnoreCase))) { return true; }
//check aliases
foreach (DebugConsole.Command command in DebugConsole.Commands)
@@ -2231,7 +2374,7 @@ namespace Barotrauma.Networking
clientPeer.Send(msg, DeliveryMethod.Reliable);
}
public void SetupNewCampaign(Submarine sub, string saveName, string mapSeed)
public void SetupNewCampaign(SubmarineInfo sub, string saveName, string mapSeed)
{
GameMain.NetLobbyScreen.CampaignSetupFrame.Visible = false;
@@ -2440,7 +2583,7 @@ namespace Barotrauma.Networking
if (GUI.KeyboardDispatcher.Subscriber == null)
{
bool chatKeyHit = PlayerInput.KeyHit(InputType.Chat);
bool radioKeyHit = PlayerInput.KeyHit(InputType.RadioChat);
bool radioKeyHit = PlayerInput.KeyHit(InputType.RadioChat) && (Character.Controlled == null || Character.Controlled.SpeechImpediment < 0);
if (chatKeyHit || radioKeyHit)
{
@@ -2498,6 +2641,7 @@ namespace Barotrauma.Networking
{
var transfer = fileReceiver.ActiveTransfers.First();
GameMain.NetLobbyScreen.FileTransferFrame.Visible = true;
GameMain.NetLobbyScreen.FileTransferFrame.UserData = transfer;
GameMain.NetLobbyScreen.FileTransferTitle.Text =
ToolBox.LimitString(
TextManager.GetWithVariable("DownloadingFile", "[filename]", transfer.FileName),
@@ -2789,7 +2933,7 @@ namespace Barotrauma.Networking
}
if (GameMain.GameSession?.Submarine != null)
{
errorLines.Add("Submarine: " + GameMain.GameSession.Submarine.Name);
errorLines.Add("Submarine: " + GameMain.GameSession.Submarine.Info.Name);
}
if (Level.Loaded != null)
{
@@ -2811,8 +2955,8 @@ namespace Barotrauma.Networking
errorLines.Add(" " + DebugConsole.Messages[i].Time + " - " + DebugConsole.Messages[i].Text);
}
string filePath = "event_error_log_client_" + Name + "_" + ToolBox.RemoveInvalidFileNameChars(DateTime.UtcNow.ToShortTimeString() + ".log");
filePath = Path.Combine(ServerLog.SavePath, filePath);
string filePath = "event_error_log_client_" + Name + "_" + DateTime.UtcNow.ToShortTimeString() + ".log";
filePath = Path.Combine(ServerLog.SavePath, ToolBox.RemoveInvalidFileNameChars(filePath));
if (!Directory.Exists(ServerLog.SavePath))
{

View File

@@ -91,6 +91,7 @@ namespace Barotrauma.Networking
return;
}
incomingLidgrenMessages.Clear();
netClient.ReadMessages(incomingLidgrenMessages);
foreach (NetIncomingMessage inc in incomingLidgrenMessages)
@@ -107,8 +108,6 @@ namespace Barotrauma.Networking
break;
}
}
incomingLidgrenMessages.Clear();
}
private void HandleDataMessage(NetIncomingMessage inc)

View File

@@ -204,8 +204,9 @@ namespace Barotrauma.Networking
}
}
while (Steamworks.SteamNetworking.IsP2PPacketAvailable())
for (int i=0;i<100;i++)
{
if (!Steamworks.SteamNetworking.IsP2PPacketAvailable()) { break; }
var packet = Steamworks.SteamNetworking.ReadP2PPacket();
if (packet.HasValue)
{

View File

@@ -571,6 +571,9 @@ namespace Barotrauma.Networking
var ragdollButtonBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), TextManager.Get("ServerSettingsAllowRagdollButton"));
GetPropertyData("AllowRagdollButton").AssignGUIComponent(ragdollButtonBox);
var disableBotConversationsBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), TextManager.Get("ServerSettingsDisableBotConversations"));
GetPropertyData("DisableBotConversations").AssignGUIComponent(disableBotConversationsBox);
/*var traitorRatioBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), TextManager.Get("ServerSettingsUseTraitorRatio"));
CreateLabeledSlider(roundsTab, "", out slider, out sliderLabel);

View File

@@ -15,6 +15,8 @@ namespace Barotrauma.Steam
{
static partial class SteamManager
{
private static Dictionary<Steamworks.Data.PublishedFileId, Task> modCopiesInProgress = new Dictionary<Steamworks.Data.PublishedFileId, Task>();
private static void InitializeProjectSpecific()
{
if (isInitialized) { return; }
@@ -63,20 +65,6 @@ namespace Barotrauma.Steam
private static void UpdateProjectSpecific(float deltaTime)
{
for (int i=0;i<(ugcResultPageTasks?.Count ?? 0);i++)
{
var task = ugcResultPageTasks[i];
if (task.IsCompleted)
{
if (!task.IsCompletedSuccessfully)
{
DebugConsole.ThrowError("Failed to retrieve Steam Workshop page info: TaskStatus = "+task.Status.ToString());
}
ugcResultPageTasks.RemoveAt(i);
i--;
}
}
if (ugcSubscriptionTasks != null)
{
var ugcSubscriptionKeys = ugcSubscriptionTasks.Keys.ToList();
@@ -525,7 +513,37 @@ namespace Barotrauma.Steam
}
}
private static List<Task> ugcResultPageTasks;
private static async Task<List<Steamworks.Ugc.Item>> GetWorkshopItemsAsync(Steamworks.Ugc.Query query, int clampResults = 0, Predicate<Steamworks.Ugc.Item> itemPredicate=null)
{
await Task.Yield();
int pageIndex = 1;
Steamworks.Ugc.ResultPage? resultPage = await query.GetPageAsync(pageIndex);
List<Steamworks.Ugc.Item> retVal = new List<Steamworks.Ugc.Item>();
while (resultPage.HasValue && resultPage?.ResultCount > 0)
{
if (itemPredicate != null)
{
retVal.AddRange(resultPage.Value.Entries.Where(it => itemPredicate(it)));
}
else
{
retVal.AddRange(resultPage.Value.Entries);
}
if (clampResults > 0 && retVal.Count >= clampResults)
{
retVal = retVal.Take(clampResults).ToList();
break;
}
pageIndex++;
resultPage = await query.GetPageAsync(pageIndex);
}
return retVal;
}
public static void GetSubscribedWorkshopItems(Action<IList<Steamworks.Ugc.Item>> onItemsFound, List<string> requireTags = null)
{
@@ -535,30 +553,9 @@ namespace Barotrauma.Steam
.RankedByTotalUniqueSubscriptions()
.WhereUserSubscribed()
.WithLongDescription();
if (requireTags != null) query.WithTags(requireTags);
if (requireTags != null) { query = query.WithTags(requireTags); }
ugcResultPageTasks ??= new List<Task>();
ugcResultPageTasks.Add(Task.Run(async () =>
{
int processedResults = 0; int pageIndex = 1;
Steamworks.Ugc.ResultPage? resultPage = await query.GetPageAsync(pageIndex);
while (resultPage.HasValue && resultPage?.ResultCount > 0)
{
onItemsFound?.Invoke(resultPage.Value.Entries.ToList());
processedResults += resultPage.Value.ResultCount;
pageIndex++;
if (processedResults < resultPage?.TotalCount)
{
resultPage = await query.GetPageAsync(pageIndex);
}
else
{
resultPage = null;
}
}
}));
TaskPool.Add(GetWorkshopItemsAsync(query), (task) => { onItemsFound?.Invoke(task.Result); });
}
public static void GetPopularWorkshopItems(Action<IList<Steamworks.Ugc.Item>> onItemsFound, int amount, List<string> requireTags = null)
@@ -570,15 +567,9 @@ namespace Barotrauma.Steam
.WithLongDescription();
if (requireTags != null) query.WithTags(requireTags);
ugcResultPageTasks ??= new List<Task>();
ugcResultPageTasks.Add(Task.Run(async () =>
{
int processedResults = 0; int pageIndex = 1;
Steamworks.Ugc.ResultPage? resultPage = await query.GetPageAsync(pageIndex);
TaskPool.Add(GetWorkshopItemsAsync(query, amount, (item) => !item.IsSubscribed), (task) => {
var entries = task.Result;
while (resultPage.HasValue && resultPage?.ResultCount > 0)
{
var entries = resultPage.Value.Entries.ToList();
//count the number of each unique tag
foreach (var item in entries)
{
@@ -608,27 +599,8 @@ namespace Barotrauma.Steam
}
popularTags.Insert(i, tagCommonnessKVP.Key);
}
var nonSubscribedItems = entries.Where(it => !it.IsSubscribed);
if (nonSubscribedItems.Count() > (amount-processedResults))
{
nonSubscribedItems = nonSubscribedItems.Take(amount - processedResults);
}
onItemsFound?.Invoke(nonSubscribedItems.ToList());
processedResults += resultPage.Value.ResultCount;
pageIndex++;
if (processedResults < resultPage?.TotalCount && processedResults < amount)
{
resultPage = await query.GetPageAsync(pageIndex);
}
else
{
resultPage = null;
}
}
}));
onItemsFound?.Invoke(task.Result);
});
}
public static void GetPublishedWorkshopItems(Action<IList<Steamworks.Ugc.Item>> onItemsFound, List<string> requireTags = null)
@@ -641,28 +613,7 @@ namespace Barotrauma.Steam
.WithLongDescription();
if (requireTags != null) query.WithTags(requireTags);
ugcResultPageTasks ??= new List<Task>();
ugcResultPageTasks.Add(Task.Run(async () =>
{
int processedResults = 0; int pageIndex = 1;
Steamworks.Ugc.ResultPage? resultPage = await query.GetPageAsync(pageIndex);
while (resultPage.HasValue && resultPage?.ResultCount > 0)
{
onItemsFound?.Invoke(resultPage.Value.Entries.ToList());
processedResults += resultPage.Value.ResultCount;
pageIndex++;
if (processedResults < resultPage?.TotalCount)
{
resultPage = await query.GetPageAsync(pageIndex);
}
else
{
resultPage = null;
}
}
}));
TaskPool.Add(GetWorkshopItemsAsync(query), (task) => { onItemsFound?.Invoke(task.Result); });
}
private static Dictionary<ulong, Task> ugcSubscriptionTasks;
@@ -926,7 +877,7 @@ namespace Barotrauma.Steam
/// <summary>
/// Enables a workshop item by moving it to the game folder.
/// </summary>
public static bool EnableWorkShopItem(Steamworks.Ugc.Item? item, bool allowFileOverwrite, out string errorMsg)
public static bool EnableWorkShopItem(Steamworks.Ugc.Item? item, bool allowFileOverwrite, out string errorMsg, bool selectContentPackage = false, bool suppressInstallNotif = false)
{
if (!(item?.IsInstalled ?? false))
{
@@ -972,11 +923,44 @@ namespace Barotrauma.Steam
return false;
}
Task<string> newTask = null;
lock (modCopiesInProgress)
{
if (modCopiesInProgress.ContainsKey(item.Value.Id))
{
if (!modCopiesInProgress[item.Value.Id].IsCompleted &&
!modCopiesInProgress[item.Value.Id].IsFaulted &&
!modCopiesInProgress[item.Value.Id].IsCanceled)
{
errorMsg = ""; return true;
}
modCopiesInProgress.Remove(item.Value.Id);
}
newTask = CopyWorkShopItemAsync(item, contentPackage, newContentPackagePath, metaDataFilePath, allowFileOverwrite);
modCopiesInProgress.Add(item.Value.Id, newTask);
}
TaskPool.Add(newTask,
contentPackage,
(task, cp) =>
{
if (task.IsFaulted || task.IsCanceled)
{
DebugConsole.ThrowError($"Failed to copy \"{item?.Title}\"", task.Exception);
GameMain.SteamWorkshopScreen?.SetReinstallButtonStatus(item, true, GUI.Style.Red);
return;
}
if (!string.IsNullOrWhiteSpace(task.Result))
{
DebugConsole.ThrowError($"Failed to copy \"{item?.Title}\": {task.Result}");
GameMain.SteamWorkshopScreen?.SetReinstallButtonStatus(item, true, GUI.Style.Red);
return;
}
GameMain.Config.SuppressModFolderWatcher = true;
CopyWorkShopItem(item, contentPackage, newContentPackagePath, metaDataFilePath, allowFileOverwrite, out errorMsg);
var newPackage = new ContentPackage(contentPackage.Path, newContentPackagePath)
var newPackage = new ContentPackage(cp.Path, newContentPackagePath)
{
SteamWorkshopUrl = item?.Url,
InstallTime = item?.Updated > item?.Created ? item?.Updated : item?.Created
@@ -984,7 +968,7 @@ namespace Barotrauma.Steam
foreach (ContentFile contentFile in newPackage.Files)
{
contentFile.Path = CorrectContentFilePath(contentFile.Path, contentPackage, true);
contentFile.Path = CorrectContentFilePath(contentFile.Path, cp, true);
}
if (!Directory.Exists(Path.GetDirectoryName(newContentPackagePath)))
@@ -993,6 +977,9 @@ namespace Barotrauma.Steam
}
newPackage.Save(newContentPackagePath);
ContentPackage.List.Add(newPackage);
if (selectContentPackage)
{
if (newPackage.CorePackage)
{
GameMain.Config.SelectCorePackage(newPackage);
@@ -1005,24 +992,47 @@ namespace Barotrauma.Steam
GameMain.Config.WarnIfContentPackageSelectionDirty();
GameMain.Config.SuppressModFolderWatcher = false;
if (newPackage.Files.Any(f => f.Type == ContentType.Submarine))
{
Submarine.RefreshSavedSubs();
SubmarineInfo.RefreshSavedSubs();
}
}
else if (!suppressInstallNotif)
{
GameMain.MainMenuScreen?.SetEnableModsNotification(true);
}
GameMain.Config.SuppressModFolderWatcher = false;
GameMain.SteamWorkshopScreen?.SetReinstallButtonStatus(item, true, GUI.Style.Green);
});
errorMsg = "";
return true;
}
private static bool CopyWorkShopItem(Steamworks.Ugc.Item? item, ContentPackage contentPackage, string newContentPackagePath, string metaDataFilePath, bool allowFileOverwrite, out string errorMsg)
/// <summary>
/// Asynchronously copies a Workshop item into the Mods folder.
/// </summary>
/// <returns>Returns an empty string on success, otherwise returns an error message.</returns>
private async static Task<string> CopyWorkShopItemAsync(Steamworks.Ugc.Item? item, ContentPackage contentPackage, string newContentPackagePath, string metaDataFilePath, bool allowFileOverwrite)
{
errorMsg = "";
await Task.Yield();
string targetPath = Path.GetDirectoryName(GetWorkshopItemContentPackagePath(contentPackage));
string copyingPath = Path.Combine(targetPath, CopyIndicatorFileName);
string errorMsg = "";
if (contentPackage.GameVersion > new Version(0, 9, 1, 0))
{
SaveUtil.CopyFolder(item?.Directory, Path.GetDirectoryName(GetWorkshopItemContentPackagePath(contentPackage)), copySubDirs: true, overwriteExisting: true);
return true;
Directory.CreateDirectory(targetPath);
File.WriteAllText(copyingPath, "TEMPORARY FILE");
SaveUtil.CopyFolder(item?.Directory, targetPath, copySubDirs: true, overwriteExisting: true);
File.Delete(copyingPath);
return "";
}
var allPackageFiles = Directory.GetFiles(item?.Directory, "*", SearchOption.AllDirectories);
@@ -1042,7 +1052,7 @@ namespace Barotrauma.Steam
{
errorMsg = TextManager.GetWithVariables("WorkshopErrorOverwriteOnEnable", new string[2] { "[itemname]", "[filename]" }, new string[2] { item?.Title, newContentPackagePath });
DebugConsole.NewMessage(errorMsg, Color.Red);
return false;
return errorMsg;
}
foreach (ContentFile contentFile in contentPackage.Files)
@@ -1053,13 +1063,14 @@ namespace Barotrauma.Steam
{
errorMsg = TextManager.GetWithVariables("WorkshopErrorOverwriteOnEnable", new string[2] { "[itemname]", "[filename]" }, new string[2] { item?.Title, contentFile.Path });
DebugConsole.NewMessage(errorMsg, Color.Red);
return false;
return errorMsg;
}
}
}
try
{
Directory.CreateDirectory(targetPath);
File.WriteAllText(copyingPath, "TEMPORARY FILE");
foreach (ContentFile contentFile in contentPackage.Files)
{
contentFile.Path = contentFile.Path.CleanUpPath();
@@ -1073,8 +1084,8 @@ namespace Barotrauma.Steam
}
}
contentFile.Path = CorrectContentFilePath(contentFile.Path, contentPackage, false);
contentFile.Path = CorrectContentFilePath(contentFile.Path, contentPackage,
contentFile.Type != ContentType.Submarine);
//path not allowed -> the content file must be a reference to an external file (such as some vanilla file outside the Mods folder)
if (!ContentPackage.IsModFilePathAllowed(contentFile))
@@ -1083,14 +1094,14 @@ namespace Barotrauma.Steam
if (File.Exists(sourceFile))
{
errorMsg = TextManager.GetWithVariable("WorkshopErrorIllegalPathOnEnable", "[filename]", contentFile.Path);
return false;
return errorMsg;
}
//not trying to copy anything, so this is a reference to an external file
//if the external file doesn't exist, we cannot enable the package
else if (!File.Exists(contentFile.Path))
{
errorMsg = TextManager.GetWithVariable("WorkshopErrorEnableFailed", "[itemname]", item?.Title) + " " + TextManager.GetWithVariable("WorkshopFileNotFound", "[path]", "\"" + contentFile.Path + "\"");
return false;
return errorMsg;
}
continue;
}
@@ -1105,7 +1116,7 @@ namespace Barotrauma.Steam
{
//file not present in either the mod or the game folder -> cannot enable the package
errorMsg = TextManager.GetWithVariable("WorkshopErrorEnableFailed", "[itemname]", item?.Title) + " " + TextManager.GetWithVariable("WorkshopFileNotFound", "[path]", "\"" + contentFile.Path + "\"");
return false;
return errorMsg;
}
}
@@ -1122,15 +1133,9 @@ namespace Barotrauma.Steam
Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
CorrectContentFileCopy(contentPackage, sourceFile, destinationPath, overwrite: true);
}
}
catch (Exception e)
{
errorMsg = TextManager.GetWithVariable("WorkshopErrorEnableFailed", "[itemname]", item?.Title) + " {" + e.Message + "}";
DebugConsole.NewMessage(errorMsg, Color.Red);
return false;
}
return true;
File.Delete(copyingPath);
return "";
}
private static bool CheckFileEquality(string filePath1, string filePath2)
@@ -1149,6 +1154,44 @@ namespace Barotrauma.Steam
}
}
private static void RemoveMods(Func<ContentPackage, bool> predicate)
{
var toRemove = ContentPackage.List.Where(predicate).ToList();
var packagesToDeselect = GameMain.Config.SelectedContentPackages.Where(p => toRemove.Contains(p)).ToList();
foreach (var cp in packagesToDeselect)
{
if (cp.CorePackage)
{
GameMain.Config.SelectCorePackage(ContentPackage.List.Find(cpp => cpp.CorePackage && !toRemove.Contains(cpp)));
}
else
{
GameMain.Config.DeselectContentPackage(cp);
}
}
foreach (var cp in toRemove)
{
try
{
string path = Path.GetDirectoryName(cp.Path);
if (Directory.Exists(path)) { Directory.Delete(path, true); }
}
catch (Exception e)
{
DebugConsole.ThrowError($"An error occurred while attempting to delete {Path.GetDirectoryName(cp.Path)}", e);
}
}
ContentPackage.List.RemoveAll(cp => toRemove.Contains(cp));
GameMain.Config.SelectedContentPackages.RemoveAll(cp => !ContentPackage.List.Contains(cp));
ContentPackage.SortContentPackages();
GameMain.Config.SaveNewPlayerConfig();
GameMain.Config.WarnIfContentPackageSelectionDirty();
}
/// <summary>
/// Disables a workshop item by removing the files from the game folder.
/// </summary>
@@ -1173,44 +1216,11 @@ namespace Barotrauma.Steam
GameMain.Config.SuppressModFolderWatcher = true;
try
{
var toRemove = ContentPackage.List.Where(cp => !string.IsNullOrWhiteSpace(cp.SteamWorkshopUrl) && cp.SteamWorkshopUrl == contentPackage.SteamWorkshopUrl).ToList();
var packagesToDeselect = GameMain.Config.SelectedContentPackages.Where(p => toRemove.Contains(p)).ToList();
foreach (var cp in packagesToDeselect)
{
if (cp.CorePackage)
{
GameMain.Config.SelectCorePackage(ContentPackage.List.Find(cpp => cpp.CorePackage && !toRemove.Contains(cpp)));
}
else
{
GameMain.Config.DeselectContentPackage(cp);
}
}
foreach (var cp in toRemove)
{
try
{
Directory.Delete(Path.GetDirectoryName(cp.Path), true);
RemoveMods(cp => !string.IsNullOrWhiteSpace(cp.SteamWorkshopUrl) && cp.SteamWorkshopUrl == contentPackage.SteamWorkshopUrl);
}
catch (Exception e)
{
DebugConsole.ThrowError($"An error occurred while attempting to delete {Path.GetDirectoryName(cp.Path)}", e);
}
}
ContentPackage.List.RemoveAll(cp => toRemove.Contains(cp));
GameMain.Config.SelectedContentPackages.RemoveAll(cp => !ContentPackage.List.Contains(cp));
ContentPackage.SortContentPackages();
GameMain.Config.SaveNewPlayerConfig();
GameMain.Config.WarnIfContentPackageSelectionDirty();
}
catch (Exception e)
{
errorMsg = "Disabling the workshop item \"" + item?.Title + "\" failed. " + e.Message;
errorMsg = "Disabling the workshop item \"" + item?.Title + "\" failed. " + e.Message + "\n" + e.StackTrace;
if (!noLog)
{
DebugConsole.NewMessage(errorMsg, Microsoft.Xna.Framework.Color.Red);
@@ -1219,6 +1229,8 @@ namespace Barotrauma.Steam
}
GameMain.Config.SuppressModFolderWatcher = false;
GameMain.SteamWorkshopScreen?.SetReinstallButtonStatus(item, false, null);
errorMsg = "";
return true;
}
@@ -1314,34 +1326,45 @@ namespace Barotrauma.Steam
return upToDate;
}
public static bool AutoUpdateWorkshopItems()
public static async Task<bool> AutoUpdateWorkshopItemsAsync()
{
if (!isInitialized) { return false; }
var query = new Steamworks.Ugc.Query(Steamworks.UgcType.All)
.WhereUserSubscribed()
.WithLongDescription();
//ugcResultPageTasks ??= new List<Task>();
//ugcResultPageTasks.Add();
CancellationTokenSource cancelTokenSource = new CancellationTokenSource();
CancellationToken cancelToken = cancelTokenSource.Token;
Task task = Task.Factory.StartNew(async () =>
{
int processedResults = 0; int pageIndex = 1;
Steamworks.Ugc.ResultPage? resultPage = await query.GetPageAsync(pageIndex);
while (resultPage.HasValue && resultPage?.ResultCount > 0)
List<Steamworks.Ugc.Item> items = await GetWorkshopItemsAsync(query);
GameMain.Config.SuppressModFolderWatcher = true;
//remove mods that the player is no longer subscribed to
RemoveMods(cp => !string.IsNullOrWhiteSpace(cp.SteamWorkshopUrl) && !items.Any(it => it.Id == GetWorkshopItemIDFromUrl(cp.SteamWorkshopUrl)));
GameMain.Config.SuppressModFolderWatcher = false;
foreach (var item in items)
{
foreach (var item in resultPage.Value.Entries)
{
if (cancelToken.IsCancellationRequested)
{
cancelToken.ThrowIfCancellationRequested();
}
try
{
if (!item.IsInstalled || !CheckWorkshopItemEnabled(item) || CheckWorkshopItemUpToDate(item)) { continue; }
if (!UpdateWorkshopItem(item, out string errorMsg))
if (!item.IsInstalled) { continue; }
bool installedSuccessfully = false;
string errorMsg;
if (!CheckWorkshopItemEnabled(item))
{
installedSuccessfully = EnableWorkShopItem(item, true, out errorMsg);
}
else if (!CheckWorkshopItemUpToDate(item))
{
installedSuccessfully = UpdateWorkshopItem(item, out errorMsg);
}
else
{
continue;
}
if (!installedSuccessfully)
{
DebugConsole.ThrowError(errorMsg);
new GUIMessageBox(
@@ -1366,27 +1389,14 @@ namespace Barotrauma.Steam
}
}
processedResults += resultPage.Value.ResultCount;
pageIndex++;
if (processedResults < resultPage?.TotalCount)
List<Task> tasks;
lock (modCopiesInProgress)
{
resultPage = await query.GetPageAsync(pageIndex);
tasks = modCopiesInProgress.Values.ToList();
}
else
{
resultPage = null;
}
}
}, cancelToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
await Task.WhenAll(tasks);
task.Wait(10000);
if (!task.IsCompleted)
{
cancelTokenSource.Cancel();
task.Wait();
}
return task.Status == TaskStatus.RanToCompletion;
return true;
}
public static bool UpdateWorkshopItem(Steamworks.Ugc.Item? item, out string errorMsg)
@@ -1431,7 +1441,7 @@ namespace Barotrauma.Steam
private static void CorrectContentFileCopy(ContentPackage package, string src, string dest, bool overwrite)
{
if (Path.GetExtension(src).ToLowerInvariant() == ".xml")
if (Path.GetExtension(src).Equals(".xml", StringComparison.OrdinalIgnoreCase))
{
XDocument doc = XMLExtensions.TryLoadXml(src);
if (doc != null)
@@ -1481,7 +1491,7 @@ namespace Barotrauma.Steam
{
if (checkIfFileExists)
{
ContentPackage otherContentPackage = ContentPackage.List.Find(cp => cp.Name.ToLowerInvariant() == splitPath[1].ToLowerInvariant());
ContentPackage otherContentPackage = ContentPackage.List.Find(cp => cp.Name.Equals(splitPath[1], StringComparison.OrdinalIgnoreCase));
if (otherContentPackage != null)
{
string otherPackageName = Path.GetDirectoryName(otherContentPackage.Path);
@@ -1493,7 +1503,8 @@ namespace Barotrauma.Steam
}
}
}
newPath = Path.Combine(packageName, string.Join("/", splitPath.Skip(2)));
splitPath = splitPath.Skip(Math.Clamp(splitPath.Length-1, 0, 2)).ToArray();
newPath = Path.Combine(packageName, string.Join("/", splitPath));
}
else
{

View File

@@ -93,7 +93,7 @@ namespace Barotrauma.Networking
if (client.VoipSound == null)
{
DebugConsole.Log("Recreating voipsound " + queueId);
client.VoipSound = new VoipSound(GameMain.SoundManager, client.VoipQueue);
client.VoipSound = new VoipSound(client.Name, GameMain.SoundManager, client.VoipQueue);
}
if (client.Character != null && !client.Character.IsDead && !client.Character.Removed && client.Character.SpeechImpediment <= 100.0f)
@@ -119,7 +119,7 @@ namespace Barotrauma.Networking
GameMain.NetLobbyScreen?.SetPlayerSpeaking(client);
GameMain.GameSession?.CrewManager?.SetClientSpeaking(client);
if (client.VoipSound.CurrentAmplitude > 0.1f) //TODO: might need to tweak
if ((client.VoipSound.CurrentAmplitude * client.VoipSound.Gain * GameMain.SoundManager.GetCategoryGainMultiplier("voip")) > 0.1f) //TODO: might need to tweak
{
if (client.Character != null && !client.Character.Removed)
{

View File

@@ -116,7 +116,7 @@ namespace Barotrauma
Submarine sub = data as Submarine;
if (sub == null) return;
msg.Write(sub.Name);
msg.Write(sub.Info.Name);
break;
case VoteType.Mode:
GameModePreset gameMode = data as GameModePreset;
@@ -158,7 +158,7 @@ namespace Barotrauma
{
if (item.UserData != null && item.UserData is Submarine) serversubs.Add(item.UserData as Submarine);
}
Submarine sub = serversubs.FirstOrDefault(sm => sm.Name == subName);
Submarine sub = serversubs.FirstOrDefault(sm => sm.Info.Name == subName);
SetVoteText(GameMain.NetLobbyScreen.SubList, sub, votes);
}
}

View File

@@ -11,7 +11,18 @@ namespace Barotrauma.Particles
public string OriginalName { get { return Name; } }
public string Identifier { get { return Name.ToLowerInvariant(); } }
private string _identifier;
public string Identifier
{
get
{
if (_identifier == null)
{
_identifier = Name.ToLowerInvariant();
}
return _identifier;
}
}
public string FilePath { get; private set; }
@@ -46,7 +57,7 @@ namespace Barotrauma.Particles
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() == "sprite")
if (subElement.Name.ToString().Equals("sprite", StringComparison.OrdinalIgnoreCase))
{
Sprites.Add(new Sprite(subElement));
}

View File

@@ -108,7 +108,8 @@ namespace Barotrauma.Particles
public readonly bool CopyEntityAngle;
public readonly bool DrawOnTop;
public bool DrawOnTop => forceDrawOnTop || ParticlePrefab.DrawOnTop;
private readonly bool forceDrawOnTop;
public ParticleEmitterPrefab(XElement element)
{
@@ -150,6 +151,12 @@ namespace Barotrauma.Particles
{
DistanceMin = DistanceMax = element.GetAttributeFloat("distance", 0.0f);
}
if (DistanceMax < DistanceMin)
{
var temp = DistanceMin;
DistanceMin = DistanceMax;
DistanceMax = temp;
}
if (element.Attribute("velocity") == null)
{
@@ -160,13 +167,19 @@ namespace Barotrauma.Particles
{
VelocityMin = VelocityMax = element.GetAttributeFloat("velocity", 0.0f);
}
if (VelocityMax < VelocityMin)
{
var temp = VelocityMin;
VelocityMin = VelocityMax;
VelocityMax = temp;
}
EmitInterval = element.GetAttributeFloat("emitinterval", 0.0f);
ParticlesPerSecond = element.GetAttributeInt("particlespersecond", 0);
ParticleAmount = element.GetAttributeInt("particleamount", 0);
HighQualityCollisionDetection = element.GetAttributeBool("highqualitycollisiondetection", false);
CopyEntityAngle = element.GetAttributeBool("copyentityangle", false);
DrawOnTop = element.GetAttributeBool("drawontop", false);
forceDrawOnTop = element.GetAttributeBool("drawontop", false);
}
}
}

View File

@@ -228,14 +228,7 @@ namespace Barotrauma.Particles
if (inSub.HasValue)
{
bool isOutside = particle.CurrentHull == null;
if (particle.DrawOnTop)
{
if (isOutside != inSub.Value)
{
continue;
}
}
else if (isOutside == inSub.Value)
if (!particle.DrawOnTop && isOutside == inSub.Value)
{
continue;
}

View File

@@ -199,6 +199,9 @@ namespace Barotrauma.Particles
[Editable, Serialize(DrawTargetType.Air, false, description: "Should the particle be rendered in air, water or both.")]
public DrawTargetType DrawTarget { get; private set; }
[Editable, Serialize(false, false, description: "Should the particle be always rendered on top of entities?")]
public bool DrawOnTop { get; private set; }
[Editable, Serialize(ParticleBlendState.AlphaBlend, false, description: "The type of blending to use when rendering the particle.")]
public ParticleBlendState BlendState { get; private set; }

View File

@@ -7,6 +7,8 @@ using System.Text;
using GameAnalyticsSDK.Net;
using Barotrauma.Steam;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Xml.Linq;
#if WINDOWS
using SharpDX;
@@ -22,42 +24,56 @@ namespace Barotrauma
/// </summary>
public static class Program
{
#if LINUX
/// <summary>
/// Sets the required environment variables for the game to initialize Steamworks correctly.
/// </summary>
[DllImport("linux_steam_env", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern void setLinuxEnv();
#endif
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
GameMain game = null;
string executableDir = "";
#if !DEBUG
try
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(CrashHandler);
#endif
#if LINUX
setLinuxEnv();
#endif
Game = null;
executableDir = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
Directory.SetCurrentDirectory(executableDir);
SteamManager.Initialize();
game = new GameMain(args);
game.Run();
game.Dispose();
#if !DEBUG
Game = new GameMain(args);
Game.Run();
Game.Dispose();
}
catch (Exception e)
private static GameMain Game;
private static void CrashHandler(object sender, UnhandledExceptionEventArgs args)
{
try
{
CrashDump(game, Path.Combine(executableDir,"crashreport.log"), e);
Game?.Exit();
CrashDump(Game, "crashreport.log", (Exception)args.ExceptionObject);
Game?.Dispose();
}
catch (Exception e2)
catch
{
CrashMessageBox("Barotrauma seems to have crashed, and failed to generate a crash report: "
+ e2.Message + "\n" + e2.StackTrace.ToString(),
null);
}
game?.Dispose();
//exception handler is broken, we have a serious problem here!!
return;
}
#endif
}
public static void CrashMessageBox(string message, string filePath)
@@ -83,17 +99,10 @@ namespace Barotrauma
string exePath = System.Reflection.Assembly.GetEntryAssembly().Location;
var md5 = System.Security.Cryptography.MD5.Create();
Md5Hash exeHash = null;
try
{
using (var stream = File.OpenRead(exePath))
{
exeHash = new Md5Hash(stream);
}
}
catch
{
//gotta catch them all, we don't want to throw an exception while writing a crash report
}
StreamWriter sw = new StreamWriter(filePath);
@@ -102,6 +111,33 @@ namespace Barotrauma
sb.AppendLine("\n");
sb.AppendLine("Barotrauma seems to have crashed. Sorry for the inconvenience! ");
sb.AppendLine("\n");
try
{
if (exception is GameMain.LoadingException)
{
//exception occurred in loading screen:
//assume content packages are the culprit and reset them
XDocument doc = XMLExtensions.TryLoadXml(GameSettings.PlayerSavePath);
XDocument baseDoc = XMLExtensions.TryLoadXml(GameSettings.SavePath);
if (doc != null && baseDoc != null)
{
XElement newElement = new XElement(doc.Root.Name);
newElement.Add(doc.Root.Attributes());
newElement.Add(doc.Root.Elements().Where(e => !e.Name.LocalName.Equals("contentpackage", StringComparison.InvariantCultureIgnoreCase)));
newElement.Add(baseDoc.Root.Elements().Where(e => e.Name.LocalName.Equals("contentpackage", StringComparison.InvariantCultureIgnoreCase)));
XDocument newDoc = new XDocument(newElement);
newDoc.Save(GameSettings.PlayerSavePath);
sb.AppendLine("To prevent further startup errors, installed mods will be disabled the next time you launch the game.");
sb.AppendLine("\n");
}
}
}
catch
{
//welp i guess we couldn't reset the config!
}
if (exeHash?.Hash != null)
{
sb.AppendLine(exeHash.Hash);
@@ -119,7 +155,7 @@ namespace Barotrauma
sb.AppendLine("Selected content packages: " + (!GameMain.SelectedPackages.Any() ? "None" : string.Join(", ", GameMain.SelectedPackages.Select(c => c.Name))));
}
sb.AppendLine("Level seed: " + ((Level.Loaded == null) ? "no level loaded" : Level.Loaded.Seed));
sb.AppendLine("Loaded submarine: " + ((Submarine.MainSub == null) ? "None" : Submarine.MainSub.Name + " (" + Submarine.MainSub.MD5Hash + ")"));
sb.AppendLine("Loaded submarine: " + ((Submarine.MainSub == null) ? "None" : Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash + ")"));
sb.AppendLine("Selected screen: " + (Screen.Selected == null ? "None" : Screen.Selected.ToString()));
if (SteamManager.IsInitialized)
{

View File

@@ -21,7 +21,7 @@ namespace Barotrauma
private GUIButton loadGameButton, deleteMpSaveButton;
public Action<Submarine, string, string> StartNewGame;
public Action<SubmarineInfo, string, string> StartNewGame;
public Action<string> LoadGame;
public GUIButton StartButton
@@ -32,7 +32,7 @@ namespace Barotrauma
private readonly bool isMultiplayer;
public CampaignSetupUI(bool isMultiplayer, GUIComponent newGameContainer, GUIComponent loadGameContainer, IEnumerable<Submarine> submarines, IEnumerable<string> saveFiles = null)
public CampaignSetupUI(bool isMultiplayer, GUIComponent newGameContainer, GUIComponent loadGameContainer, IEnumerable<SubmarineInfo> submarines, IEnumerable<string> saveFiles = null)
{
this.isMultiplayer = isMultiplayer;
this.newGameContainer = newGameContainer;
@@ -115,12 +115,12 @@ namespace Barotrauma
return false;
}
Submarine selectedSub = null;
SubmarineInfo selectedSub = null;
if (!isMultiplayer)
{
if (!(subList.SelectedData is Submarine)) { return false; }
selectedSub = subList.SelectedData as Submarine;
if (!(subList.SelectedData is SubmarineInfo)) { return false; }
selectedSub = subList.SelectedData as SubmarineInfo;
}
else
{
@@ -226,7 +226,7 @@ namespace Barotrauma
{
foreach (GUIComponent child in subList.Content.Children)
{
var sub = child.UserData as Submarine;
var sub = child.UserData as SubmarineInfo;
if (sub == null) { return; }
child.Visible = string.IsNullOrEmpty(filter) ? true : sub.DisplayName.ToLower().Contains(filter.ToLower());
}
@@ -238,7 +238,7 @@ namespace Barotrauma
(subPreviewContainer.Parent as GUILayoutGroup)?.Recalculate();
subPreviewContainer.ClearChildren();
Submarine sub = obj as Submarine;
SubmarineInfo sub = obj as SubmarineInfo;
if (sub == null) { return true; }
sub.CreatePreviewWindow(subPreviewContainer);
@@ -278,7 +278,7 @@ namespace Barotrauma
saveNameBox.Text = Path.GetFileNameWithoutExtension(savePath);
}
public void UpdateSubList(IEnumerable<Submarine> submarines)
public void UpdateSubList(IEnumerable<SubmarineInfo> submarines)
{
#if !DEBUG
var subsToShow = submarines.Where(s => !s.HasTag(SubmarineTag.HideInMenus));
@@ -288,7 +288,7 @@ namespace Barotrauma
subList.ClearChildren();
foreach (Submarine sub in subsToShow)
foreach (SubmarineInfo sub in subsToShow)
{
var textBlock = new GUITextBlock(
new RectTransform(new Vector2(1, 0.1f), subList.Content.RectTransform) { MinSize = new Point(0, 30) },
@@ -319,7 +319,7 @@ namespace Barotrauma
};
}
}
if (Submarine.SavedSubmarines.Any())
if (SubmarineInfo.SavedSubmarines.Any())
{
var nonShuttles = subsToShow.Where(s => !s.HasTag(SubmarineTag.Shuttle)).ToList();
if (nonShuttles.Count > 0)
@@ -392,18 +392,19 @@ namespace Barotrauma
{
nameText.Text = Path.GetFileNameWithoutExtension(saveFile);
XDocument doc = SaveUtil.LoadGameSessionDoc(saveFile);
if (doc.Root.GetChildElement("multiplayercampaign") != null)
{
//multiplayer campaign save in the wrong folder -> don't show the save
saveList.Content.RemoveChild(saveFrame);
continue;
}
if (doc?.Root == null)
{
DebugConsole.ThrowError("Error loading save file \"" + saveFile + "\". The file may be corrupted.");
nameText.TextColor = GUI.Style.Red;
continue;
}
if (doc.Root.GetChildElement("multiplayercampaign") != null)
{
//multiplayer campaign save in the wrong folder -> don't show the save
saveList.Content.RemoveChild(saveFrame);
continue;
}
subName = doc.Root.GetAttributeString("submarine", "");
saveTime = doc.Root.GetAttributeString("savetime", "");
contentPackageStr = doc.Root.GetAttributeString("selectedcontentpackages", "");

View File

@@ -119,8 +119,8 @@ namespace Barotrauma.CharacterEditor
if (Submarine.MainSub == null)
{
ResetVariables();
Submarine.MainSub = new Submarine("Content/AnimEditor.sub");
Submarine.MainSub.Load(unloadPrevious: false, showWarningMessages: false);
var subInfo = new SubmarineInfo("Content/AnimEditor.sub");
Submarine.MainSub = new Submarine(subInfo);
Submarine.MainSub.PhysicsBody.Enabled = false;
originalWall = new WallGroup(new List<Structure>(Structure.WallList));
CloneWalls();
@@ -3347,6 +3347,7 @@ namespace Barotrauma.CharacterEditor
void CreateCloseButton(SerializableEntityEditor editor, Action onButtonClicked, float size = 1)
{
if (editor == null) { return; }
int height = 30;
var parent = new GUIFrame(new RectTransform(new Point(editor.Rect.Width, (int)(height * size * GUI.yScale)), editor.RectTransform, isFixedSize: true), style: null)
{
@@ -3366,6 +3367,7 @@ namespace Barotrauma.CharacterEditor
void CreateAddButtonAtLast(ParamsEditor editor, Action onButtonClicked, string text)
{
if (editor == null) { return; }
var parentFrame = new GUIFrame(new RectTransform(new Point(editor.EditorBox.Rect.Width, (int)(50 * GUI.yScale)), editor.EditorBox.Content.RectTransform), style: null, color: ParamsEditor.Color)
{
CanBeFocused = false
@@ -3383,6 +3385,7 @@ namespace Barotrauma.CharacterEditor
void CreateAddButton(SerializableEntityEditor editor, Action onButtonClicked, string text)
{
if (editor == null) { return; }
var parent = new GUIFrame(new RectTransform(new Point(editor.Rect.Width, (int)(60 * GUI.yScale)), editor.RectTransform), style: null)
{
CanBeFocused = false
@@ -4386,7 +4389,7 @@ namespace Barotrauma.CharacterEditor
ResetParamsEditor();
}
limb.PullJointWorldAnchorA = ScreenToSim(PlayerInput.MousePosition);
TryUpdateLimbParam(limb, "pullpos", ConvertUnits.ToDisplayUnits(limb.PullJointLocalAnchorA / limb.Params.Ragdoll.LimbScale));
TryUpdateLimbParam(limb, "pullpos", ConvertUnits.ToDisplayUnits(limb.PullJointLocalAnchorA / limb.Params.Scale / limb.Params.Ragdoll.LimbScale));
GUI.DrawLine(spriteBatch, SimToScreen(limb.SimPosition), tformedPullPos, Color.MediumPurple);
});
}
@@ -4469,7 +4472,7 @@ namespace Barotrauma.CharacterEditor
if (joint.BodyA == limb.body.FarseerBody)
{
joint.LocalAnchorA += input;
Vector2 transformedValue = ConvertUnits.ToDisplayUnits(joint.LocalAnchorA / RagdollParams.JointScale);
Vector2 transformedValue = ConvertUnits.ToDisplayUnits(joint.LocalAnchorA / joint.Scale);
TryUpdateJointParam(joint, "limb1anchor", transformedValue);
// Snap all selected joints to the first selected
if (copyJointSettings)
@@ -4484,7 +4487,7 @@ namespace Barotrauma.CharacterEditor
else if (joint.BodyB == limb.body.FarseerBody)
{
joint.LocalAnchorB += input;
Vector2 transformedValue = ConvertUnits.ToDisplayUnits(joint.LocalAnchorB / RagdollParams.JointScale);
Vector2 transformedValue = ConvertUnits.ToDisplayUnits(joint.LocalAnchorB / joint.Scale);
TryUpdateJointParam(joint, "limb2anchor", transformedValue);
// Snap all selected joints to the first selected
if (copyJointSettings)
@@ -4504,12 +4507,12 @@ namespace Barotrauma.CharacterEditor
if (joint.BodyA == limb.body.FarseerBody && otherJoint.BodyA == otherLimb.body.FarseerBody)
{
otherJoint.LocalAnchorA = joint.LocalAnchorA;
TryUpdateJointParam(otherJoint, "limb1anchor", ConvertUnits.ToDisplayUnits(joint.LocalAnchorA / RagdollParams.JointScale));
TryUpdateJointParam(otherJoint, "limb1anchor", ConvertUnits.ToDisplayUnits(joint.LocalAnchorA / joint.Scale));
}
else if (joint.BodyB == limb.body.FarseerBody && otherJoint.BodyB == otherLimb.body.FarseerBody)
{
otherJoint.LocalAnchorB = joint.LocalAnchorB;
TryUpdateJointParam(otherJoint, "limb2anchor", ConvertUnits.ToDisplayUnits(joint.LocalAnchorB / RagdollParams.JointScale));
TryUpdateJointParam(otherJoint, "limb2anchor", ConvertUnits.ToDisplayUnits(joint.LocalAnchorB / joint.Scale));
}
});
}
@@ -4873,10 +4876,10 @@ namespace Barotrauma.CharacterEditor
{
// We want the collider to be slightly smaller than the source rect, because the source rect is usually a bit bigger than the graphic.
float multiplier = 0.85f;
l.body.SetSize(new Vector2(ConvertUnits.ToSimUnits(width), ConvertUnits.ToSimUnits(height)) * RagdollParams.LimbScale * RagdollParams.TextureScale * multiplier);
TryUpdateLimbParam(l, "radius", ConvertUnits.ToDisplayUnits(l.body.radius / RagdollParams.LimbScale / RagdollParams.TextureScale));
TryUpdateLimbParam(l, "width", ConvertUnits.ToDisplayUnits(l.body.width / RagdollParams.LimbScale / RagdollParams.TextureScale));
TryUpdateLimbParam(l, "height", ConvertUnits.ToDisplayUnits(l.body.height / RagdollParams.LimbScale / RagdollParams.TextureScale));
l.body.SetSize(new Vector2(ConvertUnits.ToSimUnits(width), ConvertUnits.ToSimUnits(height)) * l.Scale * RagdollParams.TextureScale * multiplier);
TryUpdateLimbParam(l, "radius", ConvertUnits.ToDisplayUnits(l.body.radius / l.Params.Scale / RagdollParams.LimbScale / RagdollParams.TextureScale));
TryUpdateLimbParam(l, "width", ConvertUnits.ToDisplayUnits(l.body.width / l.Params.Scale / RagdollParams.LimbScale / RagdollParams.TextureScale));
TryUpdateLimbParam(l, "height", ConvertUnits.ToDisplayUnits(l.body.height / l.Params.Scale / RagdollParams.LimbScale / RagdollParams.TextureScale));
}
void RecalculateOrigin(Limb l)
{
@@ -4963,7 +4966,7 @@ namespace Barotrauma.CharacterEditor
{
continue;
}
Vector2 tformedJointPos = jointPos = jointPos / RagdollParams.JointScale / limb.TextureScale * spriteSheetZoom;
Vector2 tformedJointPos = jointPos = jointPos / joint.Scale / limb.TextureScale * spriteSheetZoom;
tformedJointPos.Y = -tformedJointPos.Y;
tformedJointPos.X *= character.AnimController.Dir;
tformedJointPos += limbScreenPos;
@@ -4991,11 +4994,11 @@ namespace Barotrauma.CharacterEditor
Vector2 input = ConvertUnits.ToSimUnits(scaledMouseSpeed);
input.Y = -input.Y;
input.X *= character.AnimController.Dir;
input *= RagdollParams.JointScale * limb.TextureScale / spriteSheetZoom;
input *= joint.Scale * limb.TextureScale / spriteSheetZoom;
if (joint.BodyA == limb.body.FarseerBody)
{
joint.LocalAnchorA += input;
Vector2 transformedValue = ConvertUnits.ToDisplayUnits(joint.LocalAnchorA / RagdollParams.JointScale);
Vector2 transformedValue = ConvertUnits.ToDisplayUnits(joint.LocalAnchorA / joint.Scale);
TryUpdateJointParam(joint, "limb1anchor", transformedValue);
// Snap all selected joints to the first selected
if (copyJointSettings)
@@ -5010,7 +5013,7 @@ namespace Barotrauma.CharacterEditor
else if (joint.BodyB == limb.body.FarseerBody)
{
joint.LocalAnchorB += input;
Vector2 transformedValue = ConvertUnits.ToDisplayUnits(joint.LocalAnchorB / RagdollParams.JointScale);
Vector2 transformedValue = ConvertUnits.ToDisplayUnits(joint.LocalAnchorB / joint.Scale);
TryUpdateJointParam(joint, "limb2anchor", transformedValue);
// Snap all selected joints to the first selected
if (copyJointSettings)
@@ -5029,12 +5032,12 @@ namespace Barotrauma.CharacterEditor
if (joint.BodyA == limb.body.FarseerBody && otherJoint.BodyA == otherLimb.body.FarseerBody)
{
otherJoint.LocalAnchorA = joint.LocalAnchorA;
TryUpdateJointParam(otherJoint, "limb1anchor", ConvertUnits.ToDisplayUnits(joint.LocalAnchorA / RagdollParams.JointScale));
TryUpdateJointParam(otherJoint, "limb1anchor", ConvertUnits.ToDisplayUnits(joint.LocalAnchorA / joint.Scale));
}
else if (joint.BodyB == limb.body.FarseerBody && otherJoint.BodyB == otherLimb.body.FarseerBody)
{
otherJoint.LocalAnchorB = joint.LocalAnchorB;
TryUpdateJointParam(otherJoint, "limb2anchor", ConvertUnits.ToDisplayUnits(joint.LocalAnchorB / RagdollParams.JointScale));
TryUpdateJointParam(otherJoint, "limb2anchor", ConvertUnits.ToDisplayUnits(joint.LocalAnchorB / joint.Scale));
}
});
}

View File

@@ -394,7 +394,7 @@ namespace Barotrauma.CharacterEditor
return false;
}
var path = Path.GetFileName(TexturePath);
if (!path.EndsWith(".png", StringComparison.InvariantCultureIgnoreCase))
if (!path.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
{
GUI.AddMessage(TextManager.Get("WrongFileType"), GUI.Style.Red);
texturePathElement.Flash(GUI.Style.Red);
@@ -724,8 +724,8 @@ namespace Barotrauma.CharacterEditor
{
ParseLimbsFromGUIElements();
ParseJointsFromGUIElements();
var main = LimbXElements.Values.Select(xe => xe.Attribute("type")).Where(a => a.Value.ToLowerInvariant() == "torso").FirstOrDefault() ??
LimbXElements.Values.Select(xe => xe.Attribute("type")).Where(a => a.Value.ToLowerInvariant() == "head").FirstOrDefault();
var main = LimbXElements.Values.Select(xe => xe.Attribute("type")).Where(a => a.Value.Equals("torso", StringComparison.OrdinalIgnoreCase)).FirstOrDefault() ??
LimbXElements.Values.Select(xe => xe.Attribute("type")).Where(a => a.Value.Equals("head", StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
if (main == null)
{
GUI.AddMessage(GetCharacterEditorTranslation("MissingTorsoOrHead"), GUI.Style.Red);

View File

@@ -91,7 +91,13 @@ namespace Barotrauma
c.DoVisibilityCheck(cam);
if (c.IsVisible != wasVisible)
{
c.AnimController.Limbs.ForEach(l => { if (l.LightSource != null) l.LightSource.Enabled = c.IsVisible; });
c.AnimController.Limbs.ForEach(l =>
{
if (l.LightSource != null)
{
l.LightSource.Enabled = c.IsVisible;
}
});
}
}
@@ -117,9 +123,11 @@ namespace Barotrauma
if (Submarine.MainSubs[i] == null) continue;
if (Level.Loaded != null && Submarine.MainSubs[i].WorldPosition.Y < Level.MaxEntityDepth) continue;
Vector2 position = Submarine.MainSubs[i].SubBody != null ? Submarine.MainSubs[i].WorldPosition : Submarine.MainSubs[i].HiddenSubPosition;
Color indicatorColor = i == 0 ? Color.LightBlue * 0.5f : GUI.Style.Red * 0.5f;
GUI.DrawIndicator(
spriteBatch, Submarine.MainSubs[i].WorldPosition, cam,
spriteBatch, position, cam,
Math.Max(Submarine.MainSub.Borders.Width, Submarine.MainSub.Borders.Height),
GUI.SubmarineIcon, indicatorColor);
}
@@ -282,14 +290,23 @@ namespace Barotrauma
}
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.LinearWrap, DepthStencilState.None, null, null, cam.Transform);
foreach (Character c in Character.CharacterList) c.DrawFront(spriteBatch, cam);
if (Level.Loaded != null) Level.Loaded.DrawFront(spriteBatch, cam);
if (GameMain.DebugDraw && GameMain.GameSession?.EventManager != null)
foreach (Character c in Character.CharacterList)
{
c.DrawFront(spriteBatch, cam);
}
if (Level.Loaded != null)
{
Level.Loaded.DrawFront(spriteBatch, cam);
}
if (GameMain.DebugDraw)
{
MapEntity.mapEntityList.ForEach(me => me.AiTarget?.Draw(spriteBatch));
Character.CharacterList.ForEach(c => c.AiTarget?.Draw(spriteBatch));
if (GameMain.GameSession?.EventManager != null)
{
GameMain.GameSession.EventManager.DebugDraw(spriteBatch);
}
}
spriteBatch.End();
if (GameMain.LightManager.LosEnabled && GameMain.LightManager.LosMode != LosMode.None && Character.Controlled != null)

View File

@@ -466,6 +466,7 @@ namespace Barotrauma
Submarine.Draw(spriteBatch, false);
Submarine.DrawFront(spriteBatch);
Submarine.DrawDamageable(spriteBatch, null);
GUI.DrawRectangle(spriteBatch, new Rectangle(new Point(0, -Level.Loaded.Size.Y), Level.Loaded.Size), Color.White, thickness: (int)(1.0f / cam.Zoom));
spriteBatch.End();
if (lightingEnabled.Selected)
@@ -517,8 +518,21 @@ namespace Barotrauma
{
foreach (XElement element in doc.Root.Elements())
{
if (element.Name.ToString().ToLowerInvariant() != genParams.Name.ToLowerInvariant()) continue;
XElement levelParamElement = element;
if (element.IsOverride())
{
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().Equals(genParams.Name, StringComparison.OrdinalIgnoreCase))
{
SerializableProperty.SerializeProperties(genParams, subElement, true);
}
}
}
else if (element.Name.ToString().Equals(genParams.Name, StringComparison.OrdinalIgnoreCase))
{
SerializableProperty.SerializeProperties(genParams, element, true);
}
break;
}
}
@@ -539,7 +553,7 @@ namespace Barotrauma
{
foreach (XElement element in doc.Root.Elements())
{
if (element.Name.ToString().ToLowerInvariant() != levelObjPrefab.Name.ToLowerInvariant()) continue;
if (!element.Name.ToString().Equals(levelObjPrefab.Name, StringComparison.OrdinalIgnoreCase)) { continue; }
levelObjPrefab.Save(element);
break;
}
@@ -564,7 +578,7 @@ namespace Barotrauma
bool elementFound = false;
foreach (XElement element in doc.Root.Elements())
{
if (element.Name.ToString().ToLowerInvariant() != genParams.Name.ToLowerInvariant()) continue;
if (!element.Name.ToString().Equals(genParams.Name, StringComparison.OrdinalIgnoreCase)) { continue; }
SerializableProperty.SerializeProperties(genParams, element, true);
elementFound = true;
}

View File

@@ -79,8 +79,6 @@ namespace Barotrauma
private IEnumerable<object> LoadRound()
{
GameMain.GameSession.StartRound(campaignUI.SelectedLevel,
reloadSub: true,
loadSecondSub: false,
mirrorLevel: GameMain.GameSession.Map.CurrentLocation != GameMain.GameSession.Map.SelectedConnection.Locations[0]);
GameMain.GameScreen.Select();

View File

@@ -31,6 +31,7 @@ namespace Barotrauma
private GUITextBox serverNameBox, /*portBox, queryPortBox,*/ passwordBox, maxPlayersBox;
private GUITickBox isPublicBox, wrongPasswordBanBox, karmaEnabledBox;
private GUIDropDown karmaPresetDD;
private readonly GUIFrame downloadingModsContainer, enableModsContainer;
private readonly GUIButton joinServerButton, hostServerButton, steamWorkshopButton;
private readonly GameMain game;
@@ -230,13 +231,31 @@ namespace Barotrauma
};
#if USE_STEAM
steamWorkshopButton = new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), customizeList.RectTransform), TextManager.Get("SteamWorkshopButton"), textAlignment: Alignment.Left, style: "MainMenuGUIButton")
var steamWorkshopButtonContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 1.0f), customizeList.RectTransform), style: null);
steamWorkshopButton = new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), steamWorkshopButtonContainer.RectTransform), TextManager.Get("SteamWorkshopButton"), textAlignment: Alignment.Left, style: "MainMenuGUIButton")
{
ForceUpperCase = true,
Enabled = false,
UserData = Tab.SteamWorkshop,
OnClicked = SelectTab
};
downloadingModsContainer = new GUIFrame(new RectTransform(new Vector2(1.4f, 0.9f), steamWorkshopButtonContainer.RectTransform,
Anchor.CenterRight, Pivot.CenterLeft)
{ RelativeOffset = new Vector2(0.3f, 0.0f) },
"MainMenuNotifBackground", Color.Yellow)
{
CanBeFocused = false,
UserData = "workshopnotif",
Visible = false
};
new GUITextBlock(new RectTransform(Vector2.One * 0.9f, downloadingModsContainer.RectTransform, Anchor.CenterLeft, Pivot.CenterLeft) { RelativeOffset = new Vector2(0.05f, 0.0f) },
TextManager.Get("ModsDownloadingNotif"), Color.Black)
{
CanBeFocused = false,
};
#endif
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), customizeList.RectTransform), TextManager.Get("SubEditorButton"), textAlignment: Alignment.Left, style: "MainMenuGUIButton")
@@ -280,13 +299,29 @@ namespace Barotrauma
RelativeSpacing = 0.035f
};
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), optionList.RectTransform), TextManager.Get("SettingsButton"), textAlignment: Alignment.Left, style: "MainMenuGUIButton")
var settingsButtonContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 1.0f), optionList.RectTransform), style: null);
new GUIButton(new RectTransform(Vector2.One, settingsButtonContainer.RectTransform), TextManager.Get("SettingsButton"), textAlignment: Alignment.Left, style: "MainMenuGUIButton")
{
ForceUpperCase = true,
UserData = Tab.Settings,
OnClicked = SelectTab
};
enableModsContainer = new GUIFrame(new RectTransform(new Vector2(1.4f, 0.9f), settingsButtonContainer.RectTransform,
Anchor.CenterRight, Pivot.CenterLeft) { RelativeOffset = new Vector2(0.5f, 0.0f) },
"MainMenuNotifBackground", Color.Yellow)
{
CanBeFocused = false,
UserData = "settingsnotif",
Visible = false
};
new GUITextBlock(new RectTransform(Vector2.One * 0.9f, enableModsContainer.RectTransform, Anchor.CenterLeft, Pivot.CenterLeft) { RelativeOffset = new Vector2(0.05f, 0.0f) },
TextManager.Get("ModsInstalledNotif"), Color.Black)
{
CanBeFocused = false
};
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), optionList.RectTransform), TextManager.Get("CreditsButton"), textAlignment: Alignment.Left, style: "MainMenuGUIButton")
{
ForceUpperCase = true,
@@ -401,12 +436,18 @@ namespace Barotrauma
GameMain.Client = null;
}
GameMain.SubEditorScreen?.ClearBackedUpSubInfo();
Submarine.Unload();
ResetButtonStates(null);
GameAnalyticsManager.SetCustomDimension01("");
if (GameMain.SteamWorkshopScreen != null)
{
CoroutineManager.StartCoroutine(GameMain.SteamWorkshopScreen.RefreshDownloadState());
}
#if OSX
// Hack for adjusting the viewport properly after splash screens on older Macs
if (firstLoadOnMac)
@@ -495,12 +536,13 @@ namespace Barotrauma
}
campaignSetupUI.CreateDefaultSaveName();
campaignSetupUI.RandomizeSeed();
campaignSetupUI.UpdateSubList(Submarine.SavedSubmarines);
campaignSetupUI.UpdateSubList(SubmarineInfo.SavedSubmarines);
break;
case Tab.LoadGame:
campaignSetupUI.UpdateLoadMenu();
break;
case Tab.Settings:
GameMain.MainMenuScreen?.SetEnableModsNotification(false);
menuTabs[(int)Tab.Settings].RectTransform.ClearChildren();
GameMain.Config.SettingsFrame.RectTransform.Parent = menuTabs[(int)Tab.Settings].RectTransform;
GameMain.Config.SettingsFrame.RectTransform.RelativeSize = Vector2.One;
@@ -631,12 +673,12 @@ namespace Barotrauma
Rand.SetLocalRandom(1);
}
Submarine selectedSub = null;
SubmarineInfo selectedSub = null;
string subName = GameMain.Config.QuickStartSubmarineName;
if (!string.IsNullOrEmpty(subName))
{
DebugConsole.NewMessage($"Loading the predefined quick start sub \"{subName}\"", Color.White);
selectedSub = Submarine.SavedSubmarines.FirstOrDefault(s =>
selectedSub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s =>
s.Name.ToLower() == subName.ToLower());
if (selectedSub == null)
@@ -647,7 +689,7 @@ namespace Barotrauma
if (selectedSub == null)
{
DebugConsole.NewMessage("Loading a random sub.", Color.White);
var subs = Submarine.SavedSubmarines.Where(s => !s.HasTag(SubmarineTag.Shuttle) && !s.HasTag(SubmarineTag.HideInMenus));
var subs = SubmarineInfo.SavedSubmarines.Where(s => !s.HasTag(SubmarineTag.Shuttle) && !s.HasTag(SubmarineTag.HideInMenus));
selectedSub = subs.ElementAt(Rand.Int(subs.Count()));
}
var gamesession = new GameSession(
@@ -684,6 +726,16 @@ namespace Barotrauma
}
}
public void SetEnableModsNotification(bool visible)
{
if (enableModsContainer != null) { enableModsContainer.Visible = visible; }
}
public void SetDownloadingModsNotification(bool visible)
{
if (downloadingModsContainer != null) { downloadingModsContainer.Visible = visible; }
}
private void ShowTutorialSkipWarning(Tab tabToContinueTo)
{
var tutorialSkipWarning = new GUIMessageBox("", TextManager.Get("tutorialskipwarning"), new string[] { TextManager.Get("tutorialwarningskiptutorials"), TextManager.Get("tutorialwarningplaytutorials") });
@@ -990,7 +1042,7 @@ namespace Barotrauma
spriteBatch.End();
}
private void StartGame(Submarine selectedSub, string saveName, string mapSeed)
private void StartGame(SubmarineInfo selectedSub, string saveName, string mapSeed)
{
if (string.IsNullOrEmpty(saveName)) return;
@@ -1027,7 +1079,7 @@ namespace Barotrauma
return;
}
selectedSub = new Submarine(Path.Combine(SaveUtil.TempPath, selectedSub.Name + ".sub"), "");
selectedSub = new SubmarineInfo(Path.Combine(SaveUtil.TempPath, selectedSub.Name + ".sub"));
GameMain.GameSession = new GameSession(selectedSub, saveName,
GameModePreset.List.Find(g => g.Identifier == "singleplayercampaign"));
@@ -1072,7 +1124,7 @@ namespace Barotrauma
var paddedLoadGame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.9f), menuTabs[(int)Tab.LoadGame].RectTransform, Anchor.Center) { AbsoluteOffset = new Point(0, 10) },
style: null);
campaignSetupUI = new CampaignSetupUI(false, paddedNewGame, paddedLoadGame, Submarine.SavedSubmarines)
campaignSetupUI = new CampaignSetupUI(false, paddedNewGame, paddedLoadGame, SubmarineInfo.SavedSubmarines)
{
LoadGame = LoadGame,
StartNewGame = StartGame

View File

@@ -208,15 +208,15 @@ namespace Barotrauma
private set;
}
public Submarine SelectedSub
public SubmarineInfo SelectedSub
{
get { return subList.SelectedData as Submarine; }
get { return subList.SelectedData as SubmarineInfo; }
set { subList.Select(value); }
}
public Submarine SelectedShuttle
public SubmarineInfo SelectedShuttle
{
get { return shuttleList.SelectedData as Submarine; }
get { return shuttleList.SelectedData as SubmarineInfo; }
}
public bool UsingShuttle
@@ -443,7 +443,7 @@ namespace Barotrauma
{
OnClicked = (btn, userdata) =>
{
if (!(userdata is FileReceiver.FileTransferIn transfer)) { return false; }
if (!(FileTransferFrame.UserData is FileReceiver.FileTransferIn transfer)) { return false; }
GameMain.Client?.CancelFileTransfer(transfer);
GameMain.Client.FileReceiver.StopTransfer(transfer);
return true;
@@ -658,7 +658,7 @@ namespace Barotrauma
OnClicked = (btn, obj) =>
{
GameMain.Client.RequestStartRound();
CoroutineManager.StartCoroutine(WaitForStartRound(StartButton, allowCancel: true), "WaitForStartRound");
CoroutineManager.StartCoroutine(WaitForStartRound(StartButton, allowCancel: false), "WaitForStartRound");
return true;
}
};
@@ -1147,6 +1147,22 @@ namespace Barotrauma
clientDisabledElements.AddRange(botSpawnModeButtons);
}
public void StopWaitingForStartRound()
{
CoroutineManager.StopCoroutines("WaitForStartRound");
GUIMessageBox.CloseAll();
if (StartButton != null)
{
StartButton.Enabled = true;
}
if (campaignUI?.StartButton != null)
{
campaignUI.StartButton.Enabled = true;
}
GUI.ClearCursorWait();
}
public IEnumerable<object> WaitForStartRound(GUIButton startButton, bool allowCancel)
{
GUI.SetCursorWaiting();
@@ -1173,7 +1189,8 @@ namespace Barotrauma
}
DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, 10);
while (Selected == GameMain.NetLobbyScreen && DateTime.Now < timeOut)
while (Selected == GameMain.NetLobbyScreen &&
DateTime.Now < timeOut)
{
msgBox.Header.Text = headerText + new string('.', ((int)Timing.TotalTime % 3 + 1));
yield return CoroutineStatus.Running;
@@ -1322,6 +1339,8 @@ namespace Barotrauma
if (GameMain.Client == null) return;
spectateButton.Visible = true;
spectateButton.Enabled = true;
StartButton.Visible = false;
}
public void SetCampaignCharacterInfo(CharacterInfo newCampaignCharacterInfo)
@@ -1609,19 +1628,19 @@ namespace Barotrauma
MissionType = missionType;
}
public void UpdateSubList(GUIComponent subList, List<Submarine> submarines)
public void UpdateSubList(GUIComponent subList, List<SubmarineInfo> submarines)
{
if (subList == null) { return; }
subList.ClearChildren();
foreach (Submarine sub in submarines)
foreach (SubmarineInfo sub in submarines)
{
AddSubmarine(subList, sub);
}
}
private void AddSubmarine(GUIComponent subList, Submarine sub)
private void AddSubmarine(GUIComponent subList, SubmarineInfo sub)
{
if (subList is GUIListBox)
{
@@ -1646,8 +1665,8 @@ namespace Barotrauma
CanBeFocused = false
};
var matchingSub = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == sub.Name && s.MD5Hash?.Hash == sub.MD5Hash?.Hash);
if (matchingSub == null) matchingSub = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == sub.Name);
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)
{
@@ -1704,7 +1723,7 @@ namespace Barotrauma
{
if (!GameMain.Client.ServerSettings.Voting.AllowSubVoting)
{
var selectedSub = component.UserData as Submarine;
var selectedSub = component.UserData as SubmarineInfo;
if (!selectedSub.RequiredContentPackagesInstalled)
{
var msgBox = new GUIMessageBox(TextManager.Get("ContentPackageMismatch"),
@@ -1729,7 +1748,7 @@ namespace Barotrauma
}
return false;
}
if (component.UserData is Submarine sub)
if (component.UserData is SubmarineInfo sub)
{
CreateSubPreview(sub);
}
@@ -1761,7 +1780,7 @@ namespace Barotrauma
}
GameMain.Client.RequestSelectMode(component.Parent.GetChildIndex(component));
HighlightMode(SelectedModeIndex);
return (presetName.ToLowerInvariant() != "multiplayercampaign");
return !presetName.Equals("multiplayercampaign", StringComparison.OrdinalIgnoreCase);
}
return false;
}
@@ -1793,6 +1812,7 @@ namespace Barotrauma
SelectedColor = Color.White * 0.85f,
OutlineColor = Color.White * 0.5f,
TextColor = Color.White,
SelectedTextColor = Color.Black,
UserData = client
};
var soundIcon = new GUIImage(new RectTransform(new Point((int)(textBlock.Rect.Height * 0.8f)), textBlock.RectTransform, Anchor.CenterRight) { AbsoluteOffset = new Point(5, 0) },
@@ -1884,7 +1904,7 @@ namespace Barotrauma
OnClicked = (btn, userdata) => { if (GUI.MouseOn == btn || GUI.MouseOn == btn.TextBlock) ClosePlayerFrame(btn, userdata); return true; }
};
Vector2 frameSize = GameMain.Client.HasPermission(ClientPermissions.ManagePermissions) ? new Vector2(.24f, .5f) : new Vector2(.24f, .24f);
Vector2 frameSize = GameMain.Client.HasPermission(ClientPermissions.ManagePermissions) ? new Vector2(.28f, .5f) : new Vector2(.28f, .24f);
var playerFrameInner = new GUIFrame(new RectTransform(frameSize, playerFrame.RectTransform, Anchor.Center) { MinSize = new Point(550, 0) });
var paddedPlayerFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.88f), playerFrameInner.RectTransform, Anchor.Center))
@@ -2111,7 +2131,7 @@ namespace Barotrauma
{
if (GameMain.Client.HasPermission(ClientPermissions.Ban))
{
var banButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonAreaTop.RectTransform),
var banButton = new GUIButton(new RectTransform(new Vector2(0.34f, 1.0f), buttonAreaTop.RectTransform),
TextManager.Get("Ban"))
{
UserData = selectedClient
@@ -2119,7 +2139,7 @@ namespace Barotrauma
banButton.OnClicked = (bt, userdata) => { BanPlayer(selectedClient); return true; };
banButton.OnClicked += ClosePlayerFrame;
var rangebanButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonAreaTop.RectTransform),
var rangebanButton = new GUIButton(new RectTransform(new Vector2(0.34f, 1.0f), buttonAreaTop.RectTransform),
TextManager.Get("BanRange"))
{
UserData = selectedClient
@@ -2132,7 +2152,7 @@ namespace Barotrauma
if (GameMain.Client != null && GameMain.Client.ServerSettings.Voting.AllowVoteKick &&
selectedClient != null && selectedClient.AllowKicking)
{
var kickVoteButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonAreaLower.RectTransform),
var kickVoteButton = new GUIButton(new RectTransform(new Vector2(0.34f, 1.0f), buttonAreaLower.RectTransform),
TextManager.Get("VoteToKick"))
{
Enabled = !selectedClient.HasKickVoteFromID(GameMain.Client.ID),
@@ -2144,7 +2164,7 @@ namespace Barotrauma
if (GameMain.Client.HasPermission(ClientPermissions.Kick) &&
selectedClient != null && selectedClient.AllowKicking)
{
var kickButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonAreaLower.RectTransform),
var kickButton = new GUIButton(new RectTransform(new Vector2(0.34f, 1.0f), buttonAreaLower.RectTransform),
TextManager.Get("Kick"))
{
UserData = selectedClient
@@ -2153,6 +2173,9 @@ namespace Barotrauma
kickButton.OnClicked += ClosePlayerFrame;
}
GUITextBlock.AutoScaleAndNormalize(
buttonAreaTop.Children.Select(c => ((GUIButton)c).TextBlock).Concat(buttonAreaLower.Children.Select(c => ((GUIButton)c).TextBlock)));
new GUITickBox(new RectTransform(new Vector2(0.25f, 1.0f), buttonAreaTop.RectTransform, Anchor.TopRight),
TextManager.Get("Mute"))
{
@@ -2162,7 +2185,7 @@ namespace Barotrauma
};
}
var closeButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonAreaLower.RectTransform, Anchor.BottomRight),
var closeButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonAreaLower.RectTransform, Anchor.TopRight),
TextManager.Get("Close"))
{
IgnoreLayoutGroups = true,
@@ -2241,7 +2264,7 @@ namespace Barotrauma
targetMicStyle = "GUIMicrophoneDisabled";
}
if (targetMicStyle.ToLowerInvariant() != currMicStyle.ToLowerInvariant())
if (!targetMicStyle.Equals(currMicStyle, StringComparison.OrdinalIgnoreCase))
{
GUI.Style.Apply(micIcon, targetMicStyle);
}
@@ -2597,7 +2620,7 @@ namespace Barotrauma
GUILayoutGroup row = null;
int itemsInRow = 0;
XElement headElement = info.Ragdoll.MainElement.Elements().FirstOrDefault(e => e.GetAttributeString("type", "").ToLowerInvariant() == "head");
XElement headElement = info.Ragdoll.MainElement.Elements().FirstOrDefault(e => e.GetAttributeString("type", "").Equals("head", StringComparison.OrdinalIgnoreCase));
XElement headSpriteElement = headElement.Element("sprite");
string spritePathWithTags = headSpriteElement.Attribute("texture").Value;
@@ -2655,8 +2678,11 @@ namespace Barotrauma
private bool SwitchJob(GUIButton button, object obj)
{
if (JobList == null) { return false; }
int childIndex = JobList.SelectedIndex;
var child = JobList.SelectedComponent;
if (child == null) { return false; }
bool moveToNext = obj != null;
@@ -2745,11 +2771,11 @@ namespace Barotrauma
availableJobs = availableJobs.ToList();
int itemsInRow = 1;
int itemsInRow = 0;
foreach (var jobPrefab in availableJobs)
{
if (itemsInRow >= 4)
if (itemsInRow >= 3)
{
row = new GUILayoutGroup(new RectTransform(Vector2.One, rows.RectTransform), true);
itemsInRow = 0;
@@ -3025,7 +3051,7 @@ namespace Barotrauma
}*/
}
public void TryDisplayCampaignSubmarine(Submarine submarine)
public void TryDisplayCampaignSubmarine(SubmarineInfo submarine)
{
string name = submarine?.Name;
bool displayed = false;
@@ -3034,13 +3060,13 @@ namespace Barotrauma
subPreviewContainer.ClearChildren();
foreach (GUIComponent child in subList.Content.Children)
{
if (!(child.UserData is Submarine sub)) { continue; }
if (!(child.UserData is SubmarineInfo sub)) { continue; }
//just check the name, even though the campaign sub may not be the exact same version
//we're selecting the sub just for show, the selection is not actually used for anything
if (sub.Name == name)
{
subList.Select(sub);
if (Submarine.SavedSubmarines.Contains(sub))
if (SubmarineInfo.SavedSubmarines.Contains(sub))
{
CreateSubPreview(sub);
displayed = true;
@@ -3201,9 +3227,9 @@ namespace Barotrauma
return false;
}
Submarine sub = subList.Content.Children
.FirstOrDefault(c => c.UserData is Submarine s && s.Name == subName && s.MD5Hash?.Hash == md5Hash)?
.UserData as Submarine;
SubmarineInfo sub = subList.Content.Children
.FirstOrDefault(c => c.UserData is SubmarineInfo s && s.Name == subName && s.MD5Hash?.Hash == md5Hash)?
.UserData as SubmarineInfo;
//matching sub found and already selected, all good
if (sub != null)
@@ -3212,7 +3238,7 @@ namespace Barotrauma
{
CreateSubPreview(sub);
}
if (subList.SelectedData is Submarine selectedSub && selectedSub.MD5Hash?.Hash == md5Hash && System.IO.File.Exists(sub.FilePath))
if (subList.SelectedData is SubmarineInfo selectedSub && selectedSub.MD5Hash?.Hash == md5Hash && System.IO.File.Exists(sub.FilePath))
{
return true;
}
@@ -3222,8 +3248,8 @@ namespace Barotrauma
if (sub == null)
{
sub = subList.Content.Children
.FirstOrDefault(c => c.UserData is Submarine s && s.Name == subName)?
.UserData as Submarine;
.FirstOrDefault(c => c.UserData is SubmarineInfo s && s.Name == subName)?
.UserData as SubmarineInfo;
}
//found a sub that at least has the same name, select it
@@ -3246,7 +3272,7 @@ namespace Barotrauma
FailedSelectedShuttle = null;
//hashes match, all good
if (sub.MD5Hash?.Hash == md5Hash && Submarine.SavedSubmarines.Contains(sub))
if (sub.MD5Hash?.Hash == md5Hash && SubmarineInfo.SavedSubmarines.Contains(sub))
{
return true;
}
@@ -3261,7 +3287,7 @@ namespace Barotrauma
FailedSelectedShuttle = new Pair<string, string>(subName, md5Hash);
string errorMsg = "";
if (sub == null || !Submarine.SavedSubmarines.Contains(sub))
if (sub == null || !SubmarineInfo.SavedSubmarines.Contains(sub))
{
errorMsg = TextManager.GetWithVariable("SubNotFoundError", "[subname]", subName) + " ";
}
@@ -3303,7 +3329,7 @@ namespace Barotrauma
return false;
}
private void CreateSubPreview(Submarine sub)
private void CreateSubPreview(SubmarineInfo sub)
{
subPreviewContainer?.ClearChildren();
sub.CreatePreviewWindow(subPreviewContainer);

View File

@@ -237,7 +237,7 @@ namespace Barotrauma
{
foreach (XElement element in doc.Root.Elements())
{
if (element.Name.ToString().ToLowerInvariant() != prefab.Name.ToLowerInvariant()) continue;
if (!element.Name.ToString().Equals(prefab.Name, StringComparison.OrdinalIgnoreCase)) { continue; }
SerializableProperty.SerializeProperties(prefab, element, true);
}
}

View File

@@ -965,7 +965,7 @@ namespace Barotrauma
child.Visible =
serverInfo.OwnerVerified &&
serverInfo.ServerName.ToLowerInvariant().Contains(searchBox.Text.ToLowerInvariant()) &&
serverInfo.ServerName.Contains(searchBox.Text, StringComparison.OrdinalIgnoreCase) &&
(!filterSameVersion.Selected || (remoteVersion != null && NetworkMember.IsCompatible(remoteVersion, GameMain.Version))) &&
(!filterPassword.Selected || !serverInfo.HasPassword) &&
(!filterIncompatible.Selected || !incompatible) &&
@@ -996,7 +996,7 @@ namespace Barotrauma
foreach (GUITickBox tickBox in gameModeTickBoxes)
{
var gameMode = (string)tickBox.UserData;
if (!tickBox.Selected && (serverInfo.GameMode == gameMode.ToLowerInvariant() || serverInfo.GameMode == gameMode))
if (!tickBox.Selected && serverInfo.GameMode.Equals(gameMode, StringComparison.OrdinalIgnoreCase))
{
child.Visible = false;
break;
@@ -1304,6 +1304,8 @@ namespace Barotrauma
{
#if DEBUG
DebugConsole.ThrowError($"Failed to parse a Steam friend's connect command ({connectCommand})", e);
#else
DebugConsole.Log($"Failed to parse a Steam friend's connect command ({connectCommand})\n" + e.StackTrace);
#endif
info.ConnectName = null;
info.ConnectEndpoint = null;
@@ -1512,7 +1514,7 @@ namespace Barotrauma
{
serverList.ClearChildren();
if (masterServerData.Substring(0, 5).ToLowerInvariant() == "error")
if (masterServerData.Substring(0, 5).Equals("error", StringComparison.OrdinalIgnoreCase))
{
DebugConsole.ThrowError("Error while connecting to master server (" + masterServerData + ")!");
return;

View File

@@ -26,10 +26,24 @@ namespace Barotrauma
//listbox that shows the files included in the item being created
private GUIListBox createItemFileList;
private FileSystemWatcher createItemWatcher;
private readonly List<GUIButton> tabButtons = new List<GUIButton>();
private readonly HashSet<string> pendingPreviewImageDownloads = new HashSet<string>();
private readonly Dictionary<string, Sprite> itemPreviewSprites = new Dictionary<string, Sprite>();
private class PendingPreviewImageDownload
{
/// <summary>
/// Was the image downloaded
/// </summary>
public bool Downloaded = false;
/// <summary>
/// How many tasks are looking to create a preview image based on this download
/// </summary>
public int PendingLoads = 1;
}
private readonly Dictionary<ulong, PendingPreviewImageDownload> pendingPreviewImageDownloads = new Dictionary<ulong, PendingPreviewImageDownload>();
private Dictionary<string, Sprite> itemPreviewSprites = new Dictionary<string, Sprite>();
private enum Tab
{
@@ -54,6 +68,8 @@ namespace Barotrauma
{
GameMain.Instance.OnResolutionChanged += CreateUI;
CreateUI();
Steamworks.SteamUGC.GlobalOnItemInstalled += OnItemInstalled;
}
private void CreateUI()
@@ -199,7 +215,7 @@ namespace Barotrauma
{
if (GUI.MouseOn is GUIButton || GUI.MouseOn?.Parent is GUIButton) { return false; }
publishedItemList.Deselect();
if (userdata is Submarine sub)
if (userdata is SubmarineInfo sub)
{
CreateWorkshopItem(sub);
}
@@ -215,6 +231,8 @@ namespace Barotrauma
createItemFrame = new GUIFrame(new RectTransform(new Vector2(0.58f, 1.0f), tabs[(int)Tab.Publish].RectTransform, Anchor.TopRight), style: null);
SelectTab(Tab.Mods);
subscribedCoroutine = CoroutineManager.StartCoroutine(PollSubscribedItems());
}
public override void Select()
@@ -230,6 +248,32 @@ namespace Barotrauma
SelectTab(Tab.Mods);
}
private void OnItemInstalled(ulong itemId)
{
RefreshSubscribedItems();
}
CoroutineHandle subscribedCoroutine;
private IEnumerable<object> PollSubscribedItems()
{
if (!SteamManager.IsInitialized) { yield return CoroutineStatus.Success; }
uint numSubscribed = 0;
while (true)
{
while (CoroutineManager.IsCoroutineRunning("Load")) { yield return new WaitForSeconds(1.0f); }
uint newNumSubscribed = Steamworks.SteamUGC.NumSubscribedItems;
if (newNumSubscribed != numSubscribed)
{
RefreshSubscribedItems();
numSubscribed = newNumSubscribed;
}
yield return new WaitForSeconds(1.0f);
}
}
private void SelectTab(Tab tab)
{
for (int i = 0; i < tabs.Length; i++)
@@ -246,6 +290,7 @@ namespace Barotrauma
};
}
createItemWatcher?.Dispose(); createItemWatcher = null;
if (Screen.Selected == this)
{
switch (tab)
@@ -272,6 +317,25 @@ namespace Barotrauma
GameMain.SteamWorkshopScreen.Select();
}
public IEnumerable<object> RefreshDownloadState()
{
bool isDownloading = true;
while (true)
{
SteamManager.GetSubscribedWorkshopItems((items) =>
{
isDownloading = items.Any(it => it.IsDownloading || it.IsDownloadPending);
GameMain.MainMenuScreen.SetDownloadingModsNotification(isDownloading);
});
if (!isDownloading) { break; }
yield return new WaitForSeconds(0.5f);
}
yield return CoroutineStatus.Success;
}
private void RefreshSubscribedItems()
{
SteamManager.GetSubscribedWorkshopItems((items) =>
@@ -279,6 +343,8 @@ namespace Barotrauma
//filter out the items published by the player (they're shown in the publish tab)
var mySteamID = SteamManager.GetSteamID();
OnItemsReceived(GetVisibleItems(items.Where(it => it.Owner.Id != mySteamID)), subscribedItemList);
GameMain.MainMenuScreen.SetDownloadingModsNotification(items.Any(it => it.IsDownloading || it.IsDownloadPending));
});
}
@@ -312,7 +378,7 @@ namespace Barotrauma
{
CanBeFocused = false
};
foreach (Submarine sub in Submarine.SavedSubmarines)
foreach (SubmarineInfo sub in SubmarineInfo.SavedSubmarines)
{
if (sub.HasTag(SubmarineTag.HideInMenus)) { continue; }
string subPath = Path.GetFullPath(sub.FilePath);
@@ -414,7 +480,7 @@ namespace Barotrauma
CanBeFocused = false
};
}
else
else if (Screen.Selected == this)
{
new GUIImage(new RectTransform(new Point(iconSize), innerFrame.RectTransform), SteamManager.DefaultPreviewImage, scaleToFit: true)
{
@@ -430,16 +496,20 @@ namespace Barotrauma
bool isNewImage;
lock (pendingPreviewImageDownloads)
{
isNewImage = !pendingPreviewImageDownloads.Contains(item?.PreviewImageUrl);
if (isNewImage) { pendingPreviewImageDownloads.Add(item?.PreviewImageUrl); }
}
isNewImage = !pendingPreviewImageDownloads.ContainsKey(item.Value.Id);
if (isNewImage)
{
if (File.Exists(imagePreviewPath))
{
File.Delete(imagePreviewPath);
}
pendingPreviewImageDownloads.Add(item.Value.Id, new PendingPreviewImageDownload());
}
}
if (isNewImage)
{
Directory.CreateDirectory(SteamManager.WorkshopItemPreviewImageFolder);
Uri baseAddress = new Uri(item?.PreviewImageUrl);
@@ -449,17 +519,24 @@ namespace Barotrauma
IRestClient client = new RestClient(directory);
var request = new RestRequest(fileName, Method.GET);
client.ExecuteAsync(request, response =>
{
OnPreviewImageDownloaded(response, imagePreviewPath,
() =>
{
lock (pendingPreviewImageDownloads)
{
pendingPreviewImageDownloads.Remove(item?.PreviewImageUrl);
pendingPreviewImageDownloads[item.Value.Id].Downloaded = true;
}
OnPreviewImageDownloaded(response, imagePreviewPath);
CoroutineManager.StartCoroutine(WaitForItemPreviewDownloaded(item, listBox, imagePreviewPath));
});
});
}
else
{
lock (pendingPreviewImageDownloads)
{
pendingPreviewImageDownloads[item.Value.Id].PendingLoads++;
}
CoroutineManager.StartCoroutine(WaitForItemPreviewDownloaded(item, listBox, imagePreviewPath));
}
}
@@ -468,7 +545,7 @@ namespace Barotrauma
{
lock (pendingPreviewImageDownloads)
{
pendingPreviewImageDownloads.Remove(item?.PreviewImageUrl);
pendingPreviewImageDownloads.Remove(item.Value.Id);
}
DebugConsole.ThrowError("Downloading the preview image of the Workshop item \"" + item?.Title + "\" failed.", e);
}
@@ -488,10 +565,11 @@ namespace Barotrauma
CanBeFocused = false
};
if ((item?.IsSubscribed ?? false) && (item?.IsInstalled ?? false))
if ((item?.IsSubscribed ?? false) && (item?.IsInstalled ?? false) && Directory.Exists(item?.Directory))
{
GUITickBox enabledTickBox = null;
try
bool installed = SteamManager.CheckWorkshopItemEnabled(item);
if (!installed)
{
bool? compatible = SteamManager.CheckWorkshopItemCompatibility(item);
if (compatible.HasValue && !compatible.Value)
@@ -504,63 +582,32 @@ namespace Barotrauma
}
else
{
enabledTickBox = new GUITickBox(new RectTransform(new Point(32, 32), rightColumn.RectTransform), null)
{
ToolTip = TextManager.Get("WorkshopItemEnabled"),
UserData = item,
};
enabledTickBox.Selected = SteamManager.CheckWorkshopItemEnabled(item);
enabledTickBox.OnSelected = ToggleItemEnabled;
}
}
catch (Exception e)
{
if (enabledTickBox != null) { enabledTickBox.Enabled = false; }
itemFrame.ToolTip = e.Message;
itemFrame.Color = GUI.Style.Red;
itemFrame.HoverColor = GUI.Style.Red;
itemFrame.SelectedColor = GUI.Style.Red;
titleText.TextColor = GUI.Style.Red;
installed = SteamManager.EnableWorkShopItem(item, true, out string errorMsg, Screen.Selected == this);
if (item?.IsSubscribed ?? false)
{
new GUIButton(new RectTransform(new Vector2(0.5f, 0.5f), rightColumn.RectTransform), TextManager.Get("WorkshopItemUnsubscribe"))
{
UserData = item,
OnClicked = (btn, userdata) =>
{
item?.Unsubscribe();
subscribedItemList.RemoveChild(subscribedItemList.Content.GetChildByUserData(item));
return true;
}
};
}
}
if (listBox != publishedItemList && SteamManager.CheckWorkshopItemEnabled(item) && !SteamManager.CheckWorkshopItemUpToDate(item))
{
new GUIButton(new RectTransform(new Vector2(0.4f, 0.5f), rightColumn.RectTransform, Anchor.BottomLeft), text: TextManager.Get("WorkshopItemUpdate"))
{
UserData = "updatebutton",
Font = GUI.SmallFont,
OnClicked = (btn, userdata) =>
{
if (SteamManager.UpdateWorkshopItem(item, out string errorMsg))
{
new GUIMessageBox("", TextManager.GetWithVariable("WorkshopItemUpdated", "[itemname]", item?.Title));
}
else
if (!installed)
{
DebugConsole.ThrowError(errorMsg);
new GUIMessageBox(
TextManager.Get("Error"),
TextManager.GetWithVariables("WorkshopItemUpdateFailed", new string[2] { "[itemname]", "[errormessage]" }, new string[2] { item?.Title, errorMsg }));
TextManager.GetWithVariables("WorkshopItemUpdateFailed", new string[2] { "[itemname]", "[errormessage]" }, new string[2] { TextManager.EnsureUTF8(item?.Title), errorMsg }));
}
}
}
if (installed)
{
bool upToDate = SteamManager.CheckWorkshopItemUpToDate(item);
if (!upToDate)
{
if (!SteamManager.UpdateWorkshopItem(item, out string errorMsg))
{
DebugConsole.ThrowError(errorMsg);
new GUIMessageBox(
TextManager.Get("Error"),
TextManager.GetWithVariables("WorkshopItemUpdateFailed", new string[2] { "[itemname]", "[errormessage]" }, new string[2] { TextManager.EnsureUTF8(item?.Title), errorMsg }));
}
btn.Enabled = false;
btn.Visible = false;
return true;
}
};
}
}
@@ -568,7 +615,11 @@ namespace Barotrauma
{
new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.5f), rightColumn.RectTransform), TextManager.Get("WorkshopItemDownloading"));
}
else
else if (item?.IsDownloadPending ?? false)
{
new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.5f), rightColumn.RectTransform), TextManager.Get("WorkshopItemDownloadPending"));
}
else if (!(item?.IsSubscribed ?? false))
{
var downloadBtn = new GUIButton(new RectTransform(new Point((int)(32 * GUI.Scale)), rightColumn.RectTransform), "", style: "GUIPlusButton")
{
@@ -579,10 +630,66 @@ namespace Barotrauma
downloadBtn.OnClicked = (btn, userdata) => { DownloadItem(itemFrame, downloadBtn, item); return true; };
}
if ((item?.IsSubscribed ?? false) && listBox == subscribedItemList)
{
var reinstallBtn = new GUIButton(new RectTransform(new Point((int)(32 * GUI.Scale)), rightColumn.RectTransform), "", style: "GUIReloadButton")
{
ToolTip = TextManager.Get("WorkshopItemReinstall"),
ForceUpperCase = true,
UserData = "reinstall"
};
reinstallBtn.OnClicked = (btn, userdata) =>
{
var elem = subscribedItemList.Content.GetChildByUserData(item);
try
{
bool reselect = GameMain.Config.SelectedContentPackages.Any(cp => !string.IsNullOrWhiteSpace(cp.SteamWorkshopUrl) && cp.SteamWorkshopUrl == item?.Url);
if (!SteamManager.DisableWorkShopItem(item, false, out string errorMsg) ||
!SteamManager.EnableWorkShopItem(item, true, out errorMsg, reselect, true))
{
DebugConsole.ThrowError($"Failed to reinstall \"{item?.Title}\": {errorMsg}", null, true);
elem.Flash(GUI.Style.Red);
}
}
catch (Exception e)
{
DebugConsole.ThrowError($"Failed to reinstall \"{item?.Title}\"", e, true);
elem.Flash(GUI.Style.Red);
}
return true;
};
var unsubBtn = new GUIButton(new RectTransform(new Point((int)(32 * GUI.Scale)), rightColumn.RectTransform), "", style: "GUIMinusButton")
{
ToolTip = TextManager.Get("WorkshopItemUnsubscribe"),
ForceUpperCase = true,
UserData = "unsubscribe"
};
unsubBtn.OnClicked = (btn, userdata) =>
{
SteamManager.DisableWorkShopItem(item, true, out _);
item?.Unsubscribe();
subscribedItemList.RemoveChild(subscribedItemList.Content.GetChildByUserData(item));
return true;
};
}
innerFrame.Recalculate();
listBox.RecalculateChildren();
}
public void SetReinstallButtonStatus(Steamworks.Ugc.Item? item, bool enabled, Color? flashColor)
{
var child = subscribedItemList.Content.FindChild((component) => { return (component.UserData is Steamworks.Ugc.Item?) && (component.UserData as Steamworks.Ugc.Item?)?.Id == item?.Id; });
if (child != null)
{
var reinstallBtn = child.FindChild("reinstall", true);
if (reinstallBtn != null) { reinstallBtn.Enabled = enabled; }
var unsubBtn = child.FindChild("unsubscribe", true);
if (unsubBtn != null) { unsubBtn.Enabled = enabled; }
if (flashColor.HasValue) { child.Flash(flashColor); }
}
}
private void RemoveItemFromLists(ulong itemID)
{
RemoveItemFromList(publishedItemList);
@@ -596,7 +703,7 @@ namespace Barotrauma
}
}
private void CreateMyItemFrame(Submarine submarine, GUIListBox listBox)
private void CreateMyItemFrame(SubmarineInfo submarine, GUIListBox listBox)
{
var itemFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.1f), listBox.Content.RectTransform, minSize: new Point(0, 80)),
style: "ListBoxElement")
@@ -629,10 +736,17 @@ namespace Barotrauma
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.4f), innerFrame.RectTransform), contentPackage.Name, textAlignment: Alignment.CenterLeft);
}
private void OnPreviewImageDownloaded(IRestResponse response, string previewImagePath)
private void OnPreviewImageDownloaded(IRestResponse response, string previewImagePath, Action action)
{
if (response.ResponseStatus == ResponseStatus.Completed)
{
TaskPool.Add(WritePreviewImageAsync(response, previewImagePath), (task) => { action?.Invoke(); });
}
}
private async Task WritePreviewImageAsync(IRestResponse response, string previewImagePath)
{
await Task.Yield();
try
{
File.WriteAllBytes(previewImagePath, response.RawBytes);
@@ -645,7 +759,6 @@ namespace Barotrauma
return;
}
}
}
private IEnumerable<object> WaitForItemPreviewDownloaded(Steamworks.Ugc.Item? item, GUIListBox listBox, string previewImagePath)
{
@@ -653,47 +766,67 @@ namespace Barotrauma
{
lock (pendingPreviewImageDownloads)
{
if (!pendingPreviewImageDownloads.Contains(item?.PreviewImageUrl)) { break; }
if (pendingPreviewImageDownloads[item.Value.Id].Downloaded){ break; }
}
yield return CoroutineStatus.Running;
yield return new WaitForSeconds(0.2f);
}
if (File.Exists(previewImagePath))
{
Sprite newSprite;
if (itemPreviewSprites.ContainsKey(item?.PreviewImageUrl))
TaskPool.Add(LoadPreviewImageAsync(item?.PreviewImageUrl, previewImagePath),
new Tuple<Steamworks.Ugc.Item?, GUIListBox>(item, listBox),
(task, tuple) =>
{
newSprite = itemPreviewSprites[item?.PreviewImageUrl];
(var it, var lb) = tuple;
var previewImage = lb.Content.FindChild(item)?.GetChildByUserData("previewimage") as GUIImage;
if (previewImage != null)
{
previewImage.Sprite = task.Result;
}
else
{
newSprite = new Sprite(previewImagePath, sourceRectangle: null);
itemPreviewSprites.Add(item?.PreviewImageUrl, newSprite);
CreateWorkshopItemFrame(it, lb);
}
if (listBox.Content.FindChild(item)?.GetChildByUserData("previewimage") is GUIImage previewImage)
if (modsPreviewFrame.FindChild(it) != null)
{
previewImage.Sprite = newSprite;
}
else
{
CreateWorkshopItemFrame(item, listBox);
}
if (modsPreviewFrame.FindChild(item) != null)
{
ShowItemPreview(item, modsPreviewFrame);
ShowItemPreview(it, modsPreviewFrame);
}
if (browsePreviewFrame.FindChild(item) != null)
{
ShowItemPreview(item, browsePreviewFrame);
ShowItemPreview(it, browsePreviewFrame);
}
lock (pendingPreviewImageDownloads)
{
pendingPreviewImageDownloads[it.Value.Id].PendingLoads--;
if (pendingPreviewImageDownloads[it.Value.Id].PendingLoads <= 0) { pendingPreviewImageDownloads.Remove(it.Value.Id); }
}
});
}
yield return CoroutineStatus.Success;
}
private async Task<Sprite> LoadPreviewImageAsync(string previewImageUrl, string previewImagePath)
{
await Task.Yield();
lock (itemPreviewSprites)
{
if (itemPreviewSprites.ContainsKey(previewImageUrl))
{
return itemPreviewSprites[previewImageUrl];
}
else
{
Sprite newSprite = new Sprite(previewImagePath, sourceRectangle: null);
itemPreviewSprites.Add(previewImageUrl, newSprite);
return newSprite;
}
}
}
private bool DownloadItem(GUIComponent frame, GUIButton downloadButton, Steamworks.Ugc.Item? item)
{
if (item == null) { return false; }
@@ -721,49 +854,6 @@ namespace Barotrauma
return true;
}
private bool ToggleItemEnabled(GUITickBox tickBox)
{
if (!(tickBox.UserData is Steamworks.Ugc.Item?)) { return false; }
var item = tickBox.UserData as Steamworks.Ugc.Item?;
if (item == null) { return false; }
//currently editing the item, don't allow enabling/disabling it
if (itemEditor?.FileId == item?.Id) { tickBox.Selected = true; return false; }
var updateButton = tickBox.Parent.FindChild("updatebutton");
string errorMsg;
if (tickBox.Selected)
{
if (!SteamManager.EnableWorkShopItem(item, false, out errorMsg))
{
tickBox.Visible = false;
tickBox.Selected = false;
if (tickBox.Parent.GetChildByUserData("titletext") is GUITextBlock titleText) { titleText.TextColor = GUI.Style.Red; }
}
}
else
{
if (!SteamManager.DisableWorkShopItem(item, false, out errorMsg))
{
tickBox.Enabled = false;
}
GameMain.Config.EnsureCoreContentPackageSelected();
}
if (updateButton != null)
{
//cannot update if enabling/disabling the item failed or if the item is not enabled
updateButton.Enabled = tickBox.Enabled && tickBox.Selected;
}
if (!string.IsNullOrEmpty(errorMsg))
{
new GUIMessageBox(TextManager.Get("Error"), errorMsg);
}
return true;
}
private void ShowItemPreview(Steamworks.Ugc.Item? item, GUIFrame itemPreviewFrame)
{
itemPreviewFrame.ClearChildren();
@@ -920,7 +1010,7 @@ namespace Barotrauma
};
}
private void CreateWorkshopItem(Submarine sub)
private void CreateWorkshopItem(SubmarineInfo sub)
{
string destinationFolder = Path.Combine("Mods", sub.Name);
itemContentPackage = ContentPackage.CreatePackage(sub.Name, Path.Combine(destinationFolder, SteamManager.MetadataFileName), corePackage: false);
@@ -940,8 +1030,8 @@ namespace Barotrauma
itemContentPackage.AddFile(sub.FilePath, ContentType.Submarine);
itemContentPackage.Name = sub.Name;
itemContentPackage.Save(itemContentPackage.Path);
ContentPackage.List.Add(itemContentPackage);
GameMain.Config.SelectContentPackage(itemContentPackage);
//ContentPackage.List.Add(itemContentPackage);
//GameMain.Config.SelectContentPackage(itemContentPackage);
itemEditor = itemEditor?.WithTitle(sub.Name).WithTag("Submarine").WithDescription(sub.Description);
@@ -1097,7 +1187,7 @@ namespace Barotrauma
var tagBtn = new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), tagHolder.Content.RectTransform, anchor: Anchor.CenterLeft),
tag.CapitaliseFirstInvariant(), style: "GUIButtonRound");
tagBtn.TextBlock.AutoScaleHorizontal = true;
tagBtn.Selected = itemEditor?.Tags?.Any(t => t.ToLowerInvariant() == tag) ?? false;
tagBtn.Selected = itemEditor?.Tags?.Any(t => t.Equals(tag, StringComparison.OrdinalIgnoreCase)) ?? false;
tagBtn.OnClicked = (btn, userdata) =>
{
@@ -1108,7 +1198,7 @@ namespace Barotrauma
}
else
{
itemEditor?.Tags?.RemoveAll(t => t.ToLowerInvariant() == tagBtn.Text.ToLowerInvariant());
itemEditor?.Tags?.RemoveAll(t => t.Equals(tagBtn.Text, StringComparison.OrdinalIgnoreCase));
tagBtn.Selected = false;
}
return true;
@@ -1201,6 +1291,16 @@ namespace Barotrauma
OnClicked = (btn, userdata) => { ToolBox.OpenFileWithShell(Path.GetFullPath(Path.GetDirectoryName(itemContentPackage.Path))); return true; }
};
createItemFileList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.35f), createItemContent.RectTransform));
createItemWatcher?.Dispose();
createItemWatcher = new FileSystemWatcher(Path.GetDirectoryName(itemContentPackage.Path))
{
Filter = "*",
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName
};
createItemWatcher.Created += OnFileSystemChanges;
createItemWatcher.Deleted += OnFileSystemChanges;
createItemWatcher.Renamed += OnFileSystemChanges;
createItemWatcher.EnableRaisingEvents = true;
RefreshCreateItemFileList();
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), createItemContent.RectTransform), isHorizontal: true)
@@ -1447,23 +1547,54 @@ namespace Barotrauma
{
destinationPath = Path.Combine(modFolder, filePathRelativeToModFolder);
}
itemContentPackage.AddFile(destinationPath, ContentType.None);
}
itemContentPackage.Save(itemContentPackage.Path);
RefreshCreateItemFileList();
}
volatile bool refreshFileList = false;
private void OnFileSystemChanges(object sender, FileSystemEventArgs e)
{
refreshFileList = true;
}
private void RefreshCreateItemFileList()
{
createItemFileList.ClearChildren();
if (itemContentPackage == null) return;
var contentTypes = Enum.GetValues(typeof(ContentType));
foreach (ContentFile contentFile in itemContentPackage.Files)
List<ContentFile> files = itemContentPackage.Files.ToList();
foreach (ContentFile contentFile in files)
{
bool fileExists = File.Exists(contentFile.Path);
if (!fileExists) { itemContentPackage.Files.Remove(contentFile); continue; }
}
List<ContentFile> allFiles = Directory.GetFiles(Path.GetDirectoryName(itemContentPackage.Path), "*", SearchOption.AllDirectories)
.Select(f => new ContentFile(f, ContentType.None))
.Where(file => Path.GetFileName(file.Path) != SteamManager.MetadataFileName &&
Path.GetFileName(file.Path) != SteamManager.PreviewImageName)
.ToList();
for (int i=0;i<allFiles.Count;i++)
{
ContentFile file = allFiles[i];
ContentFile otherFile = itemContentPackage.Files.Find(f => string.Equals(Path.GetFullPath(f.Path).CleanUpPath(),
Path.GetFullPath(file.Path).CleanUpPath(),
StringComparison.InvariantCultureIgnoreCase));
if (otherFile != null)
{
//replace the generated ContentFile object with the one that's present in the
//content package to determine which tickboxes should already be checked
allFiles[i] = otherFile;
}
}
foreach (ContentFile contentFile in allFiles)
{
bool illegalPath = !ContentPackage.IsModFilePathAllowed(contentFile);
//string pathInStagingFolder = Path.Combine(SteamManager.WorkshopItemStagingFolder, contentFile.Path);
//bool fileInStagingFolder = File.Exists(pathInStagingFolder);
bool fileExists = File.Exists(contentFile.Path);
var fileFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.12f), createItemFileList.Content.RectTransform) { MinSize = new Point(0, 20) },
@@ -1479,11 +1610,25 @@ namespace Barotrauma
RelativeSpacing = 0.05f
};
var tickBox = new GUITickBox(new RectTransform(new Vector2(0.1f, 0.8f), content.RectTransform), "")
var tickBox = new GUITickBox(new RectTransform(Vector2.One, content.RectTransform, scaleBasis: ScaleBasis.BothHeight), "")
{
Selected = fileExists && !illegalPath,
Enabled = false,
ToolTip = TextManager.Get(illegalPath ? "WorkshopItemFileNotIncluded" : "WorkshopItemFileIncluded")
Selected = itemContentPackage.Files.Contains(contentFile),
UserData = contentFile
};
tickBox.OnSelected = (tb) =>
{
ContentFile f = tb.UserData as ContentFile;
if (tb.Selected)
{
if (!itemContentPackage.Files.Contains(f)) { itemContentPackage.Files.Add(f); }
}
else
{
if (itemContentPackage.Files.Contains(f)) { itemContentPackage.Files.Remove(f); }
}
return true;
};
var nameText = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), content.RectTransform, Anchor.CenterLeft), contentFile.Path, font: GUI.SmallFont)
@@ -1523,11 +1668,30 @@ namespace Barotrauma
{
OnClicked = (btn, userdata) =>
{
itemContentPackage.RemoveFile(contentFile);
itemContentPackage.Save(itemContentPackage.Path);
RefreshCreateItemFileList();
var msgBox = new GUIMessageBox(TextManager.Get("ConfirmFileDeletionHeader"),
TextManager.GetWithVariable("ConfirmFileDeletion", "[file]", contentFile.Path),
new string[] { TextManager.Get("Yes"), TextManager.Get("Cancel") })
{
UserData = "verificationprompt"
};
msgBox.Buttons[0].OnClicked = (applyButton, obj) =>
{
try
{
File.Delete(contentFile.Path);
if (contentFile.Type == ContentType.Submarine) { SubmarineInfo.RefreshSavedSub(contentFile.Path); }
}
catch (Exception e)
{
DebugConsole.ThrowError($"Failed to delete \"${contentFile.Path}\".", e);
}
//RefreshCreateItemFileList();
RefreshMyItemList();
return true;
};
msgBox.Buttons[0].OnClicked += msgBox.Close;
msgBox.Buttons[1].OnClicked = msgBox.Close;
return true;
}
};
@@ -1536,6 +1700,8 @@ namespace Barotrauma
new Point(0, (int)(content.RectTransform.Children.Max(c => c.MinSize.Y) / content.RectTransform.RelativeSize.Y));
nameText.Text = ToolBox.LimitString(nameText.Text, nameText.Font, maxWidth: nameText.Rect.Width);
}
itemContentPackage.Save(itemContentPackage.Path);
}
private void PublishWorkshopItem()
@@ -1640,6 +1806,11 @@ namespace Barotrauma
public override void Update(double deltaTime)
{
if (refreshFileList)
{
RefreshCreateItemFileList();
refreshFileList = false;
}
}
#endregion

View File

@@ -7,6 +7,8 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using EventInput;
using Microsoft.Xna.Framework.Input;
namespace Barotrauma
{
@@ -30,6 +32,8 @@ namespace Barotrauma
private readonly Camera cam;
private SubmarineInfo backedUpSubInfo;
private Point screenResolution;
private bool lightingEnabled;
@@ -89,6 +93,9 @@ namespace Barotrauma
private Mode mode;
// Prevent the mode from changing
private bool lockMode;
public override Camera Cam
{
get { return cam; }
@@ -96,9 +103,9 @@ namespace Barotrauma
public string GetSubDescription()
{
string localizedDescription = TextManager.Get("submarine.description." + (Submarine.MainSub?.Name ?? ""), true);
string localizedDescription = TextManager.Get("submarine.description." + (Submarine.MainSub?.Info.Name ?? ""), true);
if (localizedDescription != null) { return localizedDescription; }
return (Submarine.MainSub == null) ? "" : Submarine.MainSub.Description;
return (Submarine.MainSub == null) ? "" : Submarine.MainSub.Info.Description;
}
private string GetTotalHullVolume()
@@ -214,63 +221,10 @@ namespace Barotrauma
new GUIFrame(new RectTransform(new Vector2(0.01f, 0.9f), paddedTopPanel.RectTransform), style: "VerticalLine");
subNameLabel = new GUITextBlock(new RectTransform(new Vector2(0.3f, 0.9f), paddedTopPanel.RectTransform, Anchor.CenterLeft),
TextManager.Get("unspecifiedsubfilename"), font: GUI.LargeFont, textAlignment: Alignment.CenterLeft);
linkedSubBox = new GUIDropDown(new RectTransform(new Vector2(0.15f, 0.9f), paddedTopPanel.RectTransform),
TextManager.Get("AddSubButton"), elementCount: 20)
new GUIButton(new RectTransform(new Vector2(0.9f, 0.9f), paddedTopPanel.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "TestButton")
{
ToolTip = TextManager.Get("AddSubToolTip")
};
foreach (Submarine sub in Submarine.SavedSubmarines)
{
linkedSubBox.AddItem(sub.Name, sub);
}
linkedSubBox.OnSelected += SelectLinkedSub;
linkedSubBox.OnDropped += (component, obj) =>
{
MapEntity.SelectedList.Clear();
return true;
};
new GUIFrame(new RectTransform(new Vector2(0.01f, 0.9f), paddedTopPanel.RectTransform), style: "VerticalLine");
defaultModeTickBox = new GUITickBox(new RectTransform(new Vector2(0.9f, 0.9f), paddedTopPanel.RectTransform, scaleBasis: ScaleBasis.BothHeight), "", style: "EditSubButton")
{
ToolTip = TextManager.Get("SubEditorEditingMode"),
OnSelected = (GUITickBox tBox) =>
{
if (tBox.Selected) { SetMode(Mode.Default); }
return true;
}
};
characterModeTickBox = new GUITickBox(new RectTransform(new Vector2(0.9f, 0.9f), paddedTopPanel.RectTransform, scaleBasis: ScaleBasis.BothHeight), "", style: "CharacterModeButton")
{
ToolTip = TextManager.Get("CharacterModeButton") + '\n' + TextManager.Get("CharacterModeToolTip"),
OnSelected = (GUITickBox tBox) =>
{
SetMode(tBox.Selected ? Mode.Character : Mode.Default);
return true;
}
};
wiringModeTickBox = new GUITickBox(new RectTransform(new Vector2(0.9f, 0.9f), paddedTopPanel.RectTransform, scaleBasis: ScaleBasis.BothHeight), "", style: "WiringModeButton")
{
ToolTip = TextManager.Get("WiringModeButton") + '\n' + TextManager.Get("WiringModeToolTip"),
OnSelected = (GUITickBox tBox) =>
{
SetMode(tBox.Selected ? Mode.Wiring : Mode.Default);
return true;
}
};
new GUIFrame(new RectTransform(new Vector2(0.01f, 0.9f), paddedTopPanel.RectTransform), style: "VerticalLine");
new GUIButton(new RectTransform(new Vector2(0.9f, 0.9f), paddedTopPanel.RectTransform, scaleBasis: ScaleBasis.BothHeight), "", style: "GenerateWaypointsButton")
{
ToolTip = TextManager.Get("GenerateWaypointsButton") + '\n' + TextManager.Get("GenerateWaypointsToolTip"),
OnClicked = GenerateWaypoints
ToolTip = TextManager.Get("TestSubButton"),
OnClicked = TestSubmarine
};
new GUIFrame(new RectTransform(new Vector2(0.01f, 0.9f), paddedTopPanel.RectTransform), style: "VerticalLine");
@@ -282,7 +236,7 @@ namespace Barotrauma
{
previouslyUsedPanel.Visible = false;
showEntitiesPanel.Visible = !showEntitiesPanel.Visible;
showEntitiesPanel.RectTransform.AbsoluteOffset = new Point(btn.Rect.X, TopPanel.Rect.Height);
showEntitiesPanel.RectTransform.AbsoluteOffset = new Point(Math.Max(Math.Max(btn.Rect.X, entityCountPanel.Rect.Right), saveAssemblyFrame.Rect.Right), TopPanel.Rect.Height);
return true;
}
};
@@ -294,7 +248,110 @@ namespace Barotrauma
{
showEntitiesPanel.Visible = false;
previouslyUsedPanel.Visible = !previouslyUsedPanel.Visible;
previouslyUsedPanel.RectTransform.AbsoluteOffset = new Point(btn.Rect.X, TopPanel.Rect.Height);
previouslyUsedPanel.RectTransform.AbsoluteOffset = new Point(Math.Max(Math.Max(btn.Rect.X, entityCountPanel.Rect.Right), saveAssemblyFrame.Rect.Right), TopPanel.Rect.Height);
return true;
}
};
new GUIFrame(new RectTransform(new Vector2(0.01f, 0.9f), paddedTopPanel.RectTransform), style: "VerticalLine");
subNameLabel = new GUITextBlock(new RectTransform(new Vector2(0.3f, 0.9f), paddedTopPanel.RectTransform, Anchor.CenterLeft),
TextManager.Get("unspecifiedsubfilename"), font: GUI.LargeFont, textAlignment: Alignment.CenterLeft);
linkedSubBox = new GUIDropDown(new RectTransform(new Vector2(0.15f, 0.9f), paddedTopPanel.RectTransform),
TextManager.Get("AddSubButton"), elementCount: 20)
{
ToolTip = TextManager.Get("AddSubToolTip")
};
foreach (SubmarineInfo sub in SubmarineInfo.SavedSubmarines)
{
linkedSubBox.AddItem(sub.Name, sub);
}
linkedSubBox.OnSelected += SelectLinkedSub;
linkedSubBox.OnDropped += (component, obj) =>
{
MapEntity.SelectedList.Clear();
return true;
};
var spacing = new GUIFrame(new RectTransform(new Vector2(0.02f, 1.0f), paddedTopPanel.RectTransform), style: null);
new GUIFrame(new RectTransform(new Vector2(0.1f, 0.9f), spacing.RectTransform, Anchor.Center), style: "VerticalLine");
defaultModeTickBox = new GUITickBox(new RectTransform(new Vector2(0.9f, 0.9f), paddedTopPanel.RectTransform, scaleBasis: ScaleBasis.BothHeight), "", style: "EditSubButton")
{
ToolTip = TextManager.Get("SubEditorEditingMode"),
OnSelected = (GUITickBox tBox) =>
{
if (!lockMode)
{
if (tBox.Selected) { SetMode(Mode.Default); }
return true;
}
else { return false; }
}
};
characterModeTickBox = new GUITickBox(new RectTransform(new Vector2(0.9f, 0.9f), paddedTopPanel.RectTransform, scaleBasis: ScaleBasis.BothHeight), "", style: "CharacterModeButton")
{
ToolTip = TextManager.Get("CharacterModeButton") + '\n' + TextManager.Get("CharacterModeToolTip"),
OnSelected = (GUITickBox tBox) =>
{
if (!lockMode)
{
SetMode(tBox.Selected ? Mode.Character : Mode.Default);
return true;
}
else { return false; }
}
};
wiringModeTickBox = new GUITickBox(new RectTransform(new Vector2(0.9f, 0.9f), paddedTopPanel.RectTransform, scaleBasis: ScaleBasis.BothHeight), "", style: "WiringModeButton")
{
ToolTip = TextManager.Get("WiringModeButton") + '\n' + TextManager.Get("WiringModeToolTip"),
OnSelected = (GUITickBox tBox) =>
{
if (!lockMode)
{
SetMode(tBox.Selected ? Mode.Wiring : Mode.Default);
return true;
}
else { return false; }
}
};
spacing = new GUIFrame(new RectTransform(new Vector2(0.02f, 1.0f), paddedTopPanel.RectTransform), style: null);
new GUIFrame(new RectTransform(new Vector2(0.1f, 0.9f), spacing.RectTransform, Anchor.Center), style: "VerticalLine");
new GUIButton(new RectTransform(new Vector2(0.9f, 0.9f), paddedTopPanel.RectTransform, scaleBasis: ScaleBasis.BothHeight), "", style: "GenerateWaypointsButton")
{
ToolTip = TextManager.Get("GenerateWaypointsButton") + '\n' + TextManager.Get("GenerateWaypointsToolTip"),
OnClicked = (btn, userdata) =>
{
if (WayPoint.WayPointList.Any())
{
var generateWaypointsVerification = new GUIMessageBox("", TextManager.Get("generatewaypointsverification"), new string[] { TextManager.Get("ok"), TextManager.Get("cancel") });
generateWaypointsVerification.Buttons[0].OnClicked = (btn, userdata) =>
{
if (GenerateWaypoints())
{
GUI.AddMessage(TextManager.Get("waypointsgeneratedsuccesfully"), GUI.Style.Green);
}
WayPoint.ShowWayPoints = true;
generateWaypointsVerification.Close();
return true;
};
generateWaypointsVerification.Buttons[1].OnClicked = generateWaypointsVerification.Close;
}
else
{
if (GenerateWaypoints())
{
GUI.AddMessage(TextManager.Get("waypointsgeneratedsuccesfully"), GUI.Style.Green);
}
WayPoint.ShowWayPoints = true;
}
return true;
}
};
@@ -325,8 +382,7 @@ namespace Barotrauma
showEntitiesPanel = new GUIFrame(new RectTransform(new Vector2(0.08f, 0.5f), GUI.Canvas)
{
MinSize = new Point(170, 0),
AbsoluteOffset = new Point(visibilityButton.Rect.X, TopPanel.Rect.Height)
MinSize = new Point(170, 0)
})
{
Visible = false
@@ -613,6 +669,41 @@ namespace Barotrauma
screenResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
}
private bool TestSubmarine(GUIButton button, object obj)
{
List<string> errorMsgs = new List<string>();
if (!Hull.hullList.Any())
{
errorMsgs.Add(TextManager.Get("NoHullsWarning"));
}
if (!WayPoint.WayPointList.Any(wp => wp.ShouldBeSaved && wp.SpawnType == SpawnType.Human))
{
errorMsgs.Add(TextManager.Get("NoHumanSpawnpointWarning"));
}
if (errorMsgs.Any())
{
new GUIMessageBox(TextManager.Get("Error"), string.Join("\n\n", errorMsgs), new Vector2(0.25f, 0.0f), new Point(400, 200));
return true;
}
backedUpSubInfo = new SubmarineInfo(Submarine.MainSub);
GameMain.GameScreen.Select();
GameSession gameSession = new GameSession(backedUpSubInfo, "", GameModePreset.List.Find(gm => gm.Identifier == "subtest"), null);
gameSession.StartRound(null, false);
return true;
}
public void ClearBackedUpSubInfo()
{
backedUpSubInfo = null;
}
private void UpdateEntityList()
{
entityList.Content.ClearChildren();
@@ -741,9 +832,20 @@ namespace Barotrauma
{
base.Select();
GameMain.LightManager.AmbientLight =
Level.Loaded?.GenerationParams?.AmbientLightColor ??
LevelGenerationParams.LevelParams?.FirstOrDefault()?.AmbientLightColor ??
new Color(20, 20, 20, 255);
UpdateEntityList();
string name = (Submarine.MainSub == null) ? TextManager.Get("unspecifiedsubfilename") : Submarine.MainSub.Name;
if (backedUpSubInfo != null)
{
Submarine.Unload();
}
string name = (Submarine.MainSub == null) ? TextManager.Get("unspecifiedsubfilename") : Submarine.MainSub.Info.Name;
if (backedUpSubInfo != null) { name = backedUpSubInfo.Name; }
subNameLabel.Text = ToolBox.LimitString(name, subNameLabel.Font, subNameLabel.Rect.Width);
foreach (MapEntityPrefab prefab in MapEntityPrefab.List)
@@ -760,23 +862,26 @@ namespace Barotrauma
GUI.ForceMouseOn(null);
SetMode(Mode.Default);
if (Submarine.MainSub != null)
if (backedUpSubInfo != null)
{
Submarine.MainSub = new Submarine(backedUpSubInfo);
backedUpSubInfo = null;
}
else if (Submarine.MainSub == null)
{
var subInfo = new SubmarineInfo();
Submarine.MainSub = new Submarine(subInfo);
}
Submarine.MainSub.SetPrevTransform(Submarine.MainSub.Position);
Submarine.MainSub.UpdateTransform();
Submarine.MainSub.UpdateTransform(interpolate: false);
cam.Position = Submarine.MainSub.Position + Submarine.MainSub.HiddenSubPosition;
}
else
{
Submarine.MainSub = new Submarine(Path.Combine(Submarine.SavePath, TextManager.Get("UnspecifiedSubFileName") + ".sub"), "", false);
cam.Position = Submarine.MainSub.Position;
}
GameMain.SoundManager.SetCategoryGainMultiplier("default", 0.0f, 0);
GameMain.SoundManager.SetCategoryGainMultiplier("waterambience", 0.0f, 0);
linkedSubBox.ClearChildren();
foreach (Submarine sub in Submarine.SavedSubmarines)
foreach (SubmarineInfo sub in SubmarineInfo.SavedSubmarines)
{
linkedSubBox.AddItem(sub.Name, sub);
}
@@ -987,27 +1092,37 @@ namespace Barotrauma
nameBox.Flash();
return false;
}
var result = SaveSubToFile(nameBox.Text);
saveFrame = null;
return result;
}
foreach (char illegalChar in Path.GetInvalidFileNameChars())
private bool SaveSubToFile(string name)
{
if (nameBox.Text.Contains(illegalChar))
if (string.IsNullOrWhiteSpace(name))
{
GUI.AddMessage(TextManager.GetWithVariable("SubNameIllegalCharsWarning", "[illegalchar]", illegalChar.ToString()), GUI.Style.Red);
nameBox.Flash();
GUI.AddMessage(TextManager.Get("SubNameMissingWarning"), GUI.Style.Red);
return false;
}
foreach (var illegalChar in Path.GetInvalidFileNameChars())
{
if (!name.Contains(illegalChar)) continue;
GUI.AddMessage(TextManager.GetWithVariable("SubNameIllegalCharsWarning", "[illegalchar]", illegalChar.ToString()), GUI.Style.Red);
return false;
}
string savePath = nameBox.Text + ".sub";
string savePath = name + ".sub";
string prevSavePath = null;
if (Submarine.MainSub != null)
if (!string.IsNullOrEmpty(Submarine.MainSub?.Info.FilePath) &&
Submarine.MainSub.Info.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
{
prevSavePath = Submarine.MainSub.FilePath;
savePath = Path.Combine(Path.GetDirectoryName(Submarine.MainSub.FilePath), savePath);
prevSavePath = Submarine.MainSub.Info.FilePath.CleanUpPath();
savePath = Path.Combine(Path.GetDirectoryName(Submarine.MainSub.Info.FilePath), savePath).CleanUpPath();
}
else
{
savePath = Path.Combine(Submarine.SavePath, savePath);
savePath = Path.Combine(SubmarineInfo.SavePath, savePath);
}
#if !DEBUG
@@ -1015,8 +1130,8 @@ namespace Barotrauma
if (vanilla != null)
{
var vanillaSubs = vanilla.GetFilesOfType(ContentType.Submarine);
string pathToCompare = savePath.Replace(@"\", @"/").ToLowerInvariant();
if (vanillaSubs.Any(sub => sub.Replace(@"\", @"/").ToLowerInvariant() == pathToCompare))
string pathToCompare = savePath.Replace(@"\", @"/");
if (vanillaSubs.Any(sub => sub.Replace(@"\", @"/").Equals(pathToCompare, StringComparison.OrdinalIgnoreCase)))
{
GUI.AddMessage(TextManager.Get("CannotEditVanillaSubs"), GUI.Style.Red, font: GUI.LargeFont);
return false;
@@ -1024,37 +1139,34 @@ namespace Barotrauma
}
#endif
if (previewImage.Sprite?.Texture != null)
if (previewImage?.Sprite?.Texture != null)
{
using (MemoryStream imgStream = new MemoryStream())
{
previewImage.Sprite.Texture.SaveAsPng(imgStream, previewImage.Sprite.Texture.Width, previewImage.Sprite.Texture.Height);
Submarine.SaveCurrent(savePath, imgStream);
Submarine.MainSub.SaveAs(savePath, imgStream);
}
}
else
{
Submarine.SaveCurrent(savePath);
Submarine.MainSub.SaveAs(savePath);
}
Submarine.MainSub.CheckForErrors();
Submarine.MainSub?.CheckForErrors();
GUI.AddMessage(TextManager.GetWithVariable("SubSavedNotification", "[filepath]", Submarine.MainSub.FilePath), GUI.Style.Green);
Submarine.RefreshSavedSub(savePath);
GUI.AddMessage(TextManager.GetWithVariable("SubSavedNotification", "[filepath]", savePath), GUI.Style.Green);
SubmarineInfo.RefreshSavedSub(savePath);
if (prevSavePath != null && prevSavePath != savePath)
{
Submarine.RefreshSavedSub(prevSavePath);
SubmarineInfo.RefreshSavedSub(prevSavePath);
}
linkedSubBox.ClearChildren();
foreach (Submarine sub in Submarine.SavedSubmarines)
foreach (SubmarineInfo sub in SubmarineInfo.SavedSubmarines)
{
linkedSubBox.AddItem(sub.Name, sub);
}
subNameLabel.Text = ToolBox.LimitString(Submarine.MainSub.Name, subNameLabel.Font, subNameLabel.Rect.Width);
saveFrame = null;
subNameLabel.Text = ToolBox.LimitString(Submarine.MainSub.Info.Name, subNameLabel.Font, subNameLabel.Rect.Width);
return false;
}
@@ -1160,15 +1272,15 @@ namespace Barotrauma
crewSizeMin.OnValueChanged += (numberInput) =>
{
crewSizeMax.IntValue = Math.Max(crewSizeMax.IntValue, numberInput.IntValue);
Submarine.MainSub.RecommendedCrewSizeMin = crewSizeMin.IntValue;
Submarine.MainSub.RecommendedCrewSizeMax = crewSizeMax.IntValue;
Submarine.MainSub.Info.RecommendedCrewSizeMin = crewSizeMin.IntValue;
Submarine.MainSub.Info.RecommendedCrewSizeMax = crewSizeMax.IntValue;
};
crewSizeMax.OnValueChanged += (numberInput) =>
{
crewSizeMin.IntValue = Math.Min(crewSizeMin.IntValue, numberInput.IntValue);
Submarine.MainSub.RecommendedCrewSizeMin = crewSizeMin.IntValue;
Submarine.MainSub.RecommendedCrewSizeMax = crewSizeMax.IntValue;
Submarine.MainSub.Info.RecommendedCrewSizeMin = crewSizeMin.IntValue;
Submarine.MainSub.Info.RecommendedCrewSizeMax = crewSizeMax.IntValue;
};
var crewExpArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.04f), leftColumn.RectTransform), isHorizontal: true)
@@ -1191,7 +1303,7 @@ namespace Barotrauma
if (currentIndex < 0) currentIndex = crewExperienceLevels.Length - 1;
experienceText.UserData = crewExperienceLevels[currentIndex];
experienceText.Text = TextManager.Get(crewExperienceLevels[currentIndex]);
Submarine.MainSub.RecommendedCrewExperience = (string)experienceText.UserData;
Submarine.MainSub.Info.RecommendedCrewExperience = (string)experienceText.UserData;
return true;
};
@@ -1202,18 +1314,18 @@ namespace Barotrauma
if (currentIndex >= crewExperienceLevels.Length) currentIndex = 0;
experienceText.UserData = crewExperienceLevels[currentIndex];
experienceText.Text = TextManager.Get(crewExperienceLevels[currentIndex]);
Submarine.MainSub.RecommendedCrewExperience = (string)experienceText.UserData;
Submarine.MainSub.Info.RecommendedCrewExperience = (string)experienceText.UserData;
return true;
};
if (Submarine.MainSub != null)
{
int min = Submarine.MainSub.RecommendedCrewSizeMin;
int max = Submarine.MainSub.RecommendedCrewSizeMax;
int min = Submarine.MainSub.Info.RecommendedCrewSizeMin;
int max = Submarine.MainSub.Info.RecommendedCrewSizeMax;
crewSizeMin.IntValue = min;
crewSizeMax.IntValue = max;
experienceText.UserData = string.IsNullOrEmpty(Submarine.MainSub.RecommendedCrewExperience) ?
crewExperienceLevels[0] : Submarine.MainSub.RecommendedCrewExperience;
experienceText.UserData = string.IsNullOrEmpty(Submarine.MainSub.Info.RecommendedCrewExperience) ?
crewExperienceLevels[0] : Submarine.MainSub.Info.RecommendedCrewExperience;
experienceText.Text = TextManager.Get((string)experienceText.UserData);
}
@@ -1222,7 +1334,7 @@ namespace Barotrauma
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), rightColumn.RectTransform), TextManager.Get("SubPreviewImage"), font: GUI.SubHeadingFont);
var previewImageHolder = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.5f), rightColumn.RectTransform), style: null) { Color = Color.Black, CanBeFocused = false };
previewImage = new GUIImage(new RectTransform(Vector2.One, previewImageHolder.RectTransform), Submarine.MainSub?.PreviewImage, scaleToFit: true);
previewImage = new GUIImage(new RectTransform(Vector2.One, previewImageHolder.RectTransform), Submarine.MainSub?.Info.PreviewImage, scaleToFit: true);
var previewImageButtonHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), isHorizontal: true) { Stretch = true, RelativeSpacing = 0.05f };
@@ -1236,7 +1348,7 @@ namespace Barotrauma
previewImage.Sprite = new Sprite(TextureLoader.FromStream(imgStream), null, null);
if (Submarine.MainSub != null)
{
Submarine.MainSub.PreviewImage = previewImage.Sprite;
Submarine.MainSub.Info.PreviewImage = previewImage.Sprite;
}
}
return true;
@@ -1258,7 +1370,7 @@ namespace Barotrauma
previewImage.Sprite = new Sprite(file, sourceRectangle: null);
if (Submarine.MainSub != null)
{
Submarine.MainSub.PreviewImage = previewImage.Sprite;
Submarine.MainSub.Info.PreviewImage = previewImage.Sprite;
}
};
FileSelection.ClearFileTypeFilters();
@@ -1288,7 +1400,7 @@ namespace Barotrauma
var tagTickBox = new GUITickBox(new RectTransform(new Vector2(0.2f, 0.2f), tagContainer.Content.RectTransform),
tagStr, font: GUI.SmallFont)
{
Selected = Submarine.MainSub == null ? false : Submarine.MainSub.HasTag(tag),
Selected = Submarine.MainSub == null ? false : Submarine.MainSub.Info.HasTag(tag),
UserData = tag,
OnSelected = (GUITickBox tickBox) =>
@@ -1296,11 +1408,11 @@ namespace Barotrauma
if (Submarine.MainSub == null) return false;
if (tickBox.Selected)
{
Submarine.MainSub.AddTag((SubmarineTag)tickBox.UserData);
Submarine.MainSub.Info.AddTag((SubmarineTag)tickBox.UserData);
}
else
{
Submarine.MainSub.RemoveTag((SubmarineTag)tickBox.UserData);
Submarine.MainSub.Info.RemoveTag((SubmarineTag)tickBox.UserData);
}
return true;
}
@@ -1313,7 +1425,7 @@ namespace Barotrauma
var contentPackList = new GUIListBox(new RectTransform(new Vector2(0.5f, 1.0f - contentPackagesLabel.RectTransform.RelativeSize.Y),
horizontalArea.RectTransform, Anchor.BottomRight));
List<string> contentPacks = Submarine.MainSub.RequiredContentPackages.ToList();
List<string> contentPacks = Submarine.MainSub.Info.RequiredContentPackages.ToList();
foreach (ContentPackage contentPack in ContentPackage.List)
{
//don't show content packages that only define submarine files
@@ -1326,18 +1438,18 @@ namespace Barotrauma
{
var cpTickBox = new GUITickBox(new RectTransform(new Vector2(0.2f, 0.2f), contentPackList.Content.RectTransform), contentPackageName, font: GUI.SmallFont)
{
Selected = Submarine.MainSub.RequiredContentPackages.Contains(contentPackageName),
Selected = Submarine.MainSub.Info.RequiredContentPackages.Contains(contentPackageName),
UserData = contentPackageName
};
cpTickBox.OnSelected += (GUITickBox tickBox) =>
{
if (tickBox.Selected)
{
Submarine.MainSub.RequiredContentPackages.Add((string)tickBox.UserData);
Submarine.MainSub.Info.RequiredContentPackages.Add((string)tickBox.UserData);
}
else
{
Submarine.MainSub.RequiredContentPackages.Remove((string)tickBox.UserData);
Submarine.MainSub.Info.RequiredContentPackages.Remove((string)tickBox.UserData);
}
return true;
};
@@ -1363,7 +1475,7 @@ namespace Barotrauma
};
paddedSaveFrame.Recalculate();
leftColumn.Recalculate();
descriptionBox.Text = Submarine.MainSub == null ? "" : Submarine.MainSub.Description;
descriptionBox.Text = Submarine.MainSub == null ? "" : Submarine.MainSub.Info.Description;
submarineDescriptionCharacterCount.Text = descriptionBox.Text.Length + " / " + submarineDescriptionLimit;
}
@@ -1513,7 +1625,7 @@ namespace Barotrauma
#if DEBUG
deleteBtn.Enabled = true;
#else
deleteBtn.Enabled = userData is Submarine sub && !sub.IsVanillaSubmarine();
deleteBtn.Enabled = userData is Submarine sub && !sub.Info.IsVanillaSubmarine();
#endif
}
return true;
@@ -1524,7 +1636,7 @@ namespace Barotrauma
searchBox.OnDeselected += (sender, userdata) => { searchTitle.Visible = true; };
searchBox.OnTextChanged += (textBox, text) => { FilterSubs(subList, text); return true; };
foreach (Submarine sub in Submarine.SavedSubmarines)
foreach (SubmarineInfo sub in SubmarineInfo.SavedSubmarines)
{
GUITextBlock textBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), subList.Content.RectTransform) { MinSize = new Point(0, 30) },
ToolBox.LimitString(sub.Name, GUI.Font, subList.Rect.Width - 80))
@@ -1554,7 +1666,7 @@ namespace Barotrauma
{
if (subList.SelectedComponent != null)
{
TryDeleteSub(subList.SelectedComponent.UserData as Submarine);
TryDeleteSub(subList.SelectedComponent.UserData as SubmarineInfo);
}
deleteButton.Enabled = false;
return true;
@@ -1586,7 +1698,7 @@ namespace Barotrauma
foreach (GUIComponent child in subList.Content.Children)
{
if (!(child.UserData is Submarine sub)) { return; }
child.Visible = string.IsNullOrEmpty(filter) ? true : sub.Name.ToLower().Contains(filter.ToLower());
child.Visible = string.IsNullOrEmpty(filter) ? true : sub.Info.Name.ToLower().Contains(filter.ToLower());
}
}
@@ -1606,14 +1718,14 @@ namespace Barotrauma
}
if (subList.SelectedComponent == null) { return false; }
if (!(subList.SelectedComponent.UserData is Submarine selectedSub)) { return false; }
if (!(subList.SelectedComponent.UserData is SubmarineInfo selectedSubInfo)) { return false; }
selectedSub.Load(true);
Submarine.Unload();
var selectedSub = new Submarine(selectedSubInfo);
Submarine.MainSub = selectedSub;
Submarine.MainSub.SetPrevTransform(Submarine.MainSub.Position);
Submarine.MainSub.UpdateTransform();
Submarine.MainSub.UpdateTransform(interpolate: false);
string name = Submarine.MainSub.Name;
string name = Submarine.MainSub.Info.Name;
subNameLabel.Text = ToolBox.LimitString(name, subNameLabel.Font, subNameLabel.Rect.Width);
cam.Position = Submarine.MainSub.Position + Submarine.MainSub.HiddenSubPosition;
@@ -1624,10 +1736,13 @@ namespace Barotrauma
foreach (Item item in Item.ItemList)
{
var lightComponent = item.GetComponent<LightComponent>();
if (lightComponent != null) lightComponent.Light.Enabled = item.ParentInventory == null;
if (lightComponent != null)
{
lightComponent.Light.Enabled = item.ParentInventory == null;
}
}
if (selectedSub.GameVersion < new Version("0.8.9.0"))
if (selectedSub.Info.GameVersion < new Version("0.8.9.0"))
{
var adjustLightsPrompt = new GUIMessageBox(TextManager.Get("Warning"), TextManager.Get("AdjustLightsPrompt"),
new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
@@ -1649,7 +1764,7 @@ namespace Barotrauma
return true;
}
private void TryDeleteSub(Submarine sub)
private void TryDeleteSub(SubmarineInfo sub)
{
if (sub == null) { return; }
@@ -1674,9 +1789,9 @@ namespace Barotrauma
{
try
{
sub.Remove();
sub.Dispose();
File.Delete(sub.FilePath);
Submarine.RefreshSavedSubs();
SubmarineInfo.RefreshSavedSubs();
CreateLoadScreen();
}
catch (Exception e)
@@ -1754,18 +1869,20 @@ namespace Barotrauma
return true;
}
public void SetMode(Mode mode)
public void SetMode(Mode newMode)
{
if (mode == this.mode) { return; }
this.mode = mode;
if (newMode == mode) { return; }
mode = newMode;
defaultModeTickBox.Selected = mode == Mode.Default;
lockMode = true;
defaultModeTickBox.Selected = newMode == Mode.Default;
defaultModeTickBox.CanBeFocused = !defaultModeTickBox.Selected;
characterModeTickBox.Selected = mode == Mode.Character;
wiringModeTickBox.Selected = mode == Mode.Wiring;
characterModeTickBox.Selected = newMode == Mode.Character;
wiringModeTickBox.Selected = newMode == Mode.Wiring;
lockMode = false;
switch (mode)
switch (newMode)
{
case Mode.Character:
CreateDummyCharacter();
@@ -1790,6 +1907,7 @@ namespace Barotrauma
}
MapEntity.DeselectAll();
MapEntity.FilteredSelectedList.Clear();
}
private void RemoveDummyCharacter()
@@ -1954,7 +2072,7 @@ namespace Barotrauma
return false;
}
if (Submarine.MainSub != null) Submarine.MainSub.Name = text;
if (Submarine.MainSub != null) Submarine.MainSub.Info.Name = text;
textBox.Deselect();
textBox.Text = text;
@@ -1968,7 +2086,7 @@ namespace Barotrauma
{
if (Submarine.MainSub != null)
{
Submarine.MainSub.Description = text;
Submarine.MainSub.Info.Description = text;
}
else
{
@@ -1994,6 +2112,7 @@ namespace Barotrauma
{
previouslyUsedPanel.Visible = false;
showEntitiesPanel.Visible = true;
showEntitiesPanel.RectTransform.AbsoluteOffset = new Point(Math.Max(entityCountPanel.Rect.Right, saveAssemblyFrame.Rect.Right), TopPanel.Rect.Height);
matchingTickBox.Selected = true;
matchingTickBox.Flash(GUI.Style.Green);
}
@@ -2004,12 +2123,10 @@ namespace Barotrauma
return false;
}
private bool GenerateWaypoints(GUIButton button, object obj)
private bool GenerateWaypoints()
{
if (Submarine.MainSub == null) return false;
WayPoint.GenerateSubWaypoints(Submarine.MainSub);
return true;
if (Submarine.MainSub == null) { return false; }
return WayPoint.GenerateSubWaypoints(Submarine.MainSub);
}
private void AddPreviouslyUsed(MapEntityPrefab mapEntityPrefab)
@@ -2406,12 +2523,53 @@ namespace Barotrauma
hullVolumeFrame.Visible = MapEntity.SelectedList.Any(s => s is Hull);
saveAssemblyFrame.Visible = MapEntity.SelectedList.Count > 0;
if (PlayerInput.KeyHit(Microsoft.Xna.Framework.Input.Keys.Tab))
if (GUI.KeyboardDispatcher.Subscriber == null)
{
// TODO adjust when the new inventory stuff rolls in
if (PlayerInput.KeyHit(Keys.Q) && mode == Mode.Default)
{
toggleEntityMenuButton.OnClicked?.Invoke(toggleEntityMenuButton, toggleEntityMenuButton.UserData);
}
if (PlayerInput.KeyHit(Keys.Tab))
{
entityFilterBox.Select();
}
if (PlayerInput.KeyDown(Keys.LeftControl))
{
// Save menu
if (PlayerInput.KeyHit(Keys.S))
{
if (PlayerInput.KeyDown(Keys.LeftShift))
{
// Save the sub without a menu
if (subNameLabel != null)
{
SaveSubToFile(subNameLabel.Text);
}
}
else
{
// Save menu
if (saveFrame == null)
{
CreateSaveScreen();
}
}
}
// 1-3 keys on the keyboard for switching modes
if (PlayerInput.KeyHit(Keys.D1)) { SetMode(Mode.Default); }
if (PlayerInput.KeyHit(Keys.D2)) { SetMode(Mode.Character); }
if (PlayerInput.KeyHit(Keys.D3)) { SetMode(Mode.Wiring); }
}
else
{
cam.MoveCamera((float) deltaTime, true);
}
}
if (PlayerInput.MidButtonHeld())
{
Vector2 moveSpeed = PlayerInput.MouseSpeed * (float)deltaTime * 100.0f / cam.Zoom;
@@ -2647,12 +2805,31 @@ namespace Barotrauma
if (Submarine.MainSub != null)
{
Vector2 position = Submarine.MainSub.SubBody != null ? Submarine.MainSub.WorldPosition : Submarine.MainSub.HiddenSubPosition;
GUI.DrawIndicator(
spriteBatch, Submarine.MainSub.WorldPosition, cam,
spriteBatch, position, cam,
cam.WorldView.Width,
GUI.SubmarineIcon, Color.LightBlue * 0.5f);
}
var notificationIcon = GUI.Style.GetComponentStyle("GUINotificationButton");
var tooltipStyle = GUI.Style.GetComponentStyle("GUIToolTip");
foreach (Gap gap in Gap.GapList)
{
if (gap.linkedTo.Count == 2 && gap.linkedTo[0] == gap.linkedTo[1])
{
Vector2 screenPos = Cam.WorldToScreen(gap.WorldPosition);
Rectangle rect = new Rectangle(screenPos.ToPoint() - new Point(20), new Point(40));
tooltipStyle.Sprites[GUIComponent.ComponentState.None][0].Draw(spriteBatch, rect, Color.White);
notificationIcon.Sprites[GUIComponent.ComponentState.None][0].Draw(spriteBatch, rect, GUI.Style.Orange);
if (Vector2.Distance(PlayerInput.MousePosition, screenPos) < 30 * Cam.Zoom)
{
GUIComponent.DrawToolTip(spriteBatch, TextManager.Get("gapinsidehullwarning"), new Rectangle(screenPos.ToPoint(), new Point(10)));
}
}
}
if ((CharacterMode || WiringMode) && dummyCharacter != null)
{
dummyCharacter.DrawHUD(spriteBatch, cam, false);

View File

@@ -569,15 +569,13 @@ namespace Barotrauma
Font = GUI.SmallFont,
Text = value,
OverflowClip = true,
OnEnterPressed = (textBox, text) =>
};
propertyBox.OnDeselected += (textBox, keys) =>
{
if (property.TrySetValue(entity, text))
if (property.TrySetValue(entity, textBox.Text))
{
TrySendNetworkUpdate(entity, property);
textBox.Text = (string)property.GetValue(entity);
textBox.Deselect();
}
return true;
}
};
if (translationTextTag != null)

View File

@@ -97,6 +97,32 @@ namespace Barotrauma.Sounds
if (position != null)
{
if (float.IsNaN(position.Value.X))
{
throw new Exception("Failed to set source's position: " + debugName + ", position.X is NaN");
}
if (float.IsNaN(position.Value.Y))
{
throw new Exception("Failed to set source's position: " + debugName + ", position.Y is NaN");
}
if (float.IsNaN(position.Value.Z))
{
throw new Exception("Failed to set source's position: " + debugName + ", position.Z is NaN");
}
if (float.IsInfinity(position.Value.X))
{
throw new Exception("Failed to set source's position: " + debugName + ", position.X is Infinity");
}
if (float.IsInfinity(position.Value.Y))
{
throw new Exception("Failed to set source's position: " + debugName + ", position.Y is Infinity");
}
if (float.IsInfinity(position.Value.Z))
{
throw new Exception("Failed to set source's position: " + debugName + ", position.Z is Infinity");
}
uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex);
Al.Sourcei(alSource, Al.SourceRelative, Al.False);
int alError = Al.GetError();
@@ -378,12 +404,12 @@ namespace Barotrauma.Sounds
uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex);
if (!Al.IsSource(alSource)) return false;
Al.GetSourcei(alSource, Al.SourceState, out state);
bool playing = state == Al.Playing;
int alError = Al.GetError();
if (alError != Al.NoError)
{
throw new Exception("Failed to determine playing state from source: " + debugName + ", " + Al.GetErrorString(alError));
}
bool playing = state == Al.Playing;
return playing;
}
}
@@ -615,7 +641,7 @@ namespace Barotrauma.Sounds
uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex);
int state;
Al.GetSourcei(Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.SourceState, out state);
Al.GetSourcei(alSource, Al.SourceState, out state);
bool playing = state == Al.Playing;
int alError = Al.GetError();
if (alError != Al.NoError)
@@ -727,9 +753,20 @@ namespace Barotrauma.Sounds
streamAmplitude = streamBufferAmplitudes[queueStartIndex];
Al.GetSourcei(alSource, Al.SourceState, out state);
alError = Al.GetError();
if (alError != Al.NoError)
{
throw new Exception("Failed to retrieve stream source state: " + debugName + ", " + Al.GetErrorString(alError));
}
if (state != Al.Playing)
{
Al.SourcePlay(alSource);
alError = Al.GetError();
if (alError != Al.NoError)
{
throw new Exception("Failed to start stream playback: " + debugName + ", " + Al.GetErrorString(alError));
}
}
}
@@ -738,6 +775,10 @@ namespace Barotrauma.Sounds
streamAmplitude = 0.0f;
}
}
catch (Exception e)
{
DebugConsole.ThrowError($"An exception was thrown when updating a sound stream ({debugName})", e);
}
finally
{
Monitor.Exit(mutex);

View File

@@ -123,7 +123,7 @@ namespace Barotrauma
string filePathB = b.GetAttributeString("file", "").CleanUpPath();
float baseGainB = b.GetAttributeFloat("volume", 1.0f);
float rangeB = b.GetAttributeFloat("range", 1000.0f);
return a.Name.ToString().ToLowerInvariant() == b.Name.ToString().ToLowerInvariant() &&
return a.Name.ToString().Equals(b.Name.ToString(), StringComparison.OrdinalIgnoreCase) &&
filePathA == filePathB && MathUtils.NearlyEqual(baseGainA, baseGainB) &&
MathUtils.NearlyEqual(rangeA, rangeB);
}
@@ -151,7 +151,7 @@ namespace Barotrauma
SoundCount = 1 + soundElements.Count();
var startUpSoundElement = soundElements.Find(e => e.Name.ToString().ToLowerInvariant() == "startupsound");
var startUpSoundElement = soundElements.Find(e => e.Name.ToString().Equals("startupsound", StringComparison.OrdinalIgnoreCase));
if (startUpSoundElement != null)
{
startUpSound = GameMain.SoundManager.LoadSound(startUpSoundElement, false);
@@ -182,7 +182,7 @@ namespace Barotrauma
musicClips.AddIfNotNull(newMusicClip);
if (loadedSoundElements != null)
{
if (newMusicClip.Type.ToLowerInvariant() == "menu")
if (newMusicClip.Type.Equals("menu", StringComparison.OrdinalIgnoreCase))
{
targetMusic[0] = newMusicClip;
}
@@ -742,22 +742,30 @@ namespace Barotrauma
Screen.Selected == GameMain.LevelEditorScreen ||
Screen.Selected == GameMain.ParticleEditorScreen ||
Screen.Selected == GameMain.SpriteEditorScreen ||
Screen.Selected == GameMain.SubEditorScreen)
Screen.Selected == GameMain.SubEditorScreen ||
(Screen.Selected == GameMain.GameScreen && GameMain.GameSession?.GameMode is SubTestMode))
{
return "editor";
}
if (Screen.Selected != GameMain.GameScreen) { return "menu"; }
if (Character.Controlled != null &&
Level.Loaded != null && Level.Loaded.Ruins != null &&
if (Character.Controlled != null)
{
if (Level.Loaded != null && Level.Loaded.Ruins != null &&
Level.Loaded.Ruins.Any(r => r.Area.Contains(Character.Controlled.WorldPosition)))
{
return "ruins";
}
Submarine targetSubmarine = Character.Controlled?.Submarine;
if (Character.Controlled.Submarine?.Info?.IsWreck ?? false)
{
return "wreck";
}
}
Submarine targetSubmarine = Character.Controlled?.Submarine;
if ((targetSubmarine != null && targetSubmarine.AtDamageDepth) ||
(GameMain.GameScreen != null && Screen.Selected == GameMain.GameScreen && GameMain.GameScreen.Cam.Position.Y < SubmarineBody.DamageDepth))
{

View File

@@ -59,8 +59,10 @@ namespace Barotrauma.Sounds
get { return soundChannel?.CurrentAmplitude ?? 0.0f; }
}
public VoipSound(SoundManager owner, VoipQueue q) : base(owner, "voip", true, true)
public VoipSound(string name, SoundManager owner, VoipQueue q) : base(owner, "voip", true, true)
{
Filename = $"VoIP ({name})";
VoipConfig.SetupEncoding();
ALFormat = Al.FormatMono16;
@@ -93,9 +95,28 @@ namespace Barotrauma.Sounds
public void ApplyFilters(short[] buffer, int readSamples)
{
for (int i = 0; i < readSamples; i++)
{
float fVal = ShortToFloat(buffer[i]);
if (UseMuffleFilter)
{
ApplyFilters(radioFilters, buffer, readSamples);
foreach (var filter in muffleFilters)
{
fVal = filter.Process(fVal);
}
}
if (UseRadioFilter)
{
foreach (var filter in radioFilters)
{
fVal = filter.Process(fVal);
}
}
buffer[i] = FloatToShort(fVal);
}
if (UseMuffleFilter)
{
ApplyFilters(muffleFilters, buffer, readSamples);
}
if (UseRadioFilter)
@@ -106,15 +127,6 @@ namespace Barotrauma.Sounds
private void ApplyFilters(IEnumerable<BiQuad> filters, short[] buffer, int readSamples)
{
for (int i = 0; i < readSamples; i++)
{
float fVal = ShortToFloat(buffer[i]);
foreach (var filter in filters)
{
fVal = filter.Process(fVal);
}
buffer[i] = FloatToShort(fVal);
}
}
public override SoundChannel Play(float gain, float range, Vector2 position, bool muffle = false)

View File

@@ -8,6 +8,13 @@ namespace Barotrauma
{
class DecorativeSprite : ISerializableEntity
{
public class State
{
public float RotationState;
public float OffsetState;
public bool IsActive = true;
}
public string Name => $"Decorative Sprite";
public Dictionary<string, SerializableProperty> SerializableProperties { get; set; }
@@ -113,10 +120,10 @@ namespace Barotrauma
switch (OffsetAnim)
{
case AnimationType.Sine:
offsetState = offsetState % (MathHelper.TwoPi / OffsetAnimSpeed);
offsetState %= (MathHelper.TwoPi / OffsetAnimSpeed);
return Offset * (float)Math.Sin(offsetState * OffsetAnimSpeed);
case AnimationType.Noise:
offsetState = offsetState % (1.0f / (OffsetAnimSpeed * 0.1f));
offsetState %= (1.0f / (OffsetAnimSpeed * 0.1f));
float t = offsetState * 0.1f * OffsetAnimSpeed;
return new Vector2(
@@ -146,6 +153,51 @@ namespace Barotrauma
}
}
public static void UpdateSpriteStates(Dictionary<int, List<DecorativeSprite>> spriteGroups, Dictionary<DecorativeSprite, State> animStates,
int entityID, float deltaTime, Func<PropertyConditional,bool> checkConditional)
{
foreach (int spriteGroup in spriteGroups.Keys)
{
for (int i = 0; i < spriteGroups.Count; i++)
{
var decorativeSprite = spriteGroups[spriteGroup][i];
if (decorativeSprite == null) { continue; }
if (spriteGroup > 0)
{
int activeSpriteIndex = entityID % spriteGroups[spriteGroup].Count;
if (i != activeSpriteIndex)
{
animStates[decorativeSprite].IsActive = false;
continue;
}
}
//check if the sprite is active (whether it should be drawn or not)
var spriteState = animStates[decorativeSprite];
spriteState.IsActive = true;
foreach (PropertyConditional conditional in decorativeSprite.IsActiveConditionals)
{
if (!checkConditional(conditional))
{
spriteState.IsActive = false;
break;
}
}
if (!spriteState.IsActive) { continue; }
//check if the sprite should be animated
bool animate = true;
foreach (PropertyConditional conditional in decorativeSprite.AnimationConditionals)
{
if (!checkConditional(conditional)) { animate = false; break; }
}
if (!animate) { continue; }
spriteState.OffsetState += deltaTime;
spriteState.RotationState += deltaTime;
}
}
}
public void Remove()
{
Sprite?.Remove();

Some files were not shown because too many files have changed in this diff Show More