v1.0.13.1 (first post-1.0 patch)
This commit is contained in:
@@ -10,7 +10,7 @@ namespace Barotrauma
|
||||
public override void DebugDraw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
|
||||
{
|
||||
if (Character == Character.Controlled) { return; }
|
||||
if (!debugai) { return; }
|
||||
if (!DebugAI) { return; }
|
||||
Vector2 pos = Character.WorldPosition;
|
||||
pos.Y = -pos.Y;
|
||||
Vector2 textOffset = new Vector2(-40, -160);
|
||||
|
||||
@@ -19,6 +19,17 @@ namespace Barotrauma
|
||||
|
||||
private IEnumerable<CoroutineStatus> FadeOutColors(float time)
|
||||
{
|
||||
|
||||
Dictionary<MapEntity, Color> originalColors = new Dictionary<MapEntity, Color>();
|
||||
foreach (var item in thalamusItems)
|
||||
{
|
||||
originalColors.Add(item, item.SpriteColor);
|
||||
}
|
||||
foreach (var structure in thalamusStructures)
|
||||
{
|
||||
originalColors.Add(structure, structure.SpriteColor);
|
||||
}
|
||||
|
||||
float timer = 0;
|
||||
while (timer < time)
|
||||
{
|
||||
@@ -26,15 +37,16 @@ namespace Barotrauma
|
||||
float m = MathHelper.Lerp(1, Config.DeadEntityColorMultiplier, MathUtils.InverseLerp(0, time, timer));
|
||||
foreach (var item in thalamusItems)
|
||||
{
|
||||
if (item.Color.A == 0) { continue; }
|
||||
if (item.Prefab.BrokenSprites.None())
|
||||
{
|
||||
Color c = item.Prefab.SpriteColor;
|
||||
Color c = originalColors[item];
|
||||
item.SpriteColor = new Color(c.R / 255f * m, c.G / 255f * m, c.B / 255f * m, c.A / 255f);
|
||||
}
|
||||
}
|
||||
foreach (var structure in thalamusStructures)
|
||||
{
|
||||
Color c = structure.Prefab.SpriteColor;
|
||||
Color c = originalColors[structure];
|
||||
structure.SpriteColor = new Color(c.R / 255f * m, c.G / 255f * m, c.B / 255f * m, c.A / 255f);
|
||||
}
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
@@ -6,11 +6,17 @@ namespace Barotrauma
|
||||
{
|
||||
partial class Attack
|
||||
{
|
||||
[Serialize("StructureBlunt", IsPropertySaveable.Yes), Editable()]
|
||||
[Serialize("StructureBlunt", IsPropertySaveable.Yes, description: "Name of the sound effect the attack makes when it hits a structure."), Editable()]
|
||||
public string StructureSoundType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sound to play when the attack deals damage.
|
||||
/// </summary>
|
||||
private RoundSound sound;
|
||||
|
||||
/// <summary>
|
||||
/// Particle emitter to use when the attack deals damage.
|
||||
/// </summary>
|
||||
private ParticleEmitter particleEmitter;
|
||||
|
||||
partial void InitProjSpecific(ContentXElement element)
|
||||
|
||||
@@ -582,7 +582,7 @@ namespace Barotrauma
|
||||
float closestItemDistance = Math.Max(aimAssistAmount, 2.0f);
|
||||
foreach (MapEntity entity in entityList)
|
||||
{
|
||||
if (!(entity is Item item))
|
||||
if (entity is not Item item)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -153,6 +153,7 @@ namespace Barotrauma
|
||||
private static readonly List<BossProgressBar> bossProgressBars = new List<BossProgressBar>();
|
||||
|
||||
private static readonly Dictionary<Identifier, LocalizedString> cachedHudTexts = new Dictionary<Identifier, LocalizedString>();
|
||||
private static LanguageIdentifier cachedHudTextLanguage = LanguageIdentifier.None;
|
||||
|
||||
private static GUILayoutGroup bossHealthContainer;
|
||||
|
||||
@@ -202,10 +203,15 @@ namespace Barotrauma
|
||||
|
||||
public static LocalizedString GetCachedHudText(string textTag, InputType keyBind)
|
||||
{
|
||||
if (cachedHudTextLanguage != GameSettings.CurrentConfig.Language)
|
||||
{
|
||||
cachedHudTexts.Clear();
|
||||
}
|
||||
Identifier key = (textTag + keyBind).ToIdentifier();
|
||||
if (cachedHudTexts.TryGetValue(key, out LocalizedString text)) { return text; }
|
||||
text = TextManager.GetWithVariable(textTag, "[key]", GameSettings.CurrentConfig.KeyMap.KeyBindText(keyBind)).Value;
|
||||
cachedHudTexts.Add(key, text);
|
||||
cachedHudTextLanguage = GameSettings.CurrentConfig.Language;
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
@@ -701,10 +701,11 @@ namespace Barotrauma
|
||||
blurStrength = Math.Max(blurStrength, affliction.GetScreenBlurStrength());
|
||||
radialDistortStrength = Math.Max(radialDistortStrength, affliction.GetRadialDistortStrength());
|
||||
chromaticAberrationStrength = Math.Max(chromaticAberrationStrength, affliction.GetChromaticAberrationStrength());
|
||||
|
||||
float afflictionGrainStrength = affliction.GetScreenGrainStrength();
|
||||
if (afflictionGrainStrength > 0.0f)
|
||||
{
|
||||
grainStrength = Math.Max(grainStrength, affliction.GetScreenGrainStrength());
|
||||
grainStrength = Math.Max(grainStrength, afflictionGrainStrength);
|
||||
Color afflictionGrainColor = affliction.GetActiveEffect()?.GrainColor ?? Color.White;
|
||||
grainColor = Color.Lerp(grainColor, afflictionGrainColor, (float)Math.Pow(1.0f - oxygenLowStrength, 2));
|
||||
}
|
||||
@@ -1020,12 +1021,8 @@ namespace Barotrauma
|
||||
foreach (KeyValuePair<Affliction, LimbHealth> kvp in afflictions)
|
||||
{
|
||||
var affliction = kvp.Key;
|
||||
if (affliction.Prefab.AfflictionOverlay != null)
|
||||
{
|
||||
Sprite ScreenAfflictionOverlay = affliction.Prefab.AfflictionOverlay;
|
||||
ScreenAfflictionOverlay?.Draw(spriteBatch, Vector2.Zero, Color.White * affliction.GetAfflictionOverlayMultiplier(), Vector2.Zero, 0.0f,
|
||||
new Vector2(GameMain.GraphicsWidth / DamageOverlay.size.X, GameMain.GraphicsHeight / DamageOverlay.size.Y));
|
||||
}
|
||||
affliction.Prefab.AfflictionOverlay?.Draw(spriteBatch, Vector2.Zero, Color.White * affliction.GetAfflictionOverlayMultiplier(), Vector2.Zero, 0.0f,
|
||||
new Vector2(GameMain.GraphicsWidth / DamageOverlay.size.X, GameMain.GraphicsHeight / DamageOverlay.size.Y));
|
||||
}
|
||||
|
||||
float damageOverlayAlpha = DamageOverlayTimer;
|
||||
|
||||
+3
-1
@@ -125,9 +125,11 @@ namespace Barotrauma
|
||||
|
||||
public static string IncrementModVersion(string modVersion)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(modVersion)) { return string.Empty; }
|
||||
|
||||
//look for an integer at the end of the string and increment it
|
||||
int startIndex = modVersion.Length - 1;
|
||||
while (char.IsDigit(modVersion[startIndex])) { startIndex--; }
|
||||
while (startIndex > 0 && char.IsDigit(modVersion[startIndex])) { startIndex--; }
|
||||
startIndex++;
|
||||
|
||||
if (startIndex >= modVersion.Length
|
||||
|
||||
@@ -425,6 +425,10 @@ namespace Barotrauma
|
||||
{
|
||||
CheatsEnabled = true;
|
||||
SteamAchievementManager.CheatsEnabled = true;
|
||||
if (GameMain.GameSession?.Campaign is CampaignMode campaign)
|
||||
{
|
||||
campaign.CheatsEnabled = true;
|
||||
}
|
||||
NewMessage("Enabled cheat commands.", Color.Red);
|
||||
#if USE_STEAM
|
||||
NewMessage("Steam achievements have been disabled during this play session.", Color.Red);
|
||||
@@ -632,15 +636,29 @@ namespace Barotrauma
|
||||
commands.Add(new Command("wikiimage_character", "Save an image of the currently controlled character with a transparent background.", (string[] args) =>
|
||||
{
|
||||
if (Character.Controlled == null) { return; }
|
||||
WikiImage.Create(Character.Controlled);
|
||||
try
|
||||
{
|
||||
WikiImage.Create(Character.Controlled);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("The command 'wikiimage_character' failed.", e);
|
||||
}
|
||||
}));
|
||||
|
||||
commands.Add(new Command("wikiimage_sub", "Save an image of the main submarine with a transparent background.", (string[] args) =>
|
||||
{
|
||||
if (Submarine.MainSub == null) { return; }
|
||||
MapEntity.SelectedList.Clear();
|
||||
MapEntity.ClearHighlightedEntities();
|
||||
WikiImage.Create(Submarine.MainSub);
|
||||
try
|
||||
{
|
||||
MapEntity.SelectedList.Clear();
|
||||
MapEntity.ClearHighlightedEntities();
|
||||
WikiImage.Create(Submarine.MainSub);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("The command 'wikiimage_sub' failed.", e);
|
||||
}
|
||||
}));
|
||||
|
||||
AssignRelayToServer("kick", false);
|
||||
@@ -1146,7 +1164,7 @@ namespace Barotrauma
|
||||
GameMain.LightManager.LosEnabled = true;
|
||||
GameMain.LightManager.LosAlpha = 1f;
|
||||
}
|
||||
NewMessage("Dev mode " + (GameMain.DevMode ? "enabled" : "disabled"), Color.White);
|
||||
NewMessage("Dev mode " + (GameMain.DevMode ? "enabled" : "disabled"), Color.Yellow);
|
||||
});
|
||||
AssignRelayToServer("devmode", false);
|
||||
|
||||
@@ -1248,8 +1266,8 @@ namespace Barotrauma
|
||||
|
||||
AssignOnExecute("debugai", (string[] args) =>
|
||||
{
|
||||
HumanAIController.debugai = !HumanAIController.debugai;
|
||||
if (HumanAIController.debugai)
|
||||
HumanAIController.DebugAI = !HumanAIController.DebugAI;
|
||||
if (HumanAIController.DebugAI)
|
||||
{
|
||||
GameMain.DevMode = true;
|
||||
GameMain.DebugDraw = true;
|
||||
@@ -1264,7 +1282,7 @@ namespace Barotrauma
|
||||
GameMain.LightManager.LosEnabled = true;
|
||||
GameMain.LightManager.LosAlpha = 1f;
|
||||
}
|
||||
NewMessage(HumanAIController.debugai ? "AI debug info visible" : "AI debug info hidden", Color.Yellow);
|
||||
NewMessage(HumanAIController.DebugAI ? "AI debug info visible" : "AI debug info hidden", Color.Yellow);
|
||||
});
|
||||
AssignRelayToServer("debugai", false);
|
||||
|
||||
@@ -2323,7 +2341,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (mapEntity is Item item)
|
||||
{
|
||||
item.Rect = new Rectangle(item.Rect.X, item.Rect.Y,
|
||||
item.Rect = item.DefaultRect = new Rectangle(item.Rect.X, item.Rect.Y,
|
||||
(int)(item.Prefab.Sprite.size.X * item.Prefab.Scale),
|
||||
(int)(item.Prefab.Sprite.size.Y * item.Prefab.Scale));
|
||||
}
|
||||
@@ -2859,7 +2877,7 @@ namespace Barotrauma
|
||||
NewMessage("Valid ranks are:", Color.White);
|
||||
foreach (PermissionPreset permissionPreset in PermissionPreset.List)
|
||||
{
|
||||
NewMessage(" - " + permissionPreset.Name, Color.White);
|
||||
NewMessage(" - " + permissionPreset.DisplayName, Color.White);
|
||||
}
|
||||
ShowQuestionPrompt("Rank to grant to client " + args[0] + "?", (rank) =>
|
||||
{
|
||||
@@ -3345,6 +3363,11 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
NewMessage("Level seed: " + Level.Loaded.Seed);
|
||||
NewMessage("Level generation params: " + Level.Loaded.GenerationParams.Identifier);
|
||||
NewMessage("Adjacent locations: " + (Level.Loaded.StartLocation?.Type.Identifier ?? "none".ToIdentifier()) + ", " + (Level.Loaded.StartLocation?.Type.Identifier ?? "none".ToIdentifier()));
|
||||
NewMessage("Mirrored: " + Level.Loaded.Mirrored);
|
||||
NewMessage("Level size: " + Level.Loaded.Size.X + "x" + Level.Loaded.Size.Y);
|
||||
NewMessage("Minimum main path width: " + (Level.Loaded.LevelData?.MinMainPathWidth?.ToString() ?? "unknown"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -517,6 +517,10 @@ namespace Barotrauma
|
||||
GlyphData gd = GetGlyphData(charIndex);
|
||||
if (gd.TexIndex >= 0)
|
||||
{
|
||||
if (gd.TexIndex < 0 || gd.TexIndex >= textures.Count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException($"Error while rendering text. Texture index was out of range. Text: {text}, char: {charIndex} index: {gd.TexIndex}, texture count: {textures.Count}");
|
||||
}
|
||||
Texture2D tex = textures[gd.TexIndex];
|
||||
Vector2 drawOffset;
|
||||
drawOffset.X = gd.DrawOffset.X * advanceUnit.X * scale.X - gd.DrawOffset.Y * advanceUnit.Y * scale.Y;
|
||||
|
||||
@@ -240,7 +240,7 @@ namespace Barotrauma
|
||||
|
||||
private void UpdatePending()
|
||||
{
|
||||
if (!(pendingHealList is { } healList)) { return; }
|
||||
if (pendingHealList is not { } healList) { return; }
|
||||
|
||||
ImmutableArray<MedicalClinic.NetCrewMember> pendingList = medicalClinic.PendingHeals.ToImmutableArray();
|
||||
|
||||
@@ -493,20 +493,26 @@ namespace Barotrauma
|
||||
|
||||
GUIButton treatAllButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.05f), clinicContainer.RectTransform), TextManager.Get("medicalclinic.treateveryone"))
|
||||
{
|
||||
OnClicked = (_, _) =>
|
||||
OnClicked = (button, _) =>
|
||||
{
|
||||
if (isWaitingForServer) { return true; }
|
||||
|
||||
button.Enabled = false;
|
||||
isWaitingForServer = true;
|
||||
medicalClinic.TreatAllButtonAction(OnReceived);
|
||||
|
||||
bool wasSuccessful = medicalClinic.TreatAllButtonAction(_ => ReEnableButton());
|
||||
if (!wasSuccessful) { ReEnableButton(); }
|
||||
|
||||
void ReEnableButton()
|
||||
{
|
||||
isWaitingForServer = false;
|
||||
button.Enabled = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
crewHealList = new CrewHealList(crewList, parent, treatAllButton);
|
||||
|
||||
void OnReceived(MedicalClinic.CallbackOnlyRequest obj)
|
||||
{
|
||||
isWaitingForServer = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateCrewEntry(GUIComponent parent, CrewHealList healList, CharacterInfo info, GUIComponent panel)
|
||||
@@ -524,7 +530,7 @@ namespace Barotrauma
|
||||
|
||||
new GUITextBlock(new RectTransform(Vector2.One, healthLayout.RectTransform), string.Empty, textAlignment: Alignment.Center, font: GUIStyle.SubHeadingFont)
|
||||
{
|
||||
TextGetter = () => TextManager.GetWithVariable("percentageformat", "[value]", $"{(int)(info.Character?.HealthPercentage ?? 100f)}"),
|
||||
TextGetter = () => TextManager.GetWithVariable("percentageformat", "[value]", $"{(int)MathF.Round(info.Character?.HealthPercentage ?? 100f)}"),
|
||||
TextColor = GUIStyle.Green
|
||||
};
|
||||
|
||||
@@ -585,8 +591,10 @@ namespace Barotrauma
|
||||
OnClicked = (button, _) =>
|
||||
{
|
||||
button.Enabled = false;
|
||||
medicalClinic.HealAllButtonAction(request =>
|
||||
isWaitingForServer = true;
|
||||
bool wasSuccessful = medicalClinic.HealAllButtonAction(request =>
|
||||
{
|
||||
isWaitingForServer = false;
|
||||
switch (request.HealResult)
|
||||
{
|
||||
case MedicalClinic.HealRequestResult.InsufficientFunds:
|
||||
@@ -600,6 +608,12 @@ namespace Barotrauma
|
||||
button.Enabled = true;
|
||||
ClosePopup();
|
||||
});
|
||||
|
||||
if (!wasSuccessful)
|
||||
{
|
||||
isWaitingForServer = false;
|
||||
button.Enabled = true;
|
||||
}
|
||||
ClosePopup();
|
||||
return true;
|
||||
}
|
||||
@@ -610,11 +624,19 @@ namespace Barotrauma
|
||||
ClickSound = GUISoundType.Cart,
|
||||
OnClicked = (button, _) =>
|
||||
{
|
||||
if (isWaitingForServer) { return true; }
|
||||
|
||||
button.Enabled = false;
|
||||
medicalClinic.ClearAllButtonAction(_ =>
|
||||
isWaitingForServer = true;
|
||||
|
||||
bool wasSuccessful = medicalClinic.ClearAllButtonAction(_ => ReEnableButton());
|
||||
if (!wasSuccessful) { ReEnableButton(); }
|
||||
|
||||
void ReEnableButton()
|
||||
{
|
||||
isWaitingForServer = false;
|
||||
button.Enabled = true;
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -701,10 +723,15 @@ namespace Barotrauma
|
||||
OnClicked = (button, _) =>
|
||||
{
|
||||
button.Enabled = false;
|
||||
medicalClinic.RemovePendingButtonAction(crewMember, affliction, _ =>
|
||||
bool wasSuccessful = medicalClinic.RemovePendingButtonAction(crewMember, affliction, _ =>
|
||||
{
|
||||
button.Enabled = true;
|
||||
});
|
||||
|
||||
if (!wasSuccessful)
|
||||
{
|
||||
button.Enabled = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -792,7 +819,13 @@ namespace Barotrauma
|
||||
selectedCrewAfflictionList = popupAfflictionList;
|
||||
|
||||
isWaitingForServer = true;
|
||||
medicalClinic.RequestAfflictions(info, OnReceived);
|
||||
bool wasSuccessful = medicalClinic.RequestAfflictions(info, OnReceived);
|
||||
|
||||
if (!wasSuccessful)
|
||||
{
|
||||
isWaitingForServer = false;
|
||||
ClosePopup();
|
||||
}
|
||||
|
||||
void OnReceived(MedicalClinic.AfflictionRequest request)
|
||||
{
|
||||
@@ -800,6 +833,16 @@ namespace Barotrauma
|
||||
|
||||
if (request.Result != MedicalClinic.RequestResult.Success)
|
||||
{
|
||||
switch (request.Result)
|
||||
{
|
||||
case MedicalClinic.RequestResult.CharacterInfoMissing:
|
||||
DebugConsole.ThrowError($"Unable to select character \"{info.Character?.DisplayName}\" in medical clini because the character health was missing.");
|
||||
break;
|
||||
case MedicalClinic.RequestResult.CharacterNotFound:
|
||||
DebugConsole.ThrowError($"Unable to select character \"{info.Character?.DisplayName} in medical clinic because the server was unable to find a character with ID {info.ID}.");
|
||||
break;
|
||||
}
|
||||
|
||||
feedbackBlock.Text = GetErrorText(request.Result);
|
||||
feedbackBlock.TextColor = GUIStyle.Red;
|
||||
return;
|
||||
@@ -953,14 +996,20 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
existingMember.Afflictions = existingMember.Afflictions.Concat(afflictions).ToImmutableArray();
|
||||
|
||||
ToggleElements(ElementState.Disabled, elementsToDisable);
|
||||
medicalClinic.AddPendingButtonAction(existingMember, request =>
|
||||
bool wasSuccessful = medicalClinic.AddPendingButtonAction(existingMember, request =>
|
||||
{
|
||||
if (request.Result == MedicalClinic.RequestResult.Timeout)
|
||||
{
|
||||
ToggleElements(ElementState.Enabled, elementsToDisable);
|
||||
}
|
||||
});
|
||||
|
||||
if (!wasSuccessful)
|
||||
{
|
||||
ToggleElements(ElementState.Enabled, elementsToDisable);
|
||||
}
|
||||
}
|
||||
|
||||
#warning TODO: this doesn't seem like the right place for this, and it's not clear from the method signature how this differs from ToolBox.LimitString
|
||||
@@ -1090,9 +1139,8 @@ namespace Barotrauma
|
||||
{
|
||||
return result switch
|
||||
{
|
||||
MedicalClinic.RequestResult.Error => TextManager.Get("error"),
|
||||
MedicalClinic.RequestResult.Timeout => TextManager.Get("medicalclinic.requesttimeout"),
|
||||
_ => "What the hell did you just do" // this should never happen
|
||||
_ => TextManager.Get("error")
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1072,18 +1072,19 @@ namespace Barotrauma
|
||||
if (save)
|
||||
{
|
||||
GUI.SetSavingIndicatorState(true);
|
||||
|
||||
if (GameSession.Submarine != null && !GameSession.Submarine.Removed)
|
||||
{
|
||||
GameSession.SubmarineInfo = new SubmarineInfo(GameSession.Submarine);
|
||||
}
|
||||
|
||||
// Update store stock when saving and quitting in an outpost (normally updated when CampaignMode.End() is called)
|
||||
if (GameSession?.Campaign is SinglePlayerCampaign spCampaign && Level.IsLoadedFriendlyOutpost)
|
||||
if (GameSession.Campaign is CampaignMode campaign)
|
||||
{
|
||||
spCampaign.UpdateStoreStock();
|
||||
if (campaign is SinglePlayerCampaign spCampaign && Level.IsLoadedFriendlyOutpost)
|
||||
{
|
||||
spCampaign.UpdateStoreStock();
|
||||
}
|
||||
GameSession.EventManager?.RegisterEventHistory(registerFinishedOnly: true);
|
||||
campaign.End();
|
||||
}
|
||||
|
||||
SaveUtil.SaveGame(GameSession.SavePath);
|
||||
}
|
||||
|
||||
|
||||
@@ -148,7 +148,10 @@ namespace Barotrauma
|
||||
}
|
||||
if (Submarine.MainSub == null || Level.Loaded == null) { return; }
|
||||
|
||||
endRoundButton.Visible = false;
|
||||
bool allowEndingRound = false;
|
||||
endRoundButton.Color = endRoundButton.Style.Color;
|
||||
endRoundButton.HoverColor = endRoundButton.Style.HoverColor;
|
||||
RichString overrideEndRoundButtonToolTip = string.Empty;
|
||||
var availableTransition = GetAvailableTransition(out _, out Submarine leavingSub);
|
||||
LocalizedString buttonText = "";
|
||||
switch (availableTransition)
|
||||
@@ -159,12 +162,12 @@ namespace Barotrauma
|
||||
{
|
||||
string textTag = availableTransition == TransitionType.ProgressToNextLocation ? "EnterLocation" : "EnterEmptyLocation";
|
||||
buttonText = TextManager.GetWithVariable(textTag, "[locationname]", Level.Loaded.EndLocation?.Name ?? "[ERROR]");
|
||||
endRoundButton.Visible = !ForceMapUI && !ShowCampaignUI;
|
||||
allowEndingRound = !ForceMapUI && !ShowCampaignUI;
|
||||
}
|
||||
break;
|
||||
case TransitionType.LeaveLocation:
|
||||
buttonText = TextManager.GetWithVariable("LeaveLocation", "[locationname]", Level.Loaded.StartLocation?.Name ?? "[ERROR]");
|
||||
endRoundButton.Visible = !ForceMapUI && !ShowCampaignUI;
|
||||
allowEndingRound = !ForceMapUI && !ShowCampaignUI;
|
||||
break;
|
||||
case TransitionType.ReturnToPreviousLocation:
|
||||
case TransitionType.ReturnToPreviousEmptyLocation:
|
||||
@@ -172,32 +175,37 @@ namespace Barotrauma
|
||||
{
|
||||
string textTag = availableTransition == TransitionType.ReturnToPreviousLocation ? "EnterLocation" : "EnterEmptyLocation";
|
||||
buttonText = TextManager.GetWithVariable(textTag, "[locationname]", Level.Loaded.StartLocation?.Name ?? "[ERROR]");
|
||||
endRoundButton.Visible = !ForceMapUI && !ShowCampaignUI;
|
||||
allowEndingRound = !ForceMapUI && !ShowCampaignUI;
|
||||
}
|
||||
|
||||
break;
|
||||
case TransitionType.None:
|
||||
default:
|
||||
if (Level.Loaded.Type == LevelData.LevelType.Outpost &&
|
||||
!Level.Loaded.IsEndBiome &&
|
||||
(Character.Controlled?.Submarine?.Info.Type == SubmarineType.Player || (Character.Controlled?.CurrentHull?.OutpostModuleTags.Contains("airlock".ToIdentifier()) ?? false)))
|
||||
bool inFriendlySub = Character.Controlled is { IsInFriendlySub: true };
|
||||
if (Level.Loaded.Type == LevelData.LevelType.Outpost && !Level.Loaded.IsEndBiome &&
|
||||
(inFriendlySub || (Character.Controlled?.CurrentHull?.OutpostModuleTags.Contains("airlock".ToIdentifier()) ?? false)))
|
||||
{
|
||||
if (Missions.Any(m => m is SalvageMission salvageMission && salvageMission.AnyTargetNeedsToBeRetrievedToSub))
|
||||
{
|
||||
overrideEndRoundButtonToolTip = TextManager.Get("SalvageTargetNotInSub");
|
||||
endRoundButton.Color = GUIStyle.Red * 0.7f;
|
||||
endRoundButton.HoverColor = GUIStyle.Red;
|
||||
}
|
||||
buttonText = TextManager.GetWithVariable("LeaveLocation", "[locationname]", Level.Loaded.StartLocation?.Name ?? "[ERROR]");
|
||||
endRoundButton.Visible = !ForceMapUI && !ShowCampaignUI;
|
||||
allowEndingRound = !ForceMapUI && !ShowCampaignUI;
|
||||
}
|
||||
else
|
||||
{
|
||||
endRoundButton.Visible = false;
|
||||
allowEndingRound = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (Level.IsLoadedOutpost && !ObjectiveManager.AllActiveObjectivesCompleted())
|
||||
{
|
||||
endRoundButton.Visible = false;
|
||||
allowEndingRound = false;
|
||||
}
|
||||
if (ReadyCheckButton != null) { ReadyCheckButton.Visible = allowEndingRound; }
|
||||
|
||||
if (ReadyCheckButton != null) { ReadyCheckButton.Visible = endRoundButton.Visible; }
|
||||
|
||||
endRoundButton.Visible = allowEndingRound && Character.Controlled is { IsIncapacitated: false };
|
||||
if (endRoundButton.Visible)
|
||||
{
|
||||
if (!AllowedToManageCampaign(ClientPermissions.ManageMap))
|
||||
@@ -215,7 +223,11 @@ namespace Barotrauma
|
||||
prevCampaignUIAutoOpenType = availableTransition;
|
||||
}
|
||||
endRoundButton.Text = ToolBox.LimitString(buttonText.Value, endRoundButton.Font, endRoundButton.Rect.Width - 5);
|
||||
if (endRoundButton.Text != buttonText)
|
||||
if (overrideEndRoundButtonToolTip != string.Empty)
|
||||
{
|
||||
endRoundButton.ToolTip = overrideEndRoundButtonToolTip;
|
||||
}
|
||||
else if (endRoundButton.Text != buttonText)
|
||||
{
|
||||
endRoundButton.ToolTip = buttonText;
|
||||
}
|
||||
@@ -328,6 +340,11 @@ namespace Barotrauma
|
||||
CampaignUI.UpgradeStore?.RequestRefresh();
|
||||
break;
|
||||
}
|
||||
|
||||
if (npc.AIController is HumanAIController humanAi && humanAi.IsInHostileFaction())
|
||||
{
|
||||
npc.Speak(TextManager.Get("dialoglowrepcampaigninteraction").Value, identifier: "dialoglowrepcampaigninteraction".ToIdentifier(), minDurationBetweenSimilar: 60.0f);
|
||||
}
|
||||
}
|
||||
|
||||
public override void AddToGUIUpdateList()
|
||||
|
||||
+10
-4
@@ -348,7 +348,7 @@ namespace Barotrauma
|
||||
//--------------------------------------
|
||||
|
||||
//wait for the new level to be loaded
|
||||
DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, seconds: 60);
|
||||
DateTime timeOut = DateTime.Now + GameClient.LevelTransitionTimeOut;
|
||||
while (Level.Loaded == prevLevel || Level.Loaded == null)
|
||||
{
|
||||
if (DateTime.Now > timeOut || Screen.Selected != GameMain.GameScreen) { break; }
|
||||
@@ -358,8 +358,12 @@ namespace Barotrauma
|
||||
endTransition.Stop();
|
||||
overlayColor = Color.Transparent;
|
||||
|
||||
if (DateTime.Now > timeOut) { GameMain.NetLobbyScreen.Select(); }
|
||||
if (!(Screen.Selected is RoundSummaryScreen))
|
||||
if (DateTime.Now > timeOut)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to start the round. Timed out while waiting for the level transition to finish.");
|
||||
GameMain.NetLobbyScreen.Select();
|
||||
}
|
||||
if (Screen.Selected is not RoundSummaryScreen)
|
||||
{
|
||||
if (continueButton != null)
|
||||
{
|
||||
@@ -947,7 +951,9 @@ namespace Barotrauma
|
||||
if (firedCharacter != null) { CrewManager.FireCharacter(firedCharacter); }
|
||||
}
|
||||
|
||||
if (map?.CurrentLocation?.HireManager != null && CampaignUI?.CrewManagement != null)
|
||||
if (map?.CurrentLocation?.HireManager != null && CampaignUI?.CrewManagement != null &&
|
||||
/*can't apply until we have the latest save file*/
|
||||
!NetIdUtils.IdMoreRecent(pendingSaveID, LastSaveID))
|
||||
{
|
||||
CampaignUI.CrewManagement.SetHireables(map.CurrentLocation, availableHires);
|
||||
if (hiredCharacters.Any()) { CampaignUI.CrewManagement.ValidateHires(hiredCharacters); }
|
||||
|
||||
@@ -17,7 +17,8 @@ namespace Barotrauma
|
||||
{
|
||||
Undecided,
|
||||
Success,
|
||||
Error,
|
||||
CharacterInfoMissing,
|
||||
CharacterNotFound,
|
||||
Timeout
|
||||
}
|
||||
|
||||
@@ -34,7 +35,9 @@ namespace Barotrauma
|
||||
private readonly List<RequestAction<CallbackOnlyRequest>> addRequests = new List<RequestAction<CallbackOnlyRequest>>();
|
||||
private readonly List<RequestAction<CallbackOnlyRequest>> removeRequests = new List<RequestAction<CallbackOnlyRequest>>();
|
||||
|
||||
public void RequestAfflictions(CharacterInfo info, Action<AfflictionRequest> onReceived)
|
||||
private static readonly LeakyBucket requestBucket = new(RateLimitExpiry / (float)RateLimitMaxRequests, 10);
|
||||
|
||||
public bool RequestAfflictions(CharacterInfo info, Action<AfflictionRequest> onReceived)
|
||||
{
|
||||
if (GameMain.IsSingleplayer)
|
||||
{
|
||||
@@ -42,23 +45,26 @@ namespace Barotrauma
|
||||
if (Screen.Selected is TestScreen)
|
||||
{
|
||||
onReceived.Invoke(new AfflictionRequest(RequestResult.Success, TestAfflictions.ToImmutableArray()));
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (info is not { Character.CharacterHealth: { } health })
|
||||
{
|
||||
onReceived.Invoke(new AfflictionRequest(RequestResult.Error, ImmutableArray<NetAffliction>.Empty));
|
||||
return;
|
||||
onReceived.Invoke(new AfflictionRequest(RequestResult.CharacterInfoMissing, ImmutableArray<NetAffliction>.Empty));
|
||||
return true;
|
||||
}
|
||||
|
||||
ImmutableArray<NetAffliction> pendingAfflictions = GetAllAfflictions(health).ToImmutableArray();
|
||||
ImmutableArray<NetAffliction> pendingAfflictions = GetAllAfflictions(health);
|
||||
onReceived.Invoke(new AfflictionRequest(RequestResult.Success, pendingAfflictions));
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
afflictionRequests.Add(new RequestAction<AfflictionRequest>(onReceived, GetTimeout()));
|
||||
SendAfflictionRequest(info);
|
||||
return requestBucket.TryEnqueue(() =>
|
||||
{
|
||||
afflictionRequests.Add(new RequestAction<AfflictionRequest>(onReceived, GetTimeout()));
|
||||
SendAfflictionRequest(info);
|
||||
});
|
||||
}
|
||||
|
||||
public void RequestLatestPending(Action<PendingRequest> onReceived)
|
||||
@@ -66,8 +72,11 @@ namespace Barotrauma
|
||||
// no need to worry about syncing when there's only one pair of eyes capable of looking at the UI
|
||||
if (GameMain.IsSingleplayer) { return; }
|
||||
|
||||
pendingHealRequests.Add(new RequestAction<PendingRequest>(onReceived, GetTimeout()));
|
||||
SendPendingRequest();
|
||||
requestBucket.TryEnqueue(() =>
|
||||
{
|
||||
pendingHealRequests.Add(new RequestAction<PendingRequest>(onReceived, GetTimeout()));
|
||||
SendPendingRequest();
|
||||
});
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
@@ -79,6 +88,7 @@ namespace Barotrauma
|
||||
UpdateQueue(clearAllRequests, now, onTimeout: CallbackOnlyTimeout);
|
||||
UpdateQueue(addRequests, now, onTimeout: CallbackOnlyTimeout);
|
||||
UpdateQueue(removeRequests, now, onTimeout: CallbackOnlyTimeout);
|
||||
requestBucket.Update(deltaTime);
|
||||
|
||||
static void CallbackOnlyTimeout(Action<CallbackOnlyRequest> callback) { callback(new CallbackOnlyRequest(RequestResult.Timeout)); }
|
||||
}
|
||||
@@ -146,21 +156,25 @@ namespace Barotrauma
|
||||
return (from client in clients where client.Name == ownName select client.Ping).FirstOrDefault();
|
||||
}
|
||||
|
||||
public void TreatAllButtonAction(Action<CallbackOnlyRequest> onReceived)
|
||||
public bool TreatAllButtonAction(Action<CallbackOnlyRequest> onReceived)
|
||||
{
|
||||
if (GameMain.IsSingleplayer)
|
||||
{
|
||||
AddEverythingToPending();
|
||||
onReceived(new CallbackOnlyRequest(RequestResult.Success));
|
||||
OnUpdate?.Invoke();
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
addRequests.Add(new RequestAction<CallbackOnlyRequest>(onReceived, GetTimeout()));
|
||||
ClientSend(null, NetworkHeader.ADD_EVERYTHING_TO_PENDING, DeliveryMethod.Reliable);
|
||||
return requestBucket.TryEnqueue(() =>
|
||||
{
|
||||
addRequests.Add(new RequestAction<CallbackOnlyRequest>(onReceived, GetTimeout()));
|
||||
ClientSend(null, NetworkHeader.ADD_EVERYTHING_TO_PENDING, DeliveryMethod.Reliable);
|
||||
});
|
||||
}
|
||||
|
||||
public void HealAllButtonAction(Action<HealRequest> onReceived)
|
||||
|
||||
public bool HealAllButtonAction(Action<HealRequest> onReceived)
|
||||
{
|
||||
if (GameMain.IsSingleplayer)
|
||||
{
|
||||
@@ -171,33 +185,39 @@ namespace Barotrauma
|
||||
OnUpdate?.Invoke();
|
||||
}
|
||||
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (campaign?.CampaignUI?.MedicalClinic is { } ui)
|
||||
if (campaign?.CampaignUI?.MedicalClinic is { } openedUi)
|
||||
{
|
||||
ui.ClosePopup();
|
||||
openedUi.ClosePopup();
|
||||
}
|
||||
|
||||
healAllRequests.Add(new RequestAction<HealRequest>(onReceived, GetTimeout()));
|
||||
ClientSend(null, NetworkHeader.HEAL_PENDING, DeliveryMethod.Reliable);
|
||||
return requestBucket.TryEnqueue(() =>
|
||||
{
|
||||
healAllRequests.Add(new RequestAction<HealRequest>(onReceived, GetTimeout()));
|
||||
ClientSend(null, NetworkHeader.HEAL_PENDING, DeliveryMethod.Reliable);
|
||||
});
|
||||
}
|
||||
|
||||
public void ClearAllButtonAction(Action<CallbackOnlyRequest> onReceived)
|
||||
public bool ClearAllButtonAction(Action<CallbackOnlyRequest> onReceived)
|
||||
{
|
||||
if (GameMain.IsSingleplayer)
|
||||
{
|
||||
ClearPendingHeals();
|
||||
onReceived(new CallbackOnlyRequest(RequestResult.Success));
|
||||
OnUpdate?.Invoke();
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
clearAllRequests.Add(new RequestAction<CallbackOnlyRequest>(onReceived, GetTimeout()));
|
||||
ClientSend(null, NetworkHeader.CLEAR_PENDING, DeliveryMethod.Reliable);
|
||||
return requestBucket.TryEnqueue(() =>
|
||||
{
|
||||
clearAllRequests.Add(new RequestAction<CallbackOnlyRequest>(onReceived, GetTimeout()));
|
||||
ClientSend(null, NetworkHeader.CLEAR_PENDING, DeliveryMethod.Reliable);
|
||||
});
|
||||
}
|
||||
|
||||
private void ClearRequstReceived()
|
||||
private void ClearRequestReceived()
|
||||
{
|
||||
ClearPendingHeals();
|
||||
if (TryDequeue(clearAllRequests, out var callback))
|
||||
@@ -224,28 +244,31 @@ namespace Barotrauma
|
||||
OnUpdate?.Invoke();
|
||||
}
|
||||
|
||||
public void AddPendingButtonAction(NetCrewMember crewMember, Action<CallbackOnlyRequest> onReceived)
|
||||
public bool AddPendingButtonAction(NetCrewMember crewMember, Action<CallbackOnlyRequest> onReceived)
|
||||
{
|
||||
if (GameMain.IsSingleplayer)
|
||||
{
|
||||
InsertPendingCrewMember(crewMember);
|
||||
onReceived(new CallbackOnlyRequest(RequestResult.Success));
|
||||
OnUpdate?.Invoke();
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
addRequests.Add(new RequestAction<CallbackOnlyRequest>(onReceived, GetTimeout()));
|
||||
ClientSend(crewMember, NetworkHeader.ADD_PENDING, DeliveryMethod.Reliable);
|
||||
return requestBucket.TryEnqueue(() =>
|
||||
{
|
||||
addRequests.Add(new RequestAction<CallbackOnlyRequest>(onReceived, GetTimeout()));
|
||||
ClientSend(crewMember, NetworkHeader.ADD_PENDING, DeliveryMethod.Reliable);
|
||||
});
|
||||
}
|
||||
|
||||
public void RemovePendingButtonAction(NetCrewMember crewMember, NetAffliction affliction, Action<CallbackOnlyRequest> onReceived)
|
||||
public bool RemovePendingButtonAction(NetCrewMember crewMember, NetAffliction affliction, Action<CallbackOnlyRequest> onReceived)
|
||||
{
|
||||
if (GameMain.IsSingleplayer)
|
||||
{
|
||||
RemovePendingAffliction(crewMember, affliction);
|
||||
onReceived(new CallbackOnlyRequest(RequestResult.Success));
|
||||
OnUpdate?.Invoke();
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
INetSerializableStruct removedAffliction = new NetRemovedAffliction
|
||||
@@ -254,11 +277,14 @@ namespace Barotrauma
|
||||
Affliction = affliction
|
||||
};
|
||||
|
||||
removeRequests.Add(new RequestAction<CallbackOnlyRequest>(onReceived, GetTimeout()));
|
||||
ClientSend(removedAffliction, NetworkHeader.REMOVE_PENDING, DeliveryMethod.Reliable);
|
||||
return requestBucket.TryEnqueue(() =>
|
||||
{
|
||||
removeRequests.Add(new RequestAction<CallbackOnlyRequest>(onReceived, GetTimeout()));
|
||||
ClientSend(removedAffliction, NetworkHeader.REMOVE_PENDING, DeliveryMethod.Reliable);
|
||||
});
|
||||
}
|
||||
|
||||
private void NewAdditonReceived(IReadMessage inc, MessageFlag flag)
|
||||
private void NewAdditionReceived(IReadMessage inc, MessageFlag flag)
|
||||
{
|
||||
var crewMembers = INetSerializableStruct.Read<NetCollection<NetCrewMember>>(inc);
|
||||
foreach (var crewMember in crewMembers)
|
||||
@@ -300,7 +326,7 @@ namespace Barotrauma
|
||||
NetCrewMember crewMember = INetSerializableStruct.Read<NetCrewMember>(inc);
|
||||
if (TryDequeue(afflictionRequests, out var callback))
|
||||
{
|
||||
RequestResult result = crewMember.CharacterInfoID is 0 ? RequestResult.Error : RequestResult.Success;
|
||||
RequestResult result = crewMember.CharacterInfoID is 0 ? RequestResult.CharacterNotFound : RequestResult.Success;
|
||||
callback(new AfflictionRequest(result, crewMember.Afflictions.ToImmutableArray()));
|
||||
}
|
||||
}
|
||||
@@ -336,7 +362,7 @@ namespace Barotrauma
|
||||
IWriteMessage msg = StartSending();
|
||||
msg.WriteByte((byte)header);
|
||||
netStruct?.Write(msg);
|
||||
GameMain.Client.ClientPeer?.Send(msg, deliveryMethod);
|
||||
GameMain.Client?.ClientPeer?.Send(msg, deliveryMethod);
|
||||
}
|
||||
|
||||
public void ClientRead(IReadMessage inc)
|
||||
@@ -356,7 +382,7 @@ namespace Barotrauma
|
||||
PendingRequestReceived(inc);
|
||||
break;
|
||||
case NetworkHeader.ADD_PENDING:
|
||||
NewAdditonReceived(inc, flag);
|
||||
NewAdditionReceived(inc, flag);
|
||||
break;
|
||||
case NetworkHeader.REMOVE_PENDING:
|
||||
NewRemovalReceived(inc, flag);
|
||||
@@ -365,7 +391,7 @@ namespace Barotrauma
|
||||
HealRequestReceived(inc);
|
||||
break;
|
||||
case NetworkHeader.CLEAR_PENDING:
|
||||
ClearRequstReceived();
|
||||
ClearRequestReceived();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace Barotrauma
|
||||
|
||||
private void CreateMessageBox(string author)
|
||||
{
|
||||
Vector2 relativeSize = new Vector2(0.3f * GUI.AspectRatioAdjustment, 0.15f);
|
||||
Vector2 relativeSize = new Vector2(0.2f / GUI.AspectRatioAdjustment, 0.15f);
|
||||
Point minSize = new Point(300, 200);
|
||||
msgBox = new GUIMessageBox(readyCheckHeader, readyCheckBody(author), new[] { yesButton, noButton }, relativeSize, minSize, type: GUIMessageBox.Type.Vote) { UserData = PromptData, Draggable = true };
|
||||
|
||||
|
||||
@@ -213,10 +213,11 @@ namespace Barotrauma
|
||||
};
|
||||
|
||||
List<Mission> missionsToDisplay = new List<Mission>(selectedMissions.Where(m => m.Prefab.ShowInMenus));
|
||||
if (!selectedMissions.Any() && startLocation != null)
|
||||
if (startLocation != null)
|
||||
{
|
||||
foreach (Mission mission in startLocation.SelectedMissions)
|
||||
{
|
||||
if (missionsToDisplay.Contains(mission)) { continue; }
|
||||
if (!mission.Prefab.ShowInMenus) { continue; }
|
||||
if (mission.Locations[0] == mission.Locations[1] ||
|
||||
mission.Locations.Contains(campaignMode?.Map.SelectedLocation))
|
||||
@@ -316,7 +317,7 @@ namespace Barotrauma
|
||||
RichString reputationText = displayedMission.GetReputationRewardText();
|
||||
if (!reputationText.IsNullOrEmpty())
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), reputationText);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), reputationText, wrap: true);
|
||||
}
|
||||
|
||||
int totalReward = displayedMission.GetFinalReward(Submarine.MainSub);
|
||||
|
||||
@@ -88,6 +88,11 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public void ClientEventRead(IReadMessage msg, float sendingTime)
|
||||
{
|
||||
UInt16 userID = msg.ReadUInt16();
|
||||
if (userID != Entity.NullEntityID)
|
||||
{
|
||||
user = Entity.FindEntityByID(userID) as Character;
|
||||
}
|
||||
CurrPowerConsumption = powerConsumption;
|
||||
charging = true;
|
||||
timer = Duration;
|
||||
|
||||
@@ -21,6 +21,9 @@ namespace Barotrauma.Items.Components
|
||||
/// </summary>
|
||||
private float lightColorMultiplier;
|
||||
|
||||
[Serialize(1.0f, IsPropertySaveable.Yes, description: "The scale of the light sprite.")]
|
||||
public float LightSpriteScale { get; set; }
|
||||
|
||||
public Vector2 DrawSize
|
||||
{
|
||||
get { return new Vector2(Light.Range * 2, Light.Range * 2); }
|
||||
@@ -92,7 +95,13 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
color = new Color(lightColor, Light.OverrideLightSpriteAlpha.Value);
|
||||
}
|
||||
Light.LightSprite.Draw(spriteBatch, new Vector2(drawPos.X, -drawPos.Y), color * lightBrightness, origin, -Light.Rotation, item.Scale, Light.LightSpriteEffect, itemDepth - 0.0001f);
|
||||
Light.LightSprite.Draw(spriteBatch,
|
||||
new Vector2(drawPos.X, -drawPos.Y),
|
||||
color * lightBrightness,
|
||||
origin,
|
||||
-Light.Rotation,
|
||||
item.Scale * LightSpriteScale,
|
||||
Light.LightSpriteEffect, itemDepth - 0.0001f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -528,7 +528,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (slotRect.Contains(PlayerInput.MousePosition))
|
||||
{
|
||||
var suitableIngredients = requiredItem.ItemPrefabs.Select(ip => ip.Name);
|
||||
var suitableIngredients = requiredItem.ItemPrefabs.Select(ip => ip.Name).Distinct();
|
||||
LocalizedString toolTipText = string.Join(", ", suitableIngredients.Count() > 3 ? suitableIngredients.SkipLast(suitableIngredients.Count() - 3) : suitableIngredients);
|
||||
if (suitableIngredients.Count() > 3) { toolTipText += "..."; }
|
||||
if (requiredItem.UseCondition && requiredItem.MinCondition < 1.0f)
|
||||
@@ -550,6 +550,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
toolTipText = TextManager.GetWithVariable("displayname.emptyitem", "[itemname]", toolTipText);
|
||||
}
|
||||
|
||||
toolTipText = $"‖color:{Color.White.ToStringHex()}‖{toolTipText}‖color:end‖";
|
||||
if (!requiredItemPrefab.Description.IsNullOrEmpty())
|
||||
{
|
||||
toolTipText += '\n' + requiredItemPrefab.Description;
|
||||
@@ -594,7 +596,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (tooltip != null)
|
||||
{
|
||||
GUIComponent.DrawToolTip(spriteBatch, tooltip.Tooltip, tooltip.TargetElement);
|
||||
GUIComponent.DrawToolTip(spriteBatch, RichString.Rich(tooltip.Tooltip), tooltip.TargetElement);
|
||||
tooltip = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,7 +403,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private bool VisibleOnItemFinder(Item it)
|
||||
{
|
||||
if (!item.Submarine.IsEntityFoundOnThisSub(it, includingConnectedSubs: true)) { return false; }
|
||||
if (it?.Submarine == null) { return false; }
|
||||
if (item.Submarine == null || !item.Submarine.IsEntityFoundOnThisSub(it, includingConnectedSubs: true)) { return false; }
|
||||
if (it.NonInteractable || it.HiddenInGame) { return false; }
|
||||
if (it.GetComponent<Pickable>() == null) { return false; }
|
||||
|
||||
@@ -702,6 +703,12 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private void DrawHUDFront(SpriteBatch spriteBatch, GUICustomComponent container)
|
||||
{
|
||||
if (miniMapFrame == null)
|
||||
{
|
||||
//frame not created yet, could happen if the item hasn't been inside any sub this round?
|
||||
return;
|
||||
}
|
||||
|
||||
if (Voltage < MinVoltage)
|
||||
{
|
||||
Vector2 textSize = GUIStyle.Font.MeasureString(noPowerTip);
|
||||
@@ -1057,7 +1064,9 @@ namespace Barotrauma.Items.Components
|
||||
waterVolume += linkedHull.WaterVolume;
|
||||
totalVolume += linkedHull.Volume;
|
||||
}
|
||||
hullData.HullWaterAmount = MathHelper.Clamp((int)Math.Ceiling(waterVolume / totalVolume * 100), 0, 100);
|
||||
hullData.HullWaterAmount =
|
||||
waterVolume > 1.0f ?
|
||||
MathHelper.Clamp((int)Math.Ceiling(waterVolume / totalVolume * 100), 0, 100) : 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1311,7 +1311,6 @@ namespace Barotrauma.Items.Components
|
||||
float worldPingRadiusSqr = worldPingRadius * worldPingRadius;
|
||||
|
||||
disruptedDirections.Clear();
|
||||
if (Level.Loaded == null) { return; }
|
||||
|
||||
for (var pingIndex = 0; pingIndex < activePingsCount; ++pingIndex)
|
||||
{
|
||||
@@ -1434,8 +1433,10 @@ namespace Barotrauma.Items.Components
|
||||
if (connectedSubs.Contains(submarine)) { continue; }
|
||||
}
|
||||
|
||||
Rectangle worldBorders = Submarine.MainSub.GetDockedBorders();
|
||||
worldBorders.Location += Submarine.MainSub.WorldPosition.ToPoint();
|
||||
//display the actual walls if the ping source is inside the sub (but not inside a hull, that's handled above)
|
||||
//only relevant in the end levels or maybe custom subs with some kind of non-hulled parts
|
||||
Rectangle worldBorders = submarine.GetDockedBorders();
|
||||
worldBorders.Location += submarine.WorldPosition.ToPoint();
|
||||
if (Submarine.RectContains(worldBorders, pingSource))
|
||||
{
|
||||
CreateBlipsForSubmarineWalls(submarine, pingSource, transducerPos, pingRadius, prevPingRadius, range, passive);
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Barotrauma.Items.Components
|
||||
User = Entity.FindEntityByID(userId) as Character;
|
||||
Vector2 simPosition = new Vector2(msg.ReadSingle(), msg.ReadSingle());
|
||||
float rotation = msg.ReadSingle();
|
||||
SpreadCounter = msg.ReadByte();
|
||||
spreadIndex = msg.ReadByte();
|
||||
if (User != null)
|
||||
{
|
||||
Shoot(User, simPosition, simPosition, rotation, ignoredBodies: User.AnimController.Limbs.Where(l => !l.IsSevered).Select(l => l.body.FarseerBody).ToList(), createNetworkEvent: false);
|
||||
|
||||
+50
-37
@@ -12,6 +12,8 @@ namespace Barotrauma.Items.Components
|
||||
private readonly List<GUIComponent> uiElements = new List<GUIComponent>();
|
||||
private GUILayoutGroup uiElementContainer;
|
||||
|
||||
private bool readingNetworkEvent;
|
||||
|
||||
private Point ElementMaxSize => new Point(uiElementContainer.Rect.Width, (int)(65 * GUI.yScale));
|
||||
|
||||
public override bool RecreateGUIOnResolutionChange => true;
|
||||
@@ -100,7 +102,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
ValueChanged(ni.UserData as CustomInterfaceElement, ni.FloatValue);
|
||||
}
|
||||
else
|
||||
else if (!readingNetworkEvent)
|
||||
{
|
||||
item.CreateClientEvent(this);
|
||||
}
|
||||
@@ -126,7 +128,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
ValueChanged(ni.UserData as CustomInterfaceElement, ni.IntValue);
|
||||
}
|
||||
else
|
||||
else if (!readingNetworkEvent)
|
||||
{
|
||||
item.CreateClientEvent(this);
|
||||
}
|
||||
@@ -161,7 +163,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
TickBoxToggled(tBox.UserData as CustomInterfaceElement, tBox.Selected);
|
||||
}
|
||||
else
|
||||
else if (!readingNetworkEvent)
|
||||
{
|
||||
item.CreateClientEvent(this);
|
||||
}
|
||||
@@ -181,12 +183,12 @@ namespace Barotrauma.Items.Components
|
||||
};
|
||||
btn.OnClicked += (_, userdata) =>
|
||||
{
|
||||
CustomInterfaceElement btnElement = userdata as CustomInterfaceElement;;
|
||||
CustomInterfaceElement btnElement = userdata as CustomInterfaceElement;
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
ButtonClicked(btnElement);
|
||||
}
|
||||
else
|
||||
else if (!readingNetworkEvent)
|
||||
{
|
||||
item.CreateClientEvent(this, new EventData(btnElement));
|
||||
}
|
||||
@@ -248,7 +250,7 @@ namespace Barotrauma.Items.Components
|
||||
int visibleElementCount = 0;
|
||||
foreach (var uiElement in uiElements)
|
||||
{
|
||||
if (!(uiElement.UserData is CustomInterfaceElement element)) { continue; }
|
||||
if (uiElement.UserData is not CustomInterfaceElement element) { continue; }
|
||||
bool visible = Screen.Selected == GameMain.SubEditorScreen || element.StatusEffects.Any() || element.HasPropertyName || (element.Connection != null && element.Connection.Wires.Count > 0);
|
||||
if (visible) { visibleElementCount++; }
|
||||
if (uiElement.Visible != visible)
|
||||
@@ -297,9 +299,10 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
LocalizedString CreateLabelText(int elementIndex)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(customInterfaceElementList[elementIndex].Label) ?
|
||||
var label = customInterfaceElementList[elementIndex].Label;
|
||||
return string.IsNullOrWhiteSpace(label) ?
|
||||
TextManager.GetWithVariable("connection.signaloutx", "[num]", (elementIndex + 1).ToString()) :
|
||||
customInterfaceElementList[elementIndex].Label;
|
||||
TextManager.Get(label).Fallback(label);
|
||||
}
|
||||
|
||||
uiElementContainer.Recalculate();
|
||||
@@ -334,7 +337,9 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (uiElements[i] is GUITextBox tb)
|
||||
{
|
||||
tb.Text = customInterfaceElementList[i].Signal;
|
||||
tb.Text = Screen.Selected is { IsEditor: true } ?
|
||||
customInterfaceElementList[i].Signal :
|
||||
TextManager.Get(customInterfaceElementList[i].Signal).Value;
|
||||
}
|
||||
else if (uiElements[i] is GUINumberInput ni)
|
||||
{
|
||||
@@ -386,45 +391,53 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public void ClientEventRead(IReadMessage msg, float sendingTime)
|
||||
{
|
||||
for (int i = 0; i < customInterfaceElementList.Count; i++)
|
||||
readingNetworkEvent = true;
|
||||
try
|
||||
{
|
||||
var element = customInterfaceElementList[i];
|
||||
if (element.HasPropertyName)
|
||||
for (int i = 0; i < customInterfaceElementList.Count; i++)
|
||||
{
|
||||
string newValue = msg.ReadString();
|
||||
if (!element.IsNumberInput)
|
||||
var element = customInterfaceElementList[i];
|
||||
if (element.HasPropertyName)
|
||||
{
|
||||
TextChanged(element, newValue);
|
||||
string newValue = msg.ReadString();
|
||||
if (!element.IsNumberInput)
|
||||
{
|
||||
TextChanged(element, newValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (element.NumberType)
|
||||
{
|
||||
case NumberType.Int when int.TryParse(newValue, out int value):
|
||||
ValueChanged(element, value);
|
||||
break;
|
||||
case NumberType.Float when TryParseFloatInvariantCulture(newValue, out float value):
|
||||
ValueChanged(element, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (element.NumberType)
|
||||
bool elementState = msg.ReadBoolean();
|
||||
if (element.ContinuousSignal)
|
||||
{
|
||||
case NumberType.Int when int.TryParse(newValue, out int value):
|
||||
ValueChanged(element, value);
|
||||
break;
|
||||
case NumberType.Float when TryParseFloatInvariantCulture(newValue, out float value):
|
||||
ValueChanged(element, value);
|
||||
break;
|
||||
((GUITickBox)uiElements[i]).Selected = elementState;
|
||||
TickBoxToggled(element, elementState);
|
||||
}
|
||||
else if (elementState)
|
||||
{
|
||||
ButtonClicked(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool elementState = msg.ReadBoolean();
|
||||
if (element.ContinuousSignal)
|
||||
{
|
||||
((GUITickBox)uiElements[i]).Selected = elementState;
|
||||
TickBoxToggled(element, elementState);
|
||||
}
|
||||
else if (elementState)
|
||||
{
|
||||
ButtonClicked(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UpdateSignalsProjSpecific();
|
||||
UpdateSignalsProjSpecific();
|
||||
}
|
||||
finally
|
||||
{
|
||||
readingNetworkEvent = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ namespace Barotrauma.Items.Components
|
||||
Sprite pingCircle = GUIStyle.UIThermalGlow.Value.Sprite;
|
||||
foreach (Limb limb in c.AnimController.Limbs)
|
||||
{
|
||||
if (limb.Mass < 1.0f) { continue; }
|
||||
if (limb.Mass < 0.5f && limb != c.AnimController.MainLimb) { continue; }
|
||||
float noise1 = PerlinNoise.GetPerlin((thermalEffectState + limb.Params.ID + c.ID) * 0.01f, (thermalEffectState + limb.Params.ID + c.ID) * 0.02f);
|
||||
float noise2 = PerlinNoise.GetPerlin((thermalEffectState + limb.Params.ID + c.ID) * 0.01f, (thermalEffectState + limb.Params.ID + c.ID) * 0.008f);
|
||||
Vector2 spriteScale = ConvertUnits.ToDisplayUnits(limb.body.GetSize()) / pingCircle.size * (noise1 * 0.5f + 2f);
|
||||
|
||||
@@ -1398,7 +1398,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Failed to read component state - " + components[componentIndex].GetType() + " is not IServerSerializable.");
|
||||
throw new Exception($"Failed to read component state - {components[componentIndex].GetType()} in item \"{Prefab.Identifier}\" is not IServerSerializable.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1411,13 +1411,14 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Failed to read inventory state - " + components[containerIndex].GetType() + " is not an ItemContainer.");
|
||||
throw new Exception($"Failed to read inventory state - {components[containerIndex].GetType()} in item \"{Prefab.Identifier}\" is not an ItemContainer.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EventType.Status:
|
||||
bool loadingRound = msg.ReadBoolean();
|
||||
float newCondition = msg.ReadSingle();
|
||||
SetCondition(newCondition, isNetworkEvent: true);
|
||||
SetCondition(newCondition, isNetworkEvent: true, executeEffects: !loadingRound);
|
||||
break;
|
||||
case EventType.AssignCampaignInteraction:
|
||||
CampaignInteractionType = (CampaignMode.InteractionType)msg.ReadByte();
|
||||
@@ -1459,9 +1460,9 @@ namespace Barotrauma
|
||||
byte length = msg.ReadByte();
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
var statIdentifier = INetSerializableStruct.Read<ItemStatManager.TalentStatIdentifier>(msg);
|
||||
var statIdentifier = INetSerializableStruct.Read<TalentStatIdentifier>(msg);
|
||||
var statValue = msg.ReadSingle();
|
||||
StatManager.ApplyStat(statIdentifier, statValue);
|
||||
StatManager.ApplyStatDirect(statIdentifier, statValue);
|
||||
}
|
||||
break;
|
||||
case EventType.Upgrade:
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -320,5 +321,45 @@ namespace Barotrauma
|
||||
return IsHorizontal ? rect.Height : rect.Width;
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateEditing(Camera cam, float deltaTime)
|
||||
{
|
||||
if (editingHUD == null || editingHUD.UserData != this)
|
||||
{
|
||||
editingHUD = CreateEditingHUD();
|
||||
}
|
||||
}
|
||||
private GUIComponent CreateEditingHUD(bool inGame = false)
|
||||
{
|
||||
|
||||
editingHUD = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.15f), GUI.Canvas, Anchor.CenterRight) { MinSize = new Point(400, 0) })
|
||||
{
|
||||
UserData = this
|
||||
};
|
||||
|
||||
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.85f), editingHUD.RectTransform, Anchor.Center))
|
||||
{
|
||||
Stretch = true,
|
||||
AbsoluteSpacing = (int)(GUI.Scale * 5)
|
||||
};
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform), TextManager.Get("entityname.gap"), font: GUIStyle.LargeFont);
|
||||
var hiddenInGameTickBox = new GUITickBox(new RectTransform(new Vector2(0.5f, 1.0f), paddedFrame.RectTransform), TextManager.Get("sp.hiddeningame.name"))
|
||||
{
|
||||
Selected = HiddenInGame
|
||||
};
|
||||
hiddenInGameTickBox.OnSelected += (GUITickBox tickbox) =>
|
||||
{
|
||||
HiddenInGame = tickbox.Selected;
|
||||
return true;
|
||||
};
|
||||
editingHUD.RectTransform.Resize(new Point(
|
||||
editingHUD.Rect.Width,
|
||||
(int)(paddedFrame.Children.Sum(c => c.Rect.Height + paddedFrame.AbsoluteSpacing) / paddedFrame.RectTransform.RelativeSize.Y * 1.25f)));
|
||||
|
||||
PositionEditingHUD();
|
||||
|
||||
return editingHUD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,7 +240,8 @@ namespace Barotrauma.Lights
|
||||
range *
|
||||
((Character.Controlled?.Submarine != null && light.ParentSub == Character.Controlled?.Submarine) ? 2.0f : 1.0f) *
|
||||
(light.CastShadows ? 10.0f : 1.0f) *
|
||||
(light.LightSourceParams.OverrideLightSpriteAlpha ?? (light.Color.A / 255.0f));
|
||||
(light.LightSourceParams.OverrideLightSpriteAlpha ?? (light.Color.A / 255.0f)) *
|
||||
light.PriorityMultiplier;
|
||||
}
|
||||
|
||||
//find the lights with an active light volume
|
||||
|
||||
@@ -377,6 +377,8 @@ namespace Barotrauma.Lights
|
||||
|
||||
public float Priority;
|
||||
|
||||
public float PriorityMultiplier = 1.0f;
|
||||
|
||||
private Vector2 lightTextureTargetSize;
|
||||
|
||||
public Vector2 LightTextureTargetSize
|
||||
|
||||
@@ -537,7 +537,7 @@ namespace Barotrauma
|
||||
float damage = msg.ReadRangedSingle(0.0f, 1.0f, 8) * MaxHealth;
|
||||
if (!invalidMessage && i < Sections.Length)
|
||||
{
|
||||
SetDamage(i, damage);
|
||||
SetDamage(i, damage, isNetworkEvent: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ namespace Barotrauma.Networking
|
||||
float gain = 1.0f;
|
||||
float noiseGain = 0.0f;
|
||||
Vector3? position = null;
|
||||
if (character != null)
|
||||
if (character != null && !character.IsDead)
|
||||
{
|
||||
if (GameSettings.CurrentConfig.Audio.UseDirectionalVoiceChat)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
@@ -16,6 +15,10 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
sealed class GameClient : NetworkMember
|
||||
{
|
||||
public static readonly TimeSpan CampaignSaveTransferTimeOut = new TimeSpan(0, 0, seconds: 100);
|
||||
//this should be longer than CampaignSaveTransferTimeOut - we shouldn't give up starting the round if we're still waiting for the save file
|
||||
public static readonly TimeSpan LevelTransitionTimeOut = new TimeSpan(0, 0, seconds: 150);
|
||||
|
||||
public override bool IsClient => true;
|
||||
public override bool IsServer => false;
|
||||
|
||||
@@ -76,6 +79,8 @@ namespace Barotrauma.Networking
|
||||
Interrupted
|
||||
}
|
||||
|
||||
private UInt16? debugStartGameCampaignSaveID;
|
||||
|
||||
private RoundInitStatus roundInitStatus = RoundInitStatus.NotStarted;
|
||||
|
||||
public bool RoundStarting => roundInitStatus == RoundInitStatus.Starting || roundInitStatus == RoundInitStatus.WaitingForStartGameFinalize;
|
||||
@@ -512,6 +517,7 @@ namespace Barotrauma.Networking
|
||||
DisplayInLoadingScreens = true
|
||||
};
|
||||
Quit();
|
||||
GUI.DisableHUD = false;
|
||||
GameMain.ServerListScreen.Select();
|
||||
return;
|
||||
}
|
||||
@@ -859,17 +865,24 @@ namespace Barotrauma.Networking
|
||||
ContentFile file = ContentPackageManager.EnabledPackages.All
|
||||
.Select(p =>
|
||||
p.Files.FirstOrDefault(f => f.Path == filePath))
|
||||
.FirstOrDefault(f => !(f is null));
|
||||
.FirstOrDefault(f => f is not null);
|
||||
contentToPreload.AddIfNotNull(file);
|
||||
}
|
||||
|
||||
string campaignErrorInfo = string.Empty;
|
||||
if (GameMain.GameSession?.Campaign is MultiPlayerCampaign campaign)
|
||||
{
|
||||
campaignErrorInfo = $" Round start save ID: {debugStartGameCampaignSaveID}, last save id: {campaign.LastSaveID}, pending save id: {campaign.PendingSaveID}.";
|
||||
}
|
||||
|
||||
GameMain.GameSession.EventManager.PreloadContent(contentToPreload);
|
||||
|
||||
int subEqualityCheckValue = inc.ReadInt32();
|
||||
if (subEqualityCheckValue != (Submarine.MainSub?.Info?.EqualityCheckVal ?? 0))
|
||||
{
|
||||
string errorMsg = "Submarine equality check failed. The submarine loaded at your end doesn't match the one loaded by the server." +
|
||||
" There may have been an error in receiving the up-to-date submarine file from the server.";
|
||||
string errorMsg =
|
||||
"Submarine equality check failed. The submarine loaded at your end doesn't match the one loaded by the server. " +
|
||||
$"There may have been an error in receiving the up-to-date submarine file from the server. Round init status: {roundInitStatus}." + campaignErrorInfo;
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:SubsDontMatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
throw new Exception(errorMsg);
|
||||
}
|
||||
@@ -886,7 +899,7 @@ namespace Barotrauma.Networking
|
||||
$"Mission equality check failed. Mission count doesn't match the server. " +
|
||||
$"Server: {string.Join(", ", serverMissionIdentifiers)}, " +
|
||||
$"client: {string.Join(", ", GameMain.GameSession.GameMode.Missions.Select(m => m.Prefab.Identifier))}, " +
|
||||
$"game session: {string.Join(", ", GameMain.GameSession.Missions.Select(m => m.Prefab.Identifier))})";
|
||||
$"game session: {string.Join(", ", GameMain.GameSession.Missions.Select(m => m.Prefab.Identifier))}). Round init status: {roundInitStatus}." + campaignErrorInfo;
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:MissionsCountMismatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
throw new Exception(errorMsg);
|
||||
}
|
||||
@@ -899,7 +912,7 @@ namespace Barotrauma.Networking
|
||||
$"Mission equality check failed. The mission selected at your end doesn't match the one loaded by the server " +
|
||||
$"Server: {string.Join(", ", serverMissionIdentifiers)}, " +
|
||||
$"client: {string.Join(", ", GameMain.GameSession.GameMode.Missions.Select(m => m.Prefab.Identifier))}, " +
|
||||
$"game session: {string.Join(", ", GameMain.GameSession.Missions.Select(m => m.Prefab.Identifier))})";
|
||||
$"game session: {string.Join(", ", GameMain.GameSession.Missions.Select(m => m.Prefab.Identifier))}). Round init status: {roundInitStatus}." + campaignErrorInfo;
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:MissionsDontMatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
throw new Exception(errorMsg);
|
||||
}
|
||||
@@ -922,7 +935,7 @@ namespace Barotrauma.Networking
|
||||
", level value count: " + levelEqualityCheckValues.Count +
|
||||
", seed: " + Level.Loaded.Seed +
|
||||
", sub: " + Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash.ShortRepresentation + ")" +
|
||||
", mirrored: " + Level.Loaded.Mirrored + ").";
|
||||
", mirrored: " + Level.Loaded.Mirrored + "). Round init status: " + roundInitStatus + "." + campaignErrorInfo;
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
throw new Exception(errorMsg);
|
||||
}
|
||||
@@ -1322,6 +1335,8 @@ namespace Barotrauma.Networking
|
||||
eventErrorWritten = false;
|
||||
GameMain.NetLobbyScreen.StopWaitingForStartRound();
|
||||
|
||||
debugStartGameCampaignSaveID = null;
|
||||
|
||||
while (CoroutineManager.IsCoroutineRunning("EndGame"))
|
||||
{
|
||||
EndCinematic?.Stop();
|
||||
@@ -1471,7 +1486,28 @@ namespace Barotrauma.Networking
|
||||
roundInitStatus = RoundInitStatus.Interrupted;
|
||||
yield return CoroutineStatus.Failure;
|
||||
}
|
||||
else if (campaign.Map == null)
|
||||
|
||||
if (NetIdUtils.IdMoreRecent(campaign.PendingSaveID, campaign.LastSaveID) ||
|
||||
NetIdUtils.IdMoreRecent(campaignSaveID, campaign.PendingSaveID))
|
||||
{
|
||||
campaign.PendingSaveID = campaignSaveID;
|
||||
DateTime saveFileTimeOut = DateTime.Now + CampaignSaveTransferTimeOut;
|
||||
while (NetIdUtils.IdMoreRecent(campaignSaveID, campaign.LastSaveID))
|
||||
{
|
||||
if (DateTime.Now > saveFileTimeOut)
|
||||
{
|
||||
GameStarted = true;
|
||||
new GUIMessageBox(TextManager.Get("error"), TextManager.Get("campaignsavetransfer.timeout"));
|
||||
GameMain.NetLobbyScreen.Select();
|
||||
roundInitStatus = RoundInitStatus.Interrupted;
|
||||
//use success status, even though this is a failure (no need to show a console error because we show it in the message box)
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
yield return new WaitForSeconds(0.1f);
|
||||
}
|
||||
}
|
||||
|
||||
if (campaign.Map == null)
|
||||
{
|
||||
GameStarted = true;
|
||||
DebugConsole.ThrowError("Failed to start campaign round (campaign map not loaded yet).");
|
||||
@@ -1480,30 +1516,14 @@ namespace Barotrauma.Networking
|
||||
yield return CoroutineStatus.Failure;
|
||||
}
|
||||
|
||||
if (NetIdUtils.IdMoreRecent(campaignSaveID, campaign.PendingSaveID))
|
||||
{
|
||||
campaign.PendingSaveID = campaignSaveID;
|
||||
DateTime saveFileTimeOut = DateTime.Now + new TimeSpan(0,0,60);
|
||||
while (NetIdUtils.IdMoreRecent(campaignSaveID, campaign.LastSaveID))
|
||||
{
|
||||
if (DateTime.Now > saveFileTimeOut)
|
||||
{
|
||||
GameStarted = true;
|
||||
DebugConsole.ThrowError("Failed to start campaign round (timed out while waiting for the up-to-date save file).");
|
||||
GameMain.NetLobbyScreen.Select();
|
||||
roundInitStatus = RoundInitStatus.Interrupted;
|
||||
yield return CoroutineStatus.Failure;
|
||||
}
|
||||
yield return new WaitForSeconds(0.1f);
|
||||
}
|
||||
}
|
||||
|
||||
campaign.Map.SelectLocation(selectedLocationIndex);
|
||||
|
||||
LevelData levelData = nextLocationIndex > -1 ?
|
||||
campaign.Map.Locations[nextLocationIndex].LevelData :
|
||||
campaign.Map.Connections[nextConnectionIndex].LevelData;
|
||||
|
||||
debugStartGameCampaignSaveID = campaign.LastSaveID;
|
||||
|
||||
if (roundSummary != null)
|
||||
{
|
||||
loadTask = campaign.SelectSummaryScreen(roundSummary, levelData, mirrorLevel, null);
|
||||
@@ -1697,7 +1717,7 @@ namespace Barotrauma.Networking
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
if (GameMain.GameSession != null) { GameMain.GameSession.EndRound(endMessage, traitorResults, transitionType); }
|
||||
GameMain.GameSession?.EndRound(endMessage, traitorResults, transitionType);
|
||||
|
||||
ServerSettings.ServerDetailsChanged = true;
|
||||
|
||||
@@ -2587,31 +2607,24 @@ namespace Barotrauma.Networking
|
||||
public void WriteCharacterInfo(IWriteMessage msg, string newName = null)
|
||||
{
|
||||
msg.WriteBoolean(characterInfo == null);
|
||||
msg.WritePadBits();
|
||||
if (characterInfo == null) { return; }
|
||||
|
||||
msg.WriteString(newName ?? string.Empty);
|
||||
var head = characterInfo.Head;
|
||||
|
||||
msg.WriteByte((byte)characterInfo.Head.Preset.TagSet.Count);
|
||||
foreach (Identifier tag in characterInfo.Head.Preset.TagSet)
|
||||
{
|
||||
msg.WriteIdentifier(tag);
|
||||
}
|
||||
msg.WriteByte((byte)characterInfo.Head.HairIndex);
|
||||
msg.WriteByte((byte)characterInfo.Head.BeardIndex);
|
||||
msg.WriteByte((byte)characterInfo.Head.MoustacheIndex);
|
||||
msg.WriteByte((byte)characterInfo.Head.FaceAttachmentIndex);
|
||||
msg.WriteColorR8G8B8(characterInfo.Head.SkinColor);
|
||||
msg.WriteColorR8G8B8(characterInfo.Head.HairColor);
|
||||
msg.WriteColorR8G8B8(characterInfo.Head.FacialHairColor);
|
||||
var netInfo = new NetCharacterInfo(
|
||||
NewName: newName ?? string.Empty,
|
||||
Tags: head.Preset.TagSet.ToImmutableArray(),
|
||||
HairIndex: (byte)head.HairIndex,
|
||||
BeardIndex: (byte)head.BeardIndex,
|
||||
MoustacheIndex: (byte)head.MoustacheIndex,
|
||||
FaceAttachmentIndex: (byte)head.FaceAttachmentIndex,
|
||||
SkinColor: head.SkinColor,
|
||||
HairColor: head.HairColor,
|
||||
FacialHairColor: head.FacialHairColor,
|
||||
JobVariants: GameMain.NetLobbyScreen.JobPreferences.Select(NetJobVariant.FromJobVariant).ToImmutableArray());
|
||||
|
||||
var jobPreferences = GameMain.NetLobbyScreen.JobPreferences;
|
||||
int count = Math.Min(jobPreferences.Count, 3);
|
||||
msg.WriteByte((byte)count);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
msg.WriteIdentifier(jobPreferences[i].Prefab.Identifier);
|
||||
msg.WriteByte((byte)jobPreferences[i].Variant);
|
||||
}
|
||||
msg.WriteNetSerializableStruct(netInfo);
|
||||
}
|
||||
|
||||
public void Vote(VoteType voteType, object data)
|
||||
@@ -2864,12 +2877,14 @@ namespace Barotrauma.Networking
|
||||
ClientPeer.Send(msg, DeliveryMethod.Reliable);
|
||||
}
|
||||
|
||||
public bool SpectateClicked(GUIButton button, object userData)
|
||||
public bool SpectateClicked(GUIButton button, object _)
|
||||
{
|
||||
MultiPlayerCampaign campaign =
|
||||
MultiPlayerCampaign campaign =
|
||||
GameMain.NetLobbyScreen.SelectedMode == GameMain.GameSession?.GameMode.Preset ?
|
||||
GameMain.GameSession?.GameMode as MultiPlayerCampaign : null;
|
||||
if (campaign != null && campaign.LastSaveID < campaign.PendingSaveID)
|
||||
|
||||
if (FileReceiver.ActiveTransfers.Any(t => t.FileType == FileTransferType.CampaignSave) ||
|
||||
(campaign != null && NetIdUtils.IdMoreRecent(campaign.PendingSaveID, campaign.LastSaveID)))
|
||||
{
|
||||
new GUIMessageBox("", TextManager.Get("campaignfiletransferinprogress"));
|
||||
return false;
|
||||
|
||||
@@ -92,10 +92,10 @@ namespace Barotrauma.Networking
|
||||
Name = GameMain.Client.Name,
|
||||
OwnerKey = ownerKey,
|
||||
SteamId = SteamManager.GetSteamId().Select(id => (AccountId)id),
|
||||
SteamAuthTicket = steamAuthTicket switch
|
||||
SteamAuthTicket = steamAuthTicket?.Data switch
|
||||
{
|
||||
null => Option<byte[]>.None(),
|
||||
var ticket => Option<byte[]>.Some(ticket.Data)
|
||||
var ticketData => Option<byte[]>.Some(ticketData)
|
||||
},
|
||||
GameVersion = GameMain.Version.ToString(),
|
||||
Language = GameSettings.CurrentConfig.Language.Value
|
||||
|
||||
+18
-1
@@ -111,8 +111,25 @@ namespace Barotrauma.Networking
|
||||
? NetworkConnection.TimeoutThresholdInGame
|
||||
: NetworkConnection.TimeoutThreshold;
|
||||
|
||||
IReadMessage inc = new ReadOnlyMessage(data, false, 0, dataLength, ServerConnection);
|
||||
try
|
||||
{
|
||||
IReadMessage inc = new ReadOnlyMessage(data, false, 0, dataLength, ServerConnection);
|
||||
ProcessP2PData(inc);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
string errorMsg = $"Client failed to read an incoming P2P message. {{{e}}}\n{e.StackTrace.CleanupStackTrace()}";
|
||||
GameAnalyticsManager.AddErrorEventOnce($"SteamP2PClientPeer.OnP2PData:ClientReadException{e.TargetSite}", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
#else
|
||||
if (GameSettings.CurrentConfig.VerboseLogging) { DebugConsole.ThrowError(errorMsg); }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessP2PData(IReadMessage inc)
|
||||
{
|
||||
var (deliveryMethod, packetHeader, initialization) = INetSerializableStruct.Read<PeerPacketHeaders>(inc);
|
||||
|
||||
if (!packetHeader.IsServerMessage()) { return; }
|
||||
|
||||
+22
-5
@@ -141,15 +141,31 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (remotePeer.DisconnectTime != null) { return; }
|
||||
|
||||
var peerPacketHeaders = INetSerializableStruct.Read<PeerPacketHeaders>(inc);
|
||||
|
||||
PacketHeader packetHeader = peerPacketHeaders.PacketHeader;
|
||||
try
|
||||
{
|
||||
ProcessP2PData(steamId, remotePeer, inc);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
string errorMsg = $"Server failed to read an incoming P2P message. {{{e}}}\n{e.StackTrace.CleanupStackTrace()}";
|
||||
GameAnalyticsManager.AddErrorEventOnce($"SteamP2POwnerPeer.OnP2PData:OwnerReadException{e.TargetSite}", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
#else
|
||||
if (GameSettings.CurrentConfig.VerboseLogging) { DebugConsole.ThrowError(errorMsg); }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (!remotePeer.Authenticated && !remotePeer.Authenticating && packetHeader.IsConnectionInitializationStep())
|
||||
private void ProcessP2PData(ulong steamId, RemotePeer remotePeer, IReadMessage inc)
|
||||
{
|
||||
var (deliveryMethod, packetHeader, connectionInitialization) = INetSerializableStruct.Read<PeerPacketHeaders>(inc);
|
||||
|
||||
if (remotePeer is { Authenticated: false, Authenticating: false } && packetHeader.IsConnectionInitializationStep())
|
||||
{
|
||||
remotePeer.DisconnectTime = null;
|
||||
|
||||
ConnectionInitialization initialization = peerPacketHeaders.Initialization ?? throw new Exception("Initialization step missing");
|
||||
ConnectionInitialization initialization = connectionInitialization ?? throw new Exception("Initialization step missing");
|
||||
if (initialization == ConnectionInitialization.SteamTicketAndVersion)
|
||||
{
|
||||
remotePeer.Authenticating = true;
|
||||
@@ -181,6 +197,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
ForwardToServerProcess(outMsg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
|
||||
@@ -428,7 +428,7 @@ namespace Barotrauma.Networking
|
||||
if (Enum.TryParse(valueGetter("playstyle"), out PlayStyle playStyle)) { PlayStyle = playStyle; }
|
||||
Language = valueGetter("language")?.ToLanguageIdentifier() ?? LanguageIdentifier.None;
|
||||
|
||||
ContentPackages = ExtractContentPackageInfo(valueGetter).ToImmutableArray();
|
||||
ContentPackages = ExtractContentPackageInfo(ServerName, valueGetter).ToImmutableArray();
|
||||
|
||||
bool getBool(string key)
|
||||
{
|
||||
@@ -437,8 +437,34 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
private static ContentPackageInfo[] ExtractContentPackageInfo(Func<string, string?> valueGetter)
|
||||
private static ContentPackageInfo[] ExtractContentPackageInfo(string serverName, Func<string, string?> valueGetter)
|
||||
{
|
||||
//workaround to ServerRules queries truncating the values to 255 bytes
|
||||
int individualPackageIndex = 0;
|
||||
string? individualPackage = valueGetter($"contentpackage{individualPackageIndex}");
|
||||
if (!individualPackage.IsNullOrEmpty())
|
||||
{
|
||||
List<ContentPackageInfo> contentPackages = new List<ContentPackageInfo>();
|
||||
do
|
||||
{
|
||||
string[] splitPackageInfo = individualPackage.Split(',');
|
||||
if (splitPackageInfo.Length != 3)
|
||||
{
|
||||
DebugConsole.Log(
|
||||
$"Error in a server's content package list: malformed content package info ({individualPackage}).");
|
||||
return Array.Empty<ContentPackageInfo>();
|
||||
}
|
||||
string name = splitPackageInfo[0];
|
||||
string hash = splitPackageInfo[1];
|
||||
ulong.TryParse(splitPackageInfo[2], out ulong id);
|
||||
contentPackages.Add(new ContentPackageInfo(name, hash, Option<ContentPackageId>.Some(new SteamWorkshopId(id))));
|
||||
|
||||
individualPackageIndex++;
|
||||
individualPackage = valueGetter($"contentpackage{individualPackageIndex}");
|
||||
} while (!individualPackage.IsNullOrEmpty());
|
||||
return contentPackages.ToArray();
|
||||
}
|
||||
|
||||
string? joinedNames = valueGetter("contentpackage");
|
||||
string? joinedHashes = valueGetter("contentpackagehash");
|
||||
string? joinedWorkshopIds = valueGetter("contentpackageid");
|
||||
@@ -448,9 +474,11 @@ namespace Barotrauma.Networking
|
||||
#warning TODO: genericize
|
||||
ulong[] contentPackageIds = joinedWorkshopIds.IsNullOrEmpty() ? new ulong[1] : SteamManager.ParseWorkshopIds(joinedWorkshopIds).ToArray();
|
||||
|
||||
if (contentPackageNames.Length != contentPackageHashes.Length
|
||||
|| contentPackageHashes.Length != contentPackageIds.Length)
|
||||
if (contentPackageNames.Length != contentPackageHashes.Length || contentPackageHashes.Length != contentPackageIds.Length)
|
||||
{
|
||||
DebugConsole.Log(
|
||||
$"The number of names, hashes and Workshop IDs on server \"{serverName}\"" +
|
||||
$" doesn't match: {contentPackageNames.Length} names ({string.Join(", ", contentPackageNames)}), {contentPackageHashes.Length} hashes, {contentPackageIds.Length} ids)");
|
||||
return Array.Empty<ContentPackageInfo>();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
private static Option<ServerInfo> InfoFromListEntry(Steamworks.Data.ServerInfo entry) =>
|
||||
entry.Name.IsNullOrEmpty()
|
||||
entry.Name.IsNullOrEmpty() || entry.Address is null
|
||||
? Option<ServerInfo>.None()
|
||||
: Option<ServerInfo>.Some(new ServerInfo(new LidgrenEndpoint(entry.Address, entry.ConnectionPort))
|
||||
{
|
||||
|
||||
+2
-2
@@ -71,10 +71,10 @@ namespace Barotrauma
|
||||
|
||||
foreach (var lobby in lobbies)
|
||||
{
|
||||
string lobbyOwnerStr = lobby.GetData("lobbyowner");
|
||||
string lobbyOwnerStr = lobby.GetData("lobbyowner") ?? "";
|
||||
lobbyQuery = lobbyQuery.WithoutKeyValue("lobbyowner", lobbyOwnerStr);
|
||||
|
||||
string serverName = lobby.GetData("name");
|
||||
string serverName = lobby.GetData("name") ?? "";
|
||||
if (string.IsNullOrEmpty(serverName)) { continue; }
|
||||
|
||||
var ownerId = SteamId.Parse(lobbyOwnerStr);
|
||||
|
||||
@@ -9,6 +9,9 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
partial class ServerSettings : ISerializableEntity
|
||||
{
|
||||
private static readonly LocalizedString packetAmountTooltip = TextManager.Get("ServerSettingsMaxPacketAmountTooltip");
|
||||
private static readonly RichString packetAmountTooltipWarning = RichString.Rich($"{packetAmountTooltip}\n\n‖color:gui.red‖{TextManager.Get("PacketLimitWarning")}‖end‖");
|
||||
|
||||
partial class NetPropertyData
|
||||
{
|
||||
public GUIComponent GUIComponent;
|
||||
@@ -28,7 +31,15 @@ namespace Barotrauma.Networking
|
||||
if (GUIComponent == null) return null;
|
||||
else if (GUIComponent is GUITickBox tickBox) return tickBox.Selected;
|
||||
else if (GUIComponent is GUITextBox textBox) return textBox.Text;
|
||||
else if (GUIComponent is GUIScrollBar scrollBar) return scrollBar.BarScrollValue;
|
||||
else if (GUIComponent is GUIScrollBar scrollBar)
|
||||
{
|
||||
if (property.PropertyType == typeof(int))
|
||||
{
|
||||
return (int)MathF.Floor(scrollBar.BarScrollValue);
|
||||
}
|
||||
|
||||
return scrollBar.BarScrollValue;
|
||||
}
|
||||
else if (GUIComponent is GUIRadioButtonGroup radioButtonGroup) return radioButtonGroup.Selected;
|
||||
else if (GUIComponent is GUIDropDown dropdown) return dropdown.SelectedData;
|
||||
else if (GUIComponent is GUINumberInput numInput)
|
||||
@@ -44,9 +55,9 @@ namespace Barotrauma.Networking
|
||||
else if (GUIComponent is GUITextBox textBox) textBox.Text = (string)value;
|
||||
else if (GUIComponent is GUIScrollBar scrollBar)
|
||||
{
|
||||
if (value.GetType() == typeof(int))
|
||||
if (value is int i)
|
||||
{
|
||||
scrollBar.BarScrollValue = (int)value;
|
||||
scrollBar.BarScrollValue = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -941,11 +952,58 @@ namespace Barotrauma.Networking
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
GUILayoutGroup karmaAndDosLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.2f), antigriefingTab.RectTransform), isHorizontal: false);
|
||||
GUILayoutGroup lowerLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), karmaAndDosLayout.RectTransform), isHorizontal: true);
|
||||
GUILayoutGroup upperLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), karmaAndDosLayout.RectTransform), isHorizontal: true);
|
||||
|
||||
// karma --------------------------------------------------------------------------
|
||||
|
||||
var karmaBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), antigriefingTab.RectTransform), TextManager.Get("ServerSettingsUseKarma"));
|
||||
var karmaBox = new GUITickBox(new RectTransform(new Vector2(0.5f, 1f), upperLayout.RectTransform), TextManager.Get("ServerSettingsUseKarma"));
|
||||
GetPropertyData(nameof(KarmaEnabled)).AssignGUIComponent(karmaBox);
|
||||
|
||||
var enableDosProtection = new GUITickBox(new RectTransform(new Vector2(0.5f, 1f), upperLayout.RectTransform), TextManager.Get("ServerSettingsEnableDoSProtection"))
|
||||
{
|
||||
ToolTip = TextManager.Get("ServerSettingsEnableDoSProtectionTooltip")
|
||||
};
|
||||
GetPropertyData(nameof(EnableDoSProtection)).AssignGUIComponent(enableDosProtection);
|
||||
|
||||
CreateLabeledSlider(lowerLayout, "ServerSettingsMaxPacketAmount", out GUIScrollBar maxPacketSlider, out GUITextBlock maxPacketSliderLabel);
|
||||
LocalizedString maxPacketCountLabel = maxPacketSliderLabel.Text;
|
||||
maxPacketSlider.Step = 0.001f;
|
||||
maxPacketSlider.Range = new Vector2(PacketLimitMin, PacketLimitMax);
|
||||
maxPacketSlider.ToolTip = packetAmountTooltip;
|
||||
maxPacketSlider.OnMoved = (scrollBar, _) =>
|
||||
{
|
||||
GUITextBlock textBlock = (GUITextBlock)scrollBar.UserData;
|
||||
int value = (int)MathF.Floor(scrollBar.BarScrollValue);
|
||||
|
||||
LocalizedString valueText = value > PacketLimitMin
|
||||
? value.ToString()
|
||||
: TextManager.Get("ServerSettingsNoLimit");
|
||||
|
||||
switch (value)
|
||||
{
|
||||
case <= PacketLimitMin:
|
||||
textBlock.TextColor = GUIStyle.Green;
|
||||
scrollBar.ToolTip = packetAmountTooltip;
|
||||
break;
|
||||
case < PacketLimitWarning:
|
||||
textBlock.TextColor = GUIStyle.Red;
|
||||
scrollBar.ToolTip = packetAmountTooltipWarning;
|
||||
break;
|
||||
default:
|
||||
textBlock.TextColor = GUIStyle.TextColorNormal;
|
||||
scrollBar.ToolTip = packetAmountTooltip;
|
||||
break;
|
||||
}
|
||||
|
||||
textBlock.Text = $"{maxPacketCountLabel} {valueText}";
|
||||
return true;
|
||||
};
|
||||
GetPropertyData(nameof(MaxPacketAmount)).AssignGUIComponent(maxPacketSlider);
|
||||
maxPacketSlider.OnMoved(maxPacketSlider, maxPacketSlider.BarScroll);
|
||||
|
||||
karmaPresetDD = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.05f), antigriefingTab.RectTransform));
|
||||
foreach (string karmaPreset in GameMain.NetworkMember.KarmaManager.Presets.Keys)
|
||||
{
|
||||
|
||||
@@ -276,6 +276,8 @@ namespace Barotrauma.Networking
|
||||
if (GameMain.Client?.Character != null)
|
||||
{
|
||||
var messageType = !ForceLocal && ChatMessage.CanUseRadio(GameMain.Client.Character, out _) ? ChatMessageType.Radio : ChatMessageType.Default;
|
||||
if (GameMain.Client.Character.IsDead) { messageType = ChatMessageType.Dead; }
|
||||
|
||||
GameMain.Client.Character.ShowSpeechBubble(1.25f, ChatMessage.MessageColor[(int)messageType]);
|
||||
}
|
||||
//encode audio and enqueue it
|
||||
|
||||
@@ -146,7 +146,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
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)
|
||||
if (client.Character != null && !client.Character.Removed && !client.Character.IsDead)
|
||||
{
|
||||
Vector3 clientPos = new Vector3(client.Character.WorldPosition.X, client.Character.WorldPosition.Y, 0.0f);
|
||||
Vector3 listenerPos = GameMain.SoundManager.ListenerPosition;
|
||||
|
||||
@@ -169,7 +169,10 @@ namespace Barotrauma
|
||||
sb.AppendLine("Language: " + GameSettings.CurrentConfig.Language);
|
||||
if (ContentPackageManager.EnabledPackages.All != null)
|
||||
{
|
||||
sb.AppendLine("Selected content packages: " + (!ContentPackageManager.EnabledPackages.All.Any() ? "None" : string.Join(", ", ContentPackageManager.EnabledPackages.All.Select(c => c.Name))));
|
||||
sb.AppendLine("Selected content packages: " +
|
||||
(!ContentPackageManager.EnabledPackages.All.Any() ?
|
||||
"None" :
|
||||
string.Join(", ", ContentPackageManager.EnabledPackages.All.Select(c => $"{c.Name} ({c.Hash?.ShortRepresentation ?? "unknown"})"))));
|
||||
}
|
||||
sb.AppendLine("Level seed: " + ((Level.Loaded == null) ? "no level loaded" : Level.Loaded.Seed));
|
||||
sb.AppendLine("Loaded submarine: " + ((Submarine.MainSub == null) ? "None" : Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash + ")"));
|
||||
|
||||
+4
-8
@@ -18,7 +18,7 @@ namespace Barotrauma
|
||||
public CharacterInfo.AppearanceCustomizationMenu[] CharacterMenus { get; private set; }
|
||||
|
||||
private GUIButton nextButton;
|
||||
private GUILayoutGroup characterInfoColumns;
|
||||
private GUIListBox characterInfoColumns;
|
||||
|
||||
public SinglePlayerCampaignSetupUI(GUIComponent newGameContainer, GUIComponent loadGameContainer, IEnumerable<SubmarineInfo> submarines, IEnumerable<CampaignMode.SaveInfo> saveFiles = null)
|
||||
: base(newGameContainer, loadGameContainer)
|
||||
@@ -249,11 +249,7 @@ namespace Barotrauma
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.04f), secondPageLayout.RectTransform),
|
||||
TextManager.Get("Crew"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.TopLeft);
|
||||
|
||||
characterInfoColumns = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.86f), secondPageLayout.RectTransform), isHorizontal: true)
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.01f
|
||||
};
|
||||
characterInfoColumns = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.86f), secondPageLayout.RectTransform), isHorizontal: true);
|
||||
|
||||
var secondPageButtonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.08f),
|
||||
secondPageLayout.RectTransform), childAnchor: Anchor.BottomLeft, isHorizontal: true)
|
||||
@@ -306,8 +302,8 @@ namespace Barotrauma
|
||||
|
||||
for (int i = 0; i < characterInfos.Count; i++)
|
||||
{
|
||||
var subLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f / characterInfos.Count, 1.0f),
|
||||
characterInfoColumns.RectTransform));
|
||||
var subLayout = new GUILayoutGroup(new RectTransform(new Vector2(Math.Max(1.0f / characterInfos.Count, 0.33f), 1.0f),
|
||||
characterInfoColumns.Content.RectTransform));
|
||||
|
||||
var (characterInfo, job) = characterInfos[i];
|
||||
|
||||
|
||||
@@ -202,18 +202,21 @@ namespace Barotrauma
|
||||
case CampaignMode.InteractionType.PurchaseSub:
|
||||
submarineSelection?.Update();
|
||||
break;
|
||||
|
||||
case CampaignMode.InteractionType.Crew:
|
||||
CrewManagement?.Update();
|
||||
break;
|
||||
|
||||
case CampaignMode.InteractionType.Store:
|
||||
Store?.Update(deltaTime);
|
||||
break;
|
||||
|
||||
break;
|
||||
case CampaignMode.InteractionType.MedicalClinic:
|
||||
MedicalClinic?.Update(deltaTime);
|
||||
break;
|
||||
case CampaignMode.InteractionType.Map:
|
||||
if (StartButton != null)
|
||||
{
|
||||
StartButton.Enabled = CampaignMode.AllowedToManageCampaign(ClientPermissions.ManageMap) && Character.Controlled is { IsIncapacitated: false };
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -568,7 +571,6 @@ namespace Barotrauma
|
||||
StartButton.Visible = false;
|
||||
missionList.Enabled = false;
|
||||
}
|
||||
//locationInfoPanel?.UpdateAuto(1.0f);
|
||||
}
|
||||
|
||||
public void SelectTab(CampaignMode.InteractionType tab, Character npc = null)
|
||||
|
||||
@@ -343,7 +343,7 @@ namespace Barotrauma
|
||||
editorContainer.ClearChildren();
|
||||
paramsList.Content.ClearChildren();
|
||||
|
||||
foreach (LevelGenerationParams genParams in LevelGenerationParams.LevelParams)
|
||||
foreach (LevelGenerationParams genParams in LevelGenerationParams.LevelParams.OrderBy(p => p.Name))
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), paramsList.Content.RectTransform) { MinSize = new Point(0, 20) },
|
||||
genParams.Identifier.Value)
|
||||
@@ -359,7 +359,7 @@ namespace Barotrauma
|
||||
editorContainer.ClearChildren();
|
||||
caveParamsList.Content.ClearChildren();
|
||||
|
||||
foreach (CaveGenerationParams genParams in CaveGenerationParams.CaveParams)
|
||||
foreach (CaveGenerationParams genParams in CaveGenerationParams.CaveParams.OrderBy(p => p.Name))
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), caveParamsList.Content.RectTransform) { MinSize = new Point(0, 20) },
|
||||
genParams.Name)
|
||||
@@ -375,7 +375,7 @@ namespace Barotrauma
|
||||
editorContainer.ClearChildren();
|
||||
ruinParamsList.Content.ClearChildren();
|
||||
|
||||
foreach (RuinGenerationParams genParams in RuinGenerationParams.RuinParams)
|
||||
foreach (RuinGenerationParams genParams in RuinGenerationParams.RuinParams.OrderBy(p => p.Identifier))
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), ruinParamsList.Content.RectTransform) { MinSize = new Point(0, 20) },
|
||||
genParams.Name)
|
||||
@@ -391,7 +391,7 @@ namespace Barotrauma
|
||||
editorContainer.ClearChildren();
|
||||
outpostParamsList.Content.ClearChildren();
|
||||
|
||||
foreach (OutpostGenerationParams genParams in OutpostGenerationParams.OutpostParams)
|
||||
foreach (OutpostGenerationParams genParams in OutpostGenerationParams.OutpostParams.OrderBy(p => p.Name))
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), outpostParamsList.Content.RectTransform) { MinSize = new Point(0, 20) },
|
||||
genParams.Name)
|
||||
|
||||
@@ -2244,9 +2244,9 @@ namespace Barotrauma
|
||||
List<ContextMenuOption> rankOptions = new List<ContextMenuOption>();
|
||||
foreach (PermissionPreset rank in PermissionPreset.List)
|
||||
{
|
||||
rankOptions.Add(new ContextMenuOption(rank.Name, isEnabled: true, onSelected: () =>
|
||||
rankOptions.Add(new ContextMenuOption(rank.DisplayName, isEnabled: true, onSelected: () =>
|
||||
{
|
||||
LocalizedString label = TextManager.GetWithVariables(rank.Permissions == ClientPermissions.None ? "clearrankprompt" : "giverankprompt", ("[user]", client.Name), ("[rank]", rank.Name));
|
||||
LocalizedString label = TextManager.GetWithVariables(rank.Permissions == ClientPermissions.None ? "clearrankprompt" : "giverankprompt", ("[user]", client.Name), ("[rank]", rank.DisplayName));
|
||||
GUIMessageBox msgBox = new GUIMessageBox(string.Empty, label, new[] { TextManager.Get("Yes"), TextManager.Get("Cancel") });
|
||||
|
||||
msgBox.Buttons[0].OnClicked = delegate
|
||||
@@ -2350,7 +2350,7 @@ namespace Barotrauma
|
||||
};
|
||||
foreach (PermissionPreset permissionPreset in PermissionPreset.List)
|
||||
{
|
||||
rankDropDown.AddItem(permissionPreset.Name, permissionPreset, permissionPreset.Description);
|
||||
rankDropDown.AddItem(permissionPreset.DisplayName, permissionPreset, permissionPreset.Description);
|
||||
}
|
||||
rankDropDown.AddItem(TextManager.Get("CustomRank"), null);
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.IO;
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Steam;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using Barotrauma.IO;
|
||||
using Barotrauma.Steam;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -3546,10 +3546,45 @@ namespace Barotrauma
|
||||
TextManager.Get("LoadingVanillaSubmarineHeader"),
|
||||
TextManager.Get("LoadingVanillaSubmarineDesc"));
|
||||
|
||||
public void LoadSub(SubmarineInfo info)
|
||||
public void LoadSub(SubmarineInfo info, bool checkIdConflicts = true)
|
||||
{
|
||||
Submarine.Unload();
|
||||
Submarine selectedSub = null;
|
||||
|
||||
if (checkIdConflicts)
|
||||
{
|
||||
Dictionary<int, Identifier> entities = new Dictionary<int, Identifier>();
|
||||
foreach (var subElement in info.SubmarineElement.Elements())
|
||||
{
|
||||
int id = subElement.GetAttributeInt("ID", -1);
|
||||
Identifier identifier = subElement.GetAttributeIdentifier("identifier", string.Empty);
|
||||
if (entities.TryGetValue(id, out Identifier duplicateEntity))
|
||||
{
|
||||
var errorMsg = new GUIMessageBox(
|
||||
TextManager.Get("error"),
|
||||
TextManager.GetWithVariables("subeditor.duplicateiderror",
|
||||
("[entity1]", $"{duplicateEntity} ({id})"),
|
||||
("[entity2]", $"{identifier} ({id})")),
|
||||
new LocalizedString[] { TextManager.Get("Yes"), TextManager.Get("No") });
|
||||
errorMsg.Buttons[0].OnClicked = (bnt, userdata) =>
|
||||
{
|
||||
subElement.Remove();
|
||||
LoadSub(info, checkIdConflicts: false);
|
||||
errorMsg.Close();
|
||||
return true;
|
||||
};
|
||||
errorMsg.Buttons[1].OnClicked = (bnt, userdata) =>
|
||||
{
|
||||
LoadSub(info, checkIdConflicts: false);
|
||||
errorMsg.Close();
|
||||
return true;
|
||||
};
|
||||
return;
|
||||
}
|
||||
entities.Add(id, identifier);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
selectedSub = new Submarine(info);
|
||||
@@ -5263,7 +5298,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (PlayerInput.KeyHit(Keys.E) && mode == Mode.Default)
|
||||
if (PlayerInput.KeyHit(InputType.Use) && mode == Mode.Default)
|
||||
{
|
||||
if (dummyCharacter != null)
|
||||
{
|
||||
@@ -5354,6 +5389,16 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
var selectables = MapEntity.mapEntityList.Where(entity => entity.SelectableInEditor).ToList();
|
||||
foreach (var item in Item.ItemList)
|
||||
{
|
||||
//attached wires are not normally selectable (by clicking),
|
||||
//but let's select them manually when selecting all
|
||||
var wire = item.GetComponent<Wire>();
|
||||
if (wire != null && wire.Connections.None(c => c == null) && !selectables.Contains(item))
|
||||
{
|
||||
selectables.Add(item);
|
||||
}
|
||||
}
|
||||
lock (selectables)
|
||||
{
|
||||
selectables.ForEach(MapEntity.AddSelection);
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace Barotrauma.Steam
|
||||
CanBeFocused = false
|
||||
};
|
||||
var itemTitle = new GUITextBlock(new RectTransform(Vector2.One, itemFrame.RectTransform),
|
||||
text: item.Title);
|
||||
text: item.Title ?? "");
|
||||
var itemDownloadProgress
|
||||
= new GUIProgressBar(new RectTransform((0.5f, 0.75f),
|
||||
itemFrame.RectTransform, Anchor.CenterRight), 0.0f)
|
||||
|
||||
@@ -105,7 +105,8 @@ namespace Barotrauma.Steam
|
||||
|
||||
currentLobby?.SetData("contentpackage", string.Join(",", contentPackages.Select(cp => cp.Name)));
|
||||
currentLobby?.SetData("contentpackagehash", string.Join(",", contentPackages.Select(cp => cp.Hash.StringRepresentation)));
|
||||
currentLobby?.SetData("contentpackageid", string.Join(",", contentPackages.Select(cp => cp.UgcId)));
|
||||
currentLobby?.SetData("contentpackageid", string.Join(",", contentPackages.Select(cp
|
||||
=> cp.UgcId.TryUnwrap(out var ugcId) ? ugcId.StringRepresentation : "")));
|
||||
currentLobby?.SetData("modeselectionmode", serverSettings.ModeSelectionMode.ToString());
|
||||
currentLobby?.SetData("subselectionmode", serverSettings.SubSelectionMode.ToString());
|
||||
currentLobby?.SetData("voicechatenabled", serverSettings.VoiceChatEnabled.ToString());
|
||||
|
||||
@@ -16,6 +16,9 @@ namespace Barotrauma.Steam
|
||||
private static readonly List<Identifier> initializationErrors = new List<Identifier>();
|
||||
public static IReadOnlyList<Identifier> InitializationErrors => initializationErrors;
|
||||
|
||||
private static bool IsInitializedProjectSpecific
|
||||
=> Steamworks.SteamClient.IsValid && Steamworks.SteamClient.IsLoggedOn;
|
||||
|
||||
private static void InitializeProjectSpecific()
|
||||
{
|
||||
if (IsInitialized) { return; }
|
||||
@@ -23,7 +26,6 @@ namespace Barotrauma.Steam
|
||||
try
|
||||
{
|
||||
Steamworks.SteamClient.Init(AppID, false);
|
||||
IsInitialized = Steamworks.SteamClient.IsLoggedOn && Steamworks.SteamClient.IsValid;
|
||||
|
||||
if (IsInitialized)
|
||||
{
|
||||
@@ -43,13 +45,11 @@ namespace Barotrauma.Steam
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
IsInitialized = false;
|
||||
initializationErrors.Add("SteamDllNotFound".ToIdentifier());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("SteamManager initialization threw an exception", e);
|
||||
IsInitialized = false;
|
||||
initializationErrors.Add("SteamClientInitFailed".ToIdentifier());
|
||||
}
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ namespace Barotrauma.Steam
|
||||
{
|
||||
await Task.Yield();
|
||||
|
||||
string thumbnailUrl = item.PreviewImageUrl;
|
||||
string? thumbnailUrl = item.PreviewImageUrl;
|
||||
if (thumbnailUrl.IsNullOrWhiteSpace()) { return null; }
|
||||
var client = new RestClient(thumbnailUrl);
|
||||
var request = new RestRequest(".", Method.GET);
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Barotrauma.Steam
|
||||
private string ExtractTitle(ItemOrPackage itemOrPackage)
|
||||
=> itemOrPackage.TryGet(out ContentPackage package)
|
||||
? package.Name
|
||||
: ((Steamworks.Ugc.Item)itemOrPackage).Title;
|
||||
: (((Steamworks.Ugc.Item)itemOrPackage).Title ?? "");
|
||||
|
||||
private void CreateWorkshopItemDetailContainer(
|
||||
GUIFrame parent,
|
||||
@@ -340,6 +340,8 @@ namespace Barotrauma.Steam
|
||||
|
||||
subscribeButton.OnClicked = (button, o) =>
|
||||
{
|
||||
if (!SteamManager.IsInitialized) { return false; }
|
||||
|
||||
if (!workshopItem.IsSubscribed)
|
||||
{
|
||||
workshopItem.Subscribe();
|
||||
@@ -360,6 +362,8 @@ namespace Barotrauma.Steam
|
||||
new RectTransform(Vector2.Zero, subscribeButton.RectTransform),
|
||||
onUpdate: (deltaTime, component) =>
|
||||
{
|
||||
if (!SteamManager.IsInitialized) { return; }
|
||||
|
||||
if (subscribeButtonSprite.Style is { Identifier: { } styleId })
|
||||
{
|
||||
if (workshopItem.IsSubscribed && styleId != minusButton)
|
||||
@@ -380,6 +384,8 @@ namespace Barotrauma.Steam
|
||||
new RectTransform((1.22f, 1.22f), subscribeButtonSprite.RectTransform, Anchor.Center),
|
||||
onDraw: (spriteBatch, component) =>
|
||||
{
|
||||
if (!SteamManager.IsInitialized) { return; }
|
||||
|
||||
bool visible = workshopItem.IsSubscribed
|
||||
&& (workshopItem.IsDownloading
|
||||
|| workshopItem.IsDownloadPending
|
||||
@@ -407,6 +413,8 @@ namespace Barotrauma.Steam
|
||||
},
|
||||
onUpdate: (deltaTime, component) =>
|
||||
{
|
||||
if (!SteamManager.IsInitialized) { return; }
|
||||
|
||||
displayedDownloadAmount = Math.Min(
|
||||
workshopItem.DownloadAmount,
|
||||
MathHelper.Lerp(displayedDownloadAmount, workshopItem.DownloadAmount, 0.05f));
|
||||
@@ -450,7 +458,7 @@ namespace Barotrauma.Steam
|
||||
|
||||
var title = new GUITextBlock(
|
||||
new RectTransform(Vector2.One, itemLayout.RectTransform),
|
||||
workshopItem.Title, font: GUIStyle.Font)
|
||||
workshopItem.Title ?? "", font: GUIStyle.Font)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
@@ -570,7 +578,7 @@ namespace Barotrauma.Steam
|
||||
var titleAndAuthorLayout = new GUILayoutGroup(new RectTransform(Vector2.One, headerLayout.RectTransform));
|
||||
|
||||
var selectedTitle =
|
||||
new GUITextBlock(new RectTransform((1.0f, 0.5f), titleAndAuthorLayout.RectTransform), workshopItem.Title,
|
||||
new GUITextBlock(new RectTransform((1.0f, 0.5f), titleAndAuthorLayout.RectTransform), workshopItem.Title ?? "",
|
||||
font: GUIStyle.LargeFont);
|
||||
|
||||
var author = workshopItem.Owner;
|
||||
@@ -682,9 +690,9 @@ namespace Barotrauma.Steam
|
||||
|
||||
TaskPool.Add($"Request username for {author.Id}", author.RequestInfoAsync(), (t) =>
|
||||
{
|
||||
authorButton.Text = author.Name;
|
||||
authorButton.Text = author.Name ?? "";
|
||||
authorButton.RectTransform.NonScaledSize =
|
||||
((int)(authorButton.Font.MeasureString(author.Name).X + authorPadding.X + authorPadding.Z),
|
||||
((int)(authorButton.Font.MeasureString(author.Name ?? "").X + authorPadding.X + authorPadding.Z),
|
||||
authorButton.RectTransform.NonScaledSize.Y);
|
||||
});
|
||||
|
||||
@@ -769,7 +777,7 @@ namespace Barotrauma.Steam
|
||||
|
||||
var tagsLabel = new GUITextBlock(new RectTransform((1.0f, 0.12f), statsVertical0.RectTransform),
|
||||
TextManager.Get("WorkshopItemTags"), font: GUIStyle.SubHeadingFont);
|
||||
CreateTagsList(workshopItem.Tags.ToIdentifiers(), new RectTransform((0.97f, 0.3f), statsVertical0.RectTransform), canBeFocused: false);
|
||||
CreateTagsList((workshopItem.Tags ?? Array.Empty<string>()).ToIdentifiers(), new RectTransform((0.97f, 0.3f), statsVertical0.RectTransform), canBeFocused: false);
|
||||
#endregion
|
||||
|
||||
var descriptionListBox = new GUIListBox(new RectTransform((1.0f, 0.38f), verticalLayout.RectTransform));
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
internal class LeakyBucket
|
||||
{
|
||||
private readonly Queue<Action> queue;
|
||||
private readonly int capacity;
|
||||
private readonly float cooldownInSeconds;
|
||||
private float timer;
|
||||
|
||||
public LeakyBucket(float cooldownInSeconds, int capacity)
|
||||
{
|
||||
this.cooldownInSeconds = cooldownInSeconds;
|
||||
this.capacity = capacity;
|
||||
queue = new Queue<Action>(capacity);
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
if (timer > 0f)
|
||||
{
|
||||
timer -= deltaTime;
|
||||
return;
|
||||
}
|
||||
|
||||
if (queue.Count is 0) { return; }
|
||||
|
||||
TryDequeue();
|
||||
}
|
||||
|
||||
private void TryDequeue()
|
||||
{
|
||||
timer = cooldownInSeconds;
|
||||
if (queue.TryDequeue(out var action))
|
||||
{
|
||||
action.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryEnqueue(Action item)
|
||||
{
|
||||
if (queue.Count >= capacity) { return false; }
|
||||
queue.Enqueue(item);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,11 +142,17 @@ namespace Barotrauma
|
||||
GameMain.Instance.GraphicsDevice.SetRenderTarget(rt);
|
||||
GameMain.Instance.GraphicsDevice.Clear(Color.Transparent);
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, null, null, null, null, transform);
|
||||
Submarine.Draw(spriteBatch);
|
||||
Submarine.DrawFront(spriteBatch);
|
||||
Submarine.DrawDamageable(spriteBatch, null);
|
||||
spriteBatch.End();
|
||||
DrawBatch(() => Submarine.DrawBack(spriteBatch, true, e => e is Structure s && (e.SpriteDepth >= 0.9f || s.Prefab.BackgroundSprite != null)));
|
||||
DrawBatch(() => Submarine.DrawBack(spriteBatch, true, e => (e is not Structure || e.SpriteDepth < 0.9f)));
|
||||
DrawBatch(() => Submarine.DrawDamageable(spriteBatch, null, editing: true));
|
||||
DrawBatch(() => Submarine.DrawFront(spriteBatch, editing: true));
|
||||
|
||||
void DrawBatch(Action drawAction)
|
||||
{
|
||||
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied, null, null, null, null, transform);
|
||||
drawAction.Invoke();
|
||||
spriteBatch.End();
|
||||
}
|
||||
|
||||
GameMain.Instance.GraphicsDevice.SetRenderTarget(null);
|
||||
GameMain.Instance.GraphicsDevice.Viewport = prevViewport;
|
||||
|
||||
Reference in New Issue
Block a user