Merge branch 'master' of https://github.com/Regalis11/Barotrauma into develop
This commit is contained in:
@@ -16,6 +16,9 @@ csharp_prefer_braces = when_multiline:warning
|
|||||||
csharp_indent_case_contents_when_block = false
|
csharp_indent_case_contents_when_block = false
|
||||||
# CS1591: Missing XML comment for publicly visible type or member
|
# CS1591: Missing XML comment for publicly visible type or member
|
||||||
dotnet_diagnostic.CS1591.severity = none
|
dotnet_diagnostic.CS1591.severity = none
|
||||||
|
# IDE0090: Use 'new(...)'
|
||||||
|
csharp_style_implicit_object_creation_when_type_is_apparent = false
|
||||||
|
dotnet_diagnostic.CA1806.severity = silent
|
||||||
|
|
||||||
[*.{html,xml,csproj}]
|
[*.{html,xml,csproj}]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
|
|||||||
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -1,4 +1,5 @@
|
|||||||
# Declare files that will always have CRLF line endings on checkout.
|
# Declare files that will always have CRLF line endings on checkout.
|
||||||
*.sln text eol=crlf
|
*.sln text eol=crlf
|
||||||
*.cs text eol=crlf
|
*.cs text eol=crlf
|
||||||
*.xml text eol=crlf
|
*.xml text eol=crlf
|
||||||
|
Barotrauma\BarotraumaServer\DedicatedServer.exe text eol=lf
|
||||||
4
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
4
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -52,8 +52,8 @@ body:
|
|||||||
label: Version
|
label: Version
|
||||||
description: Which version of the game did the bug happen in? You can see the current version number in the bottom left corner of your screen in the main menu.
|
description: Which version of the game did the bug happen in? You can see the current version number in the bottom left corner of your screen in the main menu.
|
||||||
options:
|
options:
|
||||||
- 0.20.16.1
|
- 0.21.6.0
|
||||||
- 0.21.5.0 (Unstable)
|
- 0.21.6.0 (Unstable)
|
||||||
- Faction/endgame test branch
|
- Faction/endgame test branch
|
||||||
- Other
|
- Other
|
||||||
validations:
|
validations:
|
||||||
|
|||||||
@@ -154,9 +154,12 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
if (LosFadeIn && clampedTimer / PanDuration > 0.8f)
|
if (LosFadeIn && clampedTimer / PanDuration > 0.8f)
|
||||||
{
|
{
|
||||||
GameMain.LightManager.LosAlpha = ((clampedTimer / PanDuration) - 0.8f) * 5.0f;
|
if (!GameMain.DevMode)
|
||||||
|
{
|
||||||
|
GameMain.LightManager.LosEnabled = true;
|
||||||
|
GameMain.LightManager.LosAlpha = ((clampedTimer / PanDuration) - 0.8f) * 5.0f;
|
||||||
|
}
|
||||||
Lights.LightManager.ViewTarget = prevControlled ?? (targetEntity as Entity);
|
Lights.LightManager.ViewTarget = prevControlled ?? (targetEntity as Entity);
|
||||||
GameMain.LightManager.LosEnabled = true;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
timer += CoroutineManager.DeltaTime;
|
timer += CoroutineManager.DeltaTime;
|
||||||
@@ -170,8 +173,11 @@ namespace Barotrauma
|
|||||||
|
|
||||||
#if CLIENT
|
#if CLIENT
|
||||||
GUI.ScreenOverlayColor = Color.TransparentBlack;
|
GUI.ScreenOverlayColor = Color.TransparentBlack;
|
||||||
GameMain.LightManager.LosEnabled = true;
|
if (!GameMain.DevMode)
|
||||||
GameMain.LightManager.LosAlpha = 1f;
|
{
|
||||||
|
GameMain.LightManager.LosEnabled = true;
|
||||||
|
GameMain.LightManager.LosAlpha = 1f;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (prevControlled != null && !prevControlled.Removed)
|
if (prevControlled != null && !prevControlled.Removed)
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ namespace Barotrauma
|
|||||||
Collider.AngularVelocity = newAngularVelocity;
|
Collider.AngularVelocity = newAngularVelocity;
|
||||||
|
|
||||||
float distSqrd = Vector2.DistanceSquared(newPosition, Collider.SimPosition);
|
float distSqrd = Vector2.DistanceSquared(newPosition, Collider.SimPosition);
|
||||||
float errorTolerance = character.CanMove ? 0.01f : 0.2f;
|
float errorTolerance = character.CanMove && !character.IsRagdolled ? 0.01f : 0.2f;
|
||||||
if (distSqrd > errorTolerance)
|
if (distSqrd > errorTolerance)
|
||||||
{
|
{
|
||||||
if (distSqrd > 10.0f || !character.CanMove)
|
if (distSqrd > 10.0f || !character.CanMove)
|
||||||
@@ -145,6 +145,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
MainLimb.PullJointWorldAnchorB = Collider.SimPosition;
|
MainLimb.PullJointWorldAnchorB = Collider.SimPosition;
|
||||||
MainLimb.PullJointEnabled = true;
|
MainLimb.PullJointEnabled = true;
|
||||||
|
MainLimb.body.LinearVelocity = newVelocity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -442,10 +443,20 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
foreach (Limb limb in Limbs)
|
foreach (Limb limb in Limbs)
|
||||||
{
|
{
|
||||||
if (limb == null || limb.IsSevered || limb.ActiveSprite == null || !limb.DoesFlip) { continue; }
|
if (limb == null || limb.IsSevered || !limb.DoesMirror) { continue; }
|
||||||
Vector2 spriteOrigin = limb.ActiveSprite.Origin;
|
|
||||||
spriteOrigin.X = limb.ActiveSprite.SourceRect.Width - spriteOrigin.X;
|
FlipSprite(limb.DeformSprite?.Sprite ?? limb.Sprite);
|
||||||
limb.ActiveSprite.Origin = spriteOrigin;
|
foreach (var conditionalSprite in limb.ConditionalSprites)
|
||||||
|
{
|
||||||
|
FlipSprite(conditionalSprite.DeformableSprite?.Sprite ?? conditionalSprite.Sprite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void FlipSprite(Sprite sprite)
|
||||||
|
{
|
||||||
|
if (sprite == null) { return; }
|
||||||
|
Vector2 spriteOrigin = sprite.Origin;
|
||||||
|
spriteOrigin.X = sprite.SourceRect.Width - spriteOrigin.X;
|
||||||
|
sprite.Origin = spriteOrigin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -616,7 +616,7 @@ namespace Barotrauma
|
|||||||
return closestItem;
|
return closestItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Character FindCharacterAtPosition(Vector2 mouseSimPos, float maxDist = 150.0f)
|
private Character FindCharacterAtPosition(Vector2 mouseSimPos, float maxDist = MaxHighlightDistance)
|
||||||
{
|
{
|
||||||
Character closestCharacter = null;
|
Character closestCharacter = null;
|
||||||
|
|
||||||
@@ -626,7 +626,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (!CanInteractWith(c, checkVisibility: false) || (c.AnimController?.SimplePhysicsEnabled ?? true)) { continue; }
|
if (!CanInteractWith(c, checkVisibility: false) || (c.AnimController?.SimplePhysicsEnabled ?? true)) { continue; }
|
||||||
|
|
||||||
float dist = Vector2.DistanceSquared(mouseSimPos, c.SimPosition);
|
float dist = c.GetDistanceToClosestLimb(mouseSimPos);
|
||||||
if (dist < closestDist ||
|
if (dist < closestDist ||
|
||||||
(c.CampaignInteractionType != CampaignMode.InteractionType.None && closestCharacter?.CampaignInteractionType == CampaignMode.InteractionType.None && dist * 0.9f < closestDist))
|
(c.CampaignInteractionType != CampaignMode.InteractionType.None && closestCharacter?.CampaignInteractionType == CampaignMode.InteractionType.None && dist * 0.9f < closestDist))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -608,7 +608,8 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 startPos = character.DrawPosition + (character.FocusedCharacter.DrawPosition - character.DrawPosition) * 0.7f;
|
float dist = Vector2.Distance(character.FocusedCharacter.DrawPosition, character.DrawPosition);
|
||||||
|
Vector2 startPos = character.DrawPosition + (character.FocusedCharacter.DrawPosition - character.DrawPosition) / dist * Math.Min(dist, Character.MaxDragDistance);
|
||||||
startPos = cam.WorldToScreen(startPos);
|
startPos = cam.WorldToScreen(startPos);
|
||||||
|
|
||||||
string focusName = character.FocusedCharacter.Info == null ? character.FocusedCharacter.DisplayName : character.FocusedCharacter.Info.DisplayName;
|
string focusName = character.FocusedCharacter.Info == null ? character.FocusedCharacter.DisplayName : character.FocusedCharacter.Info.DisplayName;
|
||||||
@@ -723,6 +724,8 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
bossHealthBar.TopHealthBar.BarSize = bossHealthBar.SideHealthBar.BarSize = health;
|
bossHealthBar.TopHealthBar.BarSize = bossHealthBar.SideHealthBar.BarSize = health;
|
||||||
|
Color color = bossHealthBar.Character.CharacterHealth.GetAfflictionStrength("poison") > 0 || bossHealthBar.Character.CharacterHealth.GetAfflictionStrength("paralysis") > 0 ? GUIStyle.HealthBarColorPoisoned : GUIStyle.Red;
|
||||||
|
bossHealthBar.TopHealthBar.Color = bossHealthBar.SideHealthBar.Color = color;
|
||||||
|
|
||||||
if (bossHealthBar.Character.Removed || !bossHealthBar.Character.Enabled)
|
if (bossHealthBar.Character.Removed || !bossHealthBar.Character.Enabled)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -938,7 +938,7 @@ namespace Barotrauma
|
|||||||
var headPreset = obj as HeadPreset;
|
var headPreset = obj as HeadPreset;
|
||||||
if (info.Head.Preset != headPreset)
|
if (info.Head.Preset != headPreset)
|
||||||
{
|
{
|
||||||
info.Head = new HeadInfo(info, headPreset)
|
info.Head = new HeadInfo(info, headPreset, info.Head.HairIndex, info.Head.BeardIndex, info.Head.MoustacheIndex, info.Head.FaceAttachmentIndex)
|
||||||
{
|
{
|
||||||
SkinColor = info.Head.SkinColor,
|
SkinColor = info.Head.SkinColor,
|
||||||
HairColor = info.Head.HairColor,
|
HairColor = info.Head.HairColor,
|
||||||
|
|||||||
@@ -640,8 +640,7 @@ namespace Barotrauma
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
forceAfflictionContainerUpdate = true;
|
forceAfflictionContainerUpdate = true;
|
||||||
currentDisplayedAfflictions = GetAllAfflictions(mergeSameAfflictions: true)
|
currentDisplayedAfflictions = GetAllAfflictions(mergeSameAfflictions: true, predicate: a => a.ShouldShowIcon(Character) && a.Prefab.Icon != null);
|
||||||
.FindAll(a => a.ShouldShowIcon(Character) && a.Prefab.Icon != null);
|
|
||||||
currentDisplayedAfflictions.Sort((a1, a2) =>
|
currentDisplayedAfflictions.Sort((a1, a2) =>
|
||||||
{
|
{
|
||||||
int dmgPerSecond = Math.Sign(a1.DamagePerSecond - a2.DamagePerSecond);
|
int dmgPerSecond = Math.Sign(a1.DamagePerSecond - a2.DamagePerSecond);
|
||||||
@@ -1275,7 +1274,7 @@ namespace Barotrauma
|
|||||||
//displaying an affliction we no longer have -> dirty
|
//displaying an affliction we no longer have -> dirty
|
||||||
foreach ((Affliction affliction, float strength) in displayedAfflictions)
|
foreach ((Affliction affliction, float strength) in displayedAfflictions)
|
||||||
{
|
{
|
||||||
if (!afflictions.Any(a => a.Key == affliction)) { return true; }
|
if (afflictions.None(a => a.Key == affliction && a.Key.ShouldShowIcon(Character))) { return true; }
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2072,6 +2071,8 @@ namespace Barotrauma
|
|||||||
foreach (var periodicEffect in newPeriodicEffects)
|
foreach (var periodicEffect in newPeriodicEffects)
|
||||||
{
|
{
|
||||||
if (!existingAffliction.Prefab.PeriodicEffects.Contains(periodicEffect.effect)) { continue; }
|
if (!existingAffliction.Prefab.PeriodicEffects.Contains(periodicEffect.effect)) { continue; }
|
||||||
|
if (existingAffliction.Strength < periodicEffect.effect.MinStrength) { continue; }
|
||||||
|
if (periodicEffect.effect.MaxStrength > 0 && existingAffliction.Strength > periodicEffect.effect.MaxStrength) { continue; }
|
||||||
//timer has wrapped around, apply the effect
|
//timer has wrapped around, apply the effect
|
||||||
if (periodicEffect.timer - existingAffliction.PeriodicEffectTimers[periodicEffect.effect] > periodicEffect.effect.MinInterval / 2)
|
if (periodicEffect.timer - existingAffliction.PeriodicEffectTimers[periodicEffect.effect] > periodicEffect.effect.MinInterval / 2)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#nullable enable
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
internal static class HealingCooldown
|
||||||
|
{
|
||||||
|
public static float NormalizedCooldown => MathF.Min((float) (DateTimeOffset.UtcNow - OnCooldownUntil).TotalSeconds / CooldownDuration, 0f);
|
||||||
|
public static bool IsOnCooldown => DateTimeOffset.UtcNow < OnCooldownUntil;
|
||||||
|
|
||||||
|
private static DateTimeOffset OnCooldownUntil = DateTimeOffset.MinValue;
|
||||||
|
private const float CooldownDuration = 0.5f;
|
||||||
|
|
||||||
|
public static readonly Identifier MedicalItemTag = new Identifier("medical");
|
||||||
|
|
||||||
|
public static void PutOnCooldown()
|
||||||
|
{
|
||||||
|
OnCooldownUntil = DateTimeOffset.UtcNow.AddSeconds(CooldownDuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ using Microsoft.Xna.Framework.Graphics;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Barotrauma.IO;
|
using Barotrauma.IO;
|
||||||
|
using Barotrauma.Utils;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using SpriteParams = Barotrauma.RagdollParams.SpriteParams;
|
using SpriteParams = Barotrauma.RagdollParams.SpriteParams;
|
||||||
@@ -260,9 +261,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (enableHuskSprite)
|
if (enableHuskSprite)
|
||||||
{
|
{
|
||||||
List<WearableSprite> otherWearablesWithHusk = new List<WearableSprite>() { HuskSprite };
|
OtherWearables.Insert(0, HuskSprite);
|
||||||
otherWearablesWithHusk.AddRange(OtherWearables);
|
|
||||||
OtherWearables = otherWearablesWithHusk;
|
|
||||||
UpdateWearableTypesToHide();
|
UpdateWearableTypesToHide();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -546,7 +545,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
foreach (var affliction in result.Afflictions)
|
foreach (var affliction in result.Afflictions)
|
||||||
{
|
{
|
||||||
if (affliction is AfflictionBleeding)
|
if (affliction is AfflictionBleeding bleeding && bleeding.Prefab.DamageParticles)
|
||||||
{
|
{
|
||||||
bleedingDamage += affliction.GetVitalityDecrease(null);
|
bleedingDamage += affliction.GetVitalityDecrease(null);
|
||||||
}
|
}
|
||||||
@@ -555,7 +554,7 @@ namespace Barotrauma
|
|||||||
float damage = 0;
|
float damage = 0;
|
||||||
foreach (var affliction in result.Afflictions)
|
foreach (var affliction in result.Afflictions)
|
||||||
{
|
{
|
||||||
if (affliction.Prefab.AfflictionType == "damage")
|
if (affliction.Prefab.DamageParticles && affliction.Prefab.AfflictionType == "damage")
|
||||||
{
|
{
|
||||||
damage += affliction.GetVitalityDecrease(null);
|
damage += affliction.GetVitalityDecrease(null);
|
||||||
}
|
}
|
||||||
@@ -732,7 +731,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
bool hideLimb = Hide ||
|
bool hideLimb = Hide ||
|
||||||
OtherWearables.Any(w => w.HideLimb) ||
|
OtherWearables.Any(w => w.HideLimb) ||
|
||||||
wearingItems.Any(w => w != null && w.HideLimb);
|
WearingItems.Any(w => w.HideLimb);
|
||||||
|
|
||||||
bool drawHuskSprite = HuskSprite != null && !wearableTypesToHide.Contains(WearableType.Husk);
|
bool drawHuskSprite = HuskSprite != null && !wearableTypesToHide.Contains(WearableType.Husk);
|
||||||
|
|
||||||
@@ -828,7 +827,7 @@ namespace Barotrauma
|
|||||||
LightSource.LightSpriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipVertically;
|
LightSource.LightSpriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipVertically;
|
||||||
}
|
}
|
||||||
float step = depthStep;
|
float step = depthStep;
|
||||||
WearableSprite onlyDrawable = wearingItems.Find(w => w.HideOtherWearables);
|
WearableSprite onlyDrawable = WearingItems.Find(w => w.HideOtherWearables);
|
||||||
if (Params.MirrorHorizontally)
|
if (Params.MirrorHorizontally)
|
||||||
{
|
{
|
||||||
spriteEffect = spriteEffect == SpriteEffects.None ? SpriteEffects.FlipHorizontally : SpriteEffects.None;
|
spriteEffect = spriteEffect == SpriteEffects.None ? SpriteEffects.FlipHorizontally : SpriteEffects.None;
|
||||||
@@ -965,31 +964,28 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public void UpdateWearableTypesToHide()
|
public void UpdateWearableTypesToHide()
|
||||||
{
|
{
|
||||||
|
alphaClipEffectParams?.Clear();
|
||||||
|
|
||||||
wearableTypeHidingSprites.Clear();
|
wearableTypeHidingSprites.Clear();
|
||||||
if (WearingItems != null && WearingItems.Count > 0)
|
|
||||||
|
void addWearablesFrom(IReadOnlyList<WearableSprite> wearableSprites)
|
||||||
{
|
{
|
||||||
|
if (wearableSprites.Count <= 0) { return; }
|
||||||
|
|
||||||
wearableTypeHidingSprites.AddRange(
|
wearableTypeHidingSprites.AddRange(
|
||||||
WearingItems.FindAll(w => w.HideWearablesOfType != null && w.HideWearablesOfType.Count > 0));
|
wearableSprites.Where(w => w.HideWearablesOfType.Count > 0));
|
||||||
}
|
|
||||||
if (OtherWearables != null && OtherWearables.Count > 0)
|
|
||||||
{
|
|
||||||
wearableTypeHidingSprites.AddRange(
|
|
||||||
OtherWearables.FindAll(w => w.HideWearablesOfType != null && w.HideWearablesOfType.Count > 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addWearablesFrom(WearingItems);
|
||||||
|
addWearablesFrom(OtherWearables);
|
||||||
|
|
||||||
wearableTypesToHide.Clear();
|
wearableTypesToHide.Clear();
|
||||||
if (wearableTypeHidingSprites.Count > 0)
|
|
||||||
|
if (wearableTypeHidingSprites.Count <= 0) { return; }
|
||||||
|
|
||||||
|
foreach (WearableSprite sprite in wearableTypeHidingSprites)
|
||||||
{
|
{
|
||||||
foreach (WearableSprite sprite in wearableTypeHidingSprites)
|
wearableTypesToHide.UnionWith(sprite.HideWearablesOfType);
|
||||||
{
|
|
||||||
foreach (WearableType type in sprite.HideWearablesOfType)
|
|
||||||
{
|
|
||||||
if (!wearableTypesToHide.Contains(type))
|
|
||||||
{
|
|
||||||
wearableTypesToHide.Add(type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1071,7 +1067,13 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawWearable(WearableSprite wearable, float depthStep, SpriteBatch spriteBatch, Color color, float alpha, SpriteEffects spriteEffect)
|
private (
|
||||||
|
Color FinalColor,
|
||||||
|
Vector2 Origin,
|
||||||
|
float Rotation,
|
||||||
|
float Scale,
|
||||||
|
float Depth)
|
||||||
|
CalculateDrawParameters(WearableSprite wearable, float depthStep, Color color, float alpha)
|
||||||
{
|
{
|
||||||
var sprite = ActiveSprite;
|
var sprite = ActiveSprite;
|
||||||
if (wearable.InheritSourceRect)
|
if (wearable.InheritSourceRect)
|
||||||
@@ -1163,27 +1165,118 @@ namespace Barotrauma
|
|||||||
float finalAlpha = alpha * wearableColor.A;
|
float finalAlpha = alpha * wearableColor.A;
|
||||||
Color finalColor = color.Multiply(wearableColor);
|
Color finalColor = color.Multiply(wearableColor);
|
||||||
finalColor = new Color(finalColor.R, finalColor.G, finalColor.B, (byte)finalAlpha);
|
finalColor = new Color(finalColor.R, finalColor.G, finalColor.B, (byte)finalAlpha);
|
||||||
wearable.Sprite.Draw(spriteBatch, new Vector2(body.DrawPosition.X, -body.DrawPosition.Y), finalColor, origin, rotation, scale, spriteEffect, depth);
|
|
||||||
|
return (finalColor, origin, rotation, scale, depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
private WearableSprite GetWearableSprite(WearableType type)//, bool random = false)
|
private static Effect alphaClipEffect;
|
||||||
|
private Dictionary<WearableSprite, Dictionary<string, object>> alphaClipEffectParams;
|
||||||
|
private void ApplyAlphaClip(SpriteBatch spriteBatch, WearableSprite wearable, WearableSprite alphaClipper, SpriteEffects spriteEffect)
|
||||||
|
{
|
||||||
|
SpriteRecorder.Command makeCommand(WearableSprite w)
|
||||||
|
{
|
||||||
|
var (_, origin, rotation, scale, _)
|
||||||
|
= CalculateDrawParameters(w, 0f, Color.White, 0f);
|
||||||
|
|
||||||
|
var command = SpriteRecorder.Command.FromTransform(
|
||||||
|
texture: w.Sprite.Texture,
|
||||||
|
pos: new Vector2(body.DrawPosition.X, -body.DrawPosition.Y),
|
||||||
|
srcRect: w.Sprite.SourceRect,
|
||||||
|
color: Color.White,
|
||||||
|
rotation: rotation,
|
||||||
|
origin: origin,
|
||||||
|
scale: new Vector2(scale, scale),
|
||||||
|
effects: spriteEffect,
|
||||||
|
depth: 0f,
|
||||||
|
index: 0);
|
||||||
|
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
void spacesFromCommand(WearableSprite w, SpriteRecorder.Command command, out CoordinateSpace2D textureSpace, out CoordinateSpace2D worldSpace)
|
||||||
|
{
|
||||||
|
var (topLeft, bottomLeft, topRight) = spriteEffect switch
|
||||||
|
{
|
||||||
|
SpriteEffects.None
|
||||||
|
=> (command.VertexTL, command.VertexBL, command.VertexTR),
|
||||||
|
SpriteEffects.FlipHorizontally | SpriteEffects.FlipVertically
|
||||||
|
=> (command.VertexBR, command.VertexTR, command.VertexBL),
|
||||||
|
SpriteEffects.FlipHorizontally
|
||||||
|
=> (command.VertexTR, command.VertexBR, command.VertexTL),
|
||||||
|
SpriteEffects.FlipVertically
|
||||||
|
=> (command.VertexBL, command.VertexTL, command.VertexBR)
|
||||||
|
};
|
||||||
|
|
||||||
|
textureSpace = new CoordinateSpace2D
|
||||||
|
{
|
||||||
|
Origin = topLeft.TextureCoordinate,
|
||||||
|
I = topRight.TextureCoordinate - topLeft.TextureCoordinate,
|
||||||
|
J = bottomLeft.TextureCoordinate - topLeft.TextureCoordinate
|
||||||
|
};
|
||||||
|
|
||||||
|
worldSpace = new CoordinateSpace2D
|
||||||
|
{
|
||||||
|
Origin = topLeft.Position.DiscardZ(),
|
||||||
|
I = topRight.Position.DiscardZ() - topLeft.Position.DiscardZ(),
|
||||||
|
J = bottomLeft.Position.DiscardZ() - topLeft.Position.DiscardZ()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var wearableCommand = makeCommand(wearable);
|
||||||
|
var clipperCommand = makeCommand(alphaClipper);
|
||||||
|
|
||||||
|
spacesFromCommand(wearable, wearableCommand, out var wearableTextureSpace, out var wearableWorldSpace);
|
||||||
|
spacesFromCommand(alphaClipper, clipperCommand, out var clipperTextureSpace, out var clipperWorldSpace);
|
||||||
|
|
||||||
|
var wearableUvToClipperUv =
|
||||||
|
wearableTextureSpace.CanonicalToLocal
|
||||||
|
* wearableWorldSpace.LocalToCanonical
|
||||||
|
* clipperWorldSpace.CanonicalToLocal
|
||||||
|
* clipperTextureSpace.LocalToCanonical;
|
||||||
|
|
||||||
|
alphaClipEffect ??= EffectLoader.Load("Effects/wearableclip");
|
||||||
|
alphaClipEffectParams ??= new Dictionary<WearableSprite, Dictionary<string, object>>();
|
||||||
|
if (!alphaClipEffectParams.ContainsKey(wearable)) { alphaClipEffectParams.Add(wearable, new Dictionary<string, object>()); }
|
||||||
|
|
||||||
|
var paramsToPass = new SpriteBatch.EffectWithParams
|
||||||
|
{
|
||||||
|
Effect = alphaClipEffect,
|
||||||
|
Params = alphaClipEffectParams[wearable]
|
||||||
|
};
|
||||||
|
|
||||||
|
paramsToPass.Params["wearableUvToClipperUv"] = wearableUvToClipperUv;
|
||||||
|
paramsToPass.Params["clipperTexelSize"] = 2f / alphaClipper.Sprite.Texture.Width;
|
||||||
|
paramsToPass.Params["aCutoff"] = 2f / 255f;
|
||||||
|
paramsToPass.Params["xTexture"] = wearable.Sprite.Texture;
|
||||||
|
paramsToPass.Params["xStencil"] = alphaClipper.Sprite.Texture;
|
||||||
|
spriteBatch.SwapEffect(paramsToPass);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawWearable(WearableSprite wearable, float depthStep, SpriteBatch spriteBatch, Color color, float alpha, SpriteEffects spriteEffect)
|
||||||
|
{
|
||||||
|
var (finalColor, origin, rotation, scale, depth)
|
||||||
|
= CalculateDrawParameters(wearable, depthStep, color, alpha);
|
||||||
|
|
||||||
|
var prevEffect = spriteBatch.GetCurrentEffect();
|
||||||
|
var alphaClipper = WearingItems.Find(w => w.AlphaClipOtherWearables);
|
||||||
|
bool shouldApplyAlphaClip = alphaClipper != null && wearable != alphaClipper;
|
||||||
|
if (shouldApplyAlphaClip)
|
||||||
|
{
|
||||||
|
ApplyAlphaClip(spriteBatch, wearable, alphaClipper, spriteEffect);
|
||||||
|
}
|
||||||
|
wearable.Sprite.Draw(spriteBatch, new Vector2(body.DrawPosition.X, -body.DrawPosition.Y), finalColor, origin, rotation, scale, spriteEffect, depth);
|
||||||
|
if (shouldApplyAlphaClip)
|
||||||
|
{
|
||||||
|
spriteBatch.SwapEffect(effect: prevEffect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private WearableSprite GetWearableSprite(WearableType type)
|
||||||
{
|
{
|
||||||
var info = character.Info;
|
var info = character.Info;
|
||||||
if (info == null) { return null; }
|
if (info == null) { return null; }
|
||||||
ContentXElement element;
|
ContentXElement element = info.FilterElements(info.Wearables, info.Head.Preset.TagSet, type)?.FirstOrDefault();
|
||||||
/*if (random)
|
return element != null ? new WearableSprite(element.GetChildElement("sprite"), type) : null;
|
||||||
{
|
|
||||||
element = info.FilterElements(info.Wearables, info.Head.Preset.TagSet)?.GetRandom(Rand.RandSync.ClientOnly);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{*/
|
|
||||||
element = info.FilterElements(info.Wearables, info.Head.Preset.TagSet, type)?.FirstOrDefault();
|
|
||||||
//}
|
|
||||||
if (element != null)
|
|
||||||
{
|
|
||||||
return new WearableSprite(element.GetChildElement("sprite"), type);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void RemoveProjSpecific()
|
partial void RemoveProjSpecific()
|
||||||
@@ -1206,8 +1299,8 @@ namespace Barotrauma
|
|||||||
LightSource?.Remove();
|
LightSource?.Remove();
|
||||||
LightSource = null;
|
LightSource = null;
|
||||||
|
|
||||||
OtherWearables?.ForEach(w => w.Sprite.Remove());
|
OtherWearables.ForEach(w => w.Sprite.Remove());
|
||||||
OtherWearables = null;
|
OtherWearables.Clear();
|
||||||
|
|
||||||
HuskSprite?.Sprite.Remove();
|
HuskSprite?.Sprite.Remove();
|
||||||
HuskSprite = null;
|
HuskSprite = null;
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public Option<ContentPackageId> UgcId = Option<ContentPackageId>.None();
|
public Option<ContentPackageId> UgcId = Option<ContentPackageId>.None();
|
||||||
|
|
||||||
public Option<DateTime> InstallTime = Option<DateTime>.None();
|
public Option<SerializableDateTime> InstallTime = Option<SerializableDateTime>.None();
|
||||||
|
|
||||||
public bool HasFile(File file)
|
public bool HasFile(File file)
|
||||||
=> Files.Any(f =>
|
=> Files.Any(f =>
|
||||||
@@ -120,7 +120,7 @@ namespace Barotrauma
|
|||||||
public void DiscardHashAndInstallTime()
|
public void DiscardHashAndInstallTime()
|
||||||
{
|
{
|
||||||
ExpectedHash = null;
|
ExpectedHash = null;
|
||||||
InstallTime = Option<DateTime>.None();
|
InstallTime = Option<SerializableDateTime>.None();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string IncrementModVersion(string modVersion)
|
public static string IncrementModVersion(string modVersion)
|
||||||
@@ -159,8 +159,8 @@ namespace Barotrauma
|
|||||||
addRootAttribute("gameversion", GameMain.Version);
|
addRootAttribute("gameversion", GameMain.Version);
|
||||||
if (AltNames.Any()) { addRootAttribute("altnames", string.Join(",", AltNames)); }
|
if (AltNames.Any()) { addRootAttribute("altnames", string.Join(",", AltNames)); }
|
||||||
if (ExpectedHash != null) { addRootAttribute("expectedhash", ExpectedHash.StringRepresentation); }
|
if (ExpectedHash != null) { addRootAttribute("expectedhash", ExpectedHash.StringRepresentation); }
|
||||||
if (InstallTime.TryUnwrap(out var installTime)) { addRootAttribute("installtime", ToolBox.Epoch.FromDateTime(installTime)); }
|
if (InstallTime.TryUnwrap(out var installTime)) { addRootAttribute("installtime", installTime); }
|
||||||
|
|
||||||
files.ForEach(f => rootElement.Add(f.ToXElement()));
|
files.ForEach(f => rootElement.Add(f.ToXElement()));
|
||||||
|
|
||||||
doc.Add(rootElement);
|
doc.Add(rootElement);
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ namespace Barotrauma
|
|||||||
&& ugcId is SteamWorkshopId workshopId
|
&& ugcId is SteamWorkshopId workshopId
|
||||||
&& item.Id == workshopId.Value
|
&& item.Id == workshopId.Value
|
||||||
&& p.InstallTime.TryUnwrap(out var installTime)
|
&& p.InstallTime.TryUnwrap(out var installTime)
|
||||||
&& item.LatestUpdateTime <= installTime))
|
&& item.LatestUpdateTime <= installTime.ToUtcValue()))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
if (!needInstalling.Any()) { return Enumerable.Empty<Steamworks.Ugc.Item>(); }
|
if (!needInstalling.Any()) { return Enumerable.Empty<Steamworks.Ugc.Item>(); }
|
||||||
|
|
||||||
|
|||||||
@@ -1130,6 +1130,28 @@ namespace Barotrauma
|
|||||||
});
|
});
|
||||||
AssignRelayToServer("debugdraw", false);
|
AssignRelayToServer("debugdraw", false);
|
||||||
|
|
||||||
|
AssignOnExecute("devmode", (string[] args) =>
|
||||||
|
{
|
||||||
|
if (args.None() || !bool.TryParse(args[0], out bool state))
|
||||||
|
{
|
||||||
|
state = !GameMain.DevMode;
|
||||||
|
}
|
||||||
|
GameMain.DevMode = state;
|
||||||
|
if (GameMain.DevMode)
|
||||||
|
{
|
||||||
|
GameMain.LightManager.LightingEnabled = false;
|
||||||
|
GameMain.LightManager.LosEnabled = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GameMain.LightManager.LightingEnabled = true;
|
||||||
|
GameMain.LightManager.LosEnabled = true;
|
||||||
|
GameMain.LightManager.LosAlpha = 1f;
|
||||||
|
}
|
||||||
|
NewMessage("Dev mode " + (GameMain.DevMode ? "enabled" : "disabled"), Color.White);
|
||||||
|
});
|
||||||
|
AssignRelayToServer("devmode", false);
|
||||||
|
|
||||||
AssignOnExecute("debugdrawlocalization", (string[] args) =>
|
AssignOnExecute("debugdrawlocalization", (string[] args) =>
|
||||||
{
|
{
|
||||||
if (args.None() || !bool.TryParse(args[0], out bool state))
|
if (args.None() || !bool.TryParse(args[0], out bool state))
|
||||||
@@ -1231,12 +1253,14 @@ namespace Barotrauma
|
|||||||
HumanAIController.debugai = !HumanAIController.debugai;
|
HumanAIController.debugai = !HumanAIController.debugai;
|
||||||
if (HumanAIController.debugai)
|
if (HumanAIController.debugai)
|
||||||
{
|
{
|
||||||
|
GameMain.DevMode = true;
|
||||||
GameMain.DebugDraw = true;
|
GameMain.DebugDraw = true;
|
||||||
GameMain.LightManager.LightingEnabled = false;
|
GameMain.LightManager.LightingEnabled = false;
|
||||||
GameMain.LightManager.LosEnabled = false;
|
GameMain.LightManager.LosEnabled = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
GameMain.DevMode = false;
|
||||||
GameMain.DebugDraw = false;
|
GameMain.DebugDraw = false;
|
||||||
GameMain.LightManager.LightingEnabled = true;
|
GameMain.LightManager.LightingEnabled = true;
|
||||||
GameMain.LightManager.LosEnabled = true;
|
GameMain.LightManager.LosEnabled = true;
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ partial class CheckObjectiveAction : BinaryOptionAction
|
|||||||
public enum CheckType
|
public enum CheckType
|
||||||
{
|
{
|
||||||
Added,
|
Added,
|
||||||
Completed
|
Completed,
|
||||||
|
Incomplete
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serialize(CheckType.Completed, IsPropertySaveable.Yes)]
|
[Serialize(CheckType.Completed, IsPropertySaveable.Yes)]
|
||||||
@@ -30,8 +31,13 @@ partial class CheckObjectiveAction : BinaryOptionAction
|
|||||||
{
|
{
|
||||||
CheckType.Added => true,
|
CheckType.Added => true,
|
||||||
CheckType.Completed => segment.IsCompleted,
|
CheckType.Completed => segment.IsCompleted,
|
||||||
|
CheckType.Incomplete => !segment.IsCompleted,
|
||||||
_ => false
|
_ => false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
else if (Type == CheckType.Incomplete)
|
||||||
|
{
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Barotrauma;
|
namespace Barotrauma;
|
||||||
@@ -13,11 +14,22 @@ partial class UIHighlightAction : EventAction
|
|||||||
bool useCircularFlash = false;
|
bool useCircularFlash = false;
|
||||||
if (Id != ElementId.None)
|
if (Id != ElementId.None)
|
||||||
{
|
{
|
||||||
FindAndFlashComponents(c => Equals(Id, c.UserData));
|
var predicate = (GUIComponent c) => c is not null && Equals(Id, c.UserData);
|
||||||
|
if (!FindAndFlashAddedComponents(predicate))
|
||||||
|
{
|
||||||
|
if (predicate(GUIMessageBox.VisibleBox))
|
||||||
|
{
|
||||||
|
Flash(GUIMessageBox.VisibleBox);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FindAndFlashMessageBoxComponents(predicate);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (!EntityIdentifier.IsEmpty)
|
else if (!EntityIdentifier.IsEmpty)
|
||||||
{
|
{
|
||||||
FindAndFlashComponents(c =>
|
FindAndFlashAddedComponents(c =>
|
||||||
c.UserData is MapEntityPrefab mep && mep.Identifier == EntityIdentifier || c.UserData is MapEntity me && me.Prefab.Identifier == EntityIdentifier);
|
c.UserData is MapEntityPrefab mep && mep.Identifier == EntityIdentifier || c.UserData is MapEntity me && me.Prefab.Identifier == EntityIdentifier);
|
||||||
}
|
}
|
||||||
else if (!OrderIdentifier.IsEmpty)
|
else if (!OrderIdentifier.IsEmpty)
|
||||||
@@ -26,26 +38,26 @@ partial class UIHighlightAction : EventAction
|
|||||||
bool foundMinimapNode = false;
|
bool foundMinimapNode = false;
|
||||||
if (!OrderTargetTag.IsEmpty)
|
if (!OrderTargetTag.IsEmpty)
|
||||||
{
|
{
|
||||||
foundMinimapNode = FindAndFlashComponents(c =>
|
foundMinimapNode = FindAndFlashAddedComponents(c =>
|
||||||
c.UserData is CrewManager.MinimapNodeData nodeData && nodeData.Order is Order order &&
|
c.UserData is CrewManager.MinimapNodeData nodeData && nodeData.Order is Order order &&
|
||||||
order.Identifier == OrderIdentifier && order.Option == OrderOption && order.TargetEntity is Item item && item.HasTag(OrderTargetTag));
|
order.Identifier == OrderIdentifier && order.Option == OrderOption && order.TargetEntity is Item item && item.HasTag(OrderTargetTag));
|
||||||
}
|
}
|
||||||
if (!foundMinimapNode)
|
if (!foundMinimapNode)
|
||||||
{
|
{
|
||||||
FindAndFlashComponents(c => c.UserData is Order order && order.Identifier == OrderIdentifier && order.Option == OrderOption,
|
FindAndFlashAddedComponents(c => c.UserData is Order order && order.Identifier == OrderIdentifier && order.Option == OrderOption,
|
||||||
c => c.UserData is Order order && order.Identifier == OrderIdentifier,
|
c => c.UserData is Order order && order.Identifier == OrderIdentifier,
|
||||||
c => Equals(OrderCategory, c.UserData));
|
c => Equals(OrderCategory, c.UserData));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FindAndFlashComponents(params Func<GUIComponent, bool>[] predicates)
|
bool FindAndFlashComponents(IEnumerable<GUIComponent> components, params Func<GUIComponent, bool>[] predicates)
|
||||||
{
|
{
|
||||||
foreach (var predicate in predicates)
|
foreach (var predicate in predicates)
|
||||||
{
|
{
|
||||||
if (HighlightMultiple)
|
if (HighlightMultiple)
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
foreach (var component in GUI.GetAdditions())
|
foreach (var component in components)
|
||||||
{
|
{
|
||||||
if (predicate(component))
|
if (predicate(component))
|
||||||
{
|
{
|
||||||
@@ -55,7 +67,7 @@ partial class UIHighlightAction : EventAction
|
|||||||
};
|
};
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
else if (GUI.GetAdditions().FirstOrDefault(predicate) is GUIComponent component)
|
else if (components.FirstOrDefault(predicate) is GUIComponent component)
|
||||||
{
|
{
|
||||||
Flash(component);
|
Flash(component);
|
||||||
return true;
|
return true;
|
||||||
@@ -64,6 +76,10 @@ partial class UIHighlightAction : EventAction
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FindAndFlashAddedComponents(params Func<GUIComponent, bool>[] predicates) => FindAndFlashComponents(GUI.GetAdditions(), predicates);
|
||||||
|
|
||||||
|
bool FindAndFlashMessageBoxComponents(params Func<GUIComponent, bool>[] predicates) => FindAndFlashComponents(GUIMessageBox.VisibleBox?.GetAllChildren() ?? Enumerable.Empty<GUIComponent>(), predicates);
|
||||||
|
|
||||||
void Flash(GUIComponent component)
|
void Flash(GUIComponent component)
|
||||||
{
|
{
|
||||||
if (component.FlashTimer <= 0.0f)
|
if (component.FlashTimer <= 0.0f)
|
||||||
|
|||||||
@@ -1143,14 +1143,13 @@ namespace Barotrauma
|
|||||||
bool wrap = element.GetAttributeBool("wrap", true);
|
bool wrap = element.GetAttributeBool("wrap", true);
|
||||||
Alignment alignment =
|
Alignment alignment =
|
||||||
element.GetAttributeEnum("alignment", text.Contains('\n') ? Alignment.Left : Alignment.Center);
|
element.GetAttributeEnum("alignment", text.Contains('\n') ? Alignment.Left : Alignment.Center);
|
||||||
GUIFont font;
|
if (!GUIStyle.Fonts.TryGetValue(element.GetAttributeIdentifier("font", "Font"), out GUIFont font))
|
||||||
if (!GUIStyle.Fonts.TryGetValue(element.GetAttributeIdentifier("font", "Font"), out font))
|
|
||||||
{
|
{
|
||||||
font = GUIStyle.Font;
|
font = GUIStyle.Font;
|
||||||
}
|
}
|
||||||
|
|
||||||
var textBlock = new GUITextBlock(RectTransform.Load(element, parent),
|
var textBlock = new GUITextBlock(RectTransform.Load(element, parent),
|
||||||
text, color, font, alignment, wrap: wrap, style: style)
|
RichString.Rich(text), color, font, alignment, wrap: wrap, style: style)
|
||||||
{
|
{
|
||||||
TextScale = scale
|
TextScale = scale
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -236,7 +236,8 @@ namespace Barotrauma
|
|||||||
new GUIButton(new RectTransform(new Vector2(0.3f, 0.5f), buttonContainer.RectTransform, Anchor.Center),
|
new GUIButton(new RectTransform(new Vector2(0.3f, 0.5f), buttonContainer.RectTransform, Anchor.Center),
|
||||||
style: "UIToggleButton")
|
style: "UIToggleButton")
|
||||||
{
|
{
|
||||||
OnClicked = Close
|
OnClicked = Close,
|
||||||
|
UserData = UIHighlightAction.ElementId.MessageBoxCloseButton
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
InputType? closeInput = null;
|
InputType? closeInput = null;
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ namespace Barotrauma
|
|||||||
public readonly static GUIColor HealthBarColorLow = new GUIColor("HealthBarColorLow");
|
public readonly static GUIColor HealthBarColorLow = new GUIColor("HealthBarColorLow");
|
||||||
public readonly static GUIColor HealthBarColorMedium = new GUIColor("HealthBarColorMedium");
|
public readonly static GUIColor HealthBarColorMedium = new GUIColor("HealthBarColorMedium");
|
||||||
public readonly static GUIColor HealthBarColorHigh = new GUIColor("HealthBarColorHigh");
|
public readonly static GUIColor HealthBarColorHigh = new GUIColor("HealthBarColorHigh");
|
||||||
|
public readonly static GUIColor HealthBarColorPoisoned = new GUIColor("HealthBarColorPoisoned");
|
||||||
|
|
||||||
public static Point ItemFrameMargin
|
public static Point ItemFrameMargin
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -615,7 +615,7 @@ namespace Barotrauma
|
|||||||
listBackground.SetCrop(true);
|
listBackground.SetCrop(true);
|
||||||
|
|
||||||
GUIFont font = GUIStyle.Font;
|
GUIFont font = GUIStyle.Font;
|
||||||
info.CreateSpecsWindow(specsFrame, font);
|
info.CreateSpecsWindow(specsFrame, font, includeCrushDepth: true);
|
||||||
descriptionTextBlock.Text = info.Description;
|
descriptionTextBlock.Text = info.Description;
|
||||||
descriptionTextBlock.CalculateHeightFromText();
|
descriptionTextBlock.CalculateHeightFromText();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1766,7 +1766,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
foreach (UpgradePrefab prefab in categoryData.Prefabs)
|
foreach (UpgradePrefab prefab in categoryData.Prefabs)
|
||||||
{
|
{
|
||||||
var frame = UpgradeStore.CreateUpgradeFrame(prefab, categoryData.Category, campaign, new RectTransform(new Vector2(1f, 0.3f), upgradePanel.Content.RectTransform), addBuyButton: false);
|
var frame = UpgradeStore.CreateUpgradeFrame(prefab, categoryData.Category, campaign, new RectTransform(new Vector2(1f, 0.3f), upgradePanel.Content.RectTransform), addBuyButton: false).Frame;
|
||||||
UpgradeStore.UpdateUpgradeEntry(frame, prefab, categoryData.Category, campaign);
|
UpgradeStore.UpdateUpgradeEntry(frame, prefab, categoryData.Category, campaign);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1779,7 +1779,10 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
CurrentSelectMode = GUIListBox.SelectMode.None
|
CurrentSelectMode = GUIListBox.SelectMode.None
|
||||||
};
|
};
|
||||||
sub.Info.CreateSpecsWindow(specsListBox, GUIStyle.Font, includeTitle: false, includeClass: false, includeDescription: true);
|
sub.Info.CreateSpecsWindow(specsListBox, GUIStyle.Font,
|
||||||
|
includeTitle: false,
|
||||||
|
includeClass: false,
|
||||||
|
includeDescription: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -796,7 +796,7 @@ namespace Barotrauma
|
|||||||
CharacterInfo? ownCharacterInfo = Character.Controlled?.Info ?? GameMain.Client?.CharacterInfo;
|
CharacterInfo? ownCharacterInfo = Character.Controlled?.Info ?? GameMain.Client?.CharacterInfo;
|
||||||
if (ownCharacterInfo is null) { return false; }
|
if (ownCharacterInfo is null) { return false; }
|
||||||
|
|
||||||
return info == ownCharacterInfo;
|
return info.GetIdentifierUsingOriginalName() == ownCharacterInfo.GetIdentifierUsingOriginalName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool CanManageTalents(CharacterInfo targetInfo)
|
public static bool CanManageTalents(CharacterInfo targetInfo)
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Barotrauma.Extensions;
|
using Barotrauma.Extensions;
|
||||||
using Barotrauma.Items.Components;
|
using Barotrauma.Items.Components;
|
||||||
@@ -90,6 +89,16 @@ namespace Barotrauma
|
|||||||
Repairs
|
Repairs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum UpgradeStoreUserData
|
||||||
|
{
|
||||||
|
BuyButton,
|
||||||
|
BuyButtonLayout,
|
||||||
|
ProgressBarLayout,
|
||||||
|
IncreaseLabel,
|
||||||
|
PriceLabel,
|
||||||
|
MaterialCostList
|
||||||
|
}
|
||||||
|
|
||||||
public UpgradeStore(CampaignUI campaignUI, GUIComponent parent)
|
public UpgradeStore(CampaignUI campaignUI, GUIComponent parent)
|
||||||
{
|
{
|
||||||
WaitForServerUpdate = false;
|
WaitForServerUpdate = false;
|
||||||
@@ -600,7 +609,7 @@ namespace Barotrauma
|
|||||||
GUILayoutGroup textLayout = new GUILayoutGroup(rectT(0.8f - repairIcon.RectTransform.RelativeSize.X, 1, contentLayout)) { Stretch = true };
|
GUILayoutGroup textLayout = new GUILayoutGroup(rectT(0.8f - repairIcon.RectTransform.RelativeSize.X, 1, contentLayout)) { Stretch = true };
|
||||||
new GUITextBlock(rectT(1, 0, textLayout), title, font: GUIStyle.SubHeadingFont) { CanBeFocused = false, AutoScaleHorizontal = true };
|
new GUITextBlock(rectT(1, 0, textLayout), title, font: GUIStyle.SubHeadingFont) { CanBeFocused = false, AutoScaleHorizontal = true };
|
||||||
new GUITextBlock(rectT(1, 0, textLayout), TextManager.FormatCurrency(price));
|
new GUITextBlock(rectT(1, 0, textLayout), TextManager.FormatCurrency(price));
|
||||||
GUILayoutGroup buyButtonLayout = new GUILayoutGroup(rectT(0.2f, 1, contentLayout), childAnchor: Anchor.Center) { UserData = "buybutton" };
|
GUILayoutGroup buyButtonLayout = new GUILayoutGroup(rectT(0.2f, 1, contentLayout), childAnchor: Anchor.Center) { UserData = UpgradeStoreUserData.BuyButtonLayout };
|
||||||
new GUIButton(rectT(0.7f, 0.5f, buyButtonLayout), string.Empty, style: "RepairBuyButton") { Enabled = PlayerBalance >= price && !isDisabled, OnClicked = onPressed };
|
new GUIButton(rectT(0.7f, 0.5f, buyButtonLayout), string.Empty, style: "RepairBuyButton") { Enabled = PlayerBalance >= price && !isDisabled, OnClicked = onPressed };
|
||||||
contentLayout.Recalculate();
|
contentLayout.Recalculate();
|
||||||
buyButtonLayout.Recalculate();
|
buyButtonLayout.Recalculate();
|
||||||
@@ -950,7 +959,7 @@ namespace Barotrauma
|
|||||||
frames.Add(CreateUpgradeEntry(rectT(1f, 0.25f, parent.Content), currentOrPending.UpgradePreviewSprite,
|
frames.Add(CreateUpgradeEntry(rectT(1f, 0.25f, parent.Content), currentOrPending.UpgradePreviewSprite,
|
||||||
item.PendingItemSwap != null ? TextManager.GetWithVariable("upgrades.pendingitem", "[itemname]", name) : TextManager.GetWithVariable("upgrades.installeditem", "[itemname]", nameWithQuantity),
|
item.PendingItemSwap != null ? TextManager.GetWithVariable("upgrades.pendingitem", "[itemname]", name) : TextManager.GetWithVariable("upgrades.installeditem", "[itemname]", nameWithQuantity),
|
||||||
currentOrPending.Description,
|
currentOrPending.Description,
|
||||||
0, null, addBuyButton: canUninstall, addProgressBar: false, buttonStyle: "WeaponUninstallButton"));
|
0, null, addBuyButton: canUninstall, addProgressBar: false, buttonStyle: "WeaponUninstallButton").Frame);
|
||||||
|
|
||||||
if (canUninstall && frames.Last().FindChild(c => c is GUIButton, recursive: true) is GUIButton refundButton)
|
if (canUninstall && frames.Last().FindChild(c => c is GUIButton, recursive: true) is GUIButton refundButton)
|
||||||
{
|
{
|
||||||
@@ -987,11 +996,11 @@ namespace Barotrauma
|
|||||||
|
|
||||||
int price = isPurchased || replacement == item.Prefab ? 0 : replacement.SwappableItem.GetPrice(Campaign.Map?.CurrentLocation) * linkedItems.Count();
|
int price = isPurchased || replacement == item.Prefab ? 0 : replacement.SwappableItem.GetPrice(Campaign.Map?.CurrentLocation) * linkedItems.Count();
|
||||||
|
|
||||||
frames.Add(CreateUpgradeEntry(rectT(1f, 0.25f, parent.Content), replacement.UpgradePreviewSprite, replacement.Name, replacement.Description,
|
frames.Add(CreateUpgradeEntry(rectT(1f, 0.25f, parent.Content), replacement.UpgradePreviewSprite, replacement.Name, replacement.Description,
|
||||||
price, replacement,
|
price, replacement,
|
||||||
addBuyButton: true,
|
addBuyButton: true,
|
||||||
addProgressBar: false,
|
addProgressBar: false,
|
||||||
buttonStyle: isPurchased ? "WeaponInstallButton" : "StoreAddToCrateButton"));
|
buttonStyle: isPurchased ? "WeaponInstallButton" : "StoreAddToCrateButton").Frame);
|
||||||
|
|
||||||
if (!(frames.Last().FindChild(c => c is GUIButton, recursive: true) is GUIButton buyButton)) { continue; }
|
if (!(frames.Last().FindChild(c => c is GUIButton, recursive: true) is GUIButton buyButton)) { continue; }
|
||||||
if (PlayerBalance >= price)
|
if (PlayerBalance >= price)
|
||||||
@@ -1081,13 +1090,23 @@ namespace Barotrauma
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GUIFrame CreateUpgradeFrame(UpgradePrefab prefab, UpgradeCategory category, CampaignMode campaign, RectTransform rectTransform, bool addBuyButton = true)
|
public readonly record struct BuyButtonFrame(GUILayoutGroup Layout, GUIListBox MaterialCostList, GUIButton BuyButton, GUITextBlock PriceText);
|
||||||
|
public readonly record struct ProgressBarFrame(GUITextBlock ProgressText, GUIProgressBar ProgressBar);
|
||||||
|
|
||||||
|
public readonly record struct UpgradeFrame(GUIFrame Frame,
|
||||||
|
GUIImage Icon,
|
||||||
|
GUITextBlock Name,
|
||||||
|
GUITextBlock Description,
|
||||||
|
Option<BuyButtonFrame> BuyButton,
|
||||||
|
Option<ProgressBarFrame> ProgressBar);
|
||||||
|
|
||||||
|
public static UpgradeFrame CreateUpgradeFrame(UpgradePrefab prefab, UpgradeCategory category, CampaignMode campaign, RectTransform rectTransform, bool addBuyButton = true)
|
||||||
{
|
{
|
||||||
int price = prefab.Price.GetBuyPrice(campaign.UpgradeManager.GetUpgradeLevel(prefab, category), campaign.Map?.CurrentLocation);
|
int price = prefab.Price.GetBuyPrice(campaign.UpgradeManager.GetUpgradeLevel(prefab, category), campaign.Map?.CurrentLocation);
|
||||||
return CreateUpgradeEntry(rectTransform, prefab.Sprite, prefab.Name, prefab.Description, price, new CategoryData(category, prefab), addBuyButton, upgradePrefab: prefab, currentLevel: campaign.UpgradeManager.GetUpgradeLevel(prefab, category));
|
return CreateUpgradeEntry(rectTransform, prefab.Sprite, prefab.Name, prefab.Description, price, new CategoryData(category, prefab), addBuyButton, upgradePrefab: prefab, currentLevel: campaign.UpgradeManager.GetUpgradeLevel(prefab, category));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GUIFrame CreateUpgradeEntry(RectTransform parent, Sprite sprite, LocalizedString title, LocalizedString body, int price, object? userData, bool addBuyButton = true, bool addProgressBar = true, string buttonStyle = "UpgradeBuyButton", UpgradePrefab? upgradePrefab = null, int currentLevel = 0)
|
public static UpgradeFrame CreateUpgradeEntry(RectTransform parent, Sprite sprite, LocalizedString title, LocalizedString body, int price, object? userData, bool addBuyButton = true, bool addProgressBar = true, string buttonStyle = "UpgradeBuyButton", UpgradePrefab? upgradePrefab = null, int currentLevel = 0)
|
||||||
{
|
{
|
||||||
float progressBarHeight = 0.25f;
|
float progressBarHeight = 0.25f;
|
||||||
|
|
||||||
@@ -1105,21 +1124,26 @@ namespace Barotrauma
|
|||||||
* |------------------------------------------------------------------|
|
* |------------------------------------------------------------------|
|
||||||
*/
|
*/
|
||||||
GUIFrame prefabFrame = new GUIFrame(parent, style: "ListBoxElement") { SelectedColor = Color.Transparent, UserData = userData };
|
GUIFrame prefabFrame = new GUIFrame(parent, style: "ListBoxElement") { SelectedColor = Color.Transparent, UserData = userData };
|
||||||
GUILayoutGroup prefabLayout = new GUILayoutGroup(rectT(0.98f, 0.95f, prefabFrame, Anchor.Center), isHorizontal: true) { Stretch = true };
|
GUILayoutGroup mainLayout = new GUILayoutGroup(rectT(0.98f, 0.95f, prefabFrame, Anchor.Center), isHorizontal: false);
|
||||||
GUILayoutGroup imageLayout = new GUILayoutGroup(rectT(new Point(prefabLayout.Rect.Height, prefabLayout.Rect.Height), prefabLayout), childAnchor: Anchor.Center);
|
GUILayoutGroup prefabLayout = new GUILayoutGroup(rectT(1f, addBuyButton ? 0.65f : 1f, mainLayout, Anchor.Center), isHorizontal: true) { Stretch = true };
|
||||||
var icon = new GUIImage(rectT(0.9f, 0.9f, imageLayout, scaleBasis: ScaleBasis.BothHeight), sprite, scaleToFit: true) { CanBeFocused = false };
|
GUILayoutGroup imageLayout = new GUILayoutGroup(rectT(new Point(prefabLayout.Rect.Height, prefabLayout.Rect.Height), prefabLayout), childAnchor: Anchor.Center);
|
||||||
GUILayoutGroup textLayout = new GUILayoutGroup(rectT(0.8f - imageLayout.RectTransform.RelativeSize.X, 1, prefabLayout));
|
var icon = new GUIImage(rectT(0.9f, 0.9f, imageLayout, scaleBasis: ScaleBasis.BothHeight), sprite, scaleToFit: true) { CanBeFocused = false };
|
||||||
var name = new GUITextBlock(rectT(1, 0.25f, textLayout), RichString.Rich(title), font: GUIStyle.SubHeadingFont) { AutoScaleHorizontal = true, AutoScaleVertical = true, Padding = Vector4.Zero };
|
GUILayoutGroup textLayout = new GUILayoutGroup(rectT(1f - imageLayout.RectTransform.RelativeSize.X, 1, prefabLayout));
|
||||||
GUILayoutGroup descriptionLayout = new GUILayoutGroup(rectT(1, 0.75f - progressBarHeight, textLayout));
|
var name = new GUITextBlock(rectT(1, 0.25f, textLayout), RichString.Rich(title), font: GUIStyle.SubHeadingFont) { AutoScaleHorizontal = true, AutoScaleVertical = true, Padding = Vector4.Zero };
|
||||||
var description = new GUITextBlock(rectT(1, 1, descriptionLayout), body, font: GUIStyle.SmallFont, wrap: true, textAlignment: Alignment.TopLeft) { Padding = Vector4.Zero };
|
GUILayoutGroup descriptionLayout = new GUILayoutGroup(rectT(1, 0.75f - progressBarHeight, textLayout));
|
||||||
GUILayoutGroup? progressLayout = null;
|
var description = new GUITextBlock(rectT(1, 1, descriptionLayout), body, font: GUIStyle.SmallFont, wrap: true, textAlignment: Alignment.TopLeft) { Padding = Vector4.Zero };
|
||||||
|
GUILayoutGroup? progressLayout = null;
|
||||||
GUILayoutGroup? buyButtonLayout = null;
|
GUILayoutGroup? buyButtonLayout = null;
|
||||||
|
|
||||||
|
Option<BuyButtonFrame> buyButtonOption = Option<BuyButtonFrame>.None();
|
||||||
|
Option<ProgressBarFrame> progressBarOption = Option<ProgressBarFrame>.None();
|
||||||
|
|
||||||
if (addProgressBar)
|
if (addProgressBar)
|
||||||
{
|
{
|
||||||
progressLayout = new GUILayoutGroup(rectT(1, 0.25f, textLayout), isHorizontal: true, childAnchor: Anchor.CenterLeft) { UserData = "progressbar" };
|
progressLayout = new GUILayoutGroup(rectT(1, 0.25f, textLayout), isHorizontal: true, childAnchor: Anchor.CenterLeft) { UserData = UpgradeStoreUserData.ProgressBarLayout };
|
||||||
new GUIProgressBar(rectT(0.8f, 0.75f, progressLayout), 0.0f, GUIStyle.Orange);
|
GUITextBlock progressText = new GUITextBlock(rectT(0.15f, 1, progressLayout), string.Empty, font: GUIStyle.SmallFont, textAlignment: Alignment.Center) { Padding = Vector4.Zero };
|
||||||
new GUITextBlock(rectT(0.2f, 1, progressLayout), string.Empty, font: GUIStyle.SmallFont, textAlignment: Alignment.Center) { Padding = Vector4.Zero };
|
GUIProgressBar progressBar = new GUIProgressBar(rectT(0.85f, 0.75f, progressLayout), 0.0f, GUIStyle.Orange);
|
||||||
|
progressBarOption = Option.Some(new ProgressBarFrame(progressText, progressBar));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addBuyButton)
|
if (addBuyButton)
|
||||||
@@ -1127,12 +1151,33 @@ namespace Barotrauma
|
|||||||
var formattedPrice = TextManager.FormatCurrency(Math.Abs(price));
|
var formattedPrice = TextManager.FormatCurrency(Math.Abs(price));
|
||||||
//negative price = refund
|
//negative price = refund
|
||||||
if (price < 0) { formattedPrice = "+" + formattedPrice; }
|
if (price < 0) { formattedPrice = "+" + formattedPrice; }
|
||||||
buyButtonLayout = new GUILayoutGroup(rectT(0.2f, 1, prefabLayout), childAnchor: Anchor.TopCenter) { UserData = "buybutton" };
|
buyButtonLayout = new GUILayoutGroup(rectT(1f, 0.35f, mainLayout), isHorizontal: true) { UserData = UpgradeStoreUserData.BuyButtonLayout };;
|
||||||
var priceText = new GUITextBlock(rectT(1, 0.2f, buyButtonLayout), formattedPrice, textAlignment: Alignment.Center)
|
|
||||||
|
GUIListBox materialCostList;
|
||||||
|
if (upgradePrefab is not null)
|
||||||
{
|
{
|
||||||
|
var increaseText = new GUITextBlock(rectT(imageLayout.RectTransform.RelativeSize.X, 1f, buyButtonLayout), "", textAlignment: Alignment.Center, font: GUIStyle.SubHeadingFont)
|
||||||
|
{
|
||||||
|
UserData = UpgradeStoreUserData.IncreaseLabel
|
||||||
|
};
|
||||||
|
UpdateUpgradePercentageText(increaseText, upgradePrefab, currentLevel);
|
||||||
|
materialCostList = new GUIListBox(rectT(0.65f - imageLayout.RectTransform.RelativeSize.X, 1f, buyButtonLayout), isHorizontal: true, style: null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
materialCostList = new GUIListBox(rectT(0.65f, 1f, buyButtonLayout), isHorizontal: true, style: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
materialCostList.Visible = false;
|
||||||
|
materialCostList.UserData = UpgradeStoreUserData.MaterialCostList;
|
||||||
|
|
||||||
|
var priceText = new GUITextBlock(rectT(0.2f, 1f, buyButtonLayout), formattedPrice, textAlignment: Alignment.Right)
|
||||||
|
{
|
||||||
|
UserData = UpgradeStoreUserData.PriceLabel,
|
||||||
//prices on swappable items are always visible, upgrade prices are enabled in UpdateUpgradeEntry for purchasable upgrades
|
//prices on swappable items are always visible, upgrade prices are enabled in UpdateUpgradeEntry for purchasable upgrades
|
||||||
Visible = userData is ItemPrefab
|
Visible = userData is ItemPrefab
|
||||||
};
|
};
|
||||||
|
|
||||||
if (price < 0)
|
if (price < 0)
|
||||||
{
|
{
|
||||||
priceText.TextColor = GUIStyle.Green;
|
priceText.TextColor = GUIStyle.Green;
|
||||||
@@ -1141,15 +1186,13 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
priceText.Text = string.Empty;
|
priceText.Text = string.Empty;
|
||||||
}
|
}
|
||||||
new GUIButton(rectT(0.7f, 0.5f, buyButtonLayout), string.Empty, style: buttonStyle)
|
GUIButton buyButton = new GUIButton(rectT(0.15f, 1f, buyButtonLayout), string.Empty, style: buttonStyle)
|
||||||
{
|
{
|
||||||
|
UserData = UpgradeStoreUserData.BuyButton,
|
||||||
Enabled = false
|
Enabled = false
|
||||||
};
|
};
|
||||||
if (upgradePrefab != null)
|
|
||||||
{
|
buyButtonOption = Option.Some(new BuyButtonFrame(buyButtonLayout, materialCostList, buyButton, priceText));
|
||||||
var increaseText = new GUITextBlock(rectT(1, 0.2f, buyButtonLayout), "", textAlignment: Alignment.Center);
|
|
||||||
UpdateUpgradePercentageText(increaseText, upgradePrefab, currentLevel);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
description.CalculateHeightFromText();
|
description.CalculateHeightFromText();
|
||||||
@@ -1175,7 +1218,7 @@ namespace Barotrauma
|
|||||||
progressLayout?.Recalculate();
|
progressLayout?.Recalculate();
|
||||||
buyButtonLayout?.Recalculate();
|
buyButtonLayout?.Recalculate();
|
||||||
|
|
||||||
return prefabFrame;
|
return new UpgradeFrame(prefabFrame, icon, name, description, buyButtonOption, progressBarOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void UpdateUpgradePercentageText(GUITextBlock text, UpgradePrefab upgradePrefab, int currentLevel)
|
private static void UpdateUpgradePercentageText(GUITextBlock text, UpgradePrefab upgradePrefab, int currentLevel)
|
||||||
@@ -1197,31 +1240,21 @@ namespace Barotrauma
|
|||||||
Submarine? sub = GameMain.GameSession?.Submarine ?? Submarine.MainSub;
|
Submarine? sub = GameMain.GameSession?.Submarine ?? Submarine.MainSub;
|
||||||
if (Campaign is null || sub is null) { return; }
|
if (Campaign is null || sub is null) { return; }
|
||||||
|
|
||||||
GUIFrame prefabFrame = CreateUpgradeFrame(prefab, category, Campaign, rectT(1f, 0.25f, parent));
|
UpgradeFrame prefabFrame = CreateUpgradeFrame(prefab, category, Campaign, rectT(1f, 0.4f, parent));
|
||||||
var prefabLayout = prefabFrame.GetChild<GUILayoutGroup>();
|
|
||||||
GUILayoutGroup[] childLayouts = prefabLayout.GetAllChildren<GUILayoutGroup>().ToArray();
|
if (!prefabFrame.BuyButton.TryUnwrap(out BuyButtonFrame buyButtonFrame)) { return; }
|
||||||
var imageLayout = childLayouts[0];
|
|
||||||
var icon = imageLayout.GetChild<GUIImage>();
|
|
||||||
var textLayout = childLayouts[1];
|
|
||||||
var name = textLayout.GetChild<GUITextBlock>();
|
|
||||||
GUILayoutGroup[] textChildLayouts = textLayout.GetAllChildren<GUILayoutGroup>().ToArray();
|
|
||||||
var descriptionLayout = textChildLayouts[0];
|
|
||||||
var description = descriptionLayout.GetChild<GUITextBlock>();
|
|
||||||
var progressLayout = textChildLayouts[1];
|
|
||||||
var buyButtonLayout = childLayouts[2];
|
|
||||||
var buyButton = buyButtonLayout.GetChild<GUIButton>();
|
|
||||||
|
|
||||||
if (!HasPermission || !prefab.IsApplicable(submarine.Info) || (itemsOnSubmarine != null && !itemsOnSubmarine.Any(it => category.CanBeApplied(it, prefab))))
|
if (!HasPermission || !prefab.IsApplicable(submarine.Info) || (itemsOnSubmarine != null && !itemsOnSubmarine.Any(it => category.CanBeApplied(it, prefab))))
|
||||||
{
|
{
|
||||||
prefabFrame.Enabled = false;
|
prefabFrame.Frame.Enabled = false;
|
||||||
description.Enabled = false;
|
prefabFrame.Description.Enabled = false;
|
||||||
name.Enabled = false;
|
prefabFrame.Name.Enabled = false;
|
||||||
icon.Color = Color.Gray;
|
prefabFrame.Icon.Color = Color.Gray;
|
||||||
buyButton.Enabled = false;
|
buyButtonFrame.BuyButton.Enabled = false;
|
||||||
buyButtonLayout.UserData = null; // prevent UpdateUpgradeEntry() from enabling the button
|
buyButtonFrame.Layout.UserData = null; // prevent UpdateUpgradeEntry() from enabling the button
|
||||||
}
|
}
|
||||||
|
|
||||||
buyButton.OnClicked += (button, o) =>
|
buyButtonFrame.BuyButton.OnClicked += (button, o) =>
|
||||||
{
|
{
|
||||||
LocalizedString promptBody = TextManager.GetWithVariables("Upgrades.PurchasePromptBody",
|
LocalizedString promptBody = TextManager.GetWithVariables("Upgrades.PurchasePromptBody",
|
||||||
("[upgradename]", prefab.Name),
|
("[upgradename]", prefab.Name),
|
||||||
@@ -1240,7 +1273,7 @@ namespace Barotrauma
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
UpdateUpgradeEntry(prefabFrame, prefab, category, Campaign);
|
UpdateUpgradeEntry(prefabFrame.Frame, prefab, category, Campaign);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateItemTooltip(MapEntity entity)
|
private void CreateItemTooltip(MapEntity entity)
|
||||||
@@ -1623,7 +1656,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
int maxLevel = prefab.GetMaxLevelForCurrentSub();
|
int maxLevel = prefab.GetMaxLevelForCurrentSub();
|
||||||
LocalizedString progressText = TextManager.GetWithVariables("upgrades.progressformat", ("[level]", currentLevel.ToString()), ("[maxlevel]", maxLevel.ToString()));
|
LocalizedString progressText = TextManager.GetWithVariables("upgrades.progressformat", ("[level]", currentLevel.ToString()), ("[maxlevel]", maxLevel.ToString()));
|
||||||
if (prefabFrame.FindChild("progressbar", true) is { } progressParent)
|
if (prefabFrame.FindChild(UpgradeStoreUserData.ProgressBarLayout, true) is { } progressParent)
|
||||||
{
|
{
|
||||||
GUIProgressBar bar = progressParent.GetChild<GUIProgressBar>();
|
GUIProgressBar bar = progressParent.GetChild<GUIProgressBar>();
|
||||||
if (bar != null)
|
if (bar != null)
|
||||||
@@ -1636,36 +1669,111 @@ namespace Barotrauma
|
|||||||
if (block != null) { block.Text = progressText; }
|
if (block != null) { block.Text = progressText; }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prefabFrame.FindChild("buybutton", true) is { } buttonParent)
|
if (prefabFrame.FindChild(UpgradeStoreUserData.BuyButtonLayout, true) is not { } buttonParent) { return; }
|
||||||
|
|
||||||
|
GUITextBlock priceLabel = (GUITextBlock)buttonParent.FindChild(UpgradeStoreUserData.PriceLabel, recursive: true);
|
||||||
|
priceLabel.Visible = true;
|
||||||
|
int price = prefab.Price.GetBuyPrice(campaign.UpgradeManager.GetUpgradeLevel(prefab, category), campaign.Map?.CurrentLocation);
|
||||||
|
|
||||||
|
if (!WaitForServerUpdate)
|
||||||
{
|
{
|
||||||
List<GUITextBlock> textBlocks = buttonParent.GetAllChildren<GUITextBlock>().ToList();
|
priceLabel.Text = TextManager.FormatCurrency(price);
|
||||||
|
if (currentLevel >= maxLevel)
|
||||||
GUITextBlock priceLabel = textBlocks[0];
|
|
||||||
priceLabel.Visible = true;
|
|
||||||
int price = prefab.Price.GetBuyPrice(campaign.UpgradeManager.GetUpgradeLevel(prefab, category), campaign.Map?.CurrentLocation);
|
|
||||||
|
|
||||||
if (priceLabel != null && !WaitForServerUpdate)
|
|
||||||
{
|
{
|
||||||
priceLabel.Text = TextManager.FormatCurrency(price);
|
priceLabel.Text = TextManager.Get("Upgrade.MaxedUpgrade");
|
||||||
if (currentLevel >= maxLevel)
|
|
||||||
{
|
|
||||||
priceLabel.Text = TextManager.Get("Upgrade.MaxedUpgrade");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GUIButton button = buttonParent.GetChild<GUIButton>();
|
if (buttonParent.FindChild(UpgradeStoreUserData.IncreaseLabel, recursive: true) is GUITextBlock increaseLabel && !WaitForServerUpdate)
|
||||||
if (button != null)
|
{
|
||||||
|
UpdateUpgradePercentageText(increaseLabel, prefab, currentLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isMax = currentLevel >= maxLevel;
|
||||||
|
|
||||||
|
if (buttonParent.FindChild(UpgradeStoreUserData.BuyButton, recursive: true) is GUIButton button)
|
||||||
|
{
|
||||||
|
bool canBuy = !WaitForServerUpdate && !isMax && campaign.GetBalance() >= price && prefab.HasResourcesToUpgrade(Character.Controlled, currentLevel + 1);
|
||||||
|
|
||||||
|
button.Enabled = canBuy;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prefabFrame.FindChild(UpgradeStoreUserData.MaterialCostList, true) is GUIListBox itemList)
|
||||||
|
{
|
||||||
|
if (isMax)
|
||||||
{
|
{
|
||||||
button.Enabled = currentLevel < maxLevel;
|
itemList.Visible = false;
|
||||||
if (WaitForServerUpdate || campaign.GetBalance() < price)
|
|
||||||
{
|
|
||||||
button.Enabled = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
GUITextBlock increaseLabel = textBlocks[1];
|
else
|
||||||
if (increaseLabel != null && !WaitForServerUpdate)
|
|
||||||
{
|
{
|
||||||
UpdateUpgradePercentageText(increaseLabel, prefab, currentLevel);
|
CreateMaterialCosts(itemList, prefab, currentLevel + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CreateMaterialCosts(GUIListBox list, UpgradePrefab prefab, int targetLevel)
|
||||||
|
{
|
||||||
|
list.Content.ClearChildren();
|
||||||
|
List<Item> allItems = Character.Controlled?.Inventory?.FindAllItems(recursive: true) ?? new List<Item>();
|
||||||
|
|
||||||
|
var resources = prefab.GetApplicableResources(targetLevel);
|
||||||
|
|
||||||
|
foreach (ApplicableResourceCollection collection in resources)
|
||||||
|
{
|
||||||
|
list.Visible = true;
|
||||||
|
|
||||||
|
int length = collection.MatchingItems.Length;
|
||||||
|
|
||||||
|
if (length is 0) { continue; }
|
||||||
|
|
||||||
|
ItemPrefab defaultItemPrefab = collection.MatchingItems.First();
|
||||||
|
|
||||||
|
GUILayoutGroup wrapperLayout = new GUILayoutGroup(rectT(0.25f, 1f, list.Content));
|
||||||
|
|
||||||
|
GUIFrame itemFrame = new GUIFrame(rectT(1f, 1f, wrapperLayout), style: null)
|
||||||
|
{
|
||||||
|
ToolTip = defaultItemPrefab.Name
|
||||||
|
};
|
||||||
|
|
||||||
|
bool hasItems = collection.Cost.Amount <= allItems.Count(collection.Cost.MatchesItem);
|
||||||
|
|
||||||
|
Sprite icon = defaultItemPrefab.InventoryIcon ?? prefab.Sprite;
|
||||||
|
Color iconColor = defaultItemPrefab.InventoryIcon is null ? defaultItemPrefab.SpriteColor : defaultItemPrefab.InventoryIconColor;
|
||||||
|
|
||||||
|
GUIImage itemIcon = new GUIImage(new RectTransform(Vector2.One, itemFrame.RectTransform, scaleBasis: ScaleBasis.Smallest, anchor: Anchor.Center), sprite: icon, scaleToFit: true)
|
||||||
|
{
|
||||||
|
Color = hasItems ? iconColor : iconColor * 0.9f,
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
|
||||||
|
// item count text
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.5f), itemIcon.RectTransform, anchor: Anchor.BottomRight), $"{collection.Count}", font: GUIStyle.Font, textAlignment: Alignment.BottomRight)
|
||||||
|
{
|
||||||
|
Shadow = true,
|
||||||
|
CanBeFocused = false,
|
||||||
|
Padding = Vector4.Zero,
|
||||||
|
TextColor = hasItems ? Color.White : GUIStyle.Red,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (length is 1) { continue; }
|
||||||
|
|
||||||
|
// we have more than 1 item, show a "slideshow" of the items
|
||||||
|
|
||||||
|
float index = 0f;
|
||||||
|
GUICustomComponent customComponent = new GUICustomComponent(rectT(1f, 1f, itemFrame), null, (deltaTime, component) =>
|
||||||
|
{
|
||||||
|
index += deltaTime / 3f;
|
||||||
|
if (index > length) { index = 0; }
|
||||||
|
|
||||||
|
ItemPrefab currentPrefab = collection.MatchingItems[(int)MathF.Floor(index)];
|
||||||
|
Sprite icon = currentPrefab.InventoryIcon ?? prefab.Sprite;
|
||||||
|
Color iconColor = currentPrefab.InventoryIcon is null ? currentPrefab.SpriteColor : currentPrefab.InventoryIconColor;
|
||||||
|
itemIcon.Sprite = icon;
|
||||||
|
itemIcon.Color = hasItems ? iconColor : iconColor * 0.9f;
|
||||||
|
itemFrame.ToolTip = currentPrefab.Name;
|
||||||
|
})
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,16 +17,20 @@ using System.Linq;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Barotrauma.Extensions;
|
using Barotrauma.Extensions;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
class GameMain : Game
|
class GameMain : Game
|
||||||
{
|
{
|
||||||
internal static LuaCsSetup LuaCs;
|
public static LuaCsSetup LuaCs;
|
||||||
|
public static bool ShowFPS;
|
||||||
public static bool ShowFPS = false;
|
public static bool ShowPerf;
|
||||||
public static bool ShowPerf = false;
|
|
||||||
public static bool DebugDraw;
|
public static bool DebugDraw;
|
||||||
|
/// <summary>
|
||||||
|
/// Doesn't automatically enable los or bot AI or do anything like that. Probably not fully implemented.
|
||||||
|
/// </summary>
|
||||||
|
public static bool DevMode;
|
||||||
public static bool IsSingleplayer => NetworkMember == null;
|
public static bool IsSingleplayer => NetworkMember == null;
|
||||||
public static bool IsMultiplayer => NetworkMember != null;
|
public static bool IsMultiplayer => NetworkMember != null;
|
||||||
|
|
||||||
@@ -401,7 +405,7 @@ namespace Barotrauma
|
|||||||
TextureLoader.Init(GraphicsDevice);
|
TextureLoader.Init(GraphicsDevice);
|
||||||
|
|
||||||
//do this here because we need it for the loading screen
|
//do this here because we need it for the loading screen
|
||||||
WaterRenderer.Instance = new WaterRenderer(base.GraphicsDevice, Content);
|
WaterRenderer.Instance = new WaterRenderer(base.GraphicsDevice);
|
||||||
|
|
||||||
Quad.Init(GraphicsDevice);
|
Quad.Init(GraphicsDevice);
|
||||||
|
|
||||||
@@ -479,6 +483,19 @@ namespace Barotrauma
|
|||||||
yield return CoroutineStatus.Running;
|
yield return CoroutineStatus.Running;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var corePackage = ContentPackageManager.EnabledPackages.Core;
|
||||||
|
if (corePackage.EnableError.TryUnwrap(out var error))
|
||||||
|
{
|
||||||
|
if (error.ErrorsOrException.TryGet(out ImmutableArray<string> errorMessages))
|
||||||
|
{
|
||||||
|
throw new Exception($"Error while loading the core content package \"{corePackage.Name}\": {errorMessages.First()}");
|
||||||
|
}
|
||||||
|
else if (error.ErrorsOrException.TryGet(out Exception exception))
|
||||||
|
{
|
||||||
|
throw new Exception($"Error while loading the core content package \"{corePackage.Name}\": {exception.Message}", exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TextManager.VerifyLanguageAvailable();
|
TextManager.VerifyLanguageAvailable();
|
||||||
|
|
||||||
DebugConsole.Init();
|
DebugConsole.Init();
|
||||||
@@ -502,10 +519,10 @@ namespace Barotrauma
|
|||||||
TitleScreen.LoadState = 75.0f;
|
TitleScreen.LoadState = 75.0f;
|
||||||
yield return CoroutineStatus.Running;
|
yield return CoroutineStatus.Running;
|
||||||
|
|
||||||
GameScreen = new GameScreen(GraphicsDeviceManager.GraphicsDevice, Content);
|
GameScreen = new GameScreen(GraphicsDeviceManager.GraphicsDevice);
|
||||||
|
|
||||||
ParticleManager = new ParticleManager(GameScreen.Cam);
|
ParticleManager = new ParticleManager(GameScreen.Cam);
|
||||||
LightManager = new Lights.LightManager(base.GraphicsDevice, Content);
|
LightManager = new Lights.LightManager(base.GraphicsDevice);
|
||||||
|
|
||||||
TitleScreen.LoadState = 80.0f;
|
TitleScreen.LoadState = 80.0f;
|
||||||
yield return CoroutineStatus.Running;
|
yield return CoroutineStatus.Running;
|
||||||
@@ -744,8 +761,8 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
Client.Quit();
|
Client.Quit();
|
||||||
Client = null;
|
Client = null;
|
||||||
MainMenuScreen.Select();
|
|
||||||
}
|
}
|
||||||
|
MainMenuScreen.Select();
|
||||||
|
|
||||||
if (connectCommand.EndpointOrLobby.TryGet(out ulong lobbyId))
|
if (connectCommand.EndpointOrLobby.TryGet(out ulong lobbyId))
|
||||||
{
|
{
|
||||||
@@ -1114,37 +1131,6 @@ namespace Barotrauma
|
|||||||
GameMain.LuaCs.Stop();
|
GameMain.LuaCs.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ShowEditorDisclaimer()
|
|
||||||
{
|
|
||||||
var msgBox = new GUIMessageBox(TextManager.Get("EditorDisclaimerTitle"), TextManager.Get("EditorDisclaimerText"));
|
|
||||||
var linkHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.25f), msgBox.Content.RectTransform)) { Stretch = true, RelativeSpacing = 0.025f };
|
|
||||||
linkHolder.RectTransform.MaxSize = new Point(int.MaxValue, linkHolder.Rect.Height);
|
|
||||||
List<(LocalizedString Caption, string Url)> links = new List<(LocalizedString, string)>()
|
|
||||||
{
|
|
||||||
(TextManager.Get("EditorDisclaimerWikiLink"), TextManager.Get("EditorDisclaimerWikiUrl").Fallback("https://barotraumagame.com/wiki").Value),
|
|
||||||
(TextManager.Get("EditorDisclaimerDiscordLink"), TextManager.Get("EditorDisclaimerDiscordUrl").Fallback("https://discordapp.com/invite/undertow").Value),
|
|
||||||
};
|
|
||||||
foreach (var link in links)
|
|
||||||
{
|
|
||||||
new GUIButton(new RectTransform(new Vector2(1.0f, 0.2f), linkHolder.RectTransform), link.Caption, style: "MainMenuGUIButton", textAlignment: Alignment.Left)
|
|
||||||
{
|
|
||||||
UserData = link.Url,
|
|
||||||
OnClicked = (btn, userdata) =>
|
|
||||||
{
|
|
||||||
ShowOpenUrlInWebBrowserPrompt(userdata as string);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
msgBox.InnerFrame.RectTransform.MinSize = new Point(0,
|
|
||||||
msgBox.InnerFrame.Rect.Height + linkHolder.Rect.Height + msgBox.Content.AbsoluteSpacing * 2 + 10);
|
|
||||||
var config = GameSettings.CurrentConfig;
|
|
||||||
config.EditorDisclaimerShown = true;
|
|
||||||
GameSettings.SetCurrentConfig(config);
|
|
||||||
GameSettings.SaveCurrentConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ShowBugReporter()
|
public void ShowBugReporter()
|
||||||
{
|
{
|
||||||
if (GUIMessageBox.VisibleBox != null && GUIMessageBox.VisibleBox.UserData as string == "bugreporter")
|
if (GUIMessageBox.VisibleBox != null && GUIMessageBox.VisibleBox.UserData as string == "bugreporter")
|
||||||
|
|||||||
@@ -788,7 +788,6 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ws != null)
|
if (ws != null)
|
||||||
{
|
{
|
||||||
hull = Hull.FindHull(ws.WorldPosition);
|
hull = Hull.FindHull(ws.WorldPosition);
|
||||||
@@ -802,7 +801,6 @@ namespace Barotrauma
|
|||||||
hull = Hull.FindHull(se.WorldPosition);
|
hull = Hull.FindHull(se.WorldPosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsSinglePlayer)
|
if (IsSinglePlayer)
|
||||||
{
|
{
|
||||||
order.OrderGiver?.Speak(order.GetChatMessage("", hull?.DisplayName?.Value, givingOrderToSelf: character == order.OrderGiver, isNewOrder: isNewOrder), ChatMessageType.Order);
|
order.OrderGiver?.Speak(order.GetChatMessage("", hull?.DisplayName?.Value, givingOrderToSelf: character == order.OrderGiver, isNewOrder: isNewOrder), ChatMessageType.Order);
|
||||||
@@ -817,13 +815,13 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
//can't issue an order if no characters are available
|
//can't issue an order if no characters are available
|
||||||
if (character == null) { return; }
|
if (character == null) { return; }
|
||||||
|
|
||||||
var orderGiver = order?.OrderGiver;
|
var orderGiver = order?.OrderGiver;
|
||||||
if (IsSinglePlayer)
|
if (IsSinglePlayer)
|
||||||
{
|
{
|
||||||
character.SetOrder(order, isNewOrder, speak: orderGiver != character);
|
bool isGivingOrderToSelf = orderGiver == character;
|
||||||
string message = order?.GetChatMessage(character.Name, orderGiver?.CurrentHull?.DisplayName?.Value, givingOrderToSelf: character == orderGiver, orderOption: order?.Option ?? Identifier.Empty, isNewOrder: isNewOrder);
|
character.SetOrder(order, isNewOrder, speak: !isGivingOrderToSelf);
|
||||||
orderGiver?.Speak(message);
|
string message = order?.GetChatMessage(character.Name, orderGiver?.CurrentHull?.DisplayName?.Value, isGivingOrderToSelf, orderOption: order?.Option ?? Identifier.Empty, isNewOrder: isNewOrder);
|
||||||
|
orderGiver?.Speak(message);
|
||||||
}
|
}
|
||||||
else if (orderGiver != null)
|
else if (orderGiver != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -106,12 +106,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public static bool AllowedToManageWallets()
|
public static bool AllowedToManageWallets()
|
||||||
{
|
{
|
||||||
if (GameMain.Client == null) { return true; }
|
return AllowedToManageCampaign(ClientPermissions.ManageMoney);
|
||||||
|
|
||||||
return
|
|
||||||
GameMain.Client.HasPermission(ClientPermissions.ManageMoney) ||
|
|
||||||
GameMain.Client.HasPermission(ClientPermissions.ManageCampaign) ||
|
|
||||||
GameMain.Client.IsServerOwner;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Draw(SpriteBatch spriteBatch)
|
public override void Draw(SpriteBatch spriteBatch)
|
||||||
|
|||||||
@@ -965,7 +965,7 @@ namespace Barotrauma
|
|||||||
break;
|
break;
|
||||||
case QuickUseAction.PutToEquippedItem:
|
case QuickUseAction.PutToEquippedItem:
|
||||||
//order by the condition of the contained item to prefer putting into the item with the emptiest ammo/battery/tank
|
//order by the condition of the contained item to prefer putting into the item with the emptiest ammo/battery/tank
|
||||||
foreach (Item heldItem in character.HeldItems.OrderBy(it => it.ContainedItems.FirstOrDefault()?.Condition ?? 0.0f))
|
foreach (Item heldItem in character.HeldItems.OrderByDescending(heldItem => GetContainPriority(item, heldItem)))
|
||||||
{
|
{
|
||||||
if (heldItem.OwnInventory == null) { continue; }
|
if (heldItem.OwnInventory == null) { continue; }
|
||||||
//don't allow swapping if we're moving items into an item with 1 slot holding a stack of items
|
//don't allow swapping if we're moving items into an item with 1 slot holding a stack of items
|
||||||
@@ -986,6 +986,22 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
static float GetContainPriority(Item item, Item containerItem)
|
||||||
|
{
|
||||||
|
var container = containerItem.GetComponent<ItemContainer>();
|
||||||
|
if (container == null) { return 0.0f; }
|
||||||
|
for (int i = 0; i < container.Inventory.Capacity; i++)
|
||||||
|
{
|
||||||
|
var containedItems = container.Inventory.GetItemsAt(i);
|
||||||
|
if (containedItems.Any() && container.Inventory.CanBePutInSlot(item, i))
|
||||||
|
{
|
||||||
|
//if there's a stack in the contained item that we can add the item to, prefer that
|
||||||
|
return 10.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -container.GetContainedIndicatorState();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
|
|||||||
@@ -216,16 +216,19 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
if (brokenSprite == null || !IsBroken)
|
if (brokenSprite == null || !IsBroken)
|
||||||
{
|
{
|
||||||
spriteBatch.Draw(doorSprite.Texture, pos,
|
if (doorSprite?.Texture != null)
|
||||||
getSourceRect(doorSprite, openState, IsHorizontal),
|
{
|
||||||
color, 0.0f, doorSprite.Origin, item.Scale, item.SpriteEffects, doorSprite.Depth);
|
spriteBatch.Draw(doorSprite.Texture, pos,
|
||||||
|
getSourceRect(doorSprite, openState, IsHorizontal),
|
||||||
|
color, 0.0f, doorSprite.Origin, item.Scale, item.SpriteEffects, doorSprite.Depth);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float maxCondition = item.Repairables.Any() ?
|
float maxCondition = item.Repairables.Any() ?
|
||||||
item.Repairables.Min(r => r.RepairThreshold) / 100.0f * item.MaxCondition :
|
item.Repairables.Min(r => r.RepairThreshold) / 100.0f * item.MaxCondition :
|
||||||
item.MaxCondition;
|
item.MaxCondition;
|
||||||
float healthRatio = item.Health / maxCondition;
|
float healthRatio = item.Health / maxCondition;
|
||||||
if (brokenSprite != null && healthRatio < 1.0f)
|
if (brokenSprite?.Texture != null && healthRatio < 1.0f)
|
||||||
{
|
{
|
||||||
Vector2 scale = scaleBrokenSprite ? new Vector2(1.0f - healthRatio) : Vector2.One;
|
Vector2 scale = scaleBrokenSprite ? new Vector2(1.0f - healthRatio) : Vector2.One;
|
||||||
if (IsHorizontal) { scale.X = 1; } else { scale.Y = 1; }
|
if (IsHorizontal) { scale.X = 1; } else { scale.Y = 1; }
|
||||||
@@ -285,34 +288,45 @@ namespace Barotrauma.Items.Components
|
|||||||
//sent by the server, or reverting it back to its old state if no msg from server was received
|
//sent by the server, or reverting it back to its old state if no msg from server was received
|
||||||
PredictedState = open;
|
PredictedState = open;
|
||||||
resetPredictionTimer = CorrectionDelay;
|
resetPredictionTimer = CorrectionDelay;
|
||||||
if (stateChanged) PlaySound(forcedOpen ? ActionType.OnPicked : ActionType.OnUse);
|
if (stateChanged && !IsBroken)
|
||||||
|
{
|
||||||
|
PlayInteractionSound();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
isOpen = open;
|
isOpen = open;
|
||||||
if (!isNetworkMessage || open != PredictedState)
|
if (!isNetworkMessage || open != PredictedState)
|
||||||
{
|
{
|
||||||
StopPicking(null);
|
StopPicking(null);
|
||||||
ActionType actionType = ActionType.OnUse;
|
if (!IsBroken)
|
||||||
if (forcedOpen)
|
|
||||||
{
|
{
|
||||||
actionType = ActionType.OnPicked;
|
PlayInteractionSound();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
if (open && HasSoundsOfType[(int)ActionType.OnOpen])
|
|
||||||
{
|
|
||||||
actionType = ActionType.OnOpen;
|
|
||||||
}
|
|
||||||
else if (!open && HasSoundsOfType[(int)ActionType.OnClose])
|
|
||||||
{
|
|
||||||
actionType = ActionType.OnClose;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PlaySound(actionType);
|
|
||||||
if (isOpen) { stuck = MathHelper.Clamp(stuck - StuckReductionOnOpen, 0.0f, 100.0f); }
|
if (isOpen) { stuck = MathHelper.Clamp(stuck - StuckReductionOnOpen, 0.0f, 100.0f); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PlayInteractionSound()
|
||||||
|
{
|
||||||
|
ActionType actionType = ActionType.OnUse;
|
||||||
|
if (forcedOpen)
|
||||||
|
{
|
||||||
|
actionType = ActionType.OnPicked;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (open && HasSoundsOfType[(int)ActionType.OnOpen])
|
||||||
|
{
|
||||||
|
actionType = ActionType.OnOpen;
|
||||||
|
}
|
||||||
|
else if (!open && HasSoundsOfType[(int)ActionType.OnClose])
|
||||||
|
{
|
||||||
|
actionType = ActionType.OnClose;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PlaySound(actionType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ClientEventRead(IReadMessage msg, float sendingTime)
|
public override void ClientEventRead(IReadMessage msg, float sendingTime)
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
public void DrawElectricity(SpriteBatch spriteBatch)
|
public void DrawElectricity(SpriteBatch spriteBatch)
|
||||||
{
|
{
|
||||||
if (timer <= 0.0f) { return; }
|
if (timer <= 0.0f && Screen.Selected is { IsEditor: false }) { return; }
|
||||||
for (int i = 0; i < nodes.Count; i++)
|
for (int i = 0; i < nodes.Count; i++)
|
||||||
{
|
{
|
||||||
if (nodes[i].Length <= 1.0f) { continue; }
|
if (nodes[i].Length <= 1.0f) { continue; }
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using static Barotrauma.Inventory;
|
||||||
|
|
||||||
namespace Barotrauma.Items.Components
|
namespace Barotrauma.Items.Components
|
||||||
{
|
{
|
||||||
@@ -250,6 +252,83 @@ namespace Barotrauma.Items.Components
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public float GetContainedIndicatorState()
|
||||||
|
{
|
||||||
|
if (ShowConditionInContainedStateIndicator)
|
||||||
|
{
|
||||||
|
return item.Condition / item.MaxCondition;
|
||||||
|
}
|
||||||
|
|
||||||
|
int targetSlot = Math.Max(ContainedStateIndicatorSlot, 0);
|
||||||
|
if (targetSlot >= Inventory.Capacity) { return 0.0f; }
|
||||||
|
|
||||||
|
var containedItems = Inventory.GetItemsAt(targetSlot);
|
||||||
|
if (containedItems == null) { return 0.0f; }
|
||||||
|
|
||||||
|
Item containedItem = containedItems.FirstOrDefault();
|
||||||
|
if (ShowTotalStackCapacityInContainedStateIndicator)
|
||||||
|
{
|
||||||
|
// No item on the defined slot, check if the items on other slots can be used.
|
||||||
|
containedItem ??=
|
||||||
|
containedItems.FirstOrDefault() ??
|
||||||
|
Inventory.AllItems.FirstOrDefault(it => CanBeContained(it, targetSlot));
|
||||||
|
if (containedItem == null) { return 0.0f; }
|
||||||
|
|
||||||
|
int ignoredItemCount = 0;
|
||||||
|
var subContainableItems = AllSubContainableItems;
|
||||||
|
float capacity = GetMaxStackSize(targetSlot);
|
||||||
|
if (subContainableItems != null)
|
||||||
|
{
|
||||||
|
bool useMainContainerCapacity = true;
|
||||||
|
foreach (Item it in Inventory.AllItems)
|
||||||
|
{
|
||||||
|
// Ignore all items in the sub containers.
|
||||||
|
foreach (RelatedItem ri in subContainableItems)
|
||||||
|
{
|
||||||
|
if (ri.MatchesItem(containedItem))
|
||||||
|
{
|
||||||
|
// The target item is in a subcontainer -> inverse the logic.
|
||||||
|
useMainContainerCapacity = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ri.MatchesItem(it))
|
||||||
|
{
|
||||||
|
ignoredItemCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!useMainContainerCapacity) { break; }
|
||||||
|
}
|
||||||
|
if (useMainContainerCapacity)
|
||||||
|
{
|
||||||
|
capacity *= MainContainerCapacity;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Ignore all items in the main container.
|
||||||
|
ignoredItemCount = Inventory.AllItems.Count(it => subContainableItems.Any(ri => !ri.MatchesItem(it)));
|
||||||
|
capacity *= Capacity - MainContainerCapacity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int itemCount = Inventory.AllItems.Count() - ignoredItemCount;
|
||||||
|
return Math.Min(itemCount / Math.Max(capacity, 1), 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (containedItem != null && (Inventory.Capacity == 1 || HasSubContainers))
|
||||||
|
{
|
||||||
|
int maxStackSize = Math.Min(containedItem.Prefab.MaxStackSize, GetMaxStackSize(targetSlot));
|
||||||
|
if (maxStackSize > 1 || containedItem.Prefab.HideConditionBar)
|
||||||
|
{
|
||||||
|
return containedItems.Count() / (float)maxStackSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Inventory.Capacity == 1 || ContainedStateIndicatorSlot > -1 ?
|
||||||
|
(containedItem == null ? 0.0f : containedItem.Condition / containedItem.MaxCondition) :
|
||||||
|
Inventory.EmptySlotCount / (float)Inventory.Capacity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
|
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
|
||||||
{
|
{
|
||||||
if (hideItems || (item.body != null && !item.body.Enabled)) { return; }
|
if (hideItems || (item.body != null && !item.body.Enabled)) { return; }
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ namespace Barotrauma.Items.Components
|
|||||||
private CoroutineHandle resetPredictionCoroutine;
|
private CoroutineHandle resetPredictionCoroutine;
|
||||||
private float resetPredictionTimer;
|
private float resetPredictionTimer;
|
||||||
|
|
||||||
private float currentBrightness;
|
|
||||||
|
|
||||||
public Vector2 DrawSize
|
public Vector2 DrawSize
|
||||||
{
|
{
|
||||||
get { return new Vector2(Light.Range * 2, Light.Range * 2); }
|
get { return new Vector2(Light.Range * 2, Light.Range * 2); }
|
||||||
@@ -29,14 +27,21 @@ namespace Barotrauma.Items.Components
|
|||||||
Light.Position = ParentBody != null ? ParentBody.Position : item.Position;
|
Light.Position = ParentBody != null ? ParentBody.Position : item.Position;
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void SetLightSourceState(bool enabled, float brightness)
|
partial void SetLightSourceState(bool enabled, float? brightness)
|
||||||
{
|
{
|
||||||
if (Light == null) { return; }
|
if (Light == null) { return; }
|
||||||
Light.Enabled = enabled;
|
Light.Enabled = enabled;
|
||||||
currentBrightness = brightness;
|
if (brightness.HasValue)
|
||||||
|
{
|
||||||
|
lightBrightness = brightness.Value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lightBrightness = enabled ? 1.0f : 0.0f;
|
||||||
|
}
|
||||||
if (enabled)
|
if (enabled)
|
||||||
{
|
{
|
||||||
Light.Color = LightColor.Multiply(brightness);
|
Light.Color = LightColor.Multiply(lightBrightness);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,14 +78,21 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
|
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
|
||||||
{
|
{
|
||||||
if (Light.LightSprite != null && (item.body == null || item.body.Enabled) && lightBrightness > 0.0f && IsOn && Light.Enabled)
|
if (Light?.LightSprite == null) { return; }
|
||||||
|
if ((item.body == null || item.body.Enabled) && lightBrightness > 0.0f && IsOn && Light.Enabled)
|
||||||
{
|
{
|
||||||
Vector2 origin = Light.LightSprite.Origin;
|
Vector2 origin = Light.LightSprite.Origin;
|
||||||
if ((Light.LightSpriteEffect & SpriteEffects.FlipHorizontally) == SpriteEffects.FlipHorizontally) { origin.X = Light.LightSprite.SourceRect.Width - origin.X; }
|
if ((Light.LightSpriteEffect & SpriteEffects.FlipHorizontally) == SpriteEffects.FlipHorizontally) { origin.X = Light.LightSprite.SourceRect.Width - origin.X; }
|
||||||
if ((Light.LightSpriteEffect & SpriteEffects.FlipVertically) == SpriteEffects.FlipVertically) { origin.Y = Light.LightSprite.SourceRect.Height - origin.Y; }
|
if ((Light.LightSpriteEffect & SpriteEffects.FlipVertically) == SpriteEffects.FlipVertically) { origin.Y = Light.LightSprite.SourceRect.Height - origin.Y; }
|
||||||
|
|
||||||
Vector2 drawPos = item.body?.DrawPosition ?? item.DrawPosition;
|
Vector2 drawPos = item.body?.DrawPosition ?? item.DrawPosition;
|
||||||
Light.LightSprite.Draw(spriteBatch, new Vector2(drawPos.X, -drawPos.Y), lightColor * lightBrightness, origin, -Light.Rotation, item.Scale, Light.LightSpriteEffect, itemDepth - 0.0001f);
|
|
||||||
|
Color color = lightColor;
|
||||||
|
if (Light.OverrideLightSpriteAlpha.HasValue)
|
||||||
|
{
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -413,7 +413,7 @@ namespace Barotrauma.Items.Components
|
|||||||
var wire = it.GetComponent<Wire>();
|
var wire = it.GetComponent<Wire>();
|
||||||
if (wire != null && wire.Connections.Any(c => c != null)) { return false; }
|
if (wire != null && wire.Connections.Any(c => c != null)) { return false; }
|
||||||
|
|
||||||
if (it.Container?.GetComponent<ItemContainer>() is { DrawInventory: false }) { return false; }
|
if (it.Container?.GetComponent<ItemContainer>() is { DrawInventory: false } or { AllowAccess: false }) { return false; }
|
||||||
|
|
||||||
if (it.HasTag("traitormissionitem")) { return false; }
|
if (it.HasTag("traitormissionitem")) { return false; }
|
||||||
|
|
||||||
@@ -519,7 +519,10 @@ namespace Barotrauma.Items.Components
|
|||||||
Color color = !hasPower ? NoPowerColor : turret.ActiveUser is null ? Color.DimGray : GUIStyle.Green;
|
Color color = !hasPower ? NoPowerColor : turret.ActiveUser is null ? Color.DimGray : GUIStyle.Green;
|
||||||
weaponSprite.Draw(batch, center, color, origin, rotation, scale, SpriteEffects.None);
|
weaponSprite.Draw(batch, center, color, origin, rotation, scale, SpriteEffects.None);
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
|
||||||
weaponChilds.Add(component, frame);
|
weaponChilds.Add(component, frame);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,9 @@ namespace Barotrauma.Items.Components
|
|||||||
public override bool RecreateGUIOnResolutionChange => true;
|
public override bool RecreateGUIOnResolutionChange => true;
|
||||||
|
|
||||||
public bool TriggerInfographic { get; set; }
|
public bool TriggerInfographic { get; set; }
|
||||||
|
|
||||||
|
public bool IsInfographicVisible => infographic != null && infographic.Visible;
|
||||||
|
|
||||||
partial void InitProjSpecific(ContentXElement element)
|
partial void InitProjSpecific(ContentXElement element)
|
||||||
{
|
{
|
||||||
CreateGUI();
|
CreateGUI();
|
||||||
@@ -108,6 +110,9 @@ namespace Barotrauma.Items.Components
|
|||||||
{ AbsoluteOffset = GUIStyle.ItemFrameOffset },
|
{ AbsoluteOffset = GUIStyle.ItemFrameOffset },
|
||||||
isHorizontal: true)
|
isHorizontal: true)
|
||||||
{
|
{
|
||||||
|
CanBeFocused = true,
|
||||||
|
HoverCursor = CursorState.Default,
|
||||||
|
AlwaysOverrideCursor = true,
|
||||||
RelativeSpacing = 0.012f,
|
RelativeSpacing = 0.012f,
|
||||||
Stretch = true
|
Stretch = true
|
||||||
};
|
};
|
||||||
@@ -675,7 +680,7 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TriggerInfographic)
|
if (GuiFrame is not null && GuiFrame.Visible && TriggerInfographic)
|
||||||
{
|
{
|
||||||
CreateInfrographic();
|
CreateInfrographic();
|
||||||
TriggerInfographic = false;
|
TriggerInfographic = false;
|
||||||
@@ -851,8 +856,9 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
AbsoluteOffset = new Point(0, -50).Multiply(GUI.Scale)
|
AbsoluteOffset = new Point(0, -50).Multiply(GUI.Scale)
|
||||||
};
|
};
|
||||||
new GUIButton(closeButtonRt, TextManager.Get("close"))
|
new GUIButton(closeButtonRt, TextManager.Get("closeinfographic"))
|
||||||
{
|
{
|
||||||
|
UserData = UIHighlightAction.ElementId.CloseButton,
|
||||||
OnClicked = (_, _) =>
|
OnClicked = (_, _) =>
|
||||||
{
|
{
|
||||||
CloseInfographic(Character.Controlled);
|
CloseInfographic(Character.Controlled);
|
||||||
@@ -871,6 +877,7 @@ namespace Barotrauma.Items.Components
|
|||||||
string style = arrowStyle == InfographicArrowStyle.Straight ? "InfographicArrow" : "InfographicArrowCurved";
|
string style = arrowStyle == InfographicArrowStyle.Straight ? "InfographicArrow" : "InfographicArrowCurved";
|
||||||
return new GUIImage(rt, style)
|
return new GUIImage(rt, style)
|
||||||
{
|
{
|
||||||
|
CanBeFocused = false,
|
||||||
Rotation = MathHelper.ToRadians(rotationDegrees),
|
Rotation = MathHelper.ToRadians(rotationDegrees),
|
||||||
SpriteEffects = spriteEffects
|
SpriteEffects = spriteEffects
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -329,6 +329,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
partial void UpdateSignalsProjSpecific()
|
partial void UpdateSignalsProjSpecific()
|
||||||
{
|
{
|
||||||
|
if (signals == null) { return; }
|
||||||
for (int i = 0; i < signals.Length && i < uiElements.Count; i++)
|
for (int i = 0; i < signals.Length && i < uiElements.Count; i++)
|
||||||
{
|
{
|
||||||
if (uiElements[i] is GUITextBox tb)
|
if (uiElements[i] is GUITextBox tb)
|
||||||
|
|||||||
@@ -25,14 +25,14 @@ namespace Barotrauma.Items.Components
|
|||||||
public static Color editorHighlightColor = Color.Yellow;
|
public static Color editorHighlightColor = Color.Yellow;
|
||||||
public static Color editorSelectedColor = Color.Red;
|
public static Color editorSelectedColor = Color.Red;
|
||||||
|
|
||||||
partial class WireSection
|
public partial class WireSection
|
||||||
{
|
{
|
||||||
public VertexPositionColorTexture[] vertices;
|
public VertexPositionColorTexture[] vertices;
|
||||||
public VertexPositionColorTexture[] shiftedVertices;
|
public VertexPositionColorTexture[] shiftedVertices;
|
||||||
|
|
||||||
private float cachedWidth = 0f;
|
private float cachedWidth = 0f;
|
||||||
|
|
||||||
private void RecalculateVertices(Wire wire, float width)
|
private void RecalculateVertices(Sprite wireSprite, float width)
|
||||||
{
|
{
|
||||||
if (MathUtils.NearlyEqual(cachedWidth, width)) { return; }
|
if (MathUtils.NearlyEqual(cachedWidth, width)) { return; }
|
||||||
cachedWidth = width;
|
cachedWidth = width;
|
||||||
@@ -45,13 +45,13 @@ namespace Barotrauma.Items.Components
|
|||||||
expandDir.X = -expandDir.Y;
|
expandDir.X = -expandDir.Y;
|
||||||
expandDir.Y = -temp;
|
expandDir.Y = -temp;
|
||||||
|
|
||||||
Rectangle srcRect = wire.wireSprite.SourceRect;
|
Rectangle srcRect = wireSprite.SourceRect;
|
||||||
|
|
||||||
expandDir *= width * srcRect.Height * 0.5f;
|
expandDir *= width * srcRect.Height * 0.5f;
|
||||||
|
|
||||||
Vector2 rectLocation = srcRect.Location.ToVector2();
|
Vector2 rectLocation = srcRect.Location.ToVector2();
|
||||||
Vector2 rectSize = srcRect.Size.ToVector2();
|
Vector2 rectSize = srcRect.Size.ToVector2();
|
||||||
Vector2 textureSize = new Vector2(wire.wireSprite.Texture.Width, wire.wireSprite.Texture.Height);
|
Vector2 textureSize = new Vector2(wireSprite.Texture.Width, wireSprite.Texture.Height);
|
||||||
|
|
||||||
Vector2 topLeftUv = rectLocation / textureSize;
|
Vector2 topLeftUv = rectLocation / textureSize;
|
||||||
Vector2 bottomRightUv = (rectLocation + rectSize) / textureSize;
|
Vector2 bottomRightUv = (rectLocation + rectSize) / textureSize;
|
||||||
@@ -67,10 +67,10 @@ namespace Barotrauma.Items.Components
|
|||||||
shiftedVertices = (VertexPositionColorTexture[])vertices.Clone();
|
shiftedVertices = (VertexPositionColorTexture[])vertices.Clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Draw(SpriteBatch spriteBatch, Wire wire, Color color, Vector2 offset, float depth, float width = 0.3f)
|
public void Draw(ISpriteBatch spriteBatch, Sprite wireSprite, Color color, Vector2 offset, float depth, float width = 0.3f)
|
||||||
{
|
{
|
||||||
if (width <= 0f) { return; }
|
if (width <= 0f) { return; }
|
||||||
RecalculateVertices(wire, width);
|
RecalculateVertices(wireSprite, width);
|
||||||
|
|
||||||
for (int i = 0; i < vertices.Length; i++)
|
for (int i = 0; i < vertices.Length; i++)
|
||||||
{
|
{
|
||||||
@@ -79,21 +79,22 @@ namespace Barotrauma.Items.Components
|
|||||||
shiftedVertices[i].Position.X += offset.X;
|
shiftedVertices[i].Position.X += offset.X;
|
||||||
shiftedVertices[i].Position.Y -= offset.Y;
|
shiftedVertices[i].Position.Y -= offset.Y;
|
||||||
}
|
}
|
||||||
spriteBatch.Draw(wire.wireSprite.Texture,
|
spriteBatch.Draw(
|
||||||
|
wireSprite.Texture,
|
||||||
shiftedVertices,
|
shiftedVertices,
|
||||||
depth);
|
depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Draw(SpriteBatch spriteBatch, Wire wire, Vector2 start, Vector2 end, Color color, float depth, float width = 0.3f)
|
public static void Draw(ISpriteBatch spriteBatch, Sprite wireSprite, Vector2 start, Vector2 end, Color color, float depth, float width = 0.3f)
|
||||||
{
|
{
|
||||||
start.Y = -start.Y;
|
start.Y = -start.Y;
|
||||||
end.Y = -end.Y;
|
end.Y = -end.Y;
|
||||||
|
|
||||||
spriteBatch.Draw(wire.wireSprite.Texture,
|
spriteBatch.Draw(wireSprite.Texture,
|
||||||
start, wire.wireSprite.SourceRect, color,
|
start, wireSprite.SourceRect, color,
|
||||||
MathUtils.VectorToAngle(end - start),
|
MathUtils.VectorToAngle(end - start),
|
||||||
new Vector2(0.0f, wire.wireSprite.size.Y / 2.0f),
|
new Vector2(0.0f, wireSprite.size.Y / 2.0f),
|
||||||
new Vector2((Vector2.Distance(start, end)) / wire.wireSprite.size.X, width),
|
new Vector2((Vector2.Distance(start, end)) / wireSprite.size.X, width),
|
||||||
SpriteEffects.None,
|
SpriteEffects.None,
|
||||||
depth);
|
depth);
|
||||||
}
|
}
|
||||||
@@ -123,7 +124,7 @@ namespace Barotrauma.Items.Components
|
|||||||
get => draggingWire;
|
get => draggingWire;
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void InitProjSpecific(ContentXElement element)
|
public static Sprite ExtractWireSprite(ContentXElement element)
|
||||||
{
|
{
|
||||||
if (defaultWireSprite == null)
|
if (defaultWireSprite == null)
|
||||||
{
|
{
|
||||||
@@ -133,6 +134,7 @@ namespace Barotrauma.Items.Components
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Sprite overrideSprite = null;
|
||||||
foreach (var subElement in element.Elements())
|
foreach (var subElement in element.Elements())
|
||||||
{
|
{
|
||||||
if (subElement.Name.ToString().Equals("wiresprite", StringComparison.OrdinalIgnoreCase))
|
if (subElement.Name.ToString().Equals("wiresprite", StringComparison.OrdinalIgnoreCase))
|
||||||
@@ -142,9 +144,14 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wireSprite = overrideSprite ?? defaultWireSprite;
|
return overrideSprite ?? defaultWireSprite;
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void InitProjSpecific(ContentXElement element)
|
||||||
|
{
|
||||||
|
wireSprite = ExtractWireSprite(element);
|
||||||
|
if (wireSprite != defaultWireSprite) { overrideSprite = wireSprite; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
|
public void Draw(SpriteBatch spriteBatch, bool editing, float itemDepth = -1)
|
||||||
{
|
{
|
||||||
@@ -181,20 +188,20 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
foreach (WireSection section in sections)
|
foreach (WireSection section in sections)
|
||||||
{
|
{
|
||||||
section.Draw(spriteBatch, this, Screen.Selected == GameMain.GameScreen ? higlightColor : editorHighlightColor, drawOffset, depth + 0.00001f, Width * 2.0f);
|
section.Draw(spriteBatch, wireSprite, Screen.Selected == GameMain.GameScreen ? higlightColor : editorHighlightColor, drawOffset, depth + 0.00001f, Width * 2.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (item.IsSelected)
|
else if (item.IsSelected)
|
||||||
{
|
{
|
||||||
foreach (WireSection section in sections)
|
foreach (WireSection section in sections)
|
||||||
{
|
{
|
||||||
section.Draw(spriteBatch, this, editorSelectedColor, drawOffset, depth + 0.00001f, Width * 2.0f);
|
section.Draw(spriteBatch, wireSprite, editorSelectedColor, drawOffset, depth + 0.00001f, Width * 2.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (WireSection section in sections)
|
foreach (WireSection section in sections)
|
||||||
{
|
{
|
||||||
section.Draw(spriteBatch, this, item.Color, drawOffset, depth, Width);
|
section.Draw(spriteBatch, wireSprite, item.Color, drawOffset, depth, Width);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nodes.Count > 0)
|
if (nodes.Count > 0)
|
||||||
@@ -239,13 +246,13 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
WireSection.Draw(
|
WireSection.Draw(
|
||||||
spriteBatch, this,
|
spriteBatch, wireSprite,
|
||||||
new Vector2(nodes[nodes.Count - 1].X, nodes[nodes.Count - 1].Y) + drawOffset,
|
nodes[^1] + drawOffset,
|
||||||
new Vector2(newNodePos.X, newNodePos.Y) + drawOffset,
|
new Vector2(newNodePos.X, newNodePos.Y) + drawOffset,
|
||||||
item.Color, 0.0f, Width);
|
item.Color, 0.0f, Width);
|
||||||
|
|
||||||
WireSection.Draw(
|
WireSection.Draw(
|
||||||
spriteBatch, this,
|
spriteBatch, wireSprite,
|
||||||
new Vector2(newNodePos.X, newNodePos.Y) + drawOffset,
|
new Vector2(newNodePos.X, newNodePos.Y) + drawOffset,
|
||||||
item.DrawPosition,
|
item.DrawPosition,
|
||||||
item.Color, itemDepth, Width);
|
item.Color, itemDepth, Width);
|
||||||
@@ -255,8 +262,8 @@ namespace Barotrauma.Items.Components
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
WireSection.Draw(
|
WireSection.Draw(
|
||||||
spriteBatch, this,
|
spriteBatch, wireSprite,
|
||||||
new Vector2(nodes[nodes.Count - 1].X, nodes[nodes.Count - 1].Y) + drawOffset,
|
nodes[^1] + drawOffset,
|
||||||
item.DrawPosition,
|
item.DrawPosition,
|
||||||
item.Color, 0.0f, Width);
|
item.Color, 0.0f, Width);
|
||||||
}
|
}
|
||||||
@@ -294,12 +301,12 @@ namespace Barotrauma.Items.Components
|
|||||||
Vector2 endPos = start + new Vector2((float)Math.Sin(angle), -(float)Math.Cos(angle)) * 50.0f;
|
Vector2 endPos = start + new Vector2((float)Math.Sin(angle), -(float)Math.Cos(angle)) * 50.0f;
|
||||||
|
|
||||||
WireSection.Draw(
|
WireSection.Draw(
|
||||||
spriteBatch, this,
|
spriteBatch, wireSprite,
|
||||||
start, endPos,
|
start, endPos,
|
||||||
GUIStyle.Orange, depth + 0.00001f, 0.2f);
|
GUIStyle.Orange, depth + 0.00001f, 0.2f);
|
||||||
|
|
||||||
WireSection.Draw(
|
WireSection.Draw(
|
||||||
spriteBatch, this,
|
spriteBatch, wireSprite,
|
||||||
start, start + (endPos - start) * 0.7f,
|
start, start + (endPos - start) * 0.7f,
|
||||||
item.Color, depth, 0.3f);
|
item.Color, depth, 0.3f);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
private static void GetDamageModifierText(ref LocalizedString description, DamageModifier damageModifier, Identifier afflictionIdentifier)
|
private static void GetDamageModifierText(ref LocalizedString description, DamageModifier damageModifier, Identifier afflictionIdentifier)
|
||||||
{
|
{
|
||||||
int roundedValue = (int)Math.Round((1 - damageModifier.DamageMultiplier * damageModifier.ProbabilityMultiplier) * 100);
|
int roundedValue = (int)Math.Round((1 - Math.Min(damageModifier.DamageMultiplier, damageModifier.ProbabilityMultiplier)) * 100);
|
||||||
if (roundedValue == 0) { return; }
|
if (roundedValue == 0) { return; }
|
||||||
string colorStr = XMLExtensions.ToStringHex(GUIStyle.Green);
|
string colorStr = XMLExtensions.ToStringHex(GUIStyle.Green);
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ namespace Barotrauma.Items.Components
|
|||||||
TextManager.Get($"afflictiontype.{afflictionIdentifier}").Fallback(afflictionIdentifier.Value);
|
TextManager.Get($"afflictiontype.{afflictionIdentifier}").Fallback(afflictionIdentifier.Value);
|
||||||
|
|
||||||
if (!description.IsNullOrWhiteSpace()) { description += '\n'; }
|
if (!description.IsNullOrWhiteSpace()) { description += '\n'; }
|
||||||
description += $" ‖color:{colorStr}‖{roundedValue.ToString("-0;+#")}%‖color:end‖ {afflictionName}";
|
description += $" ‖color:{colorStr}‖{roundedValue:-0;+#}%‖color:end‖ {afflictionName}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddTooltipInfo(ref LocalizedString name, ref LocalizedString description)
|
public override void AddTooltipInfo(ref LocalizedString name, ref LocalizedString description)
|
||||||
@@ -36,7 +36,6 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Identifier afflictionIdentifier in damageModifier.ParsedAfflictionIdentifiers)
|
foreach (Identifier afflictionIdentifier in damageModifier.ParsedAfflictionIdentifiers)
|
||||||
{
|
{
|
||||||
GetDamageModifierText(ref description, damageModifier, afflictionIdentifier);
|
GetDamageModifierText(ref description, damageModifier, afflictionIdentifier);
|
||||||
|
|||||||
@@ -1603,88 +1603,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (itemContainer != null && itemContainer.ShowContainedStateIndicator && itemContainer.Capacity > 0)
|
if (itemContainer != null && itemContainer.ShowContainedStateIndicator && itemContainer.Capacity > 0)
|
||||||
{
|
{
|
||||||
float containedState = 0.0f;
|
float containedState = itemContainer.GetContainedIndicatorState();
|
||||||
if (itemContainer.ShowConditionInContainedStateIndicator)
|
|
||||||
{
|
|
||||||
containedState = item.Condition / item.MaxCondition;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int targetSlot = Math.Max(itemContainer.ContainedStateIndicatorSlot, 0);
|
|
||||||
ItemSlot containedItemSlot = null;
|
|
||||||
if (targetSlot < itemContainer.Inventory.slots.Length)
|
|
||||||
{
|
|
||||||
containedItemSlot = itemContainer.Inventory.slots[targetSlot];
|
|
||||||
}
|
|
||||||
if (containedItemSlot != null)
|
|
||||||
{
|
|
||||||
Item containedItem = containedItemSlot.FirstOrDefault();
|
|
||||||
if (itemContainer.ShowTotalStackCapacityInContainedStateIndicator)
|
|
||||||
{
|
|
||||||
if (containedItem == null)
|
|
||||||
{
|
|
||||||
// No item on the defined slot, check if the items on other slots can be used.
|
|
||||||
containedItem = containedItemSlot.FirstOrDefault() ?? itemContainer.Inventory.AllItems.FirstOrDefault(it => itemContainer.CanBeContained(it, targetSlot));
|
|
||||||
}
|
|
||||||
if (containedItem != null)
|
|
||||||
{
|
|
||||||
int ignoredItemCount = 0;
|
|
||||||
var subContainableItems = itemContainer.AllSubContainableItems;
|
|
||||||
float capacity = itemContainer.GetMaxStackSize(targetSlot);
|
|
||||||
if (subContainableItems != null)
|
|
||||||
{
|
|
||||||
bool useMainContainerCapacity = true;
|
|
||||||
foreach (Item it in itemContainer.Inventory.AllItems)
|
|
||||||
{
|
|
||||||
// Ignore all items in the sub containers.
|
|
||||||
foreach (RelatedItem ri in subContainableItems)
|
|
||||||
{
|
|
||||||
if (ri.MatchesItem(containedItem))
|
|
||||||
{
|
|
||||||
// The target item is in a subcontainer -> inverse the logic.
|
|
||||||
useMainContainerCapacity = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (ri.MatchesItem(it))
|
|
||||||
{
|
|
||||||
ignoredItemCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!useMainContainerCapacity) { break; }
|
|
||||||
}
|
|
||||||
if (useMainContainerCapacity)
|
|
||||||
{
|
|
||||||
capacity *= itemContainer.MainContainerCapacity;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Ignore all items in the main container.
|
|
||||||
ignoredItemCount = itemContainer.Inventory.AllItems.Count(it => subContainableItems.Any(ri => !ri.MatchesItem(it)));
|
|
||||||
capacity *= itemContainer.Capacity - itemContainer.MainContainerCapacity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int itemCount = itemContainer.Inventory.AllItems.Count() - ignoredItemCount;
|
|
||||||
containedState = Math.Min(itemCount / Math.Max(capacity, 1), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
containedState = itemContainer.Inventory.Capacity == 1 || itemContainer.ContainedStateIndicatorSlot > -1 ?
|
|
||||||
(containedItem == null ? 0.0f : containedItem.Condition / containedItem.MaxCondition) :
|
|
||||||
itemContainer.Inventory.slots.Count(i => !i.Empty()) / (float)itemContainer.Inventory.capacity;
|
|
||||||
|
|
||||||
if (containedItem != null && (itemContainer.Inventory.Capacity == 1 || itemContainer.HasSubContainers))
|
|
||||||
{
|
|
||||||
int maxStackSize = Math.Min(containedItem.Prefab.MaxStackSize, itemContainer.GetMaxStackSize(targetSlot));
|
|
||||||
if (maxStackSize > 1 || containedItem.Prefab.HideConditionBar)
|
|
||||||
{
|
|
||||||
containedState = containedItemSlot.Items.Count / (float)maxStackSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int dir = slot.SubInventoryDir;
|
int dir = slot.SubInventoryDir;
|
||||||
Rectangle containedIndicatorArea = new Rectangle(rect.X,
|
Rectangle containedIndicatorArea = new Rectangle(rect.X,
|
||||||
dir < 0 ? rect.Bottom + HUDLayoutSettings.Padding / 2 : rect.Y - HUDLayoutSettings.Padding / 2 - ContainedIndicatorHeight, rect.Width, ContainedIndicatorHeight);
|
dir < 0 ? rect.Bottom + HUDLayoutSettings.Padding / 2 : rect.Y - HUDLayoutSettings.Padding / 2 - ContainedIndicatorHeight, rect.Width, ContainedIndicatorHeight);
|
||||||
@@ -1794,6 +1713,15 @@ namespace Barotrauma
|
|||||||
GUIStyle.SmallFont.DrawString(spriteBatch, stackCountText, stackCountPos, Color.White);
|
GUIStyle.SmallFont.DrawString(spriteBatch, stackCountText, stackCountPos, Color.White);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (HealingCooldown.IsOnCooldown && item.HasTag(HealingCooldown.MedicalItemTag))
|
||||||
|
{
|
||||||
|
RectangleF cdRect = rect;
|
||||||
|
// shrink the rect from top to bottom depending on HealingCooldown.NormalizedCooldown
|
||||||
|
cdRect.Height *= HealingCooldown.NormalizedCooldown;
|
||||||
|
cdRect.Y += rect.Height;
|
||||||
|
GUI.DrawFilledRectangle(spriteBatch, cdRect, Color.White * 0.5f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inventory != null &&
|
if (inventory != null &&
|
||||||
@@ -1807,6 +1735,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void DrawItemStateIndicator(
|
private static void DrawItemStateIndicator(
|
||||||
SpriteBatch spriteBatch, Inventory inventory,
|
SpriteBatch spriteBatch, Inventory inventory,
|
||||||
Sprite indicatorSprite, Sprite emptyIndicatorSprite, Rectangle containedIndicatorArea, float containedState,
|
Sprite indicatorSprite, Sprite emptyIndicatorSprite, Rectangle containedIndicatorArea, float containedState,
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void InitProjSpecific()
|
public void InitSpriteStates()
|
||||||
{
|
{
|
||||||
Prefab.Sprite?.EnsureLazyLoaded();
|
Prefab.Sprite?.EnsureLazyLoaded();
|
||||||
Prefab.InventoryIcon?.EnsureLazyLoaded();
|
Prefab.InventoryIcon?.EnsureLazyLoaded();
|
||||||
@@ -211,7 +211,6 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
brokenSprite.Sprite.EnsureLazyLoaded();
|
brokenSprite.Sprite.EnsureLazyLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var decorativeSprite in Prefab.DecorativeSprites)
|
foreach (var decorativeSprite in Prefab.DecorativeSprites)
|
||||||
{
|
{
|
||||||
decorativeSprite.Sprite.EnsureLazyLoaded();
|
decorativeSprite.Sprite.EnsureLazyLoaded();
|
||||||
@@ -221,6 +220,11 @@ namespace Barotrauma
|
|||||||
UpdateSpriteStates(0.0f);
|
UpdateSpriteStates(0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
partial void InitProjSpecific()
|
||||||
|
{
|
||||||
|
InitSpriteStates();
|
||||||
|
}
|
||||||
|
|
||||||
private Rectangle? cachedVisibleExtents;
|
private Rectangle? cachedVisibleExtents;
|
||||||
|
|
||||||
public void ResetCachedVisibleSize()
|
public void ResetCachedVisibleSize()
|
||||||
@@ -1409,7 +1413,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (targetComponent == null)
|
if (targetComponent == null)
|
||||||
{
|
{
|
||||||
ApplyStatusEffects(actionType, 1.0f, targetCharacter, targetLimb, useTarget, true, worldPosition: worldPosition);
|
ApplyStatusEffects(actionType, 1.0f, targetCharacter, targetLimb, useTarget, isNetworkEvent: true, worldPosition: worldPosition);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -236,6 +236,16 @@ namespace Barotrauma
|
|||||||
DecorativeSprites = decorativeSprites.ToImmutableArray();
|
DecorativeSprites = decorativeSprites.ToImmutableArray();
|
||||||
ContainedSprites = containedSprites.ToImmutableArray();
|
ContainedSprites = containedSprites.ToImmutableArray();
|
||||||
DecorativeSpriteGroups = decorativeSpriteGroups.Select(kvp => (kvp.Key, kvp.Value.ToImmutableArray())).ToImmutableDictionary();
|
DecorativeSpriteGroups = decorativeSpriteGroups.Select(kvp => (kvp.Key, kvp.Value.ToImmutableArray())).ToImmutableDictionary();
|
||||||
|
|
||||||
|
#if CLIENT
|
||||||
|
foreach (Item item in Item.ItemList)
|
||||||
|
{
|
||||||
|
if (item.Prefab == this)
|
||||||
|
{
|
||||||
|
item.InitSpriteStates();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanCharacterBuy()
|
public bool CanCharacterBuy()
|
||||||
@@ -260,16 +270,16 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public override void UpdatePlacing(Camera cam)
|
public override void UpdatePlacing(Camera cam)
|
||||||
{
|
{
|
||||||
Vector2 position = Submarine.MouseToWorldGrid(cam, Submarine.MainSub);
|
|
||||||
|
|
||||||
if (PlayerInput.SecondaryMouseButtonClicked())
|
if (PlayerInput.SecondaryMouseButtonClicked())
|
||||||
{
|
{
|
||||||
Selected = null;
|
Selected = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var potentialContainer = MapEntity.GetPotentialContainer(cam.ScreenToWorld(PlayerInput.MousePosition));
|
||||||
|
|
||||||
var potentialContainer = MapEntity.GetPotentialContainer(position);
|
Vector2 position = Submarine.MouseToWorldGrid(cam, Submarine.MainSub);
|
||||||
|
|
||||||
if (!ResizeHorizontal && !ResizeVertical)
|
if (!ResizeHorizontal && !ResizeVertical)
|
||||||
{
|
{
|
||||||
if (PlayerInput.PrimaryMouseButtonClicked() && GUI.MouseOn == null)
|
if (PlayerInput.PrimaryMouseButtonClicked() && GUI.MouseOn == null)
|
||||||
|
|||||||
@@ -293,11 +293,11 @@ namespace Barotrauma
|
|||||||
GUI.DrawRectangle(spriteBatch,
|
GUI.DrawRectangle(spriteBatch,
|
||||||
new Vector2(drawRect.X, -drawRect.Y),
|
new Vector2(drawRect.X, -drawRect.Y),
|
||||||
new Vector2(rect.Width, rect.Height),
|
new Vector2(rect.Width, rect.Height),
|
||||||
Color.Blue * alpha, false, (ID % 255) * 0.000001f, (int)Math.Max(1.5f / Screen.Selected.Cam.Zoom, 1.0f));
|
Color.Blue * alpha, false, (ID % 255) * 0.000001f, (int)Math.Max(MathF.Ceiling(1.5f / Screen.Selected.Cam.Zoom), 1.0f));
|
||||||
|
|
||||||
GUI.DrawRectangle(spriteBatch,
|
GUI.DrawRectangle(spriteBatch,
|
||||||
new Rectangle(drawRect.X, -drawRect.Y, rect.Width, rect.Height),
|
new Rectangle(drawRect.X, -drawRect.Y, rect.Width, rect.Height),
|
||||||
GUIStyle.Red * ((100.0f - OxygenPercentage) / 400.0f) * alpha, true, 0, (int)Math.Max(1.5f / Screen.Selected.Cam.Zoom, 1.0f));
|
GUIStyle.Red * ((100.0f - OxygenPercentage) / 400.0f) * alpha, true, 0, (int)Math.Max(MathF.Ceiling(1.5f / Screen.Selected.Cam.Zoom), 1.0f));
|
||||||
|
|
||||||
if (GameMain.DebugDraw)
|
if (GameMain.DebugDraw)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Content;
|
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -65,15 +64,9 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public Texture2D WaterTexture { get; }
|
public Texture2D WaterTexture { get; }
|
||||||
|
|
||||||
public WaterRenderer(GraphicsDevice graphicsDevice, ContentManager content)
|
public WaterRenderer(GraphicsDevice graphicsDevice)
|
||||||
{
|
{
|
||||||
#if WINDOWS
|
WaterEffect = EffectLoader.Load("Effects/watershader");
|
||||||
WaterEffect = content.Load<Effect>("Effects/watershader");
|
|
||||||
#endif
|
|
||||||
#if LINUX || OSX
|
|
||||||
|
|
||||||
WaterEffect = content.Load<Effect>("Effects/watershader_opengl");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
WaterTexture = TextureLoader.FromFile("Content/Effects/waterbump.png");
|
WaterTexture = TextureLoader.FromFile("Content/Effects/waterbump.png");
|
||||||
WaterEffect.Parameters["xWaterBumpMap"].SetValue(WaterTexture);
|
WaterEffect.Parameters["xWaterBumpMap"].SetValue(WaterTexture);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using Microsoft.Xna.Framework.Content;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System;
|
using System;
|
||||||
@@ -73,12 +72,14 @@ namespace Barotrauma.Lights
|
|||||||
|
|
||||||
private int recalculationCount;
|
private int recalculationCount;
|
||||||
|
|
||||||
|
private float time;
|
||||||
|
|
||||||
public IEnumerable<LightSource> Lights
|
public IEnumerable<LightSource> Lights
|
||||||
{
|
{
|
||||||
get { return lights; }
|
get { return lights; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public LightManager(GraphicsDevice graphics, ContentManager content)
|
public LightManager(GraphicsDevice graphics)
|
||||||
{
|
{
|
||||||
lights = new List<LightSource>(100);
|
lights = new List<LightSource>(100);
|
||||||
|
|
||||||
@@ -96,13 +97,8 @@ namespace Barotrauma.Lights
|
|||||||
{
|
{
|
||||||
CreateRenderTargets(graphics);
|
CreateRenderTargets(graphics);
|
||||||
|
|
||||||
#if WINDOWS
|
LosEffect = EffectLoader.Load("Effects/losshader");
|
||||||
LosEffect = content.Load<Effect>("Effects/losshader");
|
SolidColorEffect = EffectLoader.Load("Effects/solidcolor");
|
||||||
SolidColorEffect = content.Load<Effect>("Effects/solidcolor");
|
|
||||||
#else
|
|
||||||
LosEffect = content.Load<Effect>("Effects/losshader_opengl");
|
|
||||||
SolidColorEffect = content.Load<Effect>("Effects/solidcolor_opengl");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (lightEffect == null)
|
if (lightEffect == null)
|
||||||
{
|
{
|
||||||
@@ -171,10 +167,12 @@ namespace Barotrauma.Lights
|
|||||||
|
|
||||||
public void Update(float deltaTime)
|
public void Update(float deltaTime)
|
||||||
{
|
{
|
||||||
|
//wrap around if the timer gets very large, otherwise we'd start running into floating point accuracy issues
|
||||||
|
time = (time + deltaTime) % 100000.0f;
|
||||||
foreach (LightSource light in activeLights)
|
foreach (LightSource light in activeLights)
|
||||||
{
|
{
|
||||||
if (!light.Enabled) { continue; }
|
if (!light.Enabled) { continue; }
|
||||||
light.Update(deltaTime);
|
light.Update(time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -200,8 +200,6 @@ namespace Barotrauma.Lights
|
|||||||
|
|
||||||
private static Texture2D lightTexture;
|
private static Texture2D lightTexture;
|
||||||
|
|
||||||
private float blinkTimer, flickerState, pulseState;
|
|
||||||
|
|
||||||
private VertexPositionColorTexture[] vertices;
|
private VertexPositionColorTexture[] vertices;
|
||||||
private short[] indices;
|
private short[] indices;
|
||||||
|
|
||||||
@@ -486,12 +484,12 @@ namespace Barotrauma.Lights
|
|||||||
if (addLight) { GameMain.LightManager.AddLight(this); }
|
if (addLight) { GameMain.LightManager.AddLight(this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(float deltaTime)
|
public void Update(float time)
|
||||||
{
|
{
|
||||||
float brightness = 1.0f;
|
float brightness = 1.0f;
|
||||||
if (lightSourceParams.BlinkFrequency > 0.0f)
|
if (lightSourceParams.BlinkFrequency > 0.0f)
|
||||||
{
|
{
|
||||||
blinkTimer = (blinkTimer + deltaTime * lightSourceParams.BlinkFrequency) % 1.0f;
|
float blinkTimer = (time * lightSourceParams.BlinkFrequency) % 1.0f;
|
||||||
if (blinkTimer > 0.5f)
|
if (blinkTimer > 0.5f)
|
||||||
{
|
{
|
||||||
CurrentBrightness = 0.0f;
|
CurrentBrightness = 0.0f;
|
||||||
@@ -500,14 +498,13 @@ namespace Barotrauma.Lights
|
|||||||
}
|
}
|
||||||
if (lightSourceParams.PulseFrequency > 0.0f && lightSourceParams.PulseAmount > 0.0f)
|
if (lightSourceParams.PulseFrequency > 0.0f && lightSourceParams.PulseAmount > 0.0f)
|
||||||
{
|
{
|
||||||
pulseState = (pulseState + deltaTime * lightSourceParams.PulseFrequency) % 1.0f;
|
float pulseState = (time * lightSourceParams.PulseFrequency) % 1.0f;
|
||||||
//oscillate between 0-1
|
//oscillate between 0-1
|
||||||
brightness *= 1.0f - (float)(Math.Sin(pulseState * MathHelper.TwoPi) + 1.0f) / 2.0f * lightSourceParams.PulseAmount;
|
brightness *= 1.0f - (float)(Math.Sin(pulseState * MathHelper.TwoPi) + 1.0f) / 2.0f * lightSourceParams.PulseAmount;
|
||||||
}
|
}
|
||||||
if (lightSourceParams.Flicker > 0.0f)
|
if (lightSourceParams.Flicker > 0.0f && lightSourceParams.FlickerSpeed > 0.0f)
|
||||||
{
|
{
|
||||||
flickerState += deltaTime * lightSourceParams.FlickerSpeed;
|
float flickerState = (time * lightSourceParams.FlickerSpeed) % 255;
|
||||||
flickerState %= 255;
|
|
||||||
brightness *= 1.0f - PerlinNoise.GetPerlin(flickerState, flickerState * 0.5f) * lightSourceParams.Flicker;
|
brightness *= 1.0f - PerlinNoise.GetPerlin(flickerState, flickerState * 0.5f) * lightSourceParams.Flicker;
|
||||||
}
|
}
|
||||||
CurrentBrightness = brightness;
|
CurrentBrightness = brightness;
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private (Rectangle targetArea, RichString tip)? tooltip;
|
private (Rectangle targetArea, RichString tip)? tooltip;
|
||||||
|
|
||||||
private (SubmarineInfo pendingSub, float realWorldCrushDepth) pendingSubInfo;
|
private SubmarineInfo.PendingSubInfo pendingSubInfo;
|
||||||
|
|
||||||
private RichString beaconStationActiveText, beaconStationInactiveText;
|
private RichString beaconStationActiveText, beaconStationInactiveText;
|
||||||
|
|
||||||
@@ -936,39 +936,8 @@ namespace Barotrauma
|
|||||||
if (connection.LevelData.HasHuntingGrounds) { iconCount++; }
|
if (connection.LevelData.HasHuntingGrounds) { iconCount++; }
|
||||||
if (connection.Locked) { iconCount++; }
|
if (connection.Locked) { iconCount++; }
|
||||||
string tooltip = null;
|
string tooltip = null;
|
||||||
float subCrushDepth = Level.DefaultRealWorldCrushDepth;
|
|
||||||
var currentOrPendingSub = SubmarineSelection.CurrentOrPendingSubmarine();
|
|
||||||
if (Submarine.MainSub != null && Submarine.MainSub.Info == currentOrPendingSub)
|
|
||||||
{
|
|
||||||
subCrushDepth = Submarine.MainSub.RealWorldCrushDepth;
|
|
||||||
}
|
|
||||||
else if (currentOrPendingSub != null)
|
|
||||||
{
|
|
||||||
if (pendingSubInfo.pendingSub != currentOrPendingSub)
|
|
||||||
{
|
|
||||||
// Store the real world crush depth for the pending sub so that we don't have to calculate it again every time
|
|
||||||
pendingSubInfo = (currentOrPendingSub, currentOrPendingSub.GetRealWorldCrushDepth());
|
|
||||||
}
|
|
||||||
subCrushDepth = pendingSubInfo.realWorldCrushDepth;
|
|
||||||
}
|
|
||||||
if (GameMain.GameSession?.Campaign?.UpgradeManager != null)
|
|
||||||
{
|
|
||||||
var hullUpgradePrefab = UpgradePrefab.Find("increasewallhealth".ToIdentifier());
|
|
||||||
if (hullUpgradePrefab != null)
|
|
||||||
{
|
|
||||||
int pendingLevel = GameMain.GameSession.Campaign.UpgradeManager.GetUpgradeLevel(hullUpgradePrefab, hullUpgradePrefab.UpgradeCategories.First());
|
|
||||||
int currentLevel = GameMain.GameSession.Campaign.UpgradeManager.GetRealUpgradeLevel(hullUpgradePrefab, hullUpgradePrefab.UpgradeCategories.First());
|
|
||||||
if (pendingLevel > currentLevel)
|
|
||||||
{
|
|
||||||
string updateValueStr = hullUpgradePrefab.SourceElement?.GetChildElement("Structure")?.GetAttributeString("crushdepth", null);
|
|
||||||
if (!string.IsNullOrEmpty(updateValueStr))
|
|
||||||
{
|
|
||||||
subCrushDepth = PropertyReference.CalculateUpgrade(subCrushDepth, pendingLevel - currentLevel, updateValueStr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
float subCrushDepth = SubmarineInfo.GetSubCrushDepth(SubmarineSelection.CurrentOrPendingSubmarine(), ref pendingSubInfo);
|
||||||
string crushDepthWarningIconStyle = null;
|
string crushDepthWarningIconStyle = null;
|
||||||
if (connection.LevelData.InitialDepth * Physics.DisplayToRealWorldRatio > subCrushDepth)
|
if (connection.LevelData.InitialDepth * Physics.DisplayToRealWorldRatio > subCrushDepth)
|
||||||
{
|
{
|
||||||
@@ -1125,6 +1094,14 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets <see cref="pendingSubInfo"/> and forces crush depth to be calculated again for icon displaying purposes
|
||||||
|
/// </summary>
|
||||||
|
public void ResetPendingSub()
|
||||||
|
{
|
||||||
|
pendingSubInfo = new SubmarineInfo.PendingSubInfo();
|
||||||
|
}
|
||||||
|
|
||||||
partial void RemoveProjSpecific()
|
partial void RemoveProjSpecific()
|
||||||
{
|
{
|
||||||
noiseOverlay?.Remove();
|
noiseOverlay?.Remove();
|
||||||
|
|||||||
@@ -515,11 +515,11 @@ namespace Barotrauma
|
|||||||
Item targetContainer = null;
|
Item targetContainer = null;
|
||||||
bool isShiftDown = PlayerInput.IsShiftDown();
|
bool isShiftDown = PlayerInput.IsShiftDown();
|
||||||
|
|
||||||
if (!isShiftDown) return null;
|
if (!isShiftDown) { return null; }
|
||||||
|
|
||||||
foreach (MapEntity e in mapEntityList)
|
foreach (MapEntity e in mapEntityList)
|
||||||
{
|
{
|
||||||
if (!e.SelectableInEditor ||!(e is Item potentialContainer)) { continue; }
|
if (!e.SelectableInEditor || e is not Item potentialContainer) { continue; }
|
||||||
|
|
||||||
if (e.IsMouseOn(position))
|
if (e.IsMouseOn(position))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -83,7 +83,10 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
string errorMsg = "Failed to load sound file \"" + filename + "\" (file not found).";
|
string errorMsg = "Failed to load sound file \"" + filename + "\" (file not found).";
|
||||||
DebugConsole.ThrowError(errorMsg, e);
|
DebugConsole.ThrowError(errorMsg, e);
|
||||||
GameAnalyticsManager.AddErrorEventOnce("RoundSound.LoadRoundSound:FileNotFound" + filename, GameAnalyticsManager.ErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace.CleanupStackTrace());
|
if (!ContentPackageManager.ModsEnabled)
|
||||||
|
{
|
||||||
|
GameAnalyticsManager.AddErrorEventOnce("RoundSound.LoadRoundSound:FileNotFound" + filename, GameAnalyticsManager.ErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace.CleanupStackTrace());
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
catch (System.IO.InvalidDataException e)
|
catch (System.IO.InvalidDataException e)
|
||||||
|
|||||||
@@ -89,7 +89,11 @@ namespace Barotrauma
|
|||||||
CreateSpecsWindow(descriptionBox, font, includeDescription: true);
|
CreateSpecsWindow(descriptionBox, font, includeDescription: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CreateSpecsWindow(GUIListBox parent, GUIFont font, bool includeTitle = true, bool includeClass = true, bool includeDescription = false)
|
public void CreateSpecsWindow(GUIListBox parent, GUIFont font,
|
||||||
|
bool includeTitle = true,
|
||||||
|
bool includeClass = true,
|
||||||
|
bool includeDescription = false,
|
||||||
|
bool includeCrushDepth = false)
|
||||||
{
|
{
|
||||||
float leftPanelWidth = 0.6f;
|
float leftPanelWidth = 0.6f;
|
||||||
float rightPanelWidth = 0.4f / leftPanelWidth;
|
float rightPanelWidth = 0.4f / leftPanelWidth;
|
||||||
@@ -155,6 +159,22 @@ namespace Barotrauma
|
|||||||
{ CanBeFocused = false };
|
{ CanBeFocused = false };
|
||||||
cargoCapacityText.RectTransform.MinSize = new Point(0, cargoCapacityText.Children.First().Rect.Height);
|
cargoCapacityText.RectTransform.MinSize = new Point(0, cargoCapacityText.Children.First().Rect.Height);
|
||||||
|
|
||||||
|
if (includeCrushDepth)
|
||||||
|
{
|
||||||
|
var crushDepthText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), parent.Content.RectTransform),
|
||||||
|
TextManager.Get("CrushDepth"), textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(rightPanelWidth, 0.0f), crushDepthText.RectTransform, Anchor.TopRight, Pivot.TopLeft),
|
||||||
|
TextManager.GetWithVariable("meterformat", "[meters]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", GetSubCrushDepth())),
|
||||||
|
textAlignment: Alignment.TopLeft, font: font, wrap: true)
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
crushDepthText.RectTransform.MinSize = new Point(0, crushDepthText.Children.First().Rect.Height);
|
||||||
|
}
|
||||||
|
|
||||||
if (RecommendedCrewSizeMax > 0)
|
if (RecommendedCrewSizeMax > 0)
|
||||||
{
|
{
|
||||||
var crewSizeText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), parent.Content.RectTransform),
|
var crewSizeText = new GUITextBlock(new RectTransform(new Vector2(leftPanelWidth, 0), parent.Content.RectTransform),
|
||||||
@@ -227,5 +247,57 @@ namespace Barotrauma
|
|||||||
GUITextBlock.AutoScaleAndNormalize(parent.Content.GetAllChildren<GUITextBlock>().Where(c => c != submarineNameText && c != descBlock));
|
GUITextBlock.AutoScaleAndNormalize(parent.Content.GetAllChildren<GUITextBlock>().Where(c => c != submarineNameText && c != descBlock));
|
||||||
parent.ForceLayoutRecalculation();
|
parent.ForceLayoutRecalculation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public readonly record struct PendingSubInfo(SubmarineInfo PendingSub = null, bool StructuresDefineRealWorldCrushDepth = false, float RealWorldCrushDepth = Level.DefaultRealWorldCrushDepth);
|
||||||
|
|
||||||
|
private float GetSubCrushDepth()
|
||||||
|
{
|
||||||
|
var pendingSubInfo = new PendingSubInfo();
|
||||||
|
return GetSubCrushDepth(this, ref pendingSubInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float GetSubCrushDepth(SubmarineInfo subInfo, ref PendingSubInfo pendingSubInfo)
|
||||||
|
{
|
||||||
|
float subCrushDepth = Level.DefaultRealWorldCrushDepth;
|
||||||
|
if (Submarine.MainSub != null && Submarine.MainSub.Info == subInfo)
|
||||||
|
{
|
||||||
|
subCrushDepth = Submarine.MainSub.RealWorldCrushDepth;
|
||||||
|
}
|
||||||
|
else if (subInfo != null)
|
||||||
|
{
|
||||||
|
if (pendingSubInfo.PendingSub != subInfo)
|
||||||
|
{
|
||||||
|
// Store the real world crush depth for the pending sub so that we don't have to calculate it again every time
|
||||||
|
pendingSubInfo = new PendingSubInfo(subInfo, subInfo.IsCrushDepthDefinedInStructures(out float realWorldCrushDepth), realWorldCrushDepth);
|
||||||
|
}
|
||||||
|
subCrushDepth = pendingSubInfo.RealWorldCrushDepth;
|
||||||
|
}
|
||||||
|
if (GameMain.GameSession?.Campaign?.UpgradeManager != null && UpgradePrefab.Find("increasewallhealth".ToIdentifier()) is UpgradePrefab hullUpgradePrefab)
|
||||||
|
{
|
||||||
|
int pendingLevel = GameMain.GameSession.Campaign.UpgradeManager.GetUpgradeLevel(hullUpgradePrefab, hullUpgradePrefab.UpgradeCategories.First(), info: subInfo);
|
||||||
|
// If there is a sub switch pending, unless its structures have crush depth defined in their elements,
|
||||||
|
// calculate the value based on the default crush depth and pending upgrade level
|
||||||
|
int currentLevel = 0;
|
||||||
|
if (pendingSubInfo.PendingSub is null || pendingSubInfo.StructuresDefineRealWorldCrushDepth)
|
||||||
|
{
|
||||||
|
currentLevel = GameMain.GameSession.Campaign.UpgradeManager.GetRealUpgradeLevelForSub(hullUpgradePrefab, hullUpgradePrefab.UpgradeCategories.First(), subInfo);
|
||||||
|
}
|
||||||
|
if (pendingLevel > currentLevel)
|
||||||
|
{
|
||||||
|
string updateValueStr = hullUpgradePrefab.SourceElement?.GetChildElement("Structure")?.GetAttributeString("crushdepth", null);
|
||||||
|
if (!string.IsNullOrEmpty(updateValueStr))
|
||||||
|
{
|
||||||
|
if (currentLevel > 0)
|
||||||
|
{
|
||||||
|
// If the current level is greater than 0, reset the crush depth value back to the base value before calculating the upgrade
|
||||||
|
int upgradePercentage = UpgradePrefab.ParsePercentage(updateValueStr, Identifier.Empty, suppressWarnings: true);
|
||||||
|
subCrushDepth /= (1f + (upgradePercentage / 100f * currentLevel));
|
||||||
|
}
|
||||||
|
subCrushDepth = PropertyReference.CalculateUpgrade(subCrushDepth, pendingLevel, updateValueStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return subCrushDepth;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,26 +4,29 @@ using Microsoft.Xna.Framework;
|
|||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
using Barotrauma.Items.Components;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
class SubmarinePreview : IDisposable
|
sealed class SubmarinePreview : IDisposable
|
||||||
{
|
{
|
||||||
private SpriteRecorder spriteRecorder;
|
|
||||||
private readonly SubmarineInfo submarineInfo;
|
private readonly SubmarineInfo submarineInfo;
|
||||||
|
|
||||||
|
private SpriteRecorder spriteRecorder;
|
||||||
private Camera camera;
|
private Camera camera;
|
||||||
private Task loadTask;
|
private Task loadTask;
|
||||||
|
private (Vector2 Min, Vector2 Max) bounds;
|
||||||
|
|
||||||
private volatile bool isDisposed;
|
private volatile bool isDisposed;
|
||||||
|
|
||||||
private GUIFrame previewFrame;
|
private GUIFrame previewFrame;
|
||||||
|
|
||||||
private class HullCollection
|
private sealed class HullCollection
|
||||||
{
|
{
|
||||||
public readonly List<Rectangle> Rects;
|
public readonly List<Rectangle> Rects;
|
||||||
public readonly LocalizedString Name;
|
public readonly LocalizedString Name;
|
||||||
@@ -42,7 +45,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct Door
|
private readonly struct Door
|
||||||
{
|
{
|
||||||
public readonly Rectangle Rect;
|
public readonly Rectangle Rect;
|
||||||
|
|
||||||
@@ -150,7 +153,9 @@ namespace Barotrauma
|
|||||||
ScrollBarVisible = false,
|
ScrollBarVisible = false,
|
||||||
Spacing = GUI.IntScale(5)
|
Spacing = GUI.IntScale(5)
|
||||||
};
|
};
|
||||||
subInfo.CreateSpecsWindow(specsContainer, GUIStyle.Font, includeTitle: false, includeDescription: true);
|
subInfo.CreateSpecsWindow(specsContainer, GUIStyle.Font,
|
||||||
|
includeTitle: false,
|
||||||
|
includeDescription: true);
|
||||||
int width = specsContainer.Rect.Width;
|
int width = specsContainer.Rect.Width;
|
||||||
void recalculateSpecsContainerHeight()
|
void recalculateSpecsContainerHeight()
|
||||||
{
|
{
|
||||||
@@ -186,7 +191,22 @@ namespace Barotrauma
|
|||||||
});
|
});
|
||||||
recalculateSpecsContainerHeight();
|
recalculateSpecsContainerHeight();
|
||||||
|
|
||||||
GeneratePreviewMeshes();
|
TaskPool.Add(nameof(GeneratePreviewMeshes), GeneratePreviewMeshes(), _ =>
|
||||||
|
{
|
||||||
|
if (isDisposed) { return; }
|
||||||
|
// Reset the camera's position on the main thread,
|
||||||
|
// because the Camera class is not thread-safe and
|
||||||
|
// it's possible for its state to not get updated
|
||||||
|
// properly if done within a task
|
||||||
|
camera.Position = (bounds.Min + bounds.Max) * (0.5f, -0.5f);
|
||||||
|
Vector2 span2d = bounds.Max - bounds.Min;
|
||||||
|
Vector2 scaledSpan2d = span2d / camera.Resolution.ToVector2();
|
||||||
|
float scaledSpan = Math.Max(scaledSpan2d.X, scaledSpan2d.Y);
|
||||||
|
camera.MinZoom = Math.Min(0.1f, 0.4f / scaledSpan);
|
||||||
|
camera.Zoom = 0.7f / scaledSpan;
|
||||||
|
camera.StopMovement();
|
||||||
|
camera.UpdateTransform(interpolate: false, updateListener: false);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddToGUIUpdateList()
|
public static void AddToGUIUpdateList()
|
||||||
@@ -207,6 +227,7 @@ namespace Barotrauma
|
|||||||
spriteRecorder.Begin(SpriteSortMode.BackToFront);
|
spriteRecorder.Begin(SpriteSortMode.BackToFront);
|
||||||
|
|
||||||
HashSet<int> toIgnore = new HashSet<int>();
|
HashSet<int> toIgnore = new HashSet<int>();
|
||||||
|
HashSet<int> wires = new HashSet<int>();
|
||||||
|
|
||||||
foreach (var subElement in submarineInfo.SubmarineElement.Elements())
|
foreach (var subElement in submarineInfo.SubmarineElement.Elements())
|
||||||
{
|
{
|
||||||
@@ -221,7 +242,7 @@ namespace Barotrauma
|
|||||||
ExtractItemContainerIds(component, toIgnore);
|
ExtractItemContainerIds(component, toIgnore);
|
||||||
break;
|
break;
|
||||||
case "connectionpanel":
|
case "connectionpanel":
|
||||||
ExtractConnectionPanelLinks(component, toIgnore);
|
ExtractConnectionPanelLinks(component, wires);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -231,20 +252,25 @@ namespace Barotrauma
|
|||||||
await Task.Yield();
|
await Task.Yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var wireNodes = new List<XElement>();
|
||||||
|
|
||||||
foreach (var subElement in submarineInfo.SubmarineElement.Elements())
|
foreach (var subElement in submarineInfo.SubmarineElement.Elements())
|
||||||
{
|
{
|
||||||
if (subElement.GetAttributeBool("hiddeningame", false)) { continue; }
|
if (subElement.GetAttributeBool("hiddeningame", false)) { continue; }
|
||||||
switch (subElement.Name.LocalName.ToLowerInvariant())
|
switch (subElement.Name.LocalName.ToLowerInvariant())
|
||||||
{
|
{
|
||||||
|
case "structure":
|
||||||
case "item":
|
case "item":
|
||||||
if (!toIgnore.Contains(subElement.GetAttributeInt("ID", 0)))
|
var id = subElement.GetAttributeInt("ID", 0);
|
||||||
|
if (wires.Contains(id))
|
||||||
|
{
|
||||||
|
wireNodes.Add(subElement);
|
||||||
|
}
|
||||||
|
else if (!toIgnore.Contains(id))
|
||||||
{
|
{
|
||||||
BakeMapEntity(subElement);
|
BakeMapEntity(subElement);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "structure":
|
|
||||||
BakeMapEntity(subElement);
|
|
||||||
break;
|
|
||||||
case "hull":
|
case "hull":
|
||||||
Identifier identifier = subElement.GetAttributeIdentifier("roomname", "");
|
Identifier identifier = subElement.GetAttributeIdentifier("roomname", "");
|
||||||
if (!identifier.IsEmpty)
|
if (!identifier.IsEmpty)
|
||||||
@@ -261,15 +287,14 @@ namespace Barotrauma
|
|||||||
if (isDisposed) { return; }
|
if (isDisposed) { return; }
|
||||||
await Task.Yield();
|
await Task.Yield();
|
||||||
}
|
}
|
||||||
spriteRecorder.End();
|
|
||||||
|
|
||||||
camera.Position = (spriteRecorder.Min + spriteRecorder.Max) * 0.5f;
|
bounds = (spriteRecorder.Min, spriteRecorder.Max);
|
||||||
float scaledSpan = (spriteRecorder.Max - spriteRecorder.Min).X / camera.Resolution.X;
|
wireNodes.ForEach(BakeWireNodes);
|
||||||
camera.Zoom = 0.8f / scaledSpan;
|
|
||||||
camera.StopMovement();
|
spriteRecorder.End();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExtractItemContainerIds(XElement component, HashSet<int> ids)
|
private static void ExtractItemContainerIds(XElement component, HashSet<int> ids)
|
||||||
{
|
{
|
||||||
string containedString = component.GetAttributeString("contained", "");
|
string containedString = component.GetAttributeString("contained", "");
|
||||||
string[] itemIdStrings = containedString.Split(',');
|
string[] itemIdStrings = containedString.Split(',');
|
||||||
@@ -283,7 +308,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExtractConnectionPanelLinks(XElement component, HashSet<int> ids)
|
private static void ExtractConnectionPanelLinks(XElement component, HashSet<int> ids)
|
||||||
{
|
{
|
||||||
var pins = component.Elements("input").Concat(component.Elements("output"));
|
var pins = component.Elements("input").Concat(component.Elements("output"));
|
||||||
foreach (var pin in pins)
|
foreach (var pin in pins)
|
||||||
@@ -297,6 +322,39 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void BakeWireNodes(XElement element)
|
||||||
|
{
|
||||||
|
var prefabIdentifier = element.GetAttributeIdentifier("identifier", "");
|
||||||
|
if (prefabIdentifier.IsEmpty) { return; }
|
||||||
|
if (!ItemPrefab.Prefabs.TryGet(prefabIdentifier, out var prefab)) { return; }
|
||||||
|
|
||||||
|
var prefabWireComponentElement = prefab.ConfigElement.GetChildElement("wire");
|
||||||
|
if (prefabWireComponentElement is null) { return; }
|
||||||
|
|
||||||
|
var wireComponent = element.GetChildElement("wire");
|
||||||
|
if (wireComponent is null) { return; }
|
||||||
|
|
||||||
|
var color = element.GetAttributeColor("spritecolor") ?? Color.White;
|
||||||
|
|
||||||
|
var nodes = Wire.ExtractNodes(wireComponent).ToImmutableArray();
|
||||||
|
var wireSprite = Wire.ExtractWireSprite(prefab.ConfigElement);
|
||||||
|
|
||||||
|
var useSpriteDepth = element.GetAttributeBool("usespritedepth", false);
|
||||||
|
var depth =
|
||||||
|
useSpriteDepth
|
||||||
|
? element.GetAttributeFloat("spritedepth", 1.0f)
|
||||||
|
: wireSprite.Depth;
|
||||||
|
|
||||||
|
var width = prefabWireComponentElement.GetAttributeFloat("width", 0.3f);
|
||||||
|
|
||||||
|
for (int i = 0; i < nodes.Length - 1; i++)
|
||||||
|
{
|
||||||
|
var line = (Start: nodes[i], End: nodes[i + 1]);
|
||||||
|
var wireSegment = new Wire.WireSection(line.Start, line.End);
|
||||||
|
wireSegment.Draw(spriteRecorder, wireSprite, color, Vector2.Zero, depth, width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void BakeMapEntity(XElement element)
|
private void BakeMapEntity(XElement element)
|
||||||
{
|
{
|
||||||
Identifier identifier = element.GetAttributeIdentifier("identifier", Identifier.Empty);
|
Identifier identifier = element.GetAttributeIdentifier("identifier", Identifier.Empty);
|
||||||
@@ -313,27 +371,27 @@ namespace Barotrauma
|
|||||||
|
|
||||||
float rotation = element.GetAttributeFloat("rotation", 0f);
|
float rotation = element.GetAttributeFloat("rotation", 0f);
|
||||||
|
|
||||||
MapEntityPrefab prefab = null;
|
MapEntityPrefab prefab;
|
||||||
if (element.Name.ToString().Equals("item", StringComparison.OrdinalIgnoreCase) &&
|
if (element.NameAsIdentifier() == "item"
|
||||||
ItemPrefab.Prefabs.TryGet(identifier, out ItemPrefab ip))
|
&& ItemPrefab.Prefabs.TryGet(identifier, out ItemPrefab ip))
|
||||||
{
|
{
|
||||||
prefab = ip;
|
prefab = ip;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
prefab = MapEntityPrefab.List.FirstOrDefault(p => p.Identifier == identifier);
|
prefab = MapEntityPrefab.FindByIdentifier(identifier);
|
||||||
}
|
}
|
||||||
if (prefab == null) { return; }
|
if (prefab == null) { return; }
|
||||||
|
|
||||||
var texture = prefab.Sprite.Texture;
|
flippedX &= prefab.CanSpriteFlipX;
|
||||||
var srcRect = prefab.Sprite.SourceRect;
|
flippedY &= prefab.CanSpriteFlipY;
|
||||||
|
|
||||||
SpriteEffects spriteEffects = SpriteEffects.None;
|
SpriteEffects spriteEffects = SpriteEffects.None;
|
||||||
if (flippedX && ((prefab as ItemPrefab)?.CanSpriteFlipX ?? true))
|
if (flippedX)
|
||||||
{
|
{
|
||||||
spriteEffects |= SpriteEffects.FlipHorizontally;
|
spriteEffects |= SpriteEffects.FlipHorizontally;
|
||||||
}
|
}
|
||||||
if (flippedY && ((prefab as ItemPrefab)?.CanSpriteFlipY ?? true))
|
if (flippedY)
|
||||||
{
|
{
|
||||||
spriteEffects |= SpriteEffects.FlipVertically;
|
spriteEffects |= SpriteEffects.FlipVertically;
|
||||||
}
|
}
|
||||||
@@ -419,8 +477,8 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
float offsetState = 0f;
|
float offsetState = 0f;
|
||||||
Vector2 offset = decorativeSprite.GetOffset(ref offsetState, Vector2.Zero) * scale;
|
Vector2 offset = decorativeSprite.GetOffset(ref offsetState, Vector2.Zero) * scale;
|
||||||
if (flippedX && itemPrefab.CanSpriteFlipX) { offset.X = -offset.X; }
|
if (flippedX) { offset.X = -offset.X; }
|
||||||
if (flippedY && itemPrefab.CanSpriteFlipY) { offset.Y = -offset.Y; }
|
if (flippedY) { offset.Y = -offset.Y; }
|
||||||
decorativeSprite.Sprite.DrawTiled(spriteRecorder,
|
decorativeSprite.Sprite.DrawTiled(spriteRecorder,
|
||||||
new Vector2(spritePos.X + offset.X - rect.Width / 2, -(spritePos.Y + offset.Y + rect.Height / 2)),
|
new Vector2(spritePos.X + offset.X - rect.Width / 2, -(spritePos.Y + offset.Y + rect.Height / 2)),
|
||||||
rect.Size.ToVector2(), color: color,
|
rect.Size.ToVector2(), color: color,
|
||||||
@@ -451,8 +509,8 @@ namespace Barotrauma
|
|||||||
float rotationState = 0f; float offsetState = 0f;
|
float rotationState = 0f; float offsetState = 0f;
|
||||||
float rot = decorativeSprite.GetRotation(ref rotationState, 0f);
|
float rot = decorativeSprite.GetRotation(ref rotationState, 0f);
|
||||||
Vector2 offset = decorativeSprite.GetOffset(ref offsetState, Vector2.Zero) * scale;
|
Vector2 offset = decorativeSprite.GetOffset(ref offsetState, Vector2.Zero) * scale;
|
||||||
if (flippedX && itemPrefab.CanSpriteFlipX) { offset.X = -offset.X; }
|
if (flippedX) { offset.X = -offset.X; }
|
||||||
if (flippedY && itemPrefab.CanSpriteFlipY) { offset.Y = -offset.Y; }
|
if (flippedY) { offset.Y = -offset.Y; }
|
||||||
decorativeSprite.Sprite.Draw(spriteRecorder, new Vector2(spritePos.X + offset.X, -(spritePos.Y + offset.Y)), color,
|
decorativeSprite.Sprite.Draw(spriteRecorder, new Vector2(spritePos.X + offset.X, -(spritePos.Y + offset.Y)), color,
|
||||||
MathHelper.ToRadians(rotation) + rot, decorativeSprite.GetScale(0f) * scale, prefab.Sprite.effects,
|
MathHelper.ToRadians(rotation) + rot, decorativeSprite.GetScale(0f) * scale, prefab.Sprite.effects,
|
||||||
depth: Math.Min(depth + (decorativeSprite.Sprite.Depth - prefab.Sprite.Depth), 0.999f));
|
depth: Math.Min(depth + (decorativeSprite.Sprite.Depth - prefab.Sprite.Depth), 0.999f));
|
||||||
@@ -472,6 +530,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
overrideSprite = false;
|
overrideSprite = false;
|
||||||
|
|
||||||
|
float relativeScale = scale / prefab.Scale;
|
||||||
foreach (var subElement in prefab.ConfigElement.Elements())
|
foreach (var subElement in prefab.ConfigElement.Elements())
|
||||||
{
|
{
|
||||||
switch (subElement.Name.LocalName.ToLowerInvariant())
|
switch (subElement.Name.LocalName.ToLowerInvariant())
|
||||||
@@ -498,7 +557,6 @@ namespace Barotrauma
|
|||||||
relativeBarrelPos,
|
relativeBarrelPos,
|
||||||
MathHelper.ToRadians(rotation));
|
MathHelper.ToRadians(rotation));
|
||||||
|
|
||||||
float relativeScale = scale / prefab.Scale;
|
|
||||||
Vector2 drawPos = new Vector2(rect.X + rect.Width * relativeScale / 2 + transformedBarrelPos.X * relativeScale, rect.Y - rect.Height * relativeScale / 2 - transformedBarrelPos.Y * relativeScale);
|
Vector2 drawPos = new Vector2(rect.X + rect.Width * relativeScale / 2 + transformedBarrelPos.X * relativeScale, rect.Y - rect.Height * relativeScale / 2 - transformedBarrelPos.Y * relativeScale);
|
||||||
drawPos.Y = -drawPos.Y;
|
drawPos.Y = -drawPos.Y;
|
||||||
|
|
||||||
@@ -516,20 +574,22 @@ namespace Barotrauma
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case "door":
|
case "door":
|
||||||
doors.Add(new Door(rect));
|
var scaledRect = rect with { Size = (rect.Size.ToVector2() * relativeScale).ToPoint() };
|
||||||
|
|
||||||
|
doors.Add(new Door(scaledRect));
|
||||||
|
|
||||||
var doorSpriteElem = subElement.Elements().FirstOrDefault(e => e.Name.LocalName.Equals("sprite", StringComparison.OrdinalIgnoreCase));
|
var doorSpriteElem = subElement.Elements().FirstOrDefault(e => e.Name.LocalName.Equals("sprite", StringComparison.OrdinalIgnoreCase));
|
||||||
if (doorSpriteElem != null)
|
if (doorSpriteElem != null)
|
||||||
{
|
{
|
||||||
string texturePath = doorSpriteElem.GetAttributeString("texture", "");
|
string texturePath = doorSpriteElem.GetAttributeStringUnrestricted("texture", "");
|
||||||
Vector2 pos = rect.Location.ToVector2() * new Vector2(1f, -1f);
|
Vector2 pos = scaledRect.Location.ToVector2() * new Vector2(1f, -1f);
|
||||||
if (subElement.GetAttributeBool("horizontal", false))
|
if (subElement.GetAttributeBool("horizontal", false))
|
||||||
{
|
{
|
||||||
pos.Y += (float)rect.Height * 0.5f;
|
pos.Y += (float)scaledRect.Height * 0.5f;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pos.X += (float)rect.Width * 0.5f;
|
pos.X += (float)scaledRect.Width * 0.5f;
|
||||||
}
|
}
|
||||||
Sprite doorSprite = new Sprite(doorSpriteElem, texturePath.Contains("/") ? "" : Path.GetDirectoryName(prefab.FilePath));
|
Sprite doorSprite = new Sprite(doorSpriteElem, texturePath.Contains("/") ? "" : Path.GetDirectoryName(prefab.FilePath));
|
||||||
spriteRecorder.Draw(doorSprite.Texture, pos,
|
spriteRecorder.Draw(doorSprite.Texture, pos,
|
||||||
@@ -555,7 +615,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ParseUpgrades(XElement prefabConfigElement, ref float scale)
|
private void ParseUpgrades(XElement prefabConfigElement, ref float scale)
|
||||||
{
|
{
|
||||||
foreach (var upgrade in prefabConfigElement.Elements("Upgrade"))
|
foreach (var upgrade in prefabConfigElement.Elements("Upgrade"))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace Barotrauma.Networking
|
|||||||
string name,
|
string name,
|
||||||
Either<Address, AccountId> addressOrAccountId,
|
Either<Address, AccountId> addressOrAccountId,
|
||||||
string reason,
|
string reason,
|
||||||
DateTime? expiration)
|
Option<SerializableDateTime> expiration)
|
||||||
{
|
{
|
||||||
this.Name = name;
|
this.Name = name;
|
||||||
this.AddressOrAccountId = addressOrAccountId;
|
this.AddressOrAccountId = addressOrAccountId;
|
||||||
@@ -66,9 +66,20 @@ namespace Barotrauma.Networking
|
|||||||
};
|
};
|
||||||
|
|
||||||
var addressOrAccountId = bannedPlayer.AddressOrAccountId;
|
var addressOrAccountId = bannedPlayer.AddressOrAccountId;
|
||||||
GUITextBlock textBlock = new GUITextBlock(
|
|
||||||
new RectTransform(new Vector2(0.5f, 1.0f), topArea.RectTransform),
|
string nameText = bannedPlayer.Name;
|
||||||
bannedPlayer.Name + " (" + addressOrAccountId + ")") { CanBeFocused = true };
|
if (addressOrAccountId.TryCast(out Address address))
|
||||||
|
{
|
||||||
|
nameText += $" ({address.StringRepresentation})";
|
||||||
|
}
|
||||||
|
else if (addressOrAccountId.TryCast(out AccountId accountId))
|
||||||
|
{
|
||||||
|
nameText += $" ({accountId.StringRepresentation})";
|
||||||
|
}
|
||||||
|
GUITextBlock textBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), topArea.RectTransform), nameText)
|
||||||
|
{
|
||||||
|
CanBeFocused = true
|
||||||
|
};
|
||||||
textBlock.RectTransform.MinSize = new Point(
|
textBlock.RectTransform.MinSize = new Point(
|
||||||
(int)textBlock.Font.MeasureString(textBlock.Text.SanitizedValue).X, 0);
|
(int)textBlock.Font.MeasureString(textBlock.Text.SanitizedValue).X, 0);
|
||||||
|
|
||||||
@@ -83,8 +94,9 @@ namespace Barotrauma.Networking
|
|||||||
topArea.ForceLayoutRecalculation();
|
topArea.ForceLayoutRecalculation();
|
||||||
|
|
||||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedPlayerFrame.RectTransform),
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedPlayerFrame.RectTransform),
|
||||||
bannedPlayer.ExpirationTime == null ?
|
bannedPlayer.ExpirationTime.TryUnwrap(out var expirationTime)
|
||||||
TextManager.Get("BanPermanent") : TextManager.GetWithVariable("BanExpires", "[time]", bannedPlayer.ExpirationTime.Value.ToString()),
|
? TextManager.GetWithVariable("BanExpires", "[time]", expirationTime.ToLocalUserString())
|
||||||
|
: TextManager.Get("BanPermanent"),
|
||||||
font: GUIStyle.SmallFont);
|
font: GUIStyle.SmallFont);
|
||||||
|
|
||||||
LocalizedString reason = TextManager.GetServerMessage(bannedPlayer.Reason).Fallback(bannedPlayer.Reason);
|
LocalizedString reason = TextManager.GetServerMessage(bannedPlayer.Reason).Fallback(bannedPlayer.Reason);
|
||||||
@@ -106,7 +118,7 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
private bool RemoveBan(GUIButton button, object obj)
|
private bool RemoveBan(GUIButton button, object obj)
|
||||||
{
|
{
|
||||||
if (!(obj is BannedPlayer banned)) { return false; }
|
if (obj is not BannedPlayer banned) { return false; }
|
||||||
|
|
||||||
localRemovedBans.Add(banned.UniqueIdentifier);
|
localRemovedBans.Add(banned.UniqueIdentifier);
|
||||||
RecreateBanFrame();
|
RecreateBanFrame();
|
||||||
@@ -138,11 +150,11 @@ namespace Barotrauma.Networking
|
|||||||
bool includesExpiration = incMsg.ReadBoolean();
|
bool includesExpiration = incMsg.ReadBoolean();
|
||||||
incMsg.ReadPadBits();
|
incMsg.ReadPadBits();
|
||||||
|
|
||||||
DateTime? expiration = null;
|
Option<SerializableDateTime> expiration = Option<SerializableDateTime>.None();
|
||||||
if (includesExpiration)
|
if (includesExpiration)
|
||||||
{
|
{
|
||||||
double hoursFromNow = incMsg.ReadDouble();
|
double hoursFromNow = incMsg.ReadDouble();
|
||||||
expiration = DateTime.Now + TimeSpan.FromHours(hoursFromNow);
|
expiration = Option<SerializableDateTime>.Some(SerializableDateTime.LocalNow + TimeSpan.FromHours(hoursFromNow));
|
||||||
}
|
}
|
||||||
|
|
||||||
string reason = incMsg.ReadString();
|
string reason = incMsg.ReadString();
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ namespace Barotrauma.Networking
|
|||||||
if (type != ChatMessageType.Order)
|
if (type != ChatMessageType.Order)
|
||||||
{
|
{
|
||||||
changeType = (PlayerConnectionChangeType)msg.ReadByte();
|
changeType = (PlayerConnectionChangeType)msg.ReadByte();
|
||||||
txt = msg.ReadString();
|
|
||||||
}
|
}
|
||||||
|
txt = msg.ReadString();
|
||||||
|
|
||||||
string senderName = msg.ReadString();
|
string senderName = msg.ReadString();
|
||||||
Character senderCharacter = null;
|
Character senderCharacter = null;
|
||||||
@@ -87,11 +87,6 @@ namespace Barotrauma.Networking
|
|||||||
targetRoom = senderCharacter?.CurrentHull?.DisplayName?.Value;
|
targetRoom = senderCharacter?.CurrentHull?.DisplayName?.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
txt = orderPrefab.GetChatMessage(orderMessageInfo.TargetCharacter?.Name, targetRoom,
|
|
||||||
givingOrderToSelf: orderMessageInfo.TargetCharacter == senderCharacter,
|
|
||||||
orderOption: orderOption,
|
|
||||||
isNewOrder: orderMessageInfo.IsNewOrder);
|
|
||||||
|
|
||||||
if (GameMain.Client.GameStarted && Screen.Selected == GameMain.GameScreen)
|
if (GameMain.Client.GameStarted && Screen.Selected == GameMain.GameScreen)
|
||||||
{
|
{
|
||||||
Order order = null;
|
Order order = null;
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ namespace Barotrauma.Networking
|
|||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError($"Failed to start ChildServerRelay Process. File: {processInfo.FileName}, arguments: {processInfo.Arguments}");
|
DebugConsole.ThrowError($"Failed to start ChildServerRelay Process. File: {processInfo.FileName}, arguments: {processInfo.Arguments}");
|
||||||
|
ForceShutDown();
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -522,7 +522,7 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
if (GameStarted && Screen.Selected == GameMain.GameScreen)
|
if (GameStarted && Screen.Selected == GameMain.GameScreen)
|
||||||
{
|
{
|
||||||
EndVoteTickBox.Visible = ServerSettings.AllowEndVoting && HasSpawned && !(GameMain.GameSession?.GameMode is CampaignMode);
|
EndVoteTickBox.Visible = ServerSettings.AllowEndVoting && HasSpawned;
|
||||||
|
|
||||||
RespawnManager?.Update(deltaTime);
|
RespawnManager?.Update(deltaTime);
|
||||||
|
|
||||||
@@ -1104,11 +1104,7 @@ namespace Barotrauma.Networking
|
|||||||
VoipClient = new VoipClient(this, ClientPeer);
|
VoipClient = new VoipClient(this, ClientPeer);
|
||||||
|
|
||||||
//if we're still in the game, roundsummary or lobby screen, we don't need to redownload the mods
|
//if we're still in the game, roundsummary or lobby screen, we don't need to redownload the mods
|
||||||
if (!(Screen.Selected is GameScreen) && !(Screen.Selected is RoundSummaryScreen) && !(Screen.Selected is NetLobbyScreen))
|
if (Screen.Selected is GameScreen or RoundSummaryScreen or NetLobbyScreen)
|
||||||
{
|
|
||||||
GameMain.ModDownloadScreen.Select();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
EntityEventManager.ClearSelf();
|
EntityEventManager.ClearSelf();
|
||||||
foreach (Character c in Character.CharacterList)
|
foreach (Character c in Character.CharacterList)
|
||||||
@@ -1116,6 +1112,10 @@ namespace Barotrauma.Networking
|
|||||||
c.ResetNetState();
|
c.ResetNetState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GameMain.ModDownloadScreen.Select();
|
||||||
|
}
|
||||||
|
|
||||||
chatBox.InputBox.Enabled = true;
|
chatBox.InputBox.Enabled = true;
|
||||||
if (GameMain.NetLobbyScreen?.ChatInput != null)
|
if (GameMain.NetLobbyScreen?.ChatInput != null)
|
||||||
@@ -1537,8 +1537,9 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
roundInitStatus = RoundInitStatus.WaitingForStartGameFinalize;
|
roundInitStatus = RoundInitStatus.WaitingForStartGameFinalize;
|
||||||
|
|
||||||
DateTime? timeOut = null;
|
//wait for up to 30 seconds for the server to send the STARTGAMEFINALIZE message
|
||||||
TimeSpan timeOutDuration = new TimeSpan(0, 0, seconds: 30);
|
TimeSpan timeOutDuration = new TimeSpan(0, 0, seconds: 30);
|
||||||
|
DateTime timeOut = DateTime.Now + timeOutDuration;
|
||||||
DateTime requestFinalizeTime = DateTime.Now;
|
DateTime requestFinalizeTime = DateTime.Now;
|
||||||
TimeSpan requestFinalizeInterval = new TimeSpan(0, 0, 2);
|
TimeSpan requestFinalizeInterval = new TimeSpan(0, 0, 2);
|
||||||
IWriteMessage msg = new WriteOnlyMessage();
|
IWriteMessage msg = new WriteOnlyMessage();
|
||||||
@@ -1547,11 +1548,15 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
GUIMessageBox interruptPrompt = null;
|
GUIMessageBox interruptPrompt = null;
|
||||||
|
|
||||||
while (true)
|
if (includesFinalize)
|
||||||
{
|
{
|
||||||
try
|
ReadStartGameFinalize(inc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
{
|
{
|
||||||
if (timeOut.HasValue)
|
try
|
||||||
{
|
{
|
||||||
if (DateTime.Now > requestFinalizeTime)
|
if (DateTime.Now > requestFinalizeTime)
|
||||||
{
|
{
|
||||||
@@ -1585,41 +1590,30 @@ namespace Barotrauma.Networking
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
if (!connected)
|
||||||
{
|
|
||||||
if (includesFinalize)
|
|
||||||
{
|
{
|
||||||
ReadStartGameFinalize(inc);
|
roundInitStatus = RoundInitStatus.Interrupted;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//wait for up to 30 seconds for the server to send the STARTGAMEFINALIZE message
|
if (roundInitStatus != RoundInitStatus.WaitingForStartGameFinalize) { break; }
|
||||||
timeOut = DateTime.Now + timeOutDuration;
|
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
if (!connected)
|
|
||||||
{
|
{
|
||||||
roundInitStatus = RoundInitStatus.Interrupted;
|
DebugConsole.ThrowError("There was an error initializing the round.", e, true);
|
||||||
|
roundInitStatus = RoundInitStatus.Error;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (roundInitStatus != RoundInitStatus.WaitingForStartGameFinalize) { break; }
|
//waiting for a STARTGAMEFINALIZE message
|
||||||
|
yield return CoroutineStatus.Running;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
DebugConsole.ThrowError("There was an error initializing the round.", e, true);
|
|
||||||
roundInitStatus = RoundInitStatus.Error;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//waiting for a STARTGAMEFINALIZE message
|
|
||||||
yield return CoroutineStatus.Running;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interruptPrompt?.Close();
|
interruptPrompt?.Close();
|
||||||
interruptPrompt = null;
|
interruptPrompt = null;
|
||||||
|
|
||||||
if (roundInitStatus != RoundInitStatus.Started)
|
if (roundInitStatus != RoundInitStatus.Started)
|
||||||
{
|
{
|
||||||
if (roundInitStatus != RoundInitStatus.Interrupted)
|
if (roundInitStatus != RoundInitStatus.Interrupted)
|
||||||
@@ -1769,7 +1763,7 @@ namespace Barotrauma.Networking
|
|||||||
{
|
{
|
||||||
string subName = inc.ReadString();
|
string subName = inc.ReadString();
|
||||||
string subHash = inc.ReadString();
|
string subHash = inc.ReadString();
|
||||||
byte subClass = inc.ReadByte();
|
SubmarineClass subClass = (SubmarineClass)inc.ReadByte();
|
||||||
bool isShuttle = inc.ReadBoolean();
|
bool isShuttle = inc.ReadBoolean();
|
||||||
bool requiredContentPackagesInstalled = inc.ReadBoolean();
|
bool requiredContentPackagesInstalled = inc.ReadBoolean();
|
||||||
|
|
||||||
@@ -1778,7 +1772,7 @@ namespace Barotrauma.Networking
|
|||||||
{
|
{
|
||||||
matchingSub = new SubmarineInfo(Path.Combine(SaveUtil.SubmarineDownloadFolder, subName) + ".sub", subHash, tryLoad: false)
|
matchingSub = new SubmarineInfo(Path.Combine(SaveUtil.SubmarineDownloadFolder, subName) + ".sub", subHash, tryLoad: false)
|
||||||
{
|
{
|
||||||
SubmarineClass = (SubmarineClass)subClass
|
SubmarineClass = subClass
|
||||||
};
|
};
|
||||||
if (isShuttle) { matchingSub.AddTag(SubmarineTag.Shuttle); }
|
if (isShuttle) { matchingSub.AddTag(SubmarineTag.Shuttle); }
|
||||||
}
|
}
|
||||||
@@ -2011,10 +2005,10 @@ namespace Barotrauma.Networking
|
|||||||
GameMain.NetLobbyScreen.SetTraitorsEnabled(traitorsEnabled);
|
GameMain.NetLobbyScreen.SetTraitorsEnabled(traitorsEnabled);
|
||||||
GameMain.NetLobbyScreen.SetMissionType(missionType);
|
GameMain.NetLobbyScreen.SetMissionType(missionType);
|
||||||
|
|
||||||
if (!allowModeVoting) GameMain.NetLobbyScreen.SelectMode(modeIndex);
|
GameMain.NetLobbyScreen.SelectMode(modeIndex);
|
||||||
if (isInitialUpdate && GameMain.NetLobbyScreen.SelectedMode == GameModePreset.MultiPlayerCampaign)
|
if (isInitialUpdate && GameMain.NetLobbyScreen.SelectedMode == GameModePreset.MultiPlayerCampaign)
|
||||||
{
|
{
|
||||||
if (GameMain.Client.IsServerOwner) RequestSelectMode(modeIndex);
|
if (GameMain.Client.IsServerOwner) { RequestSelectMode(modeIndex); }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GameMain.NetLobbyScreen.SelectedMode == GameModePreset.MultiPlayerCampaign)
|
if (GameMain.NetLobbyScreen.SelectedMode == GameModePreset.MultiPlayerCampaign)
|
||||||
@@ -2103,13 +2097,12 @@ namespace Barotrauma.Networking
|
|||||||
case ServerNetSegment.EntityPosition:
|
case ServerNetSegment.EntityPosition:
|
||||||
inc.ReadPadBits(); //padding is required here to make sure any padding bits within tempBuffer are read correctly
|
inc.ReadPadBits(); //padding is required here to make sure any padding bits within tempBuffer are read correctly
|
||||||
|
|
||||||
bool isItem = inc.ReadBoolean(); inc.ReadPadBits();
|
|
||||||
UInt32 incomingUintIdentifier = inc.ReadUInt32();
|
|
||||||
UInt16 id = inc.ReadUInt16();
|
|
||||||
uint msgLength = inc.ReadVariableUInt32();
|
uint msgLength = inc.ReadVariableUInt32();
|
||||||
int msgEndPos = (int)(inc.BitPosition + msgLength * 8);
|
int msgEndPos = (int)(inc.BitPosition + msgLength * 8);
|
||||||
|
|
||||||
var entity = Entity.FindEntityByID(id) as IServerPositionSync;
|
var header = INetSerializableStruct.Read<EntityPositionHeader>(inc);
|
||||||
|
|
||||||
|
var entity = Entity.FindEntityByID(header.EntityId) as IServerPositionSync;
|
||||||
if (msgEndPos > inc.LengthBits)
|
if (msgEndPos > inc.LengthBits)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError($"Error while reading a position update for the entity \"({entity?.ToString() ?? "null"})\". Message length exceeds the size of the buffer.");
|
DebugConsole.ThrowError($"Error while reading a position update for the entity \"({entity?.ToString() ?? "null"})\". Message length exceeds the size of the buffer.");
|
||||||
@@ -2119,15 +2112,15 @@ namespace Barotrauma.Networking
|
|||||||
debugEntityList.Add(entity);
|
debugEntityList.Add(entity);
|
||||||
if (entity != null)
|
if (entity != null)
|
||||||
{
|
{
|
||||||
if (entity is Item != isItem)
|
if (entity is Item != header.IsItem)
|
||||||
{
|
{
|
||||||
DebugConsole.AddWarning($"Received a potentially invalid ENTITY_POSITION message. Entity type does not match (server entity is {(isItem ? "an item" : "not an item")}, client entity is {(entity?.GetType().ToString() ?? "null")}). Ignoring the message...");
|
DebugConsole.AddWarning($"Received a potentially invalid ENTITY_POSITION message. Entity type does not match (server entity is {(header.IsItem ? "an item" : "not an item")}, client entity is {(entity?.GetType().ToString() ?? "null")}). Ignoring the message...");
|
||||||
}
|
}
|
||||||
else if (entity is MapEntity { Prefab: { UintIdentifier: { } uintIdentifier } } me &&
|
else if (entity is MapEntity { Prefab.UintIdentifier: var uintIdentifier } me &&
|
||||||
uintIdentifier != incomingUintIdentifier)
|
uintIdentifier != header.PrefabUintIdentifier)
|
||||||
{
|
{
|
||||||
DebugConsole.AddWarning($"Received a potentially invalid ENTITY_POSITION message."
|
DebugConsole.AddWarning($"Received a potentially invalid ENTITY_POSITION message."
|
||||||
+$"Entity identifier does not match (server entity is {MapEntityPrefab.List.FirstOrDefault(p => p.UintIdentifier == incomingUintIdentifier)?.Identifier.Value ?? "[not found]"}, "
|
+$"Entity identifier does not match (server entity is {MapEntityPrefab.List.FirstOrDefault(p => p.UintIdentifier == header.PrefabUintIdentifier)?.Identifier.Value ?? "[not found]"}, "
|
||||||
+$"client entity is {me.Prefab.Identifier}). Ignoring the message...");
|
+$"client entity is {me.Prefab.Identifier}). Ignoring the message...");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -2135,7 +2128,6 @@ namespace Barotrauma.Networking
|
|||||||
entity.ClientReadPosition(inc, sendingTime);
|
entity.ClientReadPosition(inc, sendingTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//force to the correct position in case the entity doesn't exist
|
//force to the correct position in case the entity doesn't exist
|
||||||
//or the message wasn't read correctly for whatever reason
|
//or the message wasn't read correctly for whatever reason
|
||||||
inc.BitPosition = msgEndPos;
|
inc.BitPosition = msgEndPos;
|
||||||
@@ -2146,7 +2138,7 @@ namespace Barotrauma.Networking
|
|||||||
break;
|
break;
|
||||||
case ServerNetSegment.EntityEvent:
|
case ServerNetSegment.EntityEvent:
|
||||||
case ServerNetSegment.EntityEventInitial:
|
case ServerNetSegment.EntityEventInitial:
|
||||||
if (!EntityEventManager.Read(segment, inc, sendingTime, debugEntityList))
|
if (!EntityEventManager.Read(segment, inc, sendingTime))
|
||||||
{
|
{
|
||||||
return SegmentTableReader<ServerNetSegment>.BreakSegmentReading.Yes;
|
return SegmentTableReader<ServerNetSegment>.BreakSegmentReading.Yes;
|
||||||
}
|
}
|
||||||
@@ -2415,7 +2407,9 @@ namespace Barotrauma.Networking
|
|||||||
var newSub = new SubmarineInfo(transfer.FilePath);
|
var newSub = new SubmarineInfo(transfer.FilePath);
|
||||||
if (newSub.IsFileCorrupted) { return; }
|
if (newSub.IsFileCorrupted) { return; }
|
||||||
|
|
||||||
var existingSubs = SubmarineInfo.SavedSubmarines.Where(s => s.Name == newSub.Name && s.MD5Hash.StringRepresentation == newSub.MD5Hash.StringRepresentation).ToList();
|
var existingSubs = SubmarineInfo.SavedSubmarines
|
||||||
|
.Where(s => s.Name == newSub.Name && s.MD5Hash == newSub.MD5Hash)
|
||||||
|
.ToList();
|
||||||
foreach (SubmarineInfo existingSub in existingSubs)
|
foreach (SubmarineInfo existingSub in existingSubs)
|
||||||
{
|
{
|
||||||
existingSub.Dispose();
|
existingSub.Dispose();
|
||||||
@@ -2474,12 +2468,13 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Replace a submarine dud with the downloaded version
|
// Replace a submarine dud with the downloaded version
|
||||||
SubmarineInfo existingServerSub = ServerSubmarines.Find(s => s.Name == newSub.Name && s.MD5Hash?.StringRepresentation == newSub.MD5Hash?.StringRepresentation);
|
SubmarineInfo existingServerSub = ServerSubmarines.Find(s =>
|
||||||
|
s.Name == newSub.Name
|
||||||
|
&& s.MD5Hash == newSub.MD5Hash);
|
||||||
if (existingServerSub != null)
|
if (existingServerSub != null)
|
||||||
{
|
{
|
||||||
int existingIndex = ServerSubmarines.IndexOf(existingServerSub);
|
int existingIndex = ServerSubmarines.IndexOf(existingServerSub);
|
||||||
ServerSubmarines.RemoveAt(existingIndex);
|
ServerSubmarines[existingIndex] = newSub;
|
||||||
ServerSubmarines.Insert(existingIndex, newSub);
|
|
||||||
existingServerSub.Dispose();
|
existingServerSub.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2805,7 +2800,6 @@ namespace Barotrauma.Networking
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void RequestSelectMode(int modeIndex)
|
public void RequestSelectMode(int modeIndex)
|
||||||
{
|
{
|
||||||
if (!HasPermission(ClientPermissions.SelectMode)) return;
|
|
||||||
if (modeIndex < 0 || modeIndex >= GameMain.NetLobbyScreen.ModeList.Content.CountChildren)
|
if (modeIndex < 0 || modeIndex >= GameMain.NetLobbyScreen.ModeList.Content.CountChildren)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("Gamemode index out of bounds (" + modeIndex + ")\n" + Environment.StackTrace.CleanupStackTrace());
|
DebugConsole.ThrowError("Gamemode index out of bounds (" + modeIndex + ")\n" + Environment.StackTrace.CleanupStackTrace());
|
||||||
@@ -2859,13 +2853,14 @@ namespace Barotrauma.Networking
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tell the server to end the round (permission required)
|
/// Tell the server to end the round (permission required)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void RequestRoundEnd(bool save)
|
public void RequestRoundEnd(bool save, bool quitCampaign = false)
|
||||||
{
|
{
|
||||||
IWriteMessage msg = new WriteOnlyMessage();
|
IWriteMessage msg = new WriteOnlyMessage();
|
||||||
msg.WriteByte((byte)ClientPacketHeader.SERVER_COMMAND);
|
msg.WriteByte((byte)ClientPacketHeader.SERVER_COMMAND);
|
||||||
msg.WriteUInt16((UInt16)ClientPermissions.ManageRound);
|
msg.WriteUInt16((UInt16)ClientPermissions.ManageRound);
|
||||||
msg.WriteBoolean(true); //indicates round end
|
msg.WriteBoolean(true); //indicates round end
|
||||||
msg.WriteBoolean(save);
|
msg.WriteBoolean(save);
|
||||||
|
msg.WriteBoolean(quitCampaign);
|
||||||
|
|
||||||
ClientPeer.Send(msg, DeliveryMethod.Reliable);
|
ClientPeer.Send(msg, DeliveryMethod.Reliable);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,16 +109,15 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
private UInt16? firstNewID;
|
private UInt16? firstNewID;
|
||||||
|
|
||||||
|
private readonly List<IServerSerializable> tempEntityList = new List<IServerSerializable>();
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Read the events from the message, ignoring ones we've already received. Returns false if reading the events fails.
|
/// Read the events from the message, ignoring ones we've already received. Returns false if reading the events fails.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Read(ServerNetSegment type, IReadMessage msg, float sendingTime, List<IServerSerializable> entities)
|
public bool Read(ServerNetSegment type, IReadMessage msg, float sendingTime)
|
||||||
{
|
{
|
||||||
UInt16 unreceivedEntityEventCount = 0;
|
|
||||||
|
|
||||||
if (type == ServerNetSegment.EntityEventInitial)
|
if (type == ServerNetSegment.EntityEventInitial)
|
||||||
{
|
{
|
||||||
unreceivedEntityEventCount = msg.ReadUInt16();
|
UInt16 unreceivedEntityEventCount = msg.ReadUInt16();
|
||||||
firstNewID = msg.ReadUInt16();
|
firstNewID = msg.ReadUInt16();
|
||||||
|
|
||||||
if (GameSettings.CurrentConfig.VerboseLogging)
|
if (GameSettings.CurrentConfig.VerboseLogging)
|
||||||
@@ -143,7 +142,7 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entities.Clear();
|
tempEntityList.Clear();
|
||||||
|
|
||||||
msg.ReadPadBits();
|
msg.ReadPadBits();
|
||||||
UInt16 firstEventID = msg.ReadUInt16();
|
UInt16 firstEventID = msg.ReadUInt16();
|
||||||
@@ -156,9 +155,9 @@ namespace Barotrauma.Networking
|
|||||||
{
|
{
|
||||||
string errorMsg = $"Error while reading a message from the server. Entity event data exceeds the size of the buffer (current position: {msg.BitPosition}, length: {msg.LengthBits}).";
|
string errorMsg = $"Error while reading a message from the server. Entity event data exceeds the size of the buffer (current position: {msg.BitPosition}, length: {msg.LengthBits}).";
|
||||||
errorMsg += "\nPrevious entities:";
|
errorMsg += "\nPrevious entities:";
|
||||||
for (int j = entities.Count - 1; j >= 0; j--)
|
for (int j = tempEntityList.Count - 1; j >= 0; j--)
|
||||||
{
|
{
|
||||||
errorMsg += "\n" + (entities[j] == null ? "NULL" : entities[j].ToString());
|
errorMsg += "\n" + (tempEntityList[j] == null ? "NULL" : tempEntityList[j].ToString());
|
||||||
}
|
}
|
||||||
DebugConsole.ThrowError(errorMsg);
|
DebugConsole.ThrowError(errorMsg);
|
||||||
return false;
|
return false;
|
||||||
@@ -174,7 +173,7 @@ namespace Barotrauma.Networking
|
|||||||
DebugConsole.NewMessage("received msg " + thisEventID + " (null entity)",
|
DebugConsole.NewMessage("received msg " + thisEventID + " (null entity)",
|
||||||
Microsoft.Xna.Framework.Color.Orange);
|
Microsoft.Xna.Framework.Color.Orange);
|
||||||
}
|
}
|
||||||
entities.Add(null);
|
tempEntityList.Add(null);
|
||||||
if (thisEventID == (UInt16)(lastReceivedID + 1)) { lastReceivedID++; }
|
if (thisEventID == (UInt16)(lastReceivedID + 1)) { lastReceivedID++; }
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -182,7 +181,7 @@ namespace Barotrauma.Networking
|
|||||||
int msgLength = (int)msg.ReadVariableUInt32();
|
int msgLength = (int)msg.ReadVariableUInt32();
|
||||||
|
|
||||||
IServerSerializable entity = Entity.FindEntityByID(entityID) as IServerSerializable;
|
IServerSerializable entity = Entity.FindEntityByID(entityID) as IServerSerializable;
|
||||||
entities.Add(entity);
|
tempEntityList.Add(entity);
|
||||||
|
|
||||||
//skip the event if we've already received it or if the entity isn't found
|
//skip the event if we've already received it or if the entity isn't found
|
||||||
if (thisEventID != (UInt16)(lastReceivedID + 1) || entity == null)
|
if (thisEventID != (UInt16)(lastReceivedID + 1) || entity == null)
|
||||||
@@ -223,7 +222,7 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
if (msg.BitPosition != msgPosition + msgLength * 8)
|
if (msg.BitPosition != msgPosition + msgLength * 8)
|
||||||
{
|
{
|
||||||
var prevEntity = entities.Count >= 2 ? entities[entities.Count - 2] : null;
|
var prevEntity = tempEntityList.Count >= 2 ? tempEntityList[tempEntityList.Count - 2] : null;
|
||||||
ushort prevId = prevEntity is Entity p ? p.ID : (ushort)0;
|
ushort prevId = prevEntity is Entity p ? p.ID : (ushort)0;
|
||||||
string errorMsg = $"Message byte position incorrect after reading an event for the entity \"{entity}\" (ID {(entity is Entity e ? e.ID : 0)}). "
|
string errorMsg = $"Message byte position incorrect after reading an event for the entity \"{entity}\" (ID {(entity is Entity e ? e.ID : 0)}). "
|
||||||
+$"The previous entity was \"{prevEntity}\" (ID {prevId}) "
|
+$"The previous entity was \"{prevEntity}\" (ID {prevId}) "
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ namespace Barotrauma.Networking
|
|||||||
protected readonly bool isOwner;
|
protected readonly bool isOwner;
|
||||||
protected readonly Option<int> ownerKey;
|
protected readonly Option<int> ownerKey;
|
||||||
|
|
||||||
|
public bool IsActive => isActive;
|
||||||
|
|
||||||
protected bool isActive;
|
protected bool isActive;
|
||||||
|
|
||||||
public ClientPeer(Endpoint serverEndpoint, Callbacks callbacks, Option<int> ownerKey)
|
public ClientPeer(Endpoint serverEndpoint, Callbacks callbacks, Option<int> ownerKey)
|
||||||
@@ -80,6 +82,11 @@ namespace Barotrauma.Networking
|
|||||||
Initialization = ConnectionInitialization.SteamTicketAndVersion
|
Initialization = ConnectionInitialization.SteamTicketAndVersion
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (steamAuthTicket is { Canceled: true })
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("ReadConnectionInitializationStep failed: Steam auth ticket has been cancelled.");
|
||||||
|
}
|
||||||
|
|
||||||
ClientSteamTicketAndVersionPacket body = new ClientSteamTicketAndVersionPacket
|
ClientSteamTicketAndVersionPacket body = new ClientSteamTicketAndVersionPacket
|
||||||
{
|
{
|
||||||
Name = GameMain.Client.Name,
|
Name = GameMain.Client.Name,
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ namespace Barotrauma.Networking
|
|||||||
client.Character.ShowSpeechBubble(1.25f, ChatMessage.MessageColor[(int)messageType]);
|
client.Character.ShowSpeechBubble(1.25f, ChatMessage.MessageColor[(int)messageType]);
|
||||||
|
|
||||||
client.VoipSound.UseRadioFilter = messageType == ChatMessageType.Radio && !GameSettings.CurrentConfig.Audio.DisableVoiceChatFilters;
|
client.VoipSound.UseRadioFilter = messageType == ChatMessageType.Radio && !GameSettings.CurrentConfig.Audio.DisableVoiceChatFilters;
|
||||||
|
client.RadioNoise = 0.0f;
|
||||||
if (messageType == ChatMessageType.Radio)
|
if (messageType == ChatMessageType.Radio)
|
||||||
{
|
{
|
||||||
client.VoipSound.SetRange(radio.Range * RangeNear * speechImpedimentMultiplier * rangeMultiplier, radio.Range * speechImpedimentMultiplier * rangeMultiplier);
|
client.VoipSound.SetRange(radio.Range * RangeNear * speechImpedimentMultiplier * rangeMultiplier, radio.Range * speechImpedimentMultiplier * rangeMultiplier);
|
||||||
@@ -131,7 +132,6 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
client.VoipSound.SetRange(ChatMessage.SpeakRange * RangeNear * speechImpedimentMultiplier * rangeMultiplier, ChatMessage.SpeakRange * speechImpedimentMultiplier * rangeMultiplier);
|
client.VoipSound.SetRange(ChatMessage.SpeakRange * RangeNear * speechImpedimentMultiplier * rangeMultiplier, ChatMessage.SpeakRange * speechImpedimentMultiplier * rangeMultiplier);
|
||||||
}
|
}
|
||||||
client.VoipSound.UseMuffleFilter =
|
client.VoipSound.UseMuffleFilter =
|
||||||
|
|||||||
@@ -98,16 +98,15 @@ namespace Barotrauma
|
|||||||
foreach (GUIComponent comp in listBox.Content.Children)
|
foreach (GUIComponent comp in listBox.Content.Children)
|
||||||
{
|
{
|
||||||
if (comp.UserData != userData) { continue; }
|
if (comp.UserData != userData) { continue; }
|
||||||
if (!(comp.FindChild("votes") is GUITextBlock voteText))
|
if (comp.FindChild("votes") is not GUITextBlock voteText)
|
||||||
{
|
{
|
||||||
voteText = new GUITextBlock(new RectTransform(new Point(30, comp.Rect.Height), comp.RectTransform, Anchor.CenterRight),
|
voteText = new GUITextBlock(new RectTransform(new Point(GUI.IntScale(30), comp.Rect.Height), comp.RectTransform, Anchor.CenterRight),
|
||||||
"", textAlignment: Alignment.CenterRight)
|
"", textAlignment: Alignment.Center)
|
||||||
{
|
{
|
||||||
Padding = Vector4.Zero,
|
Padding = Vector4.Zero,
|
||||||
UserData = "votes"
|
UserData = "votes"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
voteText.Text = votes == 0 ? "" : votes.ToString();
|
voteText.Text = votes == 0 ? "" : votes.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Barotrauma.IO;
|
using Barotrauma.IO;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
|
||||||
@@ -58,7 +59,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
var saveFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.1f), saveList.Content.RectTransform) { MinSize = new Point(0, 45) }, style: "ListBoxElement")
|
var saveFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.1f), saveList.Content.RectTransform) { MinSize = new Point(0, 45) }, style: "ListBoxElement")
|
||||||
{
|
{
|
||||||
UserData = saveInfo.FilePath
|
UserData = saveInfo
|
||||||
};
|
};
|
||||||
|
|
||||||
var nameText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), saveFrame.RectTransform), Path.GetFileNameWithoutExtension(saveInfo.FilePath),
|
var nameText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), saveFrame.RectTransform), Path.GetFileNameWithoutExtension(saveInfo.FilePath),
|
||||||
@@ -87,10 +88,9 @@ namespace Barotrauma
|
|||||||
};
|
};
|
||||||
|
|
||||||
string saveTimeStr = string.Empty;
|
string saveTimeStr = string.Empty;
|
||||||
if (saveInfo.SaveTime > 0)
|
if (saveInfo.SaveTime.TryUnwrap(out var time))
|
||||||
{
|
{
|
||||||
DateTime time = ToolBox.Epoch.ToDateTime(saveInfo.SaveTime);
|
saveTimeStr = time.ToLocalUserString();
|
||||||
saveTimeStr = time.ToString();
|
|
||||||
}
|
}
|
||||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), saveFrame.RectTransform),
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), saveFrame.RectTransform),
|
||||||
text: saveTimeStr, textAlignment: Alignment.Right, font: GUIStyle.SmallFont)
|
text: saveTimeStr, textAlignment: Alignment.Right, font: GUIStyle.SmallFont)
|
||||||
@@ -102,6 +102,26 @@ namespace Barotrauma
|
|||||||
return saveFrame;
|
return saveFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void SortSaveList()
|
||||||
|
{
|
||||||
|
saveList.Content.RectTransform.SortChildren((c1, c2) =>
|
||||||
|
{
|
||||||
|
if (c1.GUIComponent.UserData is not CampaignMode.SaveInfo file1
|
||||||
|
|| c2.GUIComponent.UserData is not CampaignMode.SaveInfo file2)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file1.SaveTime.TryUnwrap(out var file1WriteTime)
|
||||||
|
|| !file2.SaveTime.TryUnwrap(out var file2WriteTime))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return file2WriteTime.CompareTo(file1WriteTime);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public struct CampaignSettingElements
|
public struct CampaignSettingElements
|
||||||
{
|
{
|
||||||
public SettingValue<bool> TutorialEnabled;
|
public SettingValue<bool> TutorialEnabled;
|
||||||
@@ -303,7 +323,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
bool ChangeValue(GUIButton btn, object userData)
|
bool ChangeValue(GUIButton btn, object userData)
|
||||||
{
|
{
|
||||||
if (!(userData is int change)) { return false; }
|
if (userData is not int change) { return false; }
|
||||||
|
|
||||||
int hiddenOptions = 0;
|
int hiddenOptions = 0;
|
||||||
|
|
||||||
@@ -367,5 +387,25 @@ namespace Barotrauma
|
|||||||
return inputContainer;
|
return inputContainer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract void UpdateLoadMenu(IEnumerable<CampaignMode.SaveInfo> saveFiles = null);
|
||||||
|
|
||||||
|
protected bool DeleteSave(GUIButton button, object obj)
|
||||||
|
{
|
||||||
|
if (obj is not CampaignMode.SaveInfo saveInfo) { return false; }
|
||||||
|
|
||||||
|
var header = TextManager.Get("deletedialoglabel");
|
||||||
|
var body = TextManager.GetWithVariable("deletedialogquestion", "[file]", Path.GetFileNameWithoutExtension(saveInfo.FilePath));
|
||||||
|
|
||||||
|
EventEditorScreen.AskForConfirmation(header, body, () =>
|
||||||
|
{
|
||||||
|
SaveUtil.DeleteSave(saveInfo.FilePath);
|
||||||
|
prevSaveFiles?.RemoveAll(s => s.FilePath == saveInfo.FilePath);
|
||||||
|
UpdateLoadMenu(prevSaveFiles.ToList());
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -192,7 +192,7 @@ namespace Barotrauma
|
|||||||
yield return CoroutineStatus.Success;
|
yield return CoroutineStatus.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateLoadMenu(IEnumerable<CampaignMode.SaveInfo> saveFiles = null)
|
public override void UpdateLoadMenu(IEnumerable<CampaignMode.SaveInfo> saveFiles = null)
|
||||||
{
|
{
|
||||||
prevSaveFiles?.Clear();
|
prevSaveFiles?.Clear();
|
||||||
prevSaveFiles = null;
|
prevSaveFiles = null;
|
||||||
@@ -220,37 +220,16 @@ namespace Barotrauma
|
|||||||
CreateSaveElement(saveInfo);
|
CreateSaveElement(saveInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
saveList.Content.RectTransform.SortChildren((c1, c2) =>
|
SortSaveList();
|
||||||
{
|
|
||||||
string file1 = c1.GUIComponent.UserData as string;
|
|
||||||
string file2 = c2.GUIComponent.UserData as string;
|
|
||||||
DateTime file1WriteTime = DateTime.MinValue;
|
|
||||||
DateTime file2WriteTime = DateTime.MinValue;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
file1WriteTime = File.GetLastWriteTime(file1);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
//do nothing - DateTime.MinValue will be used and the element will get sorted at the bottom of the list
|
|
||||||
};
|
|
||||||
try
|
|
||||||
{
|
|
||||||
file2WriteTime = File.GetLastWriteTime(file2);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
//do nothing - DateTime.MinValue will be used and the element will get sorted at the bottom of the list
|
|
||||||
};
|
|
||||||
return file2WriteTime.CompareTo(file1WriteTime);
|
|
||||||
});
|
|
||||||
|
|
||||||
loadGameButton = new GUIButton(new RectTransform(new Vector2(0.45f, 0.12f), loadGameContainer.RectTransform, Anchor.BottomRight), TextManager.Get("LoadButton"))
|
loadGameButton = new GUIButton(new RectTransform(new Vector2(0.45f, 0.12f), loadGameContainer.RectTransform, Anchor.BottomRight), TextManager.Get("LoadButton"))
|
||||||
{
|
{
|
||||||
OnClicked = (btn, obj) =>
|
OnClicked = (btn, obj) =>
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(saveList.SelectedData as string)) { return false; }
|
if (saveList.SelectedData is not CampaignMode.SaveInfo saveInfo) { return false; }
|
||||||
LoadGame?.Invoke(saveList.SelectedData as string);
|
if (string.IsNullOrWhiteSpace(saveInfo.FilePath)) { return false; }
|
||||||
|
LoadGame?.Invoke(saveInfo.FilePath);
|
||||||
|
|
||||||
CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
|
CoroutineManager.StartCoroutine(WaitForCampaignSetup(), "WaitForCampaignSetup");
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
@@ -264,37 +243,20 @@ namespace Barotrauma
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private bool SelectSaveFile(GUIComponent component, object obj)
|
private bool SelectSaveFile(GUIComponent component, object obj)
|
||||||
{
|
{
|
||||||
string fileName = (string)obj;
|
if (obj is not CampaignMode.SaveInfo saveInfo) { return true; }
|
||||||
|
string fileName = saveInfo.FilePath;
|
||||||
|
|
||||||
loadGameButton.Enabled = true;
|
loadGameButton.Enabled = true;
|
||||||
deleteMpSaveButton.Visible = deleteMpSaveButton.Enabled = GameMain.Client.IsServerOwner;
|
deleteMpSaveButton.Visible = deleteMpSaveButton.Enabled = GameMain.Client.IsServerOwner;
|
||||||
deleteMpSaveButton.Enabled = GameMain.GameSession?.SavePath != fileName;
|
deleteMpSaveButton.Enabled = GameMain.GameSession?.SavePath != fileName;
|
||||||
if (deleteMpSaveButton.Visible)
|
if (deleteMpSaveButton.Visible)
|
||||||
{
|
{
|
||||||
deleteMpSaveButton.UserData = obj as string;
|
deleteMpSaveButton.UserData = saveInfo;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool DeleteSave(GUIButton button, object obj)
|
|
||||||
{
|
|
||||||
string saveFile = obj as string;
|
|
||||||
if (obj == null) { return false; }
|
|
||||||
|
|
||||||
var header = TextManager.Get("deletedialoglabel");
|
|
||||||
var body = TextManager.GetWithVariable("deletedialogquestion", "[file]", Path.GetFileNameWithoutExtension(saveFile));
|
|
||||||
|
|
||||||
EventEditorScreen.AskForConfirmation(header, body, () =>
|
|
||||||
{
|
|
||||||
SaveUtil.DeleteSave(saveFile);
|
|
||||||
prevSaveFiles?.RemoveAll(s => s.FilePath == saveFile);
|
|
||||||
UpdateLoadMenu(prevSaveFiles.ToList());
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -365,7 +365,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private void CreateCustomizeWindow(CampaignSettings prevSettings, Action<CampaignSettings> onClosed = null)
|
private void CreateCustomizeWindow(CampaignSettings prevSettings, Action<CampaignSettings> onClosed = null)
|
||||||
{
|
{
|
||||||
CampaignCustomizeSettings = new GUIMessageBox("", "", new[] { TextManager.Get("OK") }, new Vector2(0.25f, 0.3f), minSize: new Point(450, 350));
|
CampaignCustomizeSettings = new GUIMessageBox("", "", new[] { TextManager.Get("OK") }, new Vector2(0.25f, 0.5f), minSize: new Point(450, 350));
|
||||||
|
|
||||||
GUILayoutGroup campaignSettingContent = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.8f), CampaignCustomizeSettings.Content.RectTransform, Anchor.TopCenter));
|
GUILayoutGroup campaignSettingContent = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.8f), CampaignCustomizeSettings.Content.RectTransform, Anchor.TopCenter));
|
||||||
|
|
||||||
@@ -581,7 +581,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateLoadMenu(IEnumerable<CampaignMode.SaveInfo> saveFiles = null)
|
public override void UpdateLoadMenu(IEnumerable<CampaignMode.SaveInfo> saveFiles = null)
|
||||||
{
|
{
|
||||||
prevSaveFiles?.Clear();
|
prevSaveFiles?.Clear();
|
||||||
prevSaveFiles = null;
|
prevSaveFiles = null;
|
||||||
@@ -649,46 +649,27 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
saveList.Content.RectTransform.SortChildren((c1, c2) =>
|
SortSaveList();
|
||||||
{
|
|
||||||
string file1 = c1.GUIComponent.UserData as string;
|
|
||||||
string file2 = c2.GUIComponent.UserData as string;
|
|
||||||
DateTime file1WriteTime = DateTime.MinValue;
|
|
||||||
DateTime file2WriteTime = DateTime.MinValue;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
file1WriteTime = File.GetLastWriteTime(file1);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
//do nothing - DateTime.MinValue will be used and the element will get sorted at the bottom of the list
|
|
||||||
};
|
|
||||||
try
|
|
||||||
{
|
|
||||||
file2WriteTime = File.GetLastWriteTime(file2);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
//do nothing - DateTime.MinValue will be used and the element will get sorted at the bottom of the list
|
|
||||||
};
|
|
||||||
return file2WriteTime.CompareTo(file1WriteTime);
|
|
||||||
});
|
|
||||||
|
|
||||||
loadGameButton = new GUIButton(new RectTransform(new Vector2(0.45f, 0.12f), loadGameContainer.RectTransform, Anchor.BottomRight), TextManager.Get("LoadButton"))
|
loadGameButton = new GUIButton(new RectTransform(new Vector2(0.45f, 0.12f), loadGameContainer.RectTransform, Anchor.BottomRight), TextManager.Get("LoadButton"))
|
||||||
{
|
{
|
||||||
OnClicked = (btn, obj) =>
|
OnClicked = (btn, obj) =>
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(saveList.SelectedData as string)) { return false; }
|
if (saveList.SelectedData is not CampaignMode.SaveInfo saveInfo) { return false; }
|
||||||
LoadGame?.Invoke(saveList.SelectedData as string);
|
if (string.IsNullOrWhiteSpace(saveInfo.FilePath)) { return false; }
|
||||||
|
LoadGame?.Invoke(saveInfo.FilePath);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
Enabled = false
|
Enabled = false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool SelectSaveFile(GUIComponent component, object obj)
|
private bool SelectSaveFile(GUIComponent component, object obj)
|
||||||
{
|
{
|
||||||
string fileName = (string)obj;
|
if (obj is not CampaignMode.SaveInfo saveInfo) { return true; }
|
||||||
|
|
||||||
|
string fileName = saveInfo.FilePath;
|
||||||
|
|
||||||
XDocument doc = SaveUtil.LoadGameSessionDoc(fileName);
|
XDocument doc = SaveUtil.LoadGameSessionDoc(fileName);
|
||||||
if (doc?.Root == null)
|
if (doc?.Root == null)
|
||||||
@@ -701,72 +682,55 @@ namespace Barotrauma
|
|||||||
|
|
||||||
RemoveSaveFrame();
|
RemoveSaveFrame();
|
||||||
|
|
||||||
string subName = doc.Root.GetAttributeString("submarine", "");
|
string subName = saveInfo.SubmarineName;
|
||||||
string saveTime = doc.Root.GetAttributeString("savetime", "unknown");
|
LocalizedString saveTime = saveInfo.SaveTime
|
||||||
DateTime? time = null;
|
.Select(t => (LocalizedString)t.ToLocalUserString())
|
||||||
if (long.TryParse(saveTime, out long unixTime))
|
.Fallback(TextManager.Get("Unknown"));
|
||||||
{
|
|
||||||
time = ToolBox.Epoch.ToDateTime(unixTime);
|
|
||||||
saveTime = time.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
string mapseed = doc.Root.GetAttributeString("mapseed", "unknown");
|
string mapseed = doc.Root.GetAttributeString("mapseed", "unknown");
|
||||||
|
|
||||||
var saveFileFrame = new GUIFrame(new RectTransform(new Vector2(0.45f, 0.6f), loadGameContainer.RectTransform, Anchor.TopRight)
|
var saveFileFrame = new GUIFrame(
|
||||||
{
|
new RectTransform(new Vector2(0.45f, 0.6f), loadGameContainer.RectTransform, Anchor.TopRight)
|
||||||
RelativeOffset = new Vector2(0.0f, 0.1f)
|
{
|
||||||
}, style: "InnerFrame")
|
RelativeOffset = new Vector2(0.0f, 0.1f)
|
||||||
|
}, style: "InnerFrame")
|
||||||
{
|
{
|
||||||
UserData = "savefileframe"
|
UserData = "savefileframe"
|
||||||
};
|
};
|
||||||
|
|
||||||
var titleText = new GUITextBlock(new RectTransform(new Vector2(0.9f, 0.2f), saveFileFrame.RectTransform, Anchor.TopCenter)
|
var titleText = new GUITextBlock(
|
||||||
{
|
new RectTransform(new Vector2(0.9f, 0.2f), saveFileFrame.RectTransform, Anchor.TopCenter)
|
||||||
RelativeOffset = new Vector2(0, 0.05f)
|
{
|
||||||
},
|
RelativeOffset = new Vector2(0, 0.05f)
|
||||||
|
},
|
||||||
Path.GetFileNameWithoutExtension(fileName), font: GUIStyle.LargeFont, textAlignment: Alignment.Center);
|
Path.GetFileNameWithoutExtension(fileName), font: GUIStyle.LargeFont, textAlignment: Alignment.Center);
|
||||||
titleText.Text = ToolBox.LimitString(titleText.Text, titleText.Font, titleText.Rect.Width);
|
titleText.Text = ToolBox.LimitString(titleText.Text, titleText.Font, titleText.Rect.Width);
|
||||||
|
|
||||||
var layoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.8f, 0.5f), saveFileFrame.RectTransform, Anchor.Center)
|
var layoutGroup = new GUILayoutGroup(
|
||||||
{
|
new RectTransform(new Vector2(0.8f, 0.5f), saveFileFrame.RectTransform, Anchor.Center)
|
||||||
RelativeOffset = new Vector2(0, 0.1f)
|
{
|
||||||
});
|
RelativeOffset = new Vector2(0, 0.1f)
|
||||||
|
});
|
||||||
|
|
||||||
new GUITextBlock(new RectTransform(new Vector2(1, 0), layoutGroup.RectTransform), $"{TextManager.Get("Submarine")} : {subName}", font: GUIStyle.SmallFont);
|
new GUITextBlock(new RectTransform(new Vector2(1, 0), layoutGroup.RectTransform),
|
||||||
new GUITextBlock(new RectTransform(new Vector2(1, 0), layoutGroup.RectTransform), $"{TextManager.Get("LastSaved")} : {saveTime}", font: GUIStyle.SmallFont);
|
$"{TextManager.Get("Submarine")} : {subName}", font: GUIStyle.SmallFont);
|
||||||
new GUITextBlock(new RectTransform(new Vector2(1, 0), layoutGroup.RectTransform), $"{TextManager.Get("MapSeed")} : {mapseed}", font: GUIStyle.SmallFont);
|
new GUITextBlock(new RectTransform(new Vector2(1, 0), layoutGroup.RectTransform),
|
||||||
|
$"{TextManager.Get("LastSaved")} : {saveTime}", font: GUIStyle.SmallFont);
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1, 0), layoutGroup.RectTransform),
|
||||||
|
$"{TextManager.Get("MapSeed")} : {mapseed}", font: GUIStyle.SmallFont);
|
||||||
|
|
||||||
new GUIButton(new RectTransform(new Vector2(0.4f, 0.15f), saveFileFrame.RectTransform, Anchor.BottomCenter)
|
new GUIButton(new RectTransform(new Vector2(0.4f, 0.15f), saveFileFrame.RectTransform, Anchor.BottomCenter)
|
||||||
{
|
{
|
||||||
RelativeOffset = new Vector2(0, 0.1f)
|
RelativeOffset = new Vector2(0, 0.1f)
|
||||||
}, TextManager.Get("Delete"), style: "GUIButtonSmall")
|
}, TextManager.Get("Delete"), style: "GUIButtonSmall")
|
||||||
{
|
{
|
||||||
UserData = fileName,
|
UserData = saveInfo,
|
||||||
OnClicked = DeleteSave
|
OnClicked = DeleteSave
|
||||||
};
|
};
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool DeleteSave(GUIButton button, object obj)
|
|
||||||
{
|
|
||||||
string saveFile = obj as string;
|
|
||||||
if (obj == null) { return false; }
|
|
||||||
|
|
||||||
LocalizedString header = TextManager.Get("deletedialoglabel");
|
|
||||||
LocalizedString body = TextManager.GetWithVariable("deletedialogquestion", "[file]", Path.GetFileNameWithoutExtension(saveFile));
|
|
||||||
|
|
||||||
EventEditorScreen.AskForConfirmation(header, body, () =>
|
|
||||||
{
|
|
||||||
SaveUtil.DeleteSave(saveFile);
|
|
||||||
prevSaveFiles?.RemoveAll(s => s.FilePath == saveFile);
|
|
||||||
UpdateLoadMenu(prevSaveFiles.ToList());
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RemoveSaveFrame()
|
private void RemoveSaveFrame()
|
||||||
{
|
{
|
||||||
GUIComponent prevFrame = null;
|
GUIComponent prevFrame = null;
|
||||||
|
|||||||
@@ -551,6 +551,7 @@ namespace Barotrauma
|
|||||||
submarineSelection.RefreshSubmarineDisplay(true, setTransferOptionToTrue: true);
|
submarineSelection.RefreshSubmarineDisplay(true, setTransferOptionToTrue: true);
|
||||||
break;
|
break;
|
||||||
case CampaignMode.InteractionType.Map:
|
case CampaignMode.InteractionType.Map:
|
||||||
|
GameMain.GameSession?.Map?.ResetPendingSub();
|
||||||
//refresh mission rewards (may have been changed by e.g. a pending submarine switch)
|
//refresh mission rewards (may have been changed by e.g. a pending submarine switch)
|
||||||
foreach (GUITextBlock rewardText in missionRewardTexts)
|
foreach (GUITextBlock rewardText in missionRewardTexts)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -25,14 +25,11 @@ namespace Barotrauma.CharacterEditor
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (cam == null)
|
cam ??= new Camera()
|
||||||
{
|
{
|
||||||
cam = new Camera()
|
MinZoom = 0.1f,
|
||||||
{
|
MaxZoom = 5.0f
|
||||||
MinZoom = 0.1f,
|
};
|
||||||
MaxZoom = 5.0f
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return cam;
|
return cam;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,7 +122,7 @@ namespace Barotrauma.CharacterEditor
|
|||||||
{
|
{
|
||||||
ResetVariables();
|
ResetVariables();
|
||||||
var subInfo = new SubmarineInfo("Content/AnimEditor.sub");
|
var subInfo = new SubmarineInfo("Content/AnimEditor.sub");
|
||||||
Submarine.MainSub = new Submarine(subInfo);
|
Submarine.MainSub = new Submarine(subInfo, showErrorMessages: false);
|
||||||
if (Submarine.MainSub.PhysicsBody != null)
|
if (Submarine.MainSub.PhysicsBody != null)
|
||||||
{
|
{
|
||||||
Submarine.MainSub.PhysicsBody.Enabled = false;
|
Submarine.MainSub.PhysicsBody.Enabled = false;
|
||||||
@@ -162,11 +159,6 @@ namespace Barotrauma.CharacterEditor
|
|||||||
OpenDoors();
|
OpenDoors();
|
||||||
GameMain.Instance.ResolutionChanged += OnResolutionChanged;
|
GameMain.Instance.ResolutionChanged += OnResolutionChanged;
|
||||||
Instance = this;
|
Instance = this;
|
||||||
|
|
||||||
if (!GameSettings.CurrentConfig.EditorDisclaimerShown)
|
|
||||||
{
|
|
||||||
GameMain.Instance.ShowEditorDisclaimer();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ResetVariables()
|
private void ResetVariables()
|
||||||
@@ -267,7 +259,10 @@ namespace Barotrauma.CharacterEditor
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
GameMain.Instance.ResolutionChanged -= OnResolutionChanged;
|
GameMain.Instance.ResolutionChanged -= OnResolutionChanged;
|
||||||
GameMain.LightManager.LightingEnabled = true;
|
if (!GameMain.DevMode)
|
||||||
|
{
|
||||||
|
GameMain.LightManager.LightingEnabled = true;
|
||||||
|
}
|
||||||
ClearWidgets();
|
ClearWidgets();
|
||||||
ClearSelection();
|
ClearSelection();
|
||||||
}
|
}
|
||||||
@@ -285,6 +280,7 @@ namespace Barotrauma.CharacterEditor
|
|||||||
#region Main methods
|
#region Main methods
|
||||||
public override void AddToGUIUpdateList()
|
public override void AddToGUIUpdateList()
|
||||||
{
|
{
|
||||||
|
if (rightArea == null || leftArea == null) { return; }
|
||||||
rightArea.AddToGUIUpdateList();
|
rightArea.AddToGUIUpdateList();
|
||||||
leftArea.AddToGUIUpdateList();
|
leftArea.AddToGUIUpdateList();
|
||||||
|
|
||||||
@@ -783,7 +779,7 @@ namespace Barotrauma.CharacterEditor
|
|||||||
scaledMouseSpeed = PlayerInput.MouseSpeedPerSecond * (float)deltaTime;
|
scaledMouseSpeed = PlayerInput.MouseSpeedPerSecond * (float)deltaTime;
|
||||||
Cam.UpdateTransform(true);
|
Cam.UpdateTransform(true);
|
||||||
Submarine.CullEntities(Cam);
|
Submarine.CullEntities(Cam);
|
||||||
Submarine.MainSub.UpdateTransform();
|
Submarine.MainSub?.UpdateTransform();
|
||||||
|
|
||||||
// Lightmaps
|
// Lightmaps
|
||||||
if (GameMain.LightManager.LightingEnabled)
|
if (GameMain.LightManager.LightingEnabled)
|
||||||
@@ -1575,10 +1571,7 @@ namespace Barotrauma.CharacterEditor
|
|||||||
{
|
{
|
||||||
wayPoint = WayPoint.GetRandom(spawnType: SpawnType.Human, sub: Submarine.MainSub);
|
wayPoint = WayPoint.GetRandom(spawnType: SpawnType.Human, sub: Submarine.MainSub);
|
||||||
}
|
}
|
||||||
if (wayPoint == null)
|
wayPoint ??= WayPoint.GetRandom(sub: Submarine.MainSub);
|
||||||
{
|
|
||||||
wayPoint = WayPoint.GetRandom(sub: Submarine.MainSub);
|
|
||||||
}
|
|
||||||
spawnPosition = wayPoint.WorldPosition;
|
spawnPosition = wayPoint.WorldPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2688,10 +2681,6 @@ namespace Barotrauma.CharacterEditor
|
|||||||
|
|
||||||
// Character selection
|
// Character selection
|
||||||
var characterLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform), GetCharacterEditorTranslation("CharacterPanel"), font: GUIStyle.LargeFont);
|
var characterLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform), GetCharacterEditorTranslation("CharacterPanel"), font: GUIStyle.LargeFont);
|
||||||
var disclaimerBtn = new GUIButton(new RectTransform(new Vector2(0.2f, 0.7f), characterLabel.RectTransform, Anchor.CenterRight), style: "GUINotificationButton")
|
|
||||||
{
|
|
||||||
OnClicked = (btn, userdata) => { GameMain.Instance.ShowEditorDisclaimer(); return true; }
|
|
||||||
};
|
|
||||||
|
|
||||||
var characterDropDown = new GUIDropDown(new RectTransform(new Vector2(1, 0.2f), content.RectTransform)
|
var characterDropDown = new GUIDropDown(new RectTransform(new Vector2(1, 0.2f), content.RectTransform)
|
||||||
{
|
{
|
||||||
@@ -4007,7 +3996,7 @@ namespace Barotrauma.CharacterEditor
|
|||||||
};
|
};
|
||||||
}).Draw(spriteBatch, deltaTime);
|
}).Draw(spriteBatch, deltaTime);
|
||||||
}
|
}
|
||||||
else
|
else if (groundedParams != null)
|
||||||
{
|
{
|
||||||
GetAnimationWidget("HeadPosition", color, Color.Black, initMethod: w =>
|
GetAnimationWidget("HeadPosition", color, Color.Black, initMethod: w =>
|
||||||
{
|
{
|
||||||
@@ -4116,7 +4105,7 @@ namespace Barotrauma.CharacterEditor
|
|||||||
};
|
};
|
||||||
}).Draw(spriteBatch, deltaTime);
|
}).Draw(spriteBatch, deltaTime);
|
||||||
}
|
}
|
||||||
else
|
else if (groundedParams != null)
|
||||||
{
|
{
|
||||||
GetAnimationWidget("TorsoPosition", color, Color.Black, initMethod: w =>
|
GetAnimationWidget("TorsoPosition", color, Color.Black, initMethod: w =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -820,6 +820,15 @@ namespace Barotrauma
|
|||||||
};
|
};
|
||||||
valueInput.Text = newValue?.ToString() ?? "<type here>";
|
valueInput.Text = newValue?.ToString() ?? "<type here>";
|
||||||
}
|
}
|
||||||
|
else if (type == typeof(Identifier))
|
||||||
|
{
|
||||||
|
GUITextBox valueInput = new GUITextBox(new RectTransform(Vector2.One, layout.RectTransform), newValue?.ToString() ?? string.Empty);
|
||||||
|
valueInput.OnTextChanged += (component, o) =>
|
||||||
|
{
|
||||||
|
newValue = new Identifier(o);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
else if (type == typeof(float) || type == typeof(int))
|
else if (type == typeof(float) || type == typeof(int))
|
||||||
{
|
{
|
||||||
GUINumberInput valueInput = new GUINumberInput(new RectTransform(Vector2.One, layout.RectTransform), NumberType.Float) { FloatValue = (float) (newValue ?? 0.0f) };
|
GUINumberInput valueInput = new GUINumberInput(new RectTransform(Vector2.One, layout.RectTransform), NumberType.Float) { FloatValue = (float) (newValue ?? 0.0f) };
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using Barotrauma.Extensions;
|
using Barotrauma.Extensions;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Content;
|
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
@@ -27,7 +26,7 @@ namespace Barotrauma
|
|||||||
public Effect ThresholdTintEffect { get; private set; }
|
public Effect ThresholdTintEffect { get; private set; }
|
||||||
public Effect BlueprintEffect { get; set; }
|
public Effect BlueprintEffect { get; set; }
|
||||||
|
|
||||||
public GameScreen(GraphicsDevice graphics, ContentManager content)
|
public GameScreen(GraphicsDevice graphics)
|
||||||
{
|
{
|
||||||
cam = new Camera();
|
cam = new Camera();
|
||||||
cam.Translate(new Vector2(-10.0f, 50.0f));
|
cam.Translate(new Vector2(-10.0f, 50.0f));
|
||||||
@@ -38,20 +37,13 @@ namespace Barotrauma
|
|||||||
CreateRenderTargets(graphics);
|
CreateRenderTargets(graphics);
|
||||||
};
|
};
|
||||||
|
|
||||||
Effect LoadEffect(string path)
|
|
||||||
=> content.Load<Effect>(path
|
|
||||||
#if LINUX || OSX
|
|
||||||
+"_opengl"
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
|
|
||||||
//var blurEffect = LoadEffect("Effects/blurshader");
|
//var blurEffect = LoadEffect("Effects/blurshader");
|
||||||
damageEffect = LoadEffect("Effects/damageshader");
|
damageEffect = EffectLoader.Load("Effects/damageshader");
|
||||||
PostProcessEffect = LoadEffect("Effects/postprocess");
|
PostProcessEffect = EffectLoader.Load("Effects/postprocess");
|
||||||
GradientEffect = LoadEffect("Effects/gradientshader");
|
GradientEffect = EffectLoader.Load("Effects/gradientshader");
|
||||||
GrainEffect = LoadEffect("Effects/grainshader");
|
GrainEffect = EffectLoader.Load("Effects/grainshader");
|
||||||
ThresholdTintEffect = LoadEffect("Effects/thresholdtint");
|
ThresholdTintEffect = EffectLoader.Load("Effects/thresholdtint");
|
||||||
BlueprintEffect = LoadEffect("Effects/blueprintshader");
|
BlueprintEffect = EffectLoader.Load("Effects/blueprintshader");
|
||||||
|
|
||||||
damageStencil = TextureLoader.FromFile("Content/Map/walldamage.png");
|
damageStencil = TextureLoader.FromFile("Content/Map/walldamage.png");
|
||||||
damageEffect.Parameters["xStencil"].SetValue(damageStencil);
|
damageEffect.Parameters["xStencil"].SetValue(damageStencil);
|
||||||
|
|||||||
@@ -893,7 +893,25 @@ namespace Barotrauma
|
|||||||
GameMain.ResetNetLobbyScreen();
|
GameMain.ResetNetLobbyScreen();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string exeName = serverExecutableDropdown.SelectedComponent?.UserData is ServerExecutableFile f ? f.Path.Value : "DedicatedServer";
|
string fileName;
|
||||||
|
if (serverExecutableDropdown.SelectedComponent?.UserData is ServerExecutableFile f &&
|
||||||
|
f.ContentPackage != GameMain.VanillaContent)
|
||||||
|
{
|
||||||
|
fileName = Path.Combine(
|
||||||
|
Path.GetDirectoryName(f.Path.Value),
|
||||||
|
Path.GetFileNameWithoutExtension(f.Path.Value));
|
||||||
|
#if WINDOWS
|
||||||
|
fileName += ".exe";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#if WINDOWS
|
||||||
|
fileName = "DedicatedServer.exe";
|
||||||
|
#else
|
||||||
|
fileName = "./DedicatedServer";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
string arguments = "-name \"" + ToolBox.EscapeCharacters(name) + "\"" +
|
string arguments = "-name \"" + ToolBox.EscapeCharacters(name) + "\"" +
|
||||||
" -public " + isPublicBox.Selected.ToString() +
|
" -public " + isPublicBox.Selected.ToString() +
|
||||||
@@ -917,19 +935,10 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
int ownerKey = Math.Max(CryptoRandom.Instance.Next(), 1);
|
int ownerKey = Math.Max(CryptoRandom.Instance.Next(), 1);
|
||||||
arguments += " -ownerkey " + ownerKey;
|
arguments += " -ownerkey " + ownerKey;
|
||||||
|
|
||||||
string filename = Path.Combine(
|
|
||||||
Path.GetDirectoryName(exeName),
|
|
||||||
Path.GetFileNameWithoutExtension(exeName));
|
|
||||||
#if WINDOWS
|
|
||||||
filename += ".exe";
|
|
||||||
#else
|
|
||||||
filename = "./" + exeName;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
var processInfo = new ProcessStartInfo
|
var processInfo = new ProcessStartInfo
|
||||||
{
|
{
|
||||||
FileName = filename,
|
FileName = fileName,
|
||||||
Arguments = arguments,
|
Arguments = arguments,
|
||||||
WorkingDirectory = Directory.GetCurrentDirectory(),
|
WorkingDirectory = Directory.GetCurrentDirectory(),
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
@@ -1005,7 +1014,7 @@ namespace Barotrauma
|
|||||||
|| item.IsDownloadPending
|
|| item.IsDownloadPending
|
||||||
|| (item.InstallTime.TryGetValue(out var workshopInstallTime)
|
|| (item.InstallTime.TryGetValue(out var workshopInstallTime)
|
||||||
&& pkg.InstallTime.TryUnwrap(out var localInstallTime)
|
&& pkg.InstallTime.TryUnwrap(out var localInstallTime)
|
||||||
&& localInstallTime < workshopInstallTime)));
|
&& localInstallTime.ToUtcValue() < workshopInstallTime)));
|
||||||
|
|
||||||
modUpdateStatus = (DateTime.Now + ModUpdateInterval, count);
|
modUpdateStatus = (DateTime.Now + ModUpdateInterval, count);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -189,7 +189,8 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
public IReadOnlyList<SubmarineInfo> GetSubList()
|
public IReadOnlyList<SubmarineInfo> GetSubList()
|
||||||
=> SubList.Content.Children.Select(c => c.UserData as SubmarineInfo).ToArray();
|
=> (IReadOnlyList<SubmarineInfo>)GameMain.Client?.ServerSubmarines
|
||||||
|
?? Array.Empty<SubmarineInfo>();
|
||||||
|
|
||||||
public readonly GUIListBox PlayerList;
|
public readonly GUIListBox PlayerList;
|
||||||
|
|
||||||
@@ -929,6 +930,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
var modeTitle = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), modeContent.RectTransform), mode.Name, font: GUIStyle.SubHeadingFont);
|
var modeTitle = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), modeContent.RectTransform), mode.Name, font: GUIStyle.SubHeadingFont);
|
||||||
var modeDescription = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), modeContent.RectTransform), mode.Description, font: GUIStyle.SmallFont, wrap: true);
|
var modeDescription = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), modeContent.RectTransform), mode.Description, font: GUIStyle.SmallFont, wrap: true);
|
||||||
|
//leave some padding for the vote count text
|
||||||
|
modeDescription.Padding = new Vector4(modeDescription.Padding.X, modeDescription.Padding.Y, GUI.IntScale(30), modeDescription.Padding.W);
|
||||||
modeTitle.HoverColor = modeDescription.HoverColor = modeTitle.SelectedColor = modeDescription.SelectedColor = Color.Transparent;
|
modeTitle.HoverColor = modeDescription.HoverColor = modeTitle.SelectedColor = modeDescription.SelectedColor = Color.Transparent;
|
||||||
modeTitle.HoverTextColor = modeDescription.HoverTextColor = modeTitle.TextColor;
|
modeTitle.HoverTextColor = modeDescription.HoverTextColor = modeTitle.TextColor;
|
||||||
modeTitle.TextColor = modeDescription.TextColor = modeTitle.TextColor * 0.5f;
|
modeTitle.TextColor = modeDescription.TextColor = modeTitle.TextColor * 0.5f;
|
||||||
@@ -981,7 +984,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GameMain.Client.RequestSelectMode(ModeList.Content.GetChildIndex(ModeList.Content.GetChildByUserData(GameModePreset.Sandbox)));
|
GameMain.Client.RequestRoundEnd(save: false, quitCampaign: true);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -3291,16 +3294,15 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
//campaign running
|
//campaign running
|
||||||
settingsBlocker.Visible = true;
|
settingsBlocker.Visible = true;
|
||||||
CampaignFrame.Visible = GameMain.Client.HasPermission(ClientPermissions.ManageCampaign);
|
CampaignFrame.Visible = QuitCampaignButton.Enabled = CampaignMode.AllowedToManageCampaign(ClientPermissions.ManageRound);
|
||||||
ContinueCampaignButton.Enabled = !GameMain.Client.GameStarted && (GameMain.Client.HasPermission(ClientPermissions.ManageCampaign) || GameMain.Client.HasPermission(ClientPermissions.ManageRound));
|
ContinueCampaignButton.Enabled = !GameMain.Client.GameStarted && CampaignFrame.Visible;
|
||||||
QuitCampaignButton.Enabled = GameMain.Client.HasPermission(ClientPermissions.ManageCampaign);
|
|
||||||
CampaignSetupFrame.Visible = false;
|
CampaignSetupFrame.Visible = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CampaignFrame.Visible = false;
|
CampaignFrame.Visible = false;
|
||||||
CampaignSetupFrame.Visible = true;
|
CampaignSetupFrame.Visible = true;
|
||||||
if (!GameMain.Client.HasPermission(ClientPermissions.ManageCampaign))
|
if (!CampaignMode.AllowedToManageCampaign(ClientPermissions.ManageRound))
|
||||||
{
|
{
|
||||||
CampaignSetupFrame.ClearChildren();
|
CampaignSetupFrame.ClearChildren();
|
||||||
new GUITextBlock(new RectTransform(new Vector2(0.8f, 0.5f), CampaignSetupFrame.RectTransform, Anchor.Center),
|
new GUITextBlock(new RectTransform(new Vector2(0.8f, 0.5f), CampaignSetupFrame.RectTransform, Anchor.Center),
|
||||||
@@ -3364,7 +3366,7 @@ namespace Barotrauma
|
|||||||
CampaignFrame.Visible = CampaignSetupFrame.Visible = false;
|
CampaignFrame.Visible = CampaignSetupFrame.Visible = false;
|
||||||
}
|
}
|
||||||
RefreshEnabledElements();
|
RefreshEnabledElements();
|
||||||
if (enabled)
|
if (enabled && SelectedMode != GameModePreset.MultiPlayerCampaign)
|
||||||
{
|
{
|
||||||
ModeList.Select(GameModePreset.MultiPlayerCampaign, GUIListBox.Force.Yes);
|
ModeList.Select(GameModePreset.MultiPlayerCampaign, GUIListBox.Force.Yes);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -543,13 +543,6 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var disclaimerBtn = new GUIButton(new RectTransform(new Vector2(0.1f, 1.0f), paddedTopPanel.RectTransform, Anchor.CenterRight), style: "GUINotificationButton")
|
|
||||||
{
|
|
||||||
IgnoreLayoutGroups = true,
|
|
||||||
OnClicked = (btn, userdata) => { GameMain.Instance.ShowEditorDisclaimer(); return true; }
|
|
||||||
};
|
|
||||||
disclaimerBtn.RectTransform.MaxSize = new Point(disclaimerBtn.Rect.Height);
|
|
||||||
|
|
||||||
TopPanel.RectTransform.MinSize = new Point(0, (int)(paddedTopPanel.RectTransform.Children.Max(c => c.MinSize.Y) / paddedTopPanel.RectTransform.RelativeSize.Y));
|
TopPanel.RectTransform.MinSize = new Point(0, (int)(paddedTopPanel.RectTransform.Children.Max(c => c.MinSize.Y) / paddedTopPanel.RectTransform.RelativeSize.Y));
|
||||||
paddedTopPanel.Recalculate();
|
paddedTopPanel.Recalculate();
|
||||||
|
|
||||||
@@ -1428,7 +1421,7 @@ namespace Barotrauma
|
|||||||
else if (MainSub == null)
|
else if (MainSub == null)
|
||||||
{
|
{
|
||||||
var subInfo = new SubmarineInfo();
|
var subInfo = new SubmarineInfo();
|
||||||
MainSub = new Submarine(subInfo);
|
MainSub = new Submarine(subInfo, showErrorMessages: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
MainSub.UpdateTransform(interpolate: false);
|
MainSub.UpdateTransform(interpolate: false);
|
||||||
@@ -1465,11 +1458,6 @@ namespace Barotrauma
|
|||||||
|
|
||||||
ImageManager.OnEditorSelected();
|
ImageManager.OnEditorSelected();
|
||||||
ReconstructLayers();
|
ReconstructLayers();
|
||||||
|
|
||||||
if (!GameSettings.CurrentConfig.EditorDisclaimerShown)
|
|
||||||
{
|
|
||||||
GameMain.Instance.ShowEditorDisclaimer();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnFileDropped(string filePath, string extension)
|
public override void OnFileDropped(string filePath, string extension)
|
||||||
@@ -2729,11 +2717,13 @@ namespace Barotrauma
|
|||||||
|
|
||||||
previewImageButtonHolder.RectTransform.MinSize = new Point(0, previewImageButtonHolder.RectTransform.Children.Max(c => c.MinSize.Y));
|
previewImageButtonHolder.RectTransform.MinSize = new Point(0, previewImageButtonHolder.RectTransform.Children.Max(c => c.MinSize.Y));
|
||||||
|
|
||||||
var contentPackageTabber = new GUILayoutGroup(new RectTransform((1.0f, 0.06f), rightColumn.RectTransform), isHorizontal: true);
|
var contentPackageTabber = new GUILayoutGroup(new RectTransform((1.0f, 0.075f), rightColumn.RectTransform), isHorizontal: true);
|
||||||
|
|
||||||
GUIButton createTabberBtn(string labelTag)
|
GUIButton createTabberBtn(string labelTag)
|
||||||
{
|
{
|
||||||
var btn = new GUIButton(new RectTransform((0.5f, 1.0f), contentPackageTabber.RectTransform, Anchor.BottomCenter, Pivot.BottomCenter), TextManager.Get(labelTag), style: "GUITabButton");
|
var btn = new GUIButton(new RectTransform((0.5f, 1.0f), contentPackageTabber.RectTransform, Anchor.BottomCenter, Pivot.BottomCenter), TextManager.Get(labelTag), style: "GUITabButton");
|
||||||
|
btn.TextBlock.Wrap = true;
|
||||||
|
btn.TextBlock.SetTextPos();
|
||||||
btn.RectTransform.MaxSize = RectTransform.MaxPoint;
|
btn.RectTransform.MaxSize = RectTransform.MaxPoint;
|
||||||
btn.Children.ForEach(c => c.RectTransform.MaxSize = RectTransform.MaxPoint);
|
btn.Children.ForEach(c => c.RectTransform.MaxSize = RectTransform.MaxPoint);
|
||||||
btn.Font = GUIStyle.SmallFont;
|
btn.Font = GUIStyle.SmallFont;
|
||||||
@@ -5638,8 +5628,7 @@ namespace Barotrauma
|
|||||||
MouseDragStart = Vector2.Zero;
|
MouseDragStart = Vector2.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!saveAssemblyFrame.Rect.Contains(PlayerInput.MousePosition)
|
if ((GUI.MouseOn == null || !GUI.MouseOn.IsChildOf(TopPanel))
|
||||||
&& !snapToGridFrame.Rect.Contains(PlayerInput.MousePosition)
|
|
||||||
&& dummyCharacter?.SelectedItem == null && !WiringMode
|
&& dummyCharacter?.SelectedItem == null && !WiringMode
|
||||||
&& (GUI.MouseOn == null || MapEntity.SelectedAny || MapEntity.SelectionPos != Vector2.Zero))
|
&& (GUI.MouseOn == null || MapEntity.SelectedAny || MapEntity.SelectionPos != Vector2.Zero))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Barotrauma.Extensions;
|
|
||||||
using Barotrauma.Items.Components;
|
using Barotrauma.Items.Components;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
@@ -34,7 +33,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
BlueprintEffect.Dispose();
|
BlueprintEffect.Dispose();
|
||||||
GameMain.Instance.Content.Unload();
|
GameMain.Instance.Content.Unload();
|
||||||
BlueprintEffect = GameMain.Instance.Content.Load<Effect>("Effects/blueprintshader_opengl");
|
BlueprintEffect = EffectLoader.Load("Effects/blueprintshader");
|
||||||
GameMain.GameScreen.BlueprintEffect = BlueprintEffect;
|
GameMain.GameScreen.BlueprintEffect = BlueprintEffect;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ using System.Diagnostics;
|
|||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
class SerializableEntityEditor : GUIComponent
|
sealed class SerializableEntityEditor : GUIComponent
|
||||||
{
|
{
|
||||||
private readonly int elementHeight;
|
private readonly int elementHeight;
|
||||||
private readonly GUILayoutGroup layoutGroup;
|
private readonly GUILayoutGroup layoutGroup;
|
||||||
@@ -399,10 +399,6 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
propertyField = CreateBoolField(entity, property, boolVal, displayName, toolTip);
|
propertyField = CreateBoolField(entity, property, boolVal, displayName, toolTip);
|
||||||
}
|
}
|
||||||
else if (value is string stringVal)
|
|
||||||
{
|
|
||||||
propertyField = CreateStringField(entity, property, stringVal, displayName, toolTip);
|
|
||||||
}
|
|
||||||
else if (value.GetType().IsEnum)
|
else if (value.GetType().IsEnum)
|
||||||
{
|
{
|
||||||
if (value.GetType().IsDefined(typeof(FlagsAttribute), inherit: false))
|
if (value.GetType().IsDefined(typeof(FlagsAttribute), inherit: false))
|
||||||
@@ -450,6 +446,10 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
propertyField = CreateStringArrayField(entity, property, a, displayName, toolTip);
|
propertyField = CreateStringArrayField(entity, property, a, displayName, toolTip);
|
||||||
}
|
}
|
||||||
|
else if (value is string or Identifier)
|
||||||
|
{
|
||||||
|
propertyField = CreateStringField(entity, property, value.ToString(), displayName, toolTip);
|
||||||
|
}
|
||||||
return propertyField;
|
return propertyField;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -696,7 +696,7 @@ namespace Barotrauma
|
|||||||
propertyBox.OnEnterPressed += (box, text) => OnApply(box);
|
propertyBox.OnEnterPressed += (box, text) => OnApply(box);
|
||||||
refresh += () =>
|
refresh += () =>
|
||||||
{
|
{
|
||||||
if (!propertyBox.Selected) { propertyBox.Text = (string)property.GetValue(entity); }
|
if (!propertyBox.Selected) { propertyBox.Text = property.GetValue(entity).ToString(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
bool OnApply(GUITextBox textBox)
|
bool OnApply(GUITextBox textBox)
|
||||||
@@ -714,7 +714,7 @@ namespace Barotrauma
|
|||||||
if (SetPropertyValue(property, entity, textBox.Text))
|
if (SetPropertyValue(property, entity, textBox.Text))
|
||||||
{
|
{
|
||||||
TrySendNetworkUpdate(entity, property);
|
TrySendNetworkUpdate(entity, property);
|
||||||
textBox.Text = (string) property.GetValue(entity);
|
textBox.Text = property.GetValue(entity).ToString();
|
||||||
textBox.Flash(GUIStyle.Green, flashDuration: 1f);
|
textBox.Flash(GUIStyle.Green, flashDuration: 1f);
|
||||||
}
|
}
|
||||||
//restore the entities that were selected before applying
|
//restore the entities that were selected before applying
|
||||||
|
|||||||
@@ -648,6 +648,12 @@ namespace Barotrauma.Sounds
|
|||||||
|
|
||||||
if (isConnected == 0)
|
if (isConnected == 0)
|
||||||
{
|
{
|
||||||
|
if (!GameMain.Instance.HasLoaded)
|
||||||
|
{
|
||||||
|
//wait for loading to finish so we don't start releasing and reloading sounds when they're being loaded,
|
||||||
|
//or throw an error mid-loading that'd prevent the content package from being enabled
|
||||||
|
return;
|
||||||
|
}
|
||||||
DebugConsole.ThrowError("Playback device has been disconnected. You can select another available device in the settings.");
|
DebugConsole.ThrowError("Playback device has been disconnected. You can select another available device in the settings.");
|
||||||
SetAudioOutputDevice("<disconnected>");
|
SetAudioOutputDevice("<disconnected>");
|
||||||
Disconnected = true;
|
Disconnected = true;
|
||||||
|
|||||||
@@ -865,17 +865,18 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public static void PlayDamageSound(string damageType, float damage, Vector2 position, float range = 2000.0f, IEnumerable<Identifier> tags = null)
|
public static void PlayDamageSound(string damageType, float damage, Vector2 position, float range = 2000.0f, IEnumerable<Identifier> tags = null)
|
||||||
{
|
{
|
||||||
|
var suitableSounds = damageSounds.Where(s =>
|
||||||
|
s.DamageType == damageType &&
|
||||||
|
(s.RequiredTag.IsEmpty || (tags == null ? s.RequiredTag.IsEmpty : tags.Contains(s.RequiredTag))));
|
||||||
|
|
||||||
//if the damage is too low for any sound, don't play anything
|
//if the damage is too low for any sound, don't play anything
|
||||||
if (damageSounds.All(d => damage < d.DamageRange.X)) { return; }
|
if (suitableSounds.All(d => damage < d.DamageRange.X)) { return; }
|
||||||
|
|
||||||
//allow the damage to differ by 10 from the configured damage range,
|
//allow the damage to differ by 10 from the configured damage range,
|
||||||
//so the same amount of damage doesn't always play the same sound
|
//so the same amount of damage doesn't always play the same sound
|
||||||
float randomizedDamage = MathHelper.Clamp(damage + Rand.Range(-10.0f, 10.0f), 0.0f, 100.0f);
|
float randomizedDamage = MathHelper.Clamp(damage + Rand.Range(-10.0f, 10.0f), 0.0f, 100.0f);
|
||||||
|
suitableSounds = suitableSounds.Where(s =>
|
||||||
var suitableSounds = damageSounds.Where(s =>
|
s.DamageRange == Vector2.Zero || (randomizedDamage >= s.DamageRange.X && randomizedDamage <= s.DamageRange.Y));
|
||||||
s.DamageType == damageType &&
|
|
||||||
(s.DamageRange == Vector2.Zero || (randomizedDamage >= s.DamageRange.X && randomizedDamage <= s.DamageRange.Y)) &&
|
|
||||||
(s.RequiredTag.IsEmpty || (tags == null ? s.RequiredTag.IsEmpty : tags.Contains(s.RequiredTag))));
|
|
||||||
|
|
||||||
var damageSound = suitableSounds.GetRandomUnsynced();
|
var damageSound = suitableSounds.GetRandomUnsynced();
|
||||||
damageSound?.Sound?.Play(1.0f, range, position, muffle: !damageSound.IgnoreMuffling && ShouldMuffleSound(Character.Controlled, position, range, null));
|
damageSound?.Sound?.Play(1.0f, range, position, muffle: !damageSound.IgnoreMuffling && ShouldMuffleSound(Character.Controlled, position, range, null));
|
||||||
|
|||||||
@@ -42,12 +42,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (effect == null)
|
if (effect == null)
|
||||||
{
|
{
|
||||||
#if WINDOWS
|
effect = EffectLoader.Load("Effects/deformshader");
|
||||||
effect = GameMain.Instance.Content.Load<Effect>("Effects/deformshader");
|
|
||||||
#endif
|
|
||||||
#if LINUX || OSX
|
|
||||||
effect = GameMain.Instance.Content.Load<Effect>("Effects/deformshader_opengl");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Invert = invert;
|
Invert = invert;
|
||||||
|
|||||||
@@ -202,6 +202,7 @@ namespace Barotrauma.Steam
|
|||||||
ContentPackageManager.EnabledPackages.Core!,
|
ContentPackageManager.EnabledPackages.Core!,
|
||||||
(p) => { },
|
(p) => { },
|
||||||
heightScale: 1.0f / 13.0f);
|
heightScale: 1.0f / 13.0f);
|
||||||
|
enabledCoreDropdown.AllowNonText = true;
|
||||||
Label(topLeft, "", GUIStyle.SubHeadingFont, heightScale: 1.0f);
|
Label(topLeft, "", GUIStyle.SubHeadingFont, heightScale: 1.0f);
|
||||||
topRight.ChildAnchor = Anchor.CenterLeft;
|
topRight.ChildAnchor = Anchor.CenterLeft;
|
||||||
|
|
||||||
@@ -535,34 +536,119 @@ namespace Barotrauma.Steam
|
|||||||
bulkUpdateButton.Enabled = false;
|
bulkUpdateButton.Enabled = false;
|
||||||
bulkUpdateButton.ToolTip = "";
|
bulkUpdateButton.ToolTip = "";
|
||||||
ContentPackageManager.UpdateContentPackageList();
|
ContentPackageManager.UpdateContentPackageList();
|
||||||
|
|
||||||
|
var corePackages = ContentPackageManager.CorePackages.ToArray();
|
||||||
|
var currentCore = ContentPackageManager.EnabledPackages.Core!;
|
||||||
SwapDropdownValues<CorePackage>(enabledCoreDropdown,
|
SwapDropdownValues<CorePackage>(enabledCoreDropdown,
|
||||||
(p) => p.Name,
|
(p) => p.Name,
|
||||||
ContentPackageManager.CorePackages.ToArray(),
|
corePackages,
|
||||||
ContentPackageManager.EnabledPackages.Core!,
|
currentCore,
|
||||||
(p) =>
|
(p) =>
|
||||||
{
|
{
|
||||||
|
// Manually set dropdown text because
|
||||||
|
// adding buttons to the elements breaks
|
||||||
|
// this part of the dropdown code
|
||||||
|
enabledCoreDropdown.Text = p.Name;
|
||||||
enabledCoreDropdown.ButtonTextColor =
|
enabledCoreDropdown.ButtonTextColor =
|
||||||
p.HasAnyErrors
|
p.HasAnyErrors
|
||||||
? GUIStyle.Red
|
? GUIStyle.Red
|
||||||
: GUIStyle.TextColorNormal;
|
: GUIStyle.TextColorNormal;
|
||||||
});
|
});
|
||||||
enabledCoreDropdown.ListBox.Content.Children
|
|
||||||
.OfType<GUITextBlock>()
|
void addButtonForMod(ContentPackage mod, GUILayoutGroup parent)
|
||||||
.ForEach(tb =>
|
|
||||||
CreateModErrorInfo(
|
|
||||||
(tb.UserData as ContentPackage)!,
|
|
||||||
tb,
|
|
||||||
tb));
|
|
||||||
|
|
||||||
void addRegularModToList(RegularPackage mod, GUIListBox list)
|
|
||||||
{
|
{
|
||||||
var modFrame = new GUIFrame(new RectTransform((1.0f, 0.08f), list.Content.RectTransform),
|
if (ContentPackageManager.LocalPackages.Contains(mod))
|
||||||
|
{
|
||||||
|
var editButton = new GUIButton(new RectTransform(Vector2.One, parent.RectTransform, scaleBasis: ScaleBasis.Smallest), "",
|
||||||
|
style: "WorkshopMenu.EditButton")
|
||||||
|
{
|
||||||
|
OnClicked = (button, o) =>
|
||||||
|
{
|
||||||
|
ToolBox.OpenFileWithShell(mod.Dir);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
ToolTip = TextManager.Get("OpenLocalModInExplorer")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (ContentPackageManager.WorkshopPackages.Contains(mod))
|
||||||
|
{
|
||||||
|
var infoButton = new GUIButton(
|
||||||
|
new RectTransform(Vector2.One, parent.RectTransform, scaleBasis: ScaleBasis.Smallest), "",
|
||||||
|
style: null)
|
||||||
|
{
|
||||||
|
CanBeSelected = false,
|
||||||
|
OnClicked = (button, o) =>
|
||||||
|
{
|
||||||
|
PrepareToShowModInfo(mod);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (!SteamManager.IsInitialized)
|
||||||
|
{
|
||||||
|
infoButton.Enabled = false;
|
||||||
|
}
|
||||||
|
TaskPool.AddIfNotFound(
|
||||||
|
$"DetermineUpdateRequired{mod.UgcId}",
|
||||||
|
mod.IsUpToDate(),
|
||||||
|
t =>
|
||||||
|
{
|
||||||
|
if (!t.TryGetResult(out bool isUpToDate)) { return; }
|
||||||
|
|
||||||
|
if (isUpToDate) { return; }
|
||||||
|
|
||||||
|
infoButton.CanBeSelected = true;
|
||||||
|
infoButton.ApplyStyle(GUIStyle.ComponentStyles["WorkshopMenu.InfoButtonUpdate"]);
|
||||||
|
infoButton.ToolTip = TextManager.Get("ViewModDetailsUpdateAvailable");
|
||||||
|
bulkUpdateButton.Enabled = true;
|
||||||
|
bulkUpdateButton.ToolTip = TextManager.Get("ModUpdatesAvailable");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GUILayoutGroup createBaseModListUi(ContentPackage mod, GUIListBox listBox, float height)
|
||||||
|
{
|
||||||
|
var modFrame = new GUIFrame(new RectTransform((1.0f, height), listBox.Content.RectTransform),
|
||||||
style: "ListBoxElement")
|
style: "ListBoxElement")
|
||||||
{
|
{
|
||||||
UserData = mod
|
UserData = mod
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var frameContent = new GUILayoutGroup(new RectTransform((0.95f, 0.9f), modFrame.RectTransform, Anchor.Center), isHorizontal: true, childAnchor: Anchor.CenterLeft)
|
||||||
|
{
|
||||||
|
Stretch = true,
|
||||||
|
RelativeSpacing = 0.02f
|
||||||
|
};
|
||||||
|
|
||||||
|
var modNameScissor = new GUIScissorComponent(new RectTransform((0.8f, 1.0f), frameContent.RectTransform))
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
var modName = new GUITextBlock(new RectTransform(Vector2.One, modNameScissor.Content.RectTransform),
|
||||||
|
text: mod.Name)
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
CreateModErrorInfo(mod, modFrame, modName);
|
||||||
|
addButtonForMod(mod, frameContent);
|
||||||
|
|
||||||
|
return frameContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var element in enabledCoreDropdown.ListBox.Content.Children.ToArray())
|
||||||
|
{
|
||||||
|
enabledCoreDropdown.ListBox.RemoveChild(element);
|
||||||
|
if (element.UserData is not ContentPackage mod) { continue; }
|
||||||
|
|
||||||
|
createBaseModListUi(mod, enabledCoreDropdown.ListBox, 0.24f);
|
||||||
|
}
|
||||||
|
enabledCoreDropdown.Select(corePackages.IndexOf(currentCore));
|
||||||
|
|
||||||
|
void addRegularModToList(RegularPackage mod, GUIListBox list)
|
||||||
|
{
|
||||||
|
var frameContent = createBaseModListUi(mod, list, 0.08f);
|
||||||
|
|
||||||
|
var modFrame = frameContent.Parent;
|
||||||
|
|
||||||
var contextMenuHandler = new GUICustomComponent(new RectTransform(Vector2.Zero, modFrame.RectTransform),
|
var contextMenuHandler = new GUICustomComponent(new RectTransform(Vector2.Zero, modFrame.RectTransform),
|
||||||
onUpdate: (f, component) =>
|
onUpdate: (f, component) =>
|
||||||
{
|
{
|
||||||
@@ -639,76 +725,13 @@ namespace Barotrauma.Steam
|
|||||||
contextMenuOptions.ToArray());
|
contextMenuOptions.ToArray());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var frameContent = new GUILayoutGroup(new RectTransform((0.95f, 0.9f), modFrame.RectTransform, Anchor.Center), isHorizontal: true, childAnchor: Anchor.CenterLeft)
|
|
||||||
{
|
|
||||||
Stretch = true,
|
|
||||||
RelativeSpacing = 0.02f
|
|
||||||
};
|
|
||||||
|
|
||||||
var dragIndicator = new GUIButton(new RectTransform((0.5f, 0.5f), frameContent.RectTransform, scaleBasis: ScaleBasis.BothHeight),
|
var dragIndicator = new GUIButton(new RectTransform((0.5f, 0.5f), frameContent.RectTransform, scaleBasis: ScaleBasis.BothHeight),
|
||||||
style: "GUIDragIndicator")
|
style: "GUIDragIndicator")
|
||||||
{
|
{
|
||||||
CanBeFocused = false
|
CanBeFocused = false
|
||||||
};
|
};
|
||||||
|
dragIndicator.RectTransform.SetAsFirstChild();
|
||||||
var modNameScissor = new GUIScissorComponent(new RectTransform((0.8f, 1.0f), frameContent.RectTransform))
|
|
||||||
{
|
|
||||||
CanBeFocused = false
|
|
||||||
};
|
|
||||||
var modName = new GUITextBlock(new RectTransform(Vector2.One, modNameScissor.Content.RectTransform),
|
|
||||||
text: mod.Name)
|
|
||||||
{
|
|
||||||
CanBeFocused = false
|
|
||||||
};
|
|
||||||
CreateModErrorInfo(mod, modFrame, modName);
|
|
||||||
if (ContentPackageManager.LocalPackages.Contains(mod))
|
|
||||||
{
|
|
||||||
var editButton = new GUIButton(new RectTransform(Vector2.One, frameContent.RectTransform, scaleBasis: ScaleBasis.Smallest), "",
|
|
||||||
style: "WorkshopMenu.EditButton")
|
|
||||||
{
|
|
||||||
OnClicked = (button, o) =>
|
|
||||||
{
|
|
||||||
ToolBox.OpenFileWithShell(mod.Dir);
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
ToolTip = TextManager.Get("OpenLocalModInExplorer")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else if (ContentPackageManager.WorkshopPackages.Contains(mod))
|
|
||||||
{
|
|
||||||
var infoButton = new GUIButton(
|
|
||||||
new RectTransform(Vector2.One, frameContent.RectTransform, scaleBasis: ScaleBasis.Smallest), "",
|
|
||||||
style: null)
|
|
||||||
{
|
|
||||||
CanBeSelected = false,
|
|
||||||
OnClicked = (button, o) =>
|
|
||||||
{
|
|
||||||
PrepareToShowModInfo(mod);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (!SteamManager.IsInitialized)
|
|
||||||
{
|
|
||||||
infoButton.Enabled = false;
|
|
||||||
}
|
|
||||||
TaskPool.AddIfNotFound(
|
|
||||||
$"DetermineUpdateRequired{mod.UgcId}",
|
|
||||||
mod.IsUpToDate(),
|
|
||||||
t =>
|
|
||||||
{
|
|
||||||
if (!t.TryGetResult(out bool isUpToDate)) { return; }
|
|
||||||
|
|
||||||
if (!isUpToDate)
|
|
||||||
{
|
|
||||||
infoButton.CanBeSelected = true;
|
|
||||||
infoButton.ApplyStyle(GUIStyle.ComponentStyles["WorkshopMenu.InfoButtonUpdate"]);
|
|
||||||
infoButton.ToolTip = TextManager.Get("ViewModDetailsUpdateAvailable");
|
|
||||||
bulkUpdateButton.Enabled = true;
|
|
||||||
bulkUpdateButton.ToolTip = TextManager.Get("ModUpdatesAvailable");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void addRegularModsToList(IEnumerable<RegularPackage> mods, GUIListBox list)
|
void addRegularModsToList(IEnumerable<RegularPackage> mods, GUIListBox list)
|
||||||
@@ -729,7 +752,7 @@ namespace Barotrauma.Steam
|
|||||||
.Where(p => ContentPackageManager.RegularPackages.Contains(p)))
|
.Where(p => ContentPackageManager.RegularPackages.Contains(p)))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
var disabledMods = ContentPackageManager.RegularPackages.Where(p => !enabledMods.Contains(p));
|
var disabledMods = ContentPackageManager.RegularPackages.Where(p => !enabledMods.Contains(p));
|
||||||
|
|
||||||
addRegularModsToList(enabledMods, enabledRegularModsList);
|
addRegularModsToList(enabledMods, enabledRegularModsList);
|
||||||
if (refreshDisabled) { addRegularModsToList(disabledMods, disabledRegularModsList); }
|
if (refreshDisabled) { addRegularModsToList(disabledMods, disabledRegularModsList); }
|
||||||
|
|
||||||
@@ -747,7 +770,7 @@ namespace Barotrauma.Steam
|
|||||||
var mod = child.UserData as RegularPackage;
|
var mod = child.UserData as RegularPackage;
|
||||||
if (mod is null || !ContentPackageManager.WorkshopPackages.Contains(mod)) { continue; }
|
if (mod is null || !ContentPackageManager.WorkshopPackages.Contains(mod)) { continue; }
|
||||||
if (!mod.UgcId.TryUnwrap(out var ugcId)) { continue; }
|
if (!mod.UgcId.TryUnwrap(out var ugcId)) { continue; }
|
||||||
if (!(ugcId is SteamWorkshopId workshopId)) { continue; }
|
if (ugcId is not SteamWorkshopId workshopId) { continue; }
|
||||||
|
|
||||||
var btn = child.GetChild<GUILayoutGroup>()?.GetAllChildren<GUIButton>().Last();
|
var btn = child.GetChild<GUILayoutGroup>()?.GetAllChildren<GUIButton>().Last();
|
||||||
if (btn is null) { continue; }
|
if (btn is null) { continue; }
|
||||||
|
|||||||
@@ -218,6 +218,20 @@ namespace Barotrauma.Steam
|
|||||||
var descriptionTextBox
|
var descriptionTextBox
|
||||||
= ScrollableTextBox(rightTop, 6.0f, workshopItem.Description ?? string.Empty);
|
= ScrollableTextBox(rightTop, 6.0f, workshopItem.Description ?? string.Empty);
|
||||||
|
|
||||||
|
if (workshopItem.Id != 0)
|
||||||
|
{
|
||||||
|
TaskPool.Add(
|
||||||
|
$"GetFullDescription{workshopItem.Id}",
|
||||||
|
SteamManager.Workshop.GetItemAsap(workshopItem.Id.Value, withLongDescription: true),
|
||||||
|
t =>
|
||||||
|
{
|
||||||
|
if (!t.TryGetResult(out Steamworks.Ugc.Item? itemWithDescription)) { return; }
|
||||||
|
|
||||||
|
descriptionTextBox.Text = itemWithDescription?.Description ?? descriptionTextBox.Text;
|
||||||
|
descriptionTextBox.Deselect();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var (leftBottom, _, rightBottom)
|
var (leftBottom, _, rightBottom)
|
||||||
= CreateSidebars(mainLayout, leftWidth: 0.49f, centerWidth: 0.01f, rightWidth: 0.5f, height: 0.5f);
|
= CreateSidebars(mainLayout, leftWidth: 0.49f, centerWidth: 0.01f, rightWidth: 0.5f, height: 0.5f);
|
||||||
leftBottom.Stretch = true;
|
leftBottom.Stretch = true;
|
||||||
|
|||||||
@@ -68,10 +68,13 @@ namespace Barotrauma.Steam
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected static void SwapDropdownValues<T>(
|
protected static void SwapDropdownValues<T>(
|
||||||
GUIDropDown dropdown, Func<T, LocalizedString> textFunc, IReadOnlyList<T> values, T currentValue,
|
GUIDropDown dropdown,
|
||||||
|
Func<T, LocalizedString> textFunc,
|
||||||
|
IReadOnlyList<T> values,
|
||||||
|
T currentValue,
|
||||||
Action<T> setter)
|
Action<T> setter)
|
||||||
{
|
{
|
||||||
if (dropdown.ListBox.Content.Children.Any(c => !(c.UserData is T)))
|
if (dropdown.ListBox.Content.Children.Any(c => c.UserData is not T))
|
||||||
{
|
{
|
||||||
throw new Exception("SwapValues must preserve the type of the dropdown's userdata");
|
throw new Exception("SwapValues must preserve the type of the dropdown's userdata");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
partial class UpgradePrefab
|
sealed partial class UpgradePrefab
|
||||||
{
|
{
|
||||||
public readonly ImmutableArray<DecorativeSprite> DecorativeSprites = new ImmutableArray<DecorativeSprite>();
|
public readonly ImmutableArray<DecorativeSprite> DecorativeSprites = new ImmutableArray<DecorativeSprite>();
|
||||||
public Sprite Sprite { get; private set; }
|
public Sprite Sprite { get; private set; }
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
namespace Barotrauma;
|
||||||
|
|
||||||
|
static class EffectLoader
|
||||||
|
{
|
||||||
|
public static Effect Load(string path)
|
||||||
|
=> GameMain.Instance.Content.Load<Effect>(path
|
||||||
|
#if LINUX || OSX
|
||||||
|
+"_opengl"
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -23,36 +23,55 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public static void ConvertMasterLocalizationKit(string outputTextsDirectory, string outputConversationsDirectory, bool convertConversations)
|
public static void ConvertMasterLocalizationKit(string outputTextsDirectory, string outputConversationsDirectory, bool convertConversations)
|
||||||
{
|
{
|
||||||
string textFilePath = Path.Combine(infoTextPath, "Texts.csv");
|
List<string> languages = new List<string>();
|
||||||
string conversationFilePath = Path.Combine(infoTextPath, "NPCConversations.csv");
|
for (int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
string textFilePath;
|
||||||
|
string outputFileName;
|
||||||
|
switch (i)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
textFilePath = Path.Combine(infoTextPath, "Texts.csv");
|
||||||
|
outputFileName = "Vanilla.xml";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
textFilePath = Path.Combine(infoTextPath, "EditorTexts.csv");
|
||||||
|
outputFileName = "VanillaEditorTexts.xml";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
Dictionary<string, List<string>> xmlContent;
|
Dictionary<string, List<string>> xmlContent;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
xmlContent = ConvertInfoTextToXML(File.ReadAllLines(textFilePath, Encoding.UTF8));
|
xmlContent = ConvertInfoTextToXML(File.ReadAllLines(textFilePath, Encoding.UTF8));
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("InfoText Localization .csv to .xml conversion failed for: " + textFilePath, e);
|
DebugConsole.ThrowError("InfoText Localization .csv to .xml conversion failed for: " + textFilePath, e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (xmlContent == null)
|
if (xmlContent == null)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("InfoText Localization .csv to .xml conversion failed for: " + textFilePath);
|
DebugConsole.ThrowError("InfoText Localization .csv to .xml conversion failed for: " + textFilePath);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
foreach (string language in xmlContent.Keys)
|
foreach (string language in xmlContent.Keys)
|
||||||
{
|
{
|
||||||
string languageNoWhitespace = language.Replace(" ", "");
|
languages.Add(language);
|
||||||
string xmlFileFullPath = Path.Combine(outputTextsDirectory, $"{languageNoWhitespace}/{languageNoWhitespace}Vanilla.xml");
|
string languageNoWhitespace = language.Replace(" ", "");
|
||||||
File.WriteAllLines(xmlFileFullPath, xmlContent[language], Encoding.UTF8);
|
string xmlFileFullPath = Path.Combine(outputTextsDirectory, $"{languageNoWhitespace}/{languageNoWhitespace}{outputFileName}");
|
||||||
DebugConsole.NewMessage("InfoText localization .xml file successfully created at: " + xmlFileFullPath);
|
File.WriteAllLines(xmlFileFullPath, xmlContent[language], Encoding.UTF8);
|
||||||
|
DebugConsole.NewMessage("InfoText localization .xml file successfully created at: " + xmlFileFullPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (convertConversations)
|
if (convertConversations)
|
||||||
{
|
{
|
||||||
|
string conversationFilePath = Path.Combine(infoTextPath, "NPCConversations.csv");
|
||||||
var conversationLinesAll = File.ReadAllLines(conversationFilePath, Encoding.UTF8);
|
var conversationLinesAll = File.ReadAllLines(conversationFilePath, Encoding.UTF8);
|
||||||
foreach (string language in xmlContent.Keys)
|
foreach (string language in languages)
|
||||||
{
|
{
|
||||||
List<string> convXmlContent = ConvertConversationsToXML(conversationLinesAll, language);
|
List<string> convXmlContent = ConvertConversationsToXML(conversationLinesAll, language);
|
||||||
if (convXmlContent == null)
|
if (convXmlContent == null)
|
||||||
@@ -61,7 +80,7 @@ namespace Barotrauma
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
string languageNoWhitespace = language.Replace(" ", "");
|
string languageNoWhitespace = language.Replace(" ", "");
|
||||||
string xmlFileFullPath = Path.Combine(outputTextsDirectory, $"NpcConversations_{languageNoWhitespace}.xml");
|
string xmlFileFullPath = Path.Combine(outputConversationsDirectory, languageNoWhitespace, $"NpcConversations_{languageNoWhitespace}.xml");
|
||||||
File.WriteAllLines(xmlFileFullPath, convXmlContent, Encoding.UTF8);
|
File.WriteAllLines(xmlFileFullPath, convXmlContent, Encoding.UTF8);
|
||||||
DebugConsole.NewMessage("Conversation localization .xml file successfully created at: " + xmlFileFullPath);
|
DebugConsole.NewMessage("Conversation localization .xml file successfully created at: " + xmlFileFullPath);
|
||||||
}
|
}
|
||||||
@@ -339,7 +358,8 @@ namespace Barotrauma
|
|||||||
string[] headerSplit = csvContent[0].Split(separator);
|
string[] headerSplit = csvContent[0].Split(separator);
|
||||||
for (int i = 0; i < headerSplit.Length; i++)
|
for (int i = 0; i < headerSplit.Length; i++)
|
||||||
{
|
{
|
||||||
if (headerSplit[i] == language)
|
if (headerSplit[i] == language ||
|
||||||
|
(language == "English" && headerSplit[i]== "Line (Original)"))
|
||||||
{
|
{
|
||||||
languageColumn = i;
|
languageColumn = i;
|
||||||
break;
|
break;
|
||||||
@@ -348,6 +368,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
xmlContent.Add($"<Conversations identifier=\"vanillaconversations\" Language=\"{language}\" nowhitespace=\"{nowhitespace}\">");
|
xmlContent.Add($"<Conversations identifier=\"vanillaconversations\" Language=\"{language}\" nowhitespace=\"{nowhitespace}\">");
|
||||||
|
|
||||||
|
conversationClosingIndent.Clear();
|
||||||
int conversationStart = 1;
|
int conversationStart = 1;
|
||||||
|
|
||||||
xmlContent.Add(string.Empty);
|
xmlContent.Add(string.Empty);
|
||||||
@@ -399,9 +420,9 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
string[] nextConversationElement = csvContent[i + 1].Split(separator);
|
string[] nextConversationElement = csvContent[i + 1].Split(separator);
|
||||||
|
|
||||||
if (nextConversationElement[1] != string.Empty)
|
if (nextConversationElement[3] != string.Empty)
|
||||||
{
|
{
|
||||||
nextDepth = int.Parse(nextConversationElement[2]);
|
nextDepth = int.Parse(nextConversationElement[3]);
|
||||||
nextIsSubConvo = nextDepth > depthIndex;
|
nextIsSubConvo = nextDepth > depthIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -421,7 +442,12 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
//end of file, close remaining xml tags
|
||||||
xmlContent.Add(element.TrimEnd() + "/>");
|
xmlContent.Add(element.TrimEnd() + "/>");
|
||||||
|
for (int j = depthIndex - 1; j >= 0; j--)
|
||||||
|
{
|
||||||
|
HandleClosingElements(xmlContent, j);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,12 +459,12 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private static void HandleClosingElements(List<string> xmlContent, int targetDepth)
|
private static void HandleClosingElements(List<string> xmlContent, int targetDepth)
|
||||||
{
|
{
|
||||||
if (conversationClosingIndent.Count == 0) return;
|
if (conversationClosingIndent.Count == 0) { return; }
|
||||||
|
|
||||||
for (int k = conversationClosingIndent.Count - 1; k >= 0; k--)
|
for (int k = conversationClosingIndent.Count - 1; k >= 0; k--)
|
||||||
{
|
{
|
||||||
int currentIndent = conversationClosingIndent[k];
|
int currentIndent = conversationClosingIndent[k];
|
||||||
if (currentIndent < targetDepth) break;
|
if (currentIndent < targetDepth) { break; }
|
||||||
xmlContent.Add($"{GetIndenting(currentIndent)}</Conversation>");
|
xmlContent.Add($"{GetIndenting(currentIndent)}</Conversation>");
|
||||||
conversationClosingIndent.RemoveAt(k);
|
conversationClosingIndent.RemoveAt(k);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,28 +7,30 @@ using System.Text;
|
|||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
class SpriteRecorder : ISpriteBatch, IDisposable
|
sealed class SpriteRecorder : ISpriteBatch, IDisposable
|
||||||
{
|
{
|
||||||
private struct Command
|
public readonly record struct Command(
|
||||||
|
Texture2D Texture,
|
||||||
|
VertexPositionColorTexture VertexBL,
|
||||||
|
VertexPositionColorTexture VertexBR,
|
||||||
|
VertexPositionColorTexture VertexTL,
|
||||||
|
VertexPositionColorTexture VertexTR,
|
||||||
|
float Depth,
|
||||||
|
Vector2 Min,
|
||||||
|
Vector2 Max,
|
||||||
|
int Index)
|
||||||
{
|
{
|
||||||
public readonly Texture2D Texture;
|
public static Vector2 GetMinPosition(params VertexPositionColorTexture[] vertices)
|
||||||
public readonly VertexPositionColorTexture VertexBL;
|
=> new Vector2(
|
||||||
public readonly VertexPositionColorTexture VertexBR;
|
MathUtils.Min(vertices.Select(v => v.Position.X).ToArray()),
|
||||||
public readonly VertexPositionColorTexture VertexTL;
|
MathUtils.Min(vertices.Select(v => v.Position.Y).ToArray()));
|
||||||
public readonly VertexPositionColorTexture VertexTR;
|
|
||||||
public readonly float Depth;
|
public static Vector2 GetMaxPosition(params VertexPositionColorTexture[] vertices)
|
||||||
public readonly Vector2 Min;
|
=> new Vector2(
|
||||||
public readonly Vector2 Max;
|
MathUtils.Max(vertices.Select(v => v.Position.X).ToArray()),
|
||||||
public readonly int Index;
|
MathUtils.Max(vertices.Select(v => v.Position.Y).ToArray()));
|
||||||
|
|
||||||
public bool Overlaps(Command other)
|
public static Command FromTransform(
|
||||||
{
|
|
||||||
return
|
|
||||||
Min.X <= other.Max.X && Max.X >= other.Min.X &&
|
|
||||||
Min.Y <= other.Max.Y && Max.Y >= other.Min.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Command(
|
|
||||||
Texture2D texture,
|
Texture2D texture,
|
||||||
Vector2 pos,
|
Vector2 pos,
|
||||||
Rectangle srcRect,
|
Rectangle srcRect,
|
||||||
@@ -46,15 +48,11 @@ namespace Barotrauma
|
|||||||
int srcRectBottom = srcRect.Bottom;
|
int srcRectBottom = srcRect.Bottom;
|
||||||
if (effects.HasFlag(SpriteEffects.FlipHorizontally))
|
if (effects.HasFlag(SpriteEffects.FlipHorizontally))
|
||||||
{
|
{
|
||||||
var temp = srcRectRight;
|
(srcRectRight, srcRectLeft) = (srcRectLeft, srcRectRight);
|
||||||
srcRectRight = srcRectLeft;
|
|
||||||
srcRectLeft = temp;
|
|
||||||
}
|
}
|
||||||
if (effects.HasFlag(SpriteEffects.FlipVertically))
|
if (effects.HasFlag(SpriteEffects.FlipVertically))
|
||||||
{
|
{
|
||||||
var temp = srcRectBottom;
|
(srcRectBottom, srcRectTop) = (srcRectTop, srcRectBottom);
|
||||||
srcRectBottom = srcRectTop;
|
|
||||||
srcRectTop = temp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rotation = MathHelper.ToRadians(rotation);
|
rotation = MathHelper.ToRadians(rotation);
|
||||||
@@ -68,59 +66,63 @@ namespace Barotrauma
|
|||||||
pos.X -= origin.X * scale.X * cos - origin.Y * scale.Y * sin;
|
pos.X -= origin.X * scale.X * cos - origin.Y * scale.Y * sin;
|
||||||
pos.Y -= origin.Y * scale.Y * cos + origin.X * scale.X * sin;
|
pos.Y -= origin.Y * scale.Y * cos + origin.X * scale.X * sin;
|
||||||
|
|
||||||
Texture = texture;
|
var vertexTl = new VertexPositionColorTexture
|
||||||
|
{
|
||||||
|
Color = color,
|
||||||
|
Position = new Vector3(pos.X, pos.Y, 0f),
|
||||||
|
TextureCoordinate = new Vector2((float)srcRectLeft / (float)texture.Width, (float)srcRectTop / (float)texture.Height)
|
||||||
|
};
|
||||||
|
|
||||||
Depth = depth;
|
var vertexTr = new VertexPositionColorTexture
|
||||||
|
{
|
||||||
|
Color = color,
|
||||||
|
Position = new Vector3(pos.X + wAdd.X, pos.Y + wAdd.Y, 0f),
|
||||||
|
TextureCoordinate = new Vector2((float)srcRectRight / (float)texture.Width, (float)srcRectTop / (float)texture.Height)
|
||||||
|
};
|
||||||
|
|
||||||
VertexTL.Color = color;
|
var vertexBl = new VertexPositionColorTexture
|
||||||
VertexTR.Color = color;
|
{
|
||||||
VertexBL.Color = color;
|
Color = color,
|
||||||
VertexBR.Color = color;
|
Position = new Vector3(pos.X + hAdd.X, pos.Y + hAdd.Y, 0f),
|
||||||
|
TextureCoordinate = new Vector2((float)srcRectLeft / (float)texture.Width, (float)srcRectBottom / (float)texture.Height)
|
||||||
|
};
|
||||||
|
|
||||||
VertexTL.Position = new Vector3(pos.X, pos.Y, 0f);
|
var vertexBr = new VertexPositionColorTexture
|
||||||
VertexTR.Position = new Vector3(pos.X + wAdd.X, pos.Y + wAdd.Y, 0f);
|
{
|
||||||
VertexBL.Position = new Vector3(pos.X + hAdd.X, pos.Y + hAdd.Y, 0f);
|
Color = color,
|
||||||
VertexBR.Position = new Vector3(pos.X + wAdd.X + hAdd.X, pos.Y + wAdd.Y + hAdd.Y, 0f);
|
Position = new Vector3(pos.X + wAdd.X + hAdd.X, pos.Y + wAdd.Y + hAdd.Y, 0f),
|
||||||
|
TextureCoordinate = new Vector2((float)srcRectRight / (float)texture.Width, (float)srcRectBottom / (float)texture.Height)
|
||||||
|
};
|
||||||
|
|
||||||
Min = new Vector2(
|
var min = GetMinPosition(
|
||||||
MathUtils.Min
|
vertexTl,
|
||||||
(
|
vertexTr,
|
||||||
VertexTL.Position.X,
|
vertexBl,
|
||||||
VertexTR.Position.X,
|
vertexBr);
|
||||||
VertexBL.Position.X,
|
|
||||||
VertexBR.Position.X
|
|
||||||
),
|
|
||||||
MathUtils.Min
|
|
||||||
(
|
|
||||||
VertexTL.Position.Y,
|
|
||||||
VertexTR.Position.Y,
|
|
||||||
VertexBL.Position.Y,
|
|
||||||
VertexBR.Position.Y
|
|
||||||
));
|
|
||||||
|
|
||||||
Max = new Vector2(
|
var max = GetMaxPosition(
|
||||||
MathUtils.Max
|
vertexTl,
|
||||||
(
|
vertexTr,
|
||||||
VertexTL.Position.X,
|
vertexBl,
|
||||||
VertexTR.Position.X,
|
vertexBr);
|
||||||
VertexBL.Position.X,
|
|
||||||
VertexBR.Position.X
|
|
||||||
),
|
|
||||||
MathUtils.Max
|
|
||||||
(
|
|
||||||
VertexTL.Position.Y,
|
|
||||||
VertexTR.Position.Y,
|
|
||||||
VertexBL.Position.Y,
|
|
||||||
VertexBR.Position.Y
|
|
||||||
));
|
|
||||||
|
|
||||||
VertexTL.TextureCoordinate = new Vector2((float)srcRectLeft / (float)texture.Width, (float)srcRectTop / (float)texture.Height);
|
return new Command(
|
||||||
VertexTR.TextureCoordinate = new Vector2((float)srcRectRight / (float)texture.Width, (float)srcRectTop / (float)texture.Height);
|
texture,
|
||||||
VertexBL.TextureCoordinate = new Vector2((float)srcRectLeft / (float)texture.Width, (float)srcRectBottom / (float)texture.Height);
|
vertexBl,
|
||||||
VertexBR.TextureCoordinate = new Vector2((float)srcRectRight / (float)texture.Width, (float)srcRectBottom / (float)texture.Height);
|
vertexBr,
|
||||||
|
vertexTl,
|
||||||
Index = index;
|
vertexTr,
|
||||||
|
depth,
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Overlaps(Command other)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
Min.X <= other.Max.X && Max.X >= other.Min.X &&
|
||||||
|
Min.Y <= other.Max.Y && Max.Y >= other.Min.Y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,8 +153,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public static BasicEffect BasicEffect = null;
|
public static BasicEffect BasicEffect = null;
|
||||||
|
|
||||||
private List<RecordedBuffer> recordedBuffers = new List<RecordedBuffer>();
|
private readonly List<RecordedBuffer> recordedBuffers = new List<RecordedBuffer>();
|
||||||
private List<Command> commandList = new List<Command>();
|
private readonly List<Command> commandList = new List<Command>();
|
||||||
private SpriteSortMode currentSortMode;
|
private SpriteSortMode currentSortMode;
|
||||||
|
|
||||||
private IndexBuffer indexBuffer = null;
|
private IndexBuffer indexBuffer = null;
|
||||||
@@ -170,16 +172,45 @@ namespace Barotrauma
|
|||||||
currentSortMode = sortMode;
|
currentSortMode = sortMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Draw(Texture2D texture, Vector2 pos, Rectangle? srcRect, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float depth)
|
private void AppendCommand(Command command)
|
||||||
{
|
{
|
||||||
if (isDisposed) { return; }
|
if (isDisposed) { return; }
|
||||||
|
|
||||||
Command command = new Command(texture, pos, srcRect ?? texture.Bounds, color, rotation, origin, scale, effects, depth, commandList?.Count ?? 0);
|
|
||||||
if (commandList.Count == 0) { Min = command.Min; Max = command.Max; }
|
if (commandList.Count == 0) { Min = command.Min; Max = command.Max; }
|
||||||
Min = new Vector2(Math.Min(command.Min.X, Min.X), Math.Min(command.Min.Y, Min.Y));
|
Min = new Vector2(Math.Min(command.Min.X, Min.X), Math.Min(command.Min.Y, Min.Y));
|
||||||
Max = new Vector2(Math.Max(command.Max.X, Max.X), Math.Max(command.Max.Y, Max.Y));
|
Max = new Vector2(Math.Max(command.Max.X, Max.X), Math.Max(command.Max.Y, Max.Y));
|
||||||
|
|
||||||
commandList?.Add(command);
|
commandList.Add(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw(Texture2D texture, Vector2 pos, Rectangle? srcRect, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float depth)
|
||||||
|
{
|
||||||
|
if (isDisposed) { return; }
|
||||||
|
|
||||||
|
var command = Command.FromTransform(texture, pos, srcRect ?? texture.Bounds, color, rotation, origin, scale, effects, depth, commandList.Count);
|
||||||
|
AppendCommand(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw(Texture2D texture, VertexPositionColorTexture[] vertices, float layerDepth, int? count = null)
|
||||||
|
{
|
||||||
|
if (isDisposed) { return; }
|
||||||
|
|
||||||
|
int iters = count ?? (vertices.Length / 4);
|
||||||
|
for (int i=0;i<iters;i++)
|
||||||
|
{
|
||||||
|
var subset = vertices[((i * 4) + 0)..((i * 4) + 4)];
|
||||||
|
var command = new Command(
|
||||||
|
texture,
|
||||||
|
subset[2],
|
||||||
|
subset[3],
|
||||||
|
subset[0],
|
||||||
|
subset[1],
|
||||||
|
layerDepth,
|
||||||
|
Command.GetMinPosition(subset),
|
||||||
|
Command.GetMaxPosition(subset),
|
||||||
|
commandList.Count);
|
||||||
|
AppendCommand(command);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void End()
|
public void End()
|
||||||
@@ -309,15 +340,12 @@ namespace Barotrauma
|
|||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
isDisposed = true;
|
isDisposed = true;
|
||||||
if (recordedBuffers != null)
|
foreach (var buffer in recordedBuffers)
|
||||||
{
|
{
|
||||||
foreach (var buffer in recordedBuffers)
|
buffer.VertexBuffer.Dispose();
|
||||||
{
|
|
||||||
buffer.VertexBuffer.Dispose();
|
|
||||||
}
|
|
||||||
recordedBuffers.Clear(); recordedBuffers = null;
|
|
||||||
}
|
}
|
||||||
commandList?.Clear(); commandList = null;
|
recordedBuffers.Clear();
|
||||||
|
commandList.Clear();
|
||||||
indexBuffer?.Dispose(); indexBuffer = null;
|
indexBuffer?.Dispose(); indexBuffer = null;
|
||||||
ReadyToRender = false;
|
ReadyToRender = false;
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
Barotrauma/BarotraumaClient/Content/Effects/wearableclip.xnb
Normal file
BIN
Barotrauma/BarotraumaClient/Content/Effects/wearableclip.xnb
Normal file
Binary file not shown.
Binary file not shown.
@@ -6,3 +6,5 @@
|
|||||||
|
|
||||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Potential Code Quality Issues", "RECS0026:Possible unassigned object created by 'new'", Justification = "<Pending>", Scope = "member", Target = "~M:Barotrauma.GameSettings.CreateSettingsFrame")]
|
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Potential Code Quality Issues", "RECS0026:Possible unassigned object created by 'new'", Justification = "<Pending>", Scope = "member", Target = "~M:Barotrauma.GameSettings.CreateSettingsFrame")]
|
||||||
|
|
||||||
|
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Potential Code Quality Issues", "IDE0047")]
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma</Product>
|
<Product>Barotrauma</Product>
|
||||||
<Version>0.20.16.1</Version>
|
<Version>0.21.6.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>Barotrauma</AssemblyName>
|
<AssemblyName>Barotrauma</AssemblyName>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma</Product>
|
<Product>Barotrauma</Product>
|
||||||
<Version>0.20.16.1</Version>
|
<Version>0.21.6.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>Barotrauma</AssemblyName>
|
<AssemblyName>Barotrauma</AssemblyName>
|
||||||
|
|||||||
@@ -79,3 +79,8 @@
|
|||||||
/processorParam:DebugMode=Auto
|
/processorParam:DebugMode=Auto
|
||||||
/build:blueprintshader.fx
|
/build:blueprintshader.fx
|
||||||
|
|
||||||
|
#begin wearableclip.fx
|
||||||
|
/importer:EffectImporter
|
||||||
|
/processor:EffectProcessor
|
||||||
|
/processorParam:DebugMode=Auto
|
||||||
|
/build:wearableclip.fx
|
||||||
|
|||||||
@@ -78,3 +78,9 @@
|
|||||||
/processor:EffectProcessor
|
/processor:EffectProcessor
|
||||||
/processorParam:DebugMode=Auto
|
/processorParam:DebugMode=Auto
|
||||||
/build:thresholdtint_opengl.fx
|
/build:thresholdtint_opengl.fx
|
||||||
|
|
||||||
|
#begin wearableclip_opengl.fx
|
||||||
|
/importer:EffectImporter
|
||||||
|
/processor:EffectProcessor
|
||||||
|
/processorParam:DebugMode=Auto
|
||||||
|
/build:wearableclip_opengl.fx
|
||||||
|
|||||||
42
Barotrauma/BarotraumaClient/Shaders/wearableclip.fx
Normal file
42
Barotrauma/BarotraumaClient/Shaders/wearableclip.fx
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
|
||||||
|
Texture2D xTexture;
|
||||||
|
sampler TextureSampler : register (s0) = sampler_state { Texture = <xTexture>; };
|
||||||
|
|
||||||
|
Texture2D xStencil;
|
||||||
|
sampler StencilSampler = sampler_state { Texture = <xStencil>; };
|
||||||
|
|
||||||
|
float aCutoff;
|
||||||
|
float4x4 wearableUvToClipperUv;
|
||||||
|
float clipperTexelSize;
|
||||||
|
|
||||||
|
float stencilSample(float2 texCoord, float2 offset)
|
||||||
|
{
|
||||||
|
return xStencil.Sample(
|
||||||
|
StencilSampler,
|
||||||
|
mul(float4(texCoord.x, texCoord.y, 0, 1), wearableUvToClipperUv).xy + offset).a;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 main(float4 position : POSITION0, float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
|
||||||
|
{
|
||||||
|
float4 c = xTexture.Sample(TextureSampler, texCoord) * color;
|
||||||
|
|
||||||
|
float minStencil = stencilSample(texCoord, float2(0,0));
|
||||||
|
minStencil = min(minStencil, stencilSample(texCoord, float2(-clipperTexelSize,0)));
|
||||||
|
minStencil = min(minStencil, stencilSample(texCoord, float2(clipperTexelSize,0)));
|
||||||
|
minStencil = min(minStencil, stencilSample(texCoord, float2(0,-clipperTexelSize)));
|
||||||
|
minStencil = min(minStencil, stencilSample(texCoord, float2(0,clipperTexelSize)));
|
||||||
|
|
||||||
|
float aDiff = minStencil - aCutoff;
|
||||||
|
|
||||||
|
clip(aDiff);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
technique StencilShader
|
||||||
|
{
|
||||||
|
pass Pass1
|
||||||
|
{
|
||||||
|
PixelShader = compile ps_4_0_level_9_1 main();
|
||||||
|
}
|
||||||
|
}
|
||||||
42
Barotrauma/BarotraumaClient/Shaders/wearableclip_opengl.fx
Normal file
42
Barotrauma/BarotraumaClient/Shaders/wearableclip_opengl.fx
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
|
||||||
|
Texture2D xTexture;
|
||||||
|
sampler TextureSampler : register (s0) = sampler_state { Texture = <xTexture>; };
|
||||||
|
|
||||||
|
Texture2D xStencil;
|
||||||
|
sampler StencilSampler = sampler_state { Texture = <xStencil>; };
|
||||||
|
|
||||||
|
float aCutoff;
|
||||||
|
float4x4 wearableUvToClipperUv;
|
||||||
|
float clipperTexelSize;
|
||||||
|
|
||||||
|
float stencilSample(float2 texCoord, float2 offset)
|
||||||
|
{
|
||||||
|
return tex2D(
|
||||||
|
StencilSampler,
|
||||||
|
mul(float4(texCoord.x, texCoord.y, 0, 1), wearableUvToClipperUv).xy + offset).a;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 main(float4 position : POSITION0, float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
|
||||||
|
{
|
||||||
|
float4 c = tex2D(TextureSampler, texCoord) * color;
|
||||||
|
|
||||||
|
float minStencil = stencilSample(texCoord, float2(0,0));
|
||||||
|
minStencil = min(minStencil, stencilSample(texCoord, float2(-clipperTexelSize,0)));
|
||||||
|
minStencil = min(minStencil, stencilSample(texCoord, float2(clipperTexelSize,0)));
|
||||||
|
minStencil = min(minStencil, stencilSample(texCoord, float2(0,-clipperTexelSize)));
|
||||||
|
minStencil = min(minStencil, stencilSample(texCoord, float2(0,clipperTexelSize)));
|
||||||
|
|
||||||
|
float aDiff = minStencil - aCutoff;
|
||||||
|
|
||||||
|
clip(aDiff);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
technique StencilShader
|
||||||
|
{
|
||||||
|
pass Pass1
|
||||||
|
{
|
||||||
|
PixelShader = compile ps_2_0 main();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma</Product>
|
<Product>Barotrauma</Product>
|
||||||
<Version>0.20.16.1</Version>
|
<Version>0.21.6.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>Barotrauma</AssemblyName>
|
<AssemblyName>Barotrauma</AssemblyName>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma Dedicated Server</Product>
|
<Product>Barotrauma Dedicated Server</Product>
|
||||||
<Version>0.20.16.1</Version>
|
<Version>0.21.6.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>DedicatedServer</AssemblyName>
|
<AssemblyName>DedicatedServer</AssemblyName>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma Dedicated Server</Product>
|
<Product>Barotrauma Dedicated Server</Product>
|
||||||
<Version>0.20.16.1</Version>
|
<Version>0.21.6.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>DedicatedServer</AssemblyName>
|
<AssemblyName>DedicatedServer</AssemblyName>
|
||||||
|
|||||||
@@ -14,6 +14,13 @@ namespace Barotrauma
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Discarded;
|
public bool Discarded;
|
||||||
|
|
||||||
|
public void ApplyDeathEffects()
|
||||||
|
{
|
||||||
|
RespawnManager.ReduceCharacterSkills(this);
|
||||||
|
RemoveSavedStatValuesOnDeath();
|
||||||
|
CauseOfDeath = null;
|
||||||
|
}
|
||||||
|
|
||||||
partial void OnSkillChanged(Identifier skillIdentifier, float prevLevel, float newLevel)
|
partial void OnSkillChanged(Identifier skillIdentifier, float prevLevel, float newLevel)
|
||||||
{
|
{
|
||||||
if (Character == null || Character.Removed) { return; }
|
if (Character == null || Character.Removed) { return; }
|
||||||
|
|||||||
@@ -8,8 +8,9 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
partial class Character
|
partial class Character
|
||||||
{
|
{
|
||||||
public Address OwnerClientAddress;
|
private Address ownerClientAddress;
|
||||||
public string OwnerClientName;
|
private Option<AccountId> ownerClientAccountId;
|
||||||
|
|
||||||
public bool ClientDisconnected;
|
public bool ClientDisconnected;
|
||||||
public float KillDisconnectedTimer;
|
public float KillDisconnectedTimer;
|
||||||
|
|
||||||
@@ -19,6 +20,35 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public bool HealthUpdatePending;
|
public bool HealthUpdatePending;
|
||||||
|
|
||||||
|
public void SetOwnerClient(Client client)
|
||||||
|
{
|
||||||
|
if (client == null)
|
||||||
|
{
|
||||||
|
ownerClientAddress = null;
|
||||||
|
ownerClientAccountId = Option<AccountId>.None();
|
||||||
|
IsRemotePlayer = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ownerClientAddress = client.Connection.Endpoint.Address;
|
||||||
|
ownerClientAccountId = client.AccountId;
|
||||||
|
IsRemotePlayer = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsClientOwner(Client client)
|
||||||
|
{
|
||||||
|
if (ownerClientAccountId.TryUnwrap(out var accountId)
|
||||||
|
&& client.AccountId.TryUnwrap(out var clientId))
|
||||||
|
{
|
||||||
|
return accountId == clientId;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ownerClientAddress == client.Connection.Endpoint.Address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public float GetPositionUpdateInterval(Client recipient)
|
public float GetPositionUpdateInterval(Client recipient)
|
||||||
{
|
{
|
||||||
if (!Enabled) { return 1000.0f; }
|
if (!Enabled) { return 1000.0f; }
|
||||||
@@ -306,12 +336,8 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ServerWritePosition(IWriteMessage msg, Client c)
|
public void ServerWritePosition(ReadWriteMessage tempBuffer, Client c)
|
||||||
{
|
{
|
||||||
msg.WriteUInt16(ID);
|
|
||||||
|
|
||||||
IWriteMessage tempBuffer = new WriteOnlyMessage();
|
|
||||||
|
|
||||||
if (this == c.Character)
|
if (this == c.Character)
|
||||||
{
|
{
|
||||||
tempBuffer.WriteBoolean(true);
|
tempBuffer.WriteBoolean(true);
|
||||||
@@ -409,11 +435,6 @@ namespace Barotrauma
|
|||||||
AIController?.ServerWrite(tempBuffer);
|
AIController?.ServerWrite(tempBuffer);
|
||||||
HealthUpdatePending = false;
|
HealthUpdatePending = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
tempBuffer.WritePadBits();
|
|
||||||
|
|
||||||
msg.WriteVariableUInt32((uint)tempBuffer.LengthBytes);
|
|
||||||
msg.WriteBytes(tempBuffer.Buffer, 0, tempBuffer.LengthBytes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
public virtual void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#nullable enable
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Barotrauma.Networking;
|
||||||
|
|
||||||
|
namespace Barotrauma
|
||||||
|
{
|
||||||
|
internal static class HealingCooldown
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<Client, DateTimeOffset> HealingCooldowns = new();
|
||||||
|
|
||||||
|
// Little bit less than client's 0.5 second cooldown to account for latency
|
||||||
|
private const float CooldownDuration = 0.4f;
|
||||||
|
|
||||||
|
public static bool IsOnCooldown(Client client)
|
||||||
|
{
|
||||||
|
RemoveExpiredCooldowns();
|
||||||
|
return HealingCooldowns.ContainsKey(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetCooldown(Client client)
|
||||||
|
{
|
||||||
|
RemoveExpiredCooldowns();
|
||||||
|
DateTimeOffset newCooldown = DateTimeOffset.UtcNow.AddSeconds(CooldownDuration);
|
||||||
|
HealingCooldowns[client] = newCooldown;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RemoveExpiredCooldowns()
|
||||||
|
{
|
||||||
|
HashSet<Client>? expiredCooldowns = null;
|
||||||
|
|
||||||
|
DateTimeOffset now = DateTimeOffset.UtcNow;
|
||||||
|
|
||||||
|
foreach (var (client, cooldown) in HealingCooldowns)
|
||||||
|
{
|
||||||
|
if (now < cooldown) { continue; }
|
||||||
|
|
||||||
|
expiredCooldowns ??= new HashSet<Client>();
|
||||||
|
expiredCooldowns.Add(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expiredCooldowns is null) { return; }
|
||||||
|
|
||||||
|
foreach (Client expiredCooldown in expiredCooldowns)
|
||||||
|
{
|
||||||
|
HealingCooldowns.Remove(expiredCooldown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1401,7 +1401,7 @@ namespace Barotrauma
|
|||||||
MultiPlayerCampaign.StartCampaignSetup();
|
MultiPlayerCampaign.StartCampaignSetup();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!GameMain.Server.StartGame()) { NewMessage("Failed to start a new round", Color.Yellow); }
|
if (!GameMain.Server.TryStartGame()) { NewMessage("Failed to start a new round", Color.Yellow); }
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public static ContentPackage VanillaContent => ContentPackageManager.VanillaCorePackage;
|
public static ContentPackage VanillaContent => ContentPackageManager.VanillaCorePackage;
|
||||||
|
|
||||||
|
|
||||||
public readonly string[] CommandLineArgs;
|
public readonly string[] CommandLineArgs;
|
||||||
|
|
||||||
public GameMain(string[] args)
|
public GameMain(string[] args)
|
||||||
|
|||||||
@@ -27,12 +27,9 @@ namespace Barotrauma
|
|||||||
AnyOneAllowedToManageCampaign(permissions);
|
AnyOneAllowedToManageCampaign(permissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool AllowedToManageWallets(Client client)
|
public static bool AllowedToManageWallets(Client client)
|
||||||
{
|
{
|
||||||
return
|
return AllowedToManageCampaign(client, ClientPermissions.ManageMoney);
|
||||||
client.HasPermission(ClientPermissions.ManageCampaign) ||
|
|
||||||
client.HasPermission(ClientPermissions.ManageMoney) ||
|
|
||||||
IsOwner(client);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ShowStartMessage()
|
public override void ShowStartMessage()
|
||||||
|
|||||||
@@ -109,15 +109,22 @@ namespace Barotrauma
|
|||||||
return AccountId == other.AccountId && other.ClientAddress == ClientAddress;
|
return AccountId == other.AccountId && other.ClientAddress == ClientAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
itemData = null;
|
||||||
|
healthData = null;
|
||||||
|
WalletData = null;
|
||||||
|
}
|
||||||
|
|
||||||
public void SpawnInventoryItems(Character character, Inventory inventory)
|
public void SpawnInventoryItems(Character character, Inventory inventory)
|
||||||
{
|
{
|
||||||
if (character == null)
|
if (character == null)
|
||||||
{
|
{
|
||||||
throw new System.InvalidOperationException($"Failed to spawn inventory items. Character was null.");
|
throw new InvalidOperationException($"Failed to spawn inventory items. Character was null.");
|
||||||
}
|
}
|
||||||
if (itemData == null)
|
if (itemData == null)
|
||||||
{
|
{
|
||||||
throw new System.InvalidOperationException($"Failed to spawn inventory items for the character \"{character.Name}\". No saved inventory data.");
|
throw new InvalidOperationException($"Failed to spawn inventory items for the character \"{character.Name}\". No saved inventory data.");
|
||||||
}
|
}
|
||||||
character.SpawnInventoryItems(inventory, itemData.FromPackage(null));
|
character.SpawnInventoryItems(inventory, itemData.FromPackage(null));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
NextLevel = map.SelectedConnection?.LevelData ?? map.CurrentLocation.LevelData;
|
NextLevel = map.SelectedConnection?.LevelData ?? map.CurrentLocation.LevelData;
|
||||||
MirrorLevel = false;
|
MirrorLevel = false;
|
||||||
GameMain.Server.StartGame();
|
GameMain.Server.TryStartGame();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void StartCampaignSetup()
|
public static void StartCampaignSetup()
|
||||||
@@ -240,9 +240,7 @@ namespace Barotrauma
|
|||||||
//reduce skills if the character has died
|
//reduce skills if the character has died
|
||||||
if (characterInfo.CauseOfDeath != null && characterInfo.CauseOfDeath.Type != CauseOfDeathType.Disconnected)
|
if (characterInfo.CauseOfDeath != null && characterInfo.CauseOfDeath.Type != CauseOfDeathType.Disconnected)
|
||||||
{
|
{
|
||||||
RespawnManager.ReduceCharacterSkills(characterInfo);
|
characterInfo.ApplyDeathEffects();
|
||||||
characterInfo.RemoveSavedStatValuesOnDeath();
|
|
||||||
characterInfo.CauseOfDeath = null;
|
|
||||||
}
|
}
|
||||||
c.CharacterInfo = characterInfo;
|
c.CharacterInfo = characterInfo;
|
||||||
SetClientCharacterData(c);
|
SetClientCharacterData(c);
|
||||||
@@ -254,13 +252,21 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (data.HasSpawned && !GameMain.Server.ConnectedClients.Any(c => data.MatchesClient(c)))
|
if (data.HasSpawned && !GameMain.Server.ConnectedClients.Any(c => data.MatchesClient(c)))
|
||||||
{
|
{
|
||||||
var character = Character.CharacterList.Find(c => c.Info == data.CharacterInfo && !c.IsHusk);
|
var character = Character.CharacterList.Find(c => c.Info == data.CharacterInfo && !c.IsHusk);
|
||||||
if (character != null && (!character.IsDead || character.CauseOfDeath?.Type == CauseOfDeathType.Disconnected))
|
if (character != null &&
|
||||||
|
(!character.IsDead || character.CauseOfDeath?.Type == CauseOfDeathType.Disconnected))
|
||||||
{
|
{
|
||||||
|
//character still alive (or killed by Disconnect) -> save it as-is
|
||||||
characterData.RemoveAll(cd => cd.IsDuplicate(data));
|
characterData.RemoveAll(cd => cd.IsDuplicate(data));
|
||||||
data.Refresh(character);
|
data.Refresh(character);
|
||||||
characterData.Add(data);
|
characterData.Add(data);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//character dead or removed -> reduce skills, remove items, health data, etc
|
||||||
|
data.CharacterInfo.ApplyDeathEffects();
|
||||||
|
data.Reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,7 +401,7 @@ namespace Barotrauma
|
|||||||
yield return new WaitForSeconds(EndTransitionDuration * 0.5f);
|
yield return new WaitForSeconds(EndTransitionDuration * 0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
GameMain.Server.StartGame();
|
GameMain.Server.TryStartGame();
|
||||||
|
|
||||||
yield return CoroutineStatus.Success;
|
yield return CoroutineStatus.Success;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Barotrauma.Items.Components;
|
using Barotrauma.Extensions;
|
||||||
|
using Barotrauma.Items.Components;
|
||||||
using Barotrauma.Networking;
|
using Barotrauma.Networking;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -19,7 +20,7 @@ namespace Barotrauma
|
|||||||
bool accessible = c.Character.CanAccessInventory(this);
|
bool accessible = c.Character.CanAccessInventory(this);
|
||||||
if (this is CharacterInventory characterInventory && accessible)
|
if (this is CharacterInventory characterInventory && accessible)
|
||||||
{
|
{
|
||||||
if (Owner == null || !(Owner is Character ownerCharacter))
|
if (Owner == null || Owner is not Character ownerCharacter)
|
||||||
{
|
{
|
||||||
accessible = false;
|
accessible = false;
|
||||||
}
|
}
|
||||||
@@ -39,7 +40,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
foreach (ushort id in newItemIDs[i])
|
foreach (ushort id in newItemIDs[i])
|
||||||
{
|
{
|
||||||
if (!(Entity.FindEntityByID(id) is Item item)) { continue; }
|
if (Entity.FindEntityByID(id) is not Item item) { continue; }
|
||||||
item.PositionUpdateInterval = 0.0f;
|
item.PositionUpdateInterval = 0.0f;
|
||||||
if (item.ParentInventory != null && item.ParentInventory != this)
|
if (item.ParentInventory != null && item.ParentInventory != this)
|
||||||
{
|
{
|
||||||
@@ -94,7 +95,15 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
foreach (ushort id in newItemIDs[i])
|
foreach (ushort id in newItemIDs[i])
|
||||||
{
|
{
|
||||||
if (!(Entity.FindEntityByID(id) is Item item) || slots[i].Contains(item)) { continue; }
|
if (Entity.FindEntityByID(id) is not Item item || slots[i].Contains(item)) { continue; }
|
||||||
|
|
||||||
|
if (item.GetComponent<Pickable>() is not Pickable pickable ||
|
||||||
|
(pickable.IsAttached && !pickable.PickingDone) ||
|
||||||
|
item.AllowedSlots.None())
|
||||||
|
{
|
||||||
|
DebugConsole.AddWarning($"Client {c.Name} tried to pick up a non-pickable item \"{item}\" (parent inventory: {item.ParentInventory?.Owner.ToString() ?? "null"})");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (GameMain.Server != null)
|
if (GameMain.Server != null)
|
||||||
{
|
{
|
||||||
@@ -105,7 +114,7 @@ namespace Barotrauma
|
|||||||
(c.Character == null || item.PreviousParentInventory == null || !c.Character.CanAccessInventory(item.PreviousParentInventory)))
|
(c.Character == null || item.PreviousParentInventory == null || !c.Character.CanAccessInventory(item.PreviousParentInventory)))
|
||||||
{
|
{
|
||||||
#if DEBUG || UNSTABLE
|
#if DEBUG || UNSTABLE
|
||||||
DebugConsole.NewMessage($"Client {c.Name} failed to pick up item \"{item}\" (parent inventory: {(item.ParentInventory?.Owner.ToString() ?? "null")}). No access.", Color.Yellow);
|
DebugConsole.NewMessage($"Client {c.Name} failed to pick up item \"{item}\" (parent inventory: {item.ParentInventory?.Owner.ToString() ?? "null"}). No access.", Color.Yellow);
|
||||||
#endif
|
#endif
|
||||||
if (item.body != null && !c.PendingPositionUpdates.Contains(item))
|
if (item.body != null && !c.PendingPositionUpdates.Contains(item))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -153,25 +153,27 @@ namespace Barotrauma
|
|||||||
(components[containerIndex] as ItemContainer).Inventory.ServerEventRead(msg, c);
|
(components[containerIndex] as ItemContainer).Inventory.ServerEventRead(msg, c);
|
||||||
break;
|
break;
|
||||||
case EventType.Treatment:
|
case EventType.Treatment:
|
||||||
if (c.Character == null || !c.Character.CanInteractWith(this)) return;
|
if (c.Character == null || !c.Character.CanInteractWith(this)) { return; }
|
||||||
|
|
||||||
UInt16 characterID = msg.ReadUInt16();
|
UInt16 characterID = msg.ReadUInt16();
|
||||||
byte limbIndex = msg.ReadByte();
|
byte limbIndex = msg.ReadByte();
|
||||||
|
|
||||||
Character targetCharacter = FindEntityByID(characterID) as Character;
|
if (HealingCooldown.IsOnCooldown(c)) { return; }
|
||||||
if (targetCharacter == null) break;
|
if (FindEntityByID(characterID) is not Character targetCharacter) { break; }
|
||||||
if (targetCharacter != c.Character && c.Character.SelectedCharacter != targetCharacter) break;
|
if (targetCharacter != c.Character && c.Character.SelectedCharacter != targetCharacter) { break; }
|
||||||
|
|
||||||
|
HealingCooldown.SetCooldown(c);
|
||||||
|
|
||||||
Limb targetLimb = limbIndex < targetCharacter.AnimController.Limbs.Length ? targetCharacter.AnimController.Limbs[limbIndex] : null;
|
Limb targetLimb = limbIndex < targetCharacter.AnimController.Limbs.Length ? targetCharacter.AnimController.Limbs[limbIndex] : null;
|
||||||
|
|
||||||
if (ContainedItems == null || ContainedItems.All(i => i == null))
|
if (ContainedItems == null || ContainedItems.All(static i => i == null))
|
||||||
{
|
{
|
||||||
GameServer.Log(GameServer.CharacterLogName(c.Character) + " used item " + Name, ServerLog.MessageType.ItemInteraction);
|
GameServer.Log($"{GameServer.CharacterLogName(c.Character)} used item {Name}", ServerLog.MessageType.ItemInteraction);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GameServer.Log(
|
GameServer.Log(
|
||||||
GameServer.CharacterLogName(c.Character) + " used item " + Name + " (contained items: " + string.Join(", ", ContainedItems.Select(i => i.Name)) + ")",
|
$"{GameServer.CharacterLogName(c.Character)} used item {Name} (contained items: {string.Join(", ", ContainedItems.Select(i => i.Name))})",
|
||||||
ServerLog.MessageType.ItemInteraction);
|
ServerLog.MessageType.ItemInteraction);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,15 +350,9 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ServerWritePosition(IWriteMessage msg, Client c)
|
public void ServerWritePosition(ReadWriteMessage tempBuffer, Client c)
|
||||||
{
|
{
|
||||||
msg.WriteUInt16(ID);
|
|
||||||
|
|
||||||
IWriteMessage tempBuffer = new WriteOnlyMessage();
|
|
||||||
body.ServerWrite(tempBuffer);
|
body.ServerWrite(tempBuffer);
|
||||||
msg.WriteVariableUInt32((uint)tempBuffer.LengthBytes);
|
|
||||||
msg.WriteBytes(tempBuffer.Buffer, 0, tempBuffer.LengthBytes);
|
|
||||||
msg.WritePadBits();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CreateServerEvent<T>(T ic) where T : ItemComponent, IServerSerializable
|
public void CreateServerEvent<T>(T ic) where T : ItemComponent, IServerSerializable
|
||||||
@@ -378,7 +374,7 @@ namespace Barotrauma
|
|||||||
if (!components.Contains(ic)) { return; }
|
if (!components.Contains(ic)) { return; }
|
||||||
|
|
||||||
var eventData = new ComponentStateEventData(ic, extraData);
|
var eventData = new ComponentStateEventData(ic, extraData);
|
||||||
if (!ic.ValidateEventData(eventData)) { throw new Exception($"Component event creation failed: {typeof(T).Name}.{nameof(ItemComponent.ValidateEventData)} returned false"); }
|
if (!ic.ValidateEventData(eventData)) { throw new Exception($"Component event creation for the item \"{Prefab.Identifier}\" failed: {typeof(T).Name}.{nameof(ItemComponent.ValidateEventData)} returned false."); }
|
||||||
GameMain.Server.CreateEntityEvent(this, eventData);
|
GameMain.Server.CreateEntityEvent(this, eventData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user