(f2e516dfe) v0.9.3.2

This commit is contained in:
Joonas Rikkonen
2019-09-20 20:11:18 +03:00
parent 80698b58b0
commit 9aa12bcac2
144 changed files with 1653 additions and 1559 deletions

View File

@@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.9.2.1")]
[assembly: AssemblyFileVersion("0.9.2.1")]
[assembly: AssemblyVersion("0.9.3.2")]
[assembly: AssemblyFileVersion("0.9.3.2")]

View File

@@ -105,15 +105,15 @@ namespace Barotrauma
switch ((NetEntityEvent.Type)extraData[0])
{
case NetEntityEvent.Type.InventoryState:
msg.WriteRangedIntegerDeprecated(0, 3, 0);
msg.WriteRangedInteger(0, 0, 3);
Inventory.ClientWrite(msg, extraData);
break;
case NetEntityEvent.Type.Treatment:
msg.WriteRangedIntegerDeprecated(0, 3, 1);
msg.WriteRangedInteger(1, 0, 3);
msg.Write(AnimController.Anim == AnimController.Animation.CPR);
break;
case NetEntityEvent.Type.Status:
msg.WriteRangedIntegerDeprecated(0, 3, 2);
msg.WriteRangedInteger(2, 0, 3);
break;
}
}
@@ -131,7 +131,7 @@ namespace Barotrauma
msg.Write(inputCount);
for (int i = 0; i < inputCount; i++)
{
msg.WriteRangedIntegerDeprecated(0, (int)InputNetFlags.MaxVal, (int)memInput[i].states);
msg.WriteRangedInteger((int)memInput[i].states, 0, (int)InputNetFlags.MaxVal);
msg.Write(memInput[i].intAim);
if (memInput[i].states.HasFlag(InputNetFlags.Select) ||
memInput[i].states.HasFlag(InputNetFlags.Deselect) ||
@@ -283,9 +283,16 @@ namespace Barotrauma
case 0:
if (Inventory == null)
{
string errorMsg = "Received an inventory update message for an entity with no inventory (" + Name + ")";
string errorMsg = "Received an inventory update message for an entity with no inventory (" + Name + ", removed: " + Removed + ")";
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ClientRead:NoInventory" + ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
//read anyway to prevent messing up reading the rest of the message
byte itemCount = msg.ReadByte();
for (int i = 0; i < itemCount; i++)
{
msg.ReadUInt16();
}
}
else
{
@@ -337,7 +344,7 @@ namespace Barotrauma
public static Character ReadSpawnData(IReadMessage inc, bool spawn = true)
{
DebugConsole.NewMessage("READING CHARACTER SPAWN DATA", Color.Cyan);
DebugConsole.Log("Reading character spawn data");
if (GameMain.Client == null) return null;
@@ -433,7 +440,16 @@ namespace Barotrauma
if (causeOfDeathType == CauseOfDeathType.Affliction)
{
int afflictionIndex = msg.ReadRangedInteger(0, AfflictionPrefab.List.Count - 1);
causeOfDeathAffliction = AfflictionPrefab.List[afflictionIndex];
if (afflictionIndex < 0 || afflictionIndex >= AfflictionPrefab.List.Count)
{
string errorMsg = $"Error in CharacterNetworking.ReadStatus: affliction index out of bounds (index: {afflictionIndex}, affliction count: {AfflictionPrefab.List.Count})";
causeOfDeathType = CauseOfDeathType.Unknown;
GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ReadStatus:AfflictionIndexOutOfBounts", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
}
else
{
causeOfDeathAffliction = AfflictionPrefab.List[afflictionIndex];
}
}
byte severedLimbCount = msg.ReadByte();
@@ -452,13 +468,20 @@ namespace Barotrauma
for (int i = 0; i < severedLimbCount; i++)
{
int severedJointIndex = msg.ReadByte();
AnimController.SeverLimbJoint(AnimController.LimbJoints[severedJointIndex]);
if (severedJointIndex < 0 || severedJointIndex >= AnimController.LimbJoints.Length)
{
string errorMsg = $"Error in CharacterNetworking.ReadStatus: severed joint index out of bounds (index: {severedJointIndex}, joint count: {AnimController.LimbJoints.Length})";
GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ReadStatus:JointIndexOutOfBounts", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
}
else
{
AnimController.SeverLimbJoint(AnimController.LimbJoints[severedJointIndex]);
}
}
}
else
{
if (IsDead) Revive();
if (IsDead) { Revive(); }
CharacterHealth.ClientRead(msg);
}
}

View File

@@ -1359,7 +1359,7 @@ namespace Barotrauma
}
ShowQuestionPrompt("Permission to grant to client #" + id + "?", (perm) =>
{
GameMain.Client.SendConsoleCommand("giveperm " + id + " " + perm);
GameMain.Client?.SendConsoleCommand("giveperm " + id + " " + perm);
});
}
);
@@ -1384,7 +1384,7 @@ namespace Barotrauma
ShowQuestionPrompt("Permission to revoke from client #" + id + "?", (perm) =>
{
GameMain.Client.SendConsoleCommand("revokeperm " + id + " " + perm);
GameMain.Client?.SendConsoleCommand("revokeperm " + id + " " + perm);
});
}
);
@@ -1408,7 +1408,7 @@ namespace Barotrauma
}
ShowQuestionPrompt("Rank to grant to client #" + id + "?", (rank) =>
{
GameMain.Client.SendConsoleCommand("giverank " + id + " " + rank);
GameMain.Client?.SendConsoleCommand("giverank " + id + " " + rank);
});
}
);
@@ -1427,7 +1427,7 @@ namespace Barotrauma
ShowQuestionPrompt("Console command permissions to grant to client #" + id + "? You may enter multiple commands separated with a space.", (commandNames) =>
{
GameMain.Client.SendConsoleCommand("givecommandperm " + id + " " + commandNames);
GameMain.Client?.SendConsoleCommand("givecommandperm " + id + " " + commandNames);
});
}
);
@@ -1446,7 +1446,7 @@ namespace Barotrauma
ShowQuestionPrompt("Console command permissions to revoke from client #" + id + "? You may enter multiple commands separated with a space.", (commandNames) =>
{
GameMain.Client.SendConsoleCommand("revokecommandperm " + id + " " + commandNames);
GameMain.Client?.SendConsoleCommand("revokecommandperm " + id + " " + commandNames);
});
}
);
@@ -1487,7 +1487,7 @@ namespace Barotrauma
banDuration = parsedBanDuration;
}
GameMain.Client.SendConsoleCommand(
GameMain.Client?.SendConsoleCommand(
"banendpoint " +
args[0] + " " +
(banDuration.HasValue ? banDuration.Value.TotalSeconds.ToString() : "0") + " " +
@@ -1538,7 +1538,7 @@ namespace Barotrauma
NewMessage("Index out of bounds!", Color.Red);
return;
}
GameMain.Client.SendConsoleCommand("campaigndestination " + destinationIndex);
GameMain.Client?.SendConsoleCommand("campaigndestination " + destinationIndex);
});
}
else

View File

@@ -32,6 +32,12 @@ namespace Barotrauma
private set;
}
public bool IsCJK
{
get;
private set;
}
public uint Size
{
get
@@ -58,11 +64,16 @@ namespace Barotrauma
}
public ScalableFont(XElement element, GraphicsDevice gd = null)
: this (element.GetAttributeString("file", ""), (uint)element.GetAttributeInt("size", 14), gd, element.GetAttributeBool("dynamicloading", false))
{
: this(
element.GetAttributeString("file", ""),
(uint)element.GetAttributeInt("size", 14),
gd,
element.GetAttributeBool("dynamicloading", false),
element.GetAttributeBool("iscjk", false))
{
}
public ScalableFont(string filename, uint size, GraphicsDevice gd = null, bool dynamicLoading = false)
public ScalableFont(string filename, uint size, GraphicsDevice gd = null, bool dynamicLoading = false, bool isCJK = false)
{
lock (mutex)
{
@@ -85,6 +96,7 @@ namespace Barotrauma
this.textures = new List<Texture2D>();
this.texCoords = new Dictionary<uint, GlyphData>();
this.DynamicLoading = dynamicLoading;
this.IsCJK = isCJK;
this.graphicsDevice = gd;
if (gd != null && !dynamicLoading)

View File

@@ -83,6 +83,7 @@ namespace Barotrauma
public static ScalableFont VideoTitleFont => Style?.VideoTitleFont;
public static ScalableFont ObjectiveTitleFont => Style?.ObjectiveTitleFont;
public static ScalableFont ObjectiveNameFont => Style?.ObjectiveNameFont;
public static ScalableFont CJKFont { get; private set; }
public static UISprite UIGlow => Style.UIGlow;
@@ -154,6 +155,7 @@ namespace Barotrauma
{
GUI.graphicsDevice = graphicsDevice;
var uiStyles = ContentPackage.GetFilesOfType(selectedContentPackages, ContentType.UIStyle).ToList();
if (uiStyles.Count == 0)
{
DebugConsole.ThrowError("No UI styles defined in the selected content package!");
@@ -165,6 +167,11 @@ namespace Barotrauma
}
Style = new GUIStyle(uiStyles[0], graphicsDevice);
if (CJKFont == null)
{
CJKFont = new ScalableFont("Content/Fonts/NotoSans/NotoSansCJKsc-Bold.otf",
Font.Size, graphicsDevice, dynamicLoading: true, isCJK: true);
}
}
public static void LoadContent(bool loadSounds = true)
@@ -408,7 +415,7 @@ namespace Barotrauma
if (Character.Controlled?.Inventory != null)
{
if (!Character.Controlled.LockHands && Character.Controlled.Stun >= -0.1f && !Character.Controlled.IsDead)
if (!Character.Controlled.LockHands && Character.Controlled.Stun < 0.1f && !Character.Controlled.IsDead)
{
Inventory.DrawFront(spriteBatch);
}
@@ -1563,9 +1570,10 @@ namespace Barotrauma
button.OnClicked += (btn, userData) =>
{
var quitButton = button;
if (GameMain.GameSession != null)
if (GameMain.GameSession != null || (Screen.Selected is CharacterEditorScreen charEditScreen || Screen.Selected is SubEditorScreen subEditScreen))
{
var msgBox = new GUIMessageBox("", TextManager.Get("PauseMenuQuitVerification"), new string[] { TextManager.Get("Yes"), TextManager.Get("Cancel") })
string text = GameMain.GameSession == null ? "PauseMenuQuitVerificationEditor" : "PauseMenuQuitVerification";
var msgBox = new GUIMessageBox("", TextManager.Get(text), new string[] { TextManager.Get("Yes"), TextManager.Get("Cancel") })
{
UserData = "verificationprompt"
};

View File

@@ -188,7 +188,7 @@ namespace Barotrauma
{
if (!Visible) return;
base.Update(deltaTime);
if (Rect.Contains(PlayerInput.MousePosition) && CanBeSelected && Enabled && GUI.IsMouseOn(this))
if (Rect.Contains(PlayerInput.MousePosition) && CanBeSelected && CanBeFocused && Enabled && GUI.IsMouseOn(this))
{
state = ComponentState.Hover;
if (PlayerInput.LeftButtonDown())

View File

@@ -22,10 +22,9 @@ namespace Barotrauma
public GUIScrollBar ScrollBar { get; private set; }
public GUIFrame Content { get; private set; }
private Dictionary<GUIComponent, bool> childVisible = new Dictionary<GUIComponent, bool>();
private int totalSize;
private int spacing;
private bool childrenNeedsRecalculation;
private bool scrollBarNeedsRecalculation;
@@ -95,11 +94,7 @@ namespace Barotrauma
get { return totalSize; }
}
public int Spacing
{
get { return spacing; }
set { spacing = value; }
}
public int Spacing { get; set; }
public override Color Color
{
@@ -244,37 +239,37 @@ namespace Barotrauma
{
if (ScrollBar.IsHorizontal)
{
if (y + child.Rect.Height + spacing > Content.Rect.Height)
if (y + child.Rect.Height + Spacing > Content.Rect.Height)
{
y = 0;
x += child.Rect.Width + spacing;
x += child.Rect.Width + Spacing;
if (child.RectTransform.AbsoluteOffset.X != x || child.RectTransform.AbsoluteOffset.Y != y)
{
child.RectTransform.AbsoluteOffset = new Point(x, y);
}
y += child.Rect.Height + spacing;
y += child.Rect.Height + Spacing;
}
else
{
y += child.Rect.Height + spacing;
y += child.Rect.Height + Spacing;
}
}
else
{
if (x + child.Rect.Width + spacing > Content.Rect.Width)
if (x + child.Rect.Width + Spacing > Content.Rect.Width)
{
x = 0;
y += child.Rect.Height + spacing;
y += child.Rect.Height + Spacing;
if (child.RectTransform.AbsoluteOffset.X != x || child.RectTransform.AbsoluteOffset.Y != y)
{
child.RectTransform.AbsoluteOffset = new Point(x, y);
}
x += child.Rect.Width + spacing;
x += child.Rect.Width + Spacing;
}
else
{
x += child.Rect.Width + spacing;
x += child.Rect.Width + Spacing;
}
}
}
@@ -282,11 +277,11 @@ namespace Barotrauma
{
if (ScrollBar.IsHorizontal)
{
x += child.Rect.Width + spacing;
x += child.Rect.Width + Spacing;
}
else
{
y += child.Rect.Height + spacing;
y += child.Rect.Height + Spacing;
}
}
}
@@ -327,10 +322,23 @@ namespace Barotrauma
public override void AddToGUIUpdateList(bool ignoreChildren = false, int order = 0)
{
if (!Visible) { return; }
foreach (GUIComponent child in Content.Children)
{
if (!childVisible.ContainsKey(child)) { childVisible[child] = child.Visible; }
if (childVisible[child] != child.Visible)
{
childVisible[child] = child.Visible;
childrenNeedsRecalculation = true;
scrollBarNeedsRecalculation = true;
break;
}
}
if (childrenNeedsRecalculation)
{
RecalculateChildren();
childVisible.Clear();
}
UpdateOrder = order;
@@ -511,30 +519,30 @@ namespace Barotrauma
{
if (ScrollBar.IsHorizontal)
{
if (pos + child.Rect.Height + spacing > Content.Rect.Height)
if (pos + child.Rect.Height + Spacing > Content.Rect.Height)
{
pos = 0;
totalSize += child.Rect.Width + spacing;
totalSize += child.Rect.Width + Spacing;
}
pos += child.Rect.Height + spacing;
pos += child.Rect.Height + Spacing;
if (child == children.Last())
{
totalSize += child.Rect.Width + spacing;
totalSize += child.Rect.Width + Spacing;
}
}
else
{
if (pos + child.Rect.Width + spacing > Content.Rect.Width)
if (pos + child.Rect.Width + Spacing > Content.Rect.Width)
{
pos = 0;
totalSize += child.Rect.Height + spacing;
totalSize += child.Rect.Height + Spacing;
}
pos += child.Rect.Width + spacing;
pos += child.Rect.Width + Spacing;
if (child == children.Last())
{
totalSize += child.Rect.Height + spacing;
totalSize += child.Rect.Height + Spacing;
}
}
}
@@ -545,7 +553,7 @@ namespace Barotrauma
{
totalSize += (ScrollBar.IsHorizontal) ? child.Rect.Width : child.Rect.Height;
}
totalSize += Content.CountChildren * spacing;
totalSize += Content.CountChildren * Spacing;
}

View File

@@ -56,7 +56,21 @@ namespace Barotrauma
{
if (!Visible) return;
if (ProgressGetter != null) BarSize = ProgressGetter();
if (ProgressGetter != null)
{
float newSize = MathHelper.Clamp(ProgressGetter(), 0.0f, 1.0f);
if (!MathUtils.IsValid(newSize))
{
GameAnalyticsManager.AddErrorEventOnce(
"GUIProgressBar.Draw:GetProgress",
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"ProgressGetter of a GUIProgressBar (" + ProgressGetter.Target.ToString() + " - " + ProgressGetter.Method.ToString() + ") returned an invalid value (" + newSize + ")\n" + Environment.StackTrace);
}
else
{
BarSize = newSize;
}
}
Rectangle sliderRect = new Rectangle(
frame.Rect.X,

View File

@@ -155,7 +155,8 @@ namespace Barotrauma
string file = GetFontFilePath(element);
uint size = GetFontSize(element);
bool dynamicLoading = GetFontDynamicLoading(element);
return new ScalableFont(file, size, graphicsDevice, dynamicLoading);
bool isCJK = GetIsCJK(element);
return new ScalableFont(file, size, graphicsDevice, dynamicLoading, isCJK);
}
private uint GetFontSize(XElement element)
@@ -200,6 +201,20 @@ namespace Barotrauma
return element.GetAttributeBool("dynamicloading", false);
}
private bool GetIsCJK(XElement element)
{
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() != "override") { continue; }
string language = subElement.GetAttributeString("language", "").ToLowerInvariant();
if (GameMain.Config.Language.ToLowerInvariant() == language)
{
return subElement.GetAttributeBool("iscjk", false);
}
}
return element.GetAttributeBool("iscjk", false);
}
public GUIComponentStyle GetComponentStyle(string name)
{
componentStyles.TryGetValue(name.ToLowerInvariant(), out GUIComponentStyle style);

View File

@@ -204,8 +204,13 @@ namespace Barotrauma
if (textColor.HasValue)
{
this.textColor = textColor.Value;
}
this.Font = font ?? GUI.Font;
}
//if the text is in chinese/korean/japanese and we're not using a CJK-compatible font,
//use the default CJK font as a fallback
var selectedFont = font ?? GUI.Font;
if (TextManager.IsCJK(text) && !selectedFont.IsCJK) { selectedFont = GUI.CJKFont; }
this.Font = selectedFont;
this.textAlignment = textAlignment;
this.Wrap = wrap;
this.Text = text ?? "";

View File

@@ -190,7 +190,8 @@ namespace Barotrauma
{
if (Character.Controlled == null || Character.Controlled.SpeechImpediment >= 100.0f) { return false; }
SetCharacterOrder(null, order, null, Character.Controlled);
foreach (var hull in Character.Controlled.GetVisibleHulls())
var visibleHulls = new List<Hull>(Character.Controlled.GetVisibleHulls());
foreach (var hull in visibleHulls)
{
HumanAIController.PropagateHullSafety(Character.Controlled, hull);
HumanAIController.RefreshTargets(Character.Controlled, order, hull);

View File

@@ -199,6 +199,7 @@ namespace Barotrauma.Tutorials
SetHighlight(captain_navConsole.Item, true);
SetHighlight(captain_sonar.Item, true);
SetHighlight(captain_statusMonitor, true);
captain_navConsole.UseAutoDocking = false;
do
{
//captain_navConsoleCustomInterface.HighlightElement(0, uiHighlightColor, duration: 1.0f, pulsateAmount: 0.0f);
@@ -221,6 +222,7 @@ namespace Barotrauma.Tutorials
} while (captain_sonar.CurrentMode != Sonar.Mode.Active);
do { yield return null; } while (Vector2.Distance(Submarine.MainSub.WorldPosition, Level.Loaded.EndPosition) > 4000f);
RemoveCompletedObjective(segments[5]);
captain_navConsole.UseAutoDocking = true;
yield return new WaitForSeconds(4f, false);
TriggerTutorialSegment(6); // Docking
do

View File

@@ -256,6 +256,7 @@ namespace Barotrauma.Tutorials
GameMain.GameSession.CrewManager.AddCharacter(doctor);
GameMain.GameSession.CrewManager.AddCharacter(patient1);
GameMain.GameSession.CrewManager.ToggleCrewAreaOpen = true;
patient1.CharacterHealth.UseHealthWindow = false;
yield return new WaitForSeconds(3.0f, false);
patient1.AIController.Enabled = true;
@@ -277,6 +278,7 @@ namespace Barotrauma.Tutorials
RemoveCompletedObjective(segments[3]);
SetHighlight(doctor_medBayCabinet.Item, true);
SetDoorAccess(doctor_thirdDoor, doctor_thirdDoorLight, true);
patient1.CharacterHealth.UseHealthWindow = true;
yield return new WaitForSeconds(2.0f, false);

View File

@@ -169,7 +169,9 @@ namespace Barotrauma.Tutorials
}
engineer_wire_1 = Item.ItemList.Find(i => i.HasTag("engineer_wire_1"));
engineer_wire_1.SpriteColor = Color.Transparent;
engineer_wire_2 = Item.ItemList.Find(i => i.HasTag("engineer_wire_2"));
engineer_wire_2.SpriteColor = Color.Transparent;
engineer_lamp_1 = Item.ItemList.Find(i => i.HasTag("engineer_lamp_1")).GetComponent<Powered>();
engineer_lamp_2 = Item.ItemList.Find(i => i.HasTag("engineer_lamp_2")).GetComponent<Powered>();
engineer_fourthDoor = Item.ItemList.Find(i => i.HasTag("engineer_fourthdoor")).GetComponent<Door>();
@@ -416,6 +418,8 @@ namespace Barotrauma.Tutorials
do { CheckJunctionBoxHighlights(); yield return null; } while (!engineer_submarineJunctionBox_1.IsFullCondition || !engineer_submarineJunctionBox_2.IsFullCondition || !engineer_submarineJunctionBox_3.IsFullCondition);
CheckJunctionBoxHighlights();
RemoveCompletedObjective(segments[4]);
yield return new WaitForSeconds(2f, false);
TriggerTutorialSegment(5); // Powerup reactor
SetHighlight(engineer_submarineReactor.Item, true);
engineer.AddActiveObjectiveEntity(engineer_submarineReactor.Item, engineer_reactorIcon, engineer_reactorIconColor);
@@ -425,6 +429,8 @@ namespace Barotrauma.Tutorials
RemoveCompletedObjective(segments[5]);
GameMain.GameSession.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Engineer.Radio.Complete"), ChatMessageType.Radio, null);
yield return new WaitForSeconds(4f, false);
CoroutineManager.StartCoroutine(TutorialCompleted());
}
@@ -472,17 +478,31 @@ namespace Barotrauma.Tutorials
private void CheckGhostWires()
{
if (engineer_wire_1 != null && engineer_lamp_1.Voltage > engineer_lamp_1.MinVoltage)
Color wireColor =
Color.Orange *
MathHelper.Lerp(0.25f, 0.75f, (float)(Math.Sin((Timing.TotalTime * 4.0f)) + 1.0f) / 2.0f);
if (engineer_wire_1 != null)
{
engineer_wire_1.Remove();
engineer_wire_1 = null;
engineer_wire_1.SpriteColor = wireColor;
if (engineer_lamp_1.Voltage > engineer_lamp_1.MinVoltage)
{
engineer_wire_1.Remove();
engineer_wire_1 = null;
}
}
if (engineer_wire_2 != null && engineer_lamp_2.Voltage > engineer_lamp_2.MinVoltage)
if (engineer_wire_2 != null)
{
engineer_wire_2.Remove();
engineer_wire_2 = null;
engineer_wire_2.SpriteColor = wireColor;
if (engineer_lamp_2.Voltage > engineer_lamp_2.MinVoltage)
{
engineer_wire_2.Remove();
engineer_wire_2 = null;
}
}
}
private void HandleJunctionBoxWiringHighlights()

View File

@@ -526,6 +526,8 @@ namespace Barotrauma.Tutorials
mechanic.AddActiveObjectiveEntity(mechanic_brokenWall_2, mechanic_weldIcon, mechanic_repairIconColor);
do { yield return null; } while (WallHasDamagedSections(mechanic_brokenWall_2));
mechanic.RemoveActiveObjectiveEntity(mechanic_brokenWall_2);
yield return new WaitForSeconds(2f, false);
TriggerTutorialSegment(9, GameMain.Config.KeyBind(InputType.Use)); // Repairing machinery (pump)
SetHighlight(mechanic_brokenPump.Item, true);
mechanic_brokenPump.CanBeSelected = true;

View File

@@ -373,7 +373,7 @@ namespace Barotrauma.Tutorials
HighlightInventorySlot(officer.Inventory, "harpoongun", highlightColor, 0.5f, 0.5f, 0f);
}
yield return null;
} while (!harpoonGunChamber.Inventory.IsFull()); // Wait until all five harpons loaded
} while (!harpoonGunChamber.Inventory.IsFull()); // Wait until all six harpoons loaded
RemoveCompletedObjective(segments[5]);
SetHighlight(officer_rangedWeaponCabinet.Item, false);
SetDoorAccess(officer_fourthDoor, officer_fourthDoorLight, true);

View File

@@ -113,8 +113,8 @@ namespace Barotrauma
var tickBox = new GUITickBox(new RectTransform(tickBoxScale, contentPackageList.Content.RectTransform, scaleBasis: ScaleBasis.BothHeight), contentPackage.Name)
{
UserData = contentPackage,
OnSelected = SelectContentPackage,
Selected = SelectedContentPackages.Contains(contentPackage)
Selected = SelectedContentPackages.Contains(contentPackage),
OnSelected = SelectContentPackage
};
if (contentPackage.CorePackage)
{
@@ -153,11 +153,6 @@ namespace Barotrauma
UnsavedSettings = true;
var msgBox = new GUIMessageBox(TextManager.Get("RestartRequiredLabel"), TextManager.Get("RestartRequiredLanguage"));
//change fonts to the default font of the new language to make sure
//they can be displayed when for example changing from English to Chinese
var defaultFont = GUI.Style.LoadCurrentDefaultFont();
msgBox.Header.Font = defaultFont;
msgBox.Text.Font = defaultFont;
return true;
};
@@ -445,17 +440,11 @@ namespace Barotrauma
};
voiceChatScrollBar.OnMoved(voiceChatScrollBar, voiceChatScrollBar.BarScroll);
var leftTickBoxes = new GUILayoutGroup(new RectTransform(new Vector2(0.28f, 0.06f), tabs[(int)Tab.Audio].RectTransform, Anchor.TopLeft)
{ RelativeOffset = new Vector2(0.02f, 0.32f) })
{ RelativeSpacing = 0.01f };
var centerTickBoxes = new GUILayoutGroup(new RectTransform(new Vector2(0.4f, 0.06f), tabs[(int)Tab.Audio].RectTransform, Anchor.TopLeft)
{ RelativeOffset = new Vector2(0.3f, 0.32f) })
{ RelativeSpacing = 0.01f };
var rightTickBoxes = new GUILayoutGroup(new RectTransform(new Vector2(0.3f, 0.06f), tabs[(int)Tab.Audio].RectTransform, Anchor.TopRight)
var tickBoxes = new GUILayoutGroup(new RectTransform(new Vector2(0.28f, 0.15f), tabs[(int)Tab.Audio].RectTransform, Anchor.TopLeft)
{ RelativeOffset = new Vector2(0.02f, 0.32f) })
{ RelativeSpacing = 0.01f };
GUITickBox muteOnFocusLostBox = new GUITickBox(new RectTransform(tickBoxScale / 0.06f, leftTickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get("MuteOnFocusLost"));
GUITickBox muteOnFocusLostBox = new GUITickBox(new RectTransform(tickBoxScale / 0.18f, tickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get("MuteOnFocusLost"));
muteOnFocusLostBox.Selected = MuteOnFocusLost;
muteOnFocusLostBox.ToolTip = TextManager.Get("MuteOnFocusLostToolTip");
muteOnFocusLostBox.OnSelected = (tickBox) =>
@@ -465,7 +454,7 @@ namespace Barotrauma
return true;
};
GUITickBox dynamicRangeCompressionTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.06f, centerTickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get("DynamicRangeCompression"));
GUITickBox dynamicRangeCompressionTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.18f, tickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get("DynamicRangeCompression"));
dynamicRangeCompressionTickBox.Selected = DynamicRangeCompressionEnabled;
dynamicRangeCompressionTickBox.ToolTip = TextManager.Get("DynamicRangeCompressionToolTip");
dynamicRangeCompressionTickBox.OnSelected = (tickBox) =>
@@ -475,7 +464,7 @@ namespace Barotrauma
return true;
};
GUITickBox voipAttenuationTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.06f, rightTickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get("VoipAttenuation"));
GUITickBox voipAttenuationTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.18f, tickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get("VoipAttenuation"));
voipAttenuationTickBox.Selected = VoipAttenuationEnabled;
voipAttenuationTickBox.ToolTip = TextManager.Get("VoipAttenuationToolTip");
voipAttenuationTickBox.OnSelected = (tickBox) =>
@@ -485,8 +474,8 @@ namespace Barotrauma
return true;
};
var voipSettings = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.4f), tabs[(int)Tab.Audio].RectTransform, Anchor.TopCenter)
{ RelativeOffset = new Vector2(0.0f, 0.38f) })
var voipSettings = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.35f), tabs[(int)Tab.Audio].RectTransform, Anchor.TopCenter)
{ RelativeOffset = new Vector2(0.0f, 0.47f) })
{ RelativeSpacing = 0.01f };
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), voipSettings.RectTransform), TextManager.Get("VoiceChat"));
@@ -631,18 +620,21 @@ namespace Barotrauma
var dbMeter = new GUIProgressBar(new RectTransform(new Vector2(1.0f, 0.25f), voiceActivityGroup.RectTransform), 0.0f, Color.Lime);
dbMeter.ProgressGetter = () =>
{
if (VoipCapture.Instance == null) return 0.0f;
if (VoipCapture.Instance == null) { return 0.0f; }
dbMeter.Color = VoipCapture.Instance.LastdB > NoiseGateThreshold ? Color.Lime : Color.Orange; //TODO: i'm a filthy hack
return ((float)VoipCapture.Instance.LastdB + 100.0f) / 100.0f;
float scrollVal = double.IsNegativeInfinity(VoipCapture.Instance.LastdB) ? 0.0f : ((float)VoipCapture.Instance.LastdB + 100.0f) / 100.0f;
return scrollVal * scrollVal;
};
var noiseGateSlider = new GUIScrollBar(new RectTransform(Vector2.One, dbMeter.RectTransform, Anchor.Center), color: Color.White, barSize: 0.03f);
noiseGateSlider.Frame.Visible = false;
noiseGateSlider.Step = 0.01f;
noiseGateSlider.Range = new Vector2(-100.0f, 0.0f);
noiseGateSlider.BarScrollValue = NoiseGateThreshold;
noiseGateSlider.BarScroll = MathUtils.InverseLerp(-1.0f, 0.0f, NoiseGateThreshold);
noiseGateSlider.BarScroll *= noiseGateSlider.BarScroll;
noiseGateSlider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
{
NoiseGateThreshold = scrollBar.BarScrollValue;
NoiseGateThreshold = MathHelper.Lerp(-100.0f, 0.0f, (float)Math.Sqrt(scrollBar.BarScroll));
UnsavedSettings = true;
return true;
};
@@ -1018,6 +1010,7 @@ namespace Barotrauma
SelectedContentPackages.Remove(contentPackage);
}
}
if (contentPackage.GetFilesOfType(ContentType.Submarine).Any()) { Submarine.RefreshSavedSubs(); }
UnsavedSettings = true;
return true;
}

View File

@@ -126,6 +126,7 @@ namespace Barotrauma
public override void RemoveItem(Item item)
{
if (!Items.Contains(item)) { return; }
base.RemoveItem(item);
CreateSlots();
}
@@ -175,7 +176,12 @@ namespace Barotrauma
AssignQuickUseNumKeys();
highlightedSubInventorySlots.Clear();
highlightedSubInventorySlots.RemoveWhere(s => s.Inventory.OpenState <= 0.0f);
foreach (var subSlot in highlightedSubInventorySlots)
{
subSlot.Slot = slots[subSlot.SlotIndex];
}
//highlightedSubInventorySlots.Clear();
screenResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
CalculateBackgroundFrame();
@@ -469,6 +475,7 @@ namespace Barotrauma
}
List<SlotReference> hideSubInventories = new List<SlotReference>();
highlightedSubInventorySlots.RemoveWhere(s => s.SlotIndex < 0 || s.SlotIndex >= Items.Length || Items[s.SlotIndex] == null);
foreach (var highlightedSubInventorySlot in highlightedSubInventorySlots)
{
if (highlightedSubInventorySlot.ParentInventory == this)
@@ -646,7 +653,10 @@ namespace Barotrauma
}
}
slotRef.Inventory.OpenState = isEquippedSubInventory ? 1f : 0f; // Reset animation when initially equipped
if (isEquippedSubInventory)
{
slotRef.Inventory.OpenState = 1.0f; // Reset animation when initially equipped
}
highlightedSubInventorySlots.Add(slotRef);
slotRef.Inventory.HideTimer = 1f;

View File

@@ -146,14 +146,24 @@ namespace Barotrauma.Items.Components
if (item.body == null)
{
transformedItemPos = new Vector2(item.Rect.X, item.Rect.Y);
if (item.Submarine != null) transformedItemPos += item.Submarine.DrawPosition;
transformedItemPos = transformedItemPos + ItemPos * item.Scale;
if (item.FlippedX)
{
transformedItemPos.X = -transformedItemPos.X;
transformedItemPos.X += item.Rect.Width;
transformedItemInterval.X = -transformedItemInterval.X;
}
if (item.FlippedY)
{
transformedItemPos.Y = -transformedItemPos.Y;
transformedItemPos.Y -= item.Rect.Height;
transformedItemInterval.Y = -transformedItemInterval.Y;
}
transformedItemPos += new Vector2(item.Rect.X, item.Rect.Y);
if (item.Submarine != null) { transformedItemPos += item.Submarine.DrawPosition; }
}
else
{
Matrix transform = Matrix.CreateRotationZ(item.body.Rotation);
if (item.body.Dir == -1.0f)
{
transformedItemPos.X = -transformedItemPos.X;
@@ -169,6 +179,10 @@ namespace Barotrauma.Items.Components
Vector2 currentItemPos = transformedItemPos;
SpriteEffects spriteEffects = SpriteEffects.None;
if ((item.body != null && item.body.Dir == -1) || item.FlippedX) { spriteEffects |= SpriteEffects.FlipHorizontally; }
if (item.FlippedY) { spriteEffects |= SpriteEffects.FlipVertically; }
int i = 0;
foreach (Item containedItem in Inventory.Items)
{
@@ -192,7 +206,7 @@ namespace Barotrauma.Items.Components
containedItem.GetSpriteColor(),
-currentRotation,
containedItem.Scale,
(item.body != null && item.body.Dir == -1) ? SpriteEffects.FlipHorizontally : SpriteEffects.None,
spriteEffects,
depth: ContainedSpriteDepth < 0.0f ? containedItem.Sprite.Depth : ContainedSpriteDepth);
foreach (ItemContainer ic in containedItem.GetComponents<ItemContainer>())

View File

@@ -1,4 +1,5 @@
using Microsoft.Xna.Framework.Graphics;
using Barotrauma.Networking;
using Microsoft.Xna.Framework.Graphics;
namespace Barotrauma.Items.Components
{
@@ -72,5 +73,10 @@ namespace Barotrauma.Items.Components
GameMain.Client.ChatBox.ToggleOpen = value;
}
}
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
state = msg.ReadBoolean();
}
}
}

View File

@@ -136,7 +136,7 @@ namespace Barotrauma.Items.Components
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
{
//targetForce can only be adjusted at 10% intervals -> no need for more accuracy than this
msg.WriteRangedIntegerDeprecated(-10, 10, (int)(targetForce / 10.0f));
msg.WriteRangedInteger((int)(targetForce / 10.0f), -10, 10);
}
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)

View File

@@ -44,6 +44,16 @@ namespace Barotrauma.Items.Components
Stretch = true,
RelativeSpacing = 0.02f
};
itemList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.5f), paddedFrame.RectTransform))
{
OnSelected = (GUIComponent component, object userdata) =>
{
selectedItem = userdata as FabricationRecipe;
if (selectedItem != null) { SelectItem(Character.Controlled, selectedItem); }
return true;
}
};
var filterArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.06f), paddedFrame.RectTransform), isHorizontal: true)
{
@@ -58,16 +68,6 @@ namespace Barotrauma.Items.Components
OnClicked = (btn, userdata) => { ClearFilter(); itemFilterBox.Flash(Color.White); return true; }
};
itemList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.5f), paddedFrame.RectTransform))
{
OnSelected = (GUIComponent component, object userdata) =>
{
selectedItem = userdata as FabricationRecipe;
if (selectedItem != null) { SelectItem(Character.Controlled, selectedItem); }
return true;
}
};
inputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(0.7f, 0.15f), paddedFrame.RectTransform), style: null);
inputInventoryOverlay = new GUICustomComponent(new RectTransform(Vector2.One, inputInventoryHolder.RectTransform), DrawInputOverLay, null)
{
@@ -462,7 +462,7 @@ namespace Barotrauma.Items.Components
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
{
int itemIndex = pendingFabricatedItem == null ? -1 : fabricationRecipes.IndexOf(pendingFabricatedItem);
msg.WriteRangedIntegerDeprecated(-1, fabricationRecipes.Count - 1, itemIndex);
msg.WriteRangedInteger(itemIndex, -1, fabricationRecipes.Count - 1);
}
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)

View File

@@ -179,7 +179,7 @@ namespace Barotrauma.Items.Components
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
{
//flowpercentage can only be adjusted at 10% intervals -> no need for more accuracy than this
msg.WriteRangedIntegerDeprecated(-10, 10, (int)(flowPercentage / 10.0f));
msg.WriteRangedInteger((int)(flowPercentage / 10.0f), -10, 10);
msg.Write(IsActive);
}

View File

@@ -451,7 +451,10 @@ namespace Barotrauma.Items.Components
if (PlayerInput.KeyDown(InputType.Right)) input.X += 1.0f;
if (PlayerInput.KeyDown(InputType.Up)) input.Y += 1.0f;
if (PlayerInput.KeyDown(InputType.Down)) input.Y += -1.0f;
if (PlayerInput.KeyDown(InputType.Run)) rate = 200.0f;
if (PlayerInput.KeyDown(InputType.Run))
rate = 200.0f;
else if (PlayerInput.KeyDown(InputType.Crouch))
rate = 20.0f;
rate *= deltaTime;
input.X *= rate;

View File

@@ -73,11 +73,18 @@ namespace Barotrauma.Items.Components
set { maintainPosTickBox.Selected = value; }
}
private bool dockingModeEnabled;
public bool DockingModeEnabled
{
get { return UseAutoDocking && dockingModeEnabled; }
set { dockingModeEnabled = value; }
}
public bool UseAutoDocking
{
get;
set;
}
} = true;
public List<DockingPort> DockingSources = new List<DockingPort>();
public DockingPort ActiveDockingSource, DockingTarget;
@@ -726,6 +733,8 @@ namespace Barotrauma.Items.Components
inputCumulation = 0;
keyboardInput = Vector2.Zero;
}
if (!UseAutoDocking) { return; }
float closestDist = DockingAssistThreshold * DockingAssistThreshold;
DockingModeEnabled = false;

View File

@@ -129,7 +129,7 @@ namespace Barotrauma.Items.Components
public void ClientWrite(IWriteMessage msg, object[] extraData)
{
msg.WriteRangedIntegerDeprecated(0, 10, (int)(rechargeSpeed / MaxRechargeSpeed * 10));
msg.WriteRangedInteger((int)(rechargeSpeed / MaxRechargeSpeed * 10), 0, 10);
}
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
@@ -140,7 +140,11 @@ namespace Barotrauma.Items.Components
return;
}
RechargeSpeed = msg.ReadRangedInteger(0, 10) / 10.0f * maxRechargeSpeed;
float rechargeRate = msg.ReadRangedInteger(0, 10) / 10.0f;
RechargeSpeed = rechargeRate * MaxRechargeSpeed;
#if CLIENT
rechargeSpeedSlider.BarScroll = rechargeRate;
#endif
Charge = msg.ReadRangedSingle(0.0f, 1.0f, 8) * capacity;
}
}

View File

@@ -65,13 +65,13 @@ namespace Barotrauma.Items.Components
}
partial void UseProjSpecific(float deltaTime)
partial void UseProjSpecific(float deltaTime, Vector2 raystart)
{
if (ParticleEmitter != null)
{
float particleAngle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
ParticleEmitter.Emit(
deltaTime, item.WorldPosition + TransformedBarrelPos,
deltaTime, ConvertUnits.ToDisplayUnits(raystart),
item.CurrentHull, particleAngle, ParticleEmitter.Prefab.CopyEntityAngle ? -particleAngle : 0);
}
}

View File

@@ -1,5 +1,6 @@
using Barotrauma.Networking;
using Barotrauma.Particles;
using Barotrauma.Sounds;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Collections.Generic;
@@ -25,6 +26,8 @@ namespace Barotrauma.Items.Components
//the corresponding particle emitter is active when the condition is within this range
private List<Vector2> particleEmitterConditionRanges = new List<Vector2>();
private SoundChannel repairSoundChannel;
private string repairButtonText, repairingText;
private string sabotageButtonText, sabotagingText;
@@ -140,6 +143,19 @@ namespace Barotrauma.Items.Components
particleEmitters[i].Emit(deltaTime, item.WorldPosition, item.CurrentHull);
}
}
if (CurrentFixer != null && CurrentFixer.SelectedConstruction == item)
{
if (repairSoundChannel == null || !repairSoundChannel.IsPlaying)
{
repairSoundChannel = SoundPlayer.PlaySound("repair", item.WorldPosition, hullGuess: item.CurrentHull);
}
}
else
{
repairSoundChannel?.FadeOutAndDispose();
repairSoundChannel = null;
}
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
@@ -177,20 +193,6 @@ namespace Barotrauma.Items.Components
}
}
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
deteriorationTimer = msg.ReadSingle();
deteriorateAlwaysResetTimer = msg.ReadSingle();
DeteriorateAlways = msg.ReadBoolean();
CurrentFixer = msg.ReadBoolean() ? Character.Controlled : null;
currentFixerAction = (FixActions)msg.ReadRangedInteger(0, 2);
}
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
{
msg.WriteRangedInteger((int)requestStartFixAction, 0, 2);
}
public void Draw(SpriteBatch spriteBatch, bool editing)
{
if (GameMain.DebugDraw && Character.Controlled?.FocusedItem == item)
@@ -213,5 +215,25 @@ namespace Barotrauma.Items.Components
Color.Orange);
}
}
protected override void RemoveComponentSpecific()
{
repairSoundChannel?.FadeOutAndDispose();
repairSoundChannel = null;
}
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
deteriorationTimer = msg.ReadSingle();
deteriorateAlwaysResetTimer = msg.ReadSingle();
DeteriorateAlways = msg.ReadBoolean();
CurrentFixer = msg.ReadBoolean() ? Character.Controlled : null;
currentFixerAction = (FixActions)msg.ReadRangedInteger(0, 2);
}
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
{
msg.WriteRangedInteger((int)requestStartFixAction, 0, 2);
}
}
}

View File

@@ -1,4 +1,5 @@
using Barotrauma.Networking;
using Barotrauma.Sounds;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
@@ -12,6 +13,8 @@ namespace Barotrauma.Items.Components
{
public static Wire HighlightedWire;
private SoundChannel rewireSoundChannel;
partial void InitProjSpecific(XElement element)
{
if (GuiFrame == null) return;
@@ -20,7 +23,37 @@ namespace Barotrauma.Items.Components
UserData = this
};
}
partial void UpdateProjSpecific(float deltaTime)
{
foreach (Wire wire in DisconnectedWires)
{
if (Rand.Range(0.0f, 500.0f) < 1.0f)
{
SoundPlayer.PlaySound("zap", item.WorldPosition, hullGuess: item.CurrentHull);
Vector2 baseVel = new Vector2(0.0f, -100.0f);
for (int i = 0; i < 5; i++)
{
var particle = GameMain.ParticleManager.CreateParticle("spark", item.WorldPosition,
baseVel + Rand.Vector(100.0f), 0.0f, item.CurrentHull);
if (particle != null) { particle.Size *= Rand.Range(0.5f, 1.0f); }
}
}
}
if (user != null && user.SelectedConstruction == item && HasRequiredItems(user, addMessage: false))
{
if (rewireSoundChannel == null || !rewireSoundChannel.IsPlaying)
{
rewireSoundChannel = SoundPlayer.PlaySound("rewire", item.WorldPosition, hullGuess: item.CurrentHull);
}
}
else
{
rewireSoundChannel?.FadeOutAndDispose();
rewireSoundChannel = null;
}
}
public override void Move(Vector2 amount)
{
if (item.Submarine == null || item.Submarine.Loading || Screen.Selected != GameMain.SubEditorScreen) return;

View File

@@ -155,8 +155,8 @@ namespace Barotrauma
public class SlotReference
{
public readonly Inventory ParentInventory;
public readonly InventorySlot Slot;
public readonly int SlotIndex;
public InventorySlot Slot;
public Inventory Inventory;
@@ -741,17 +741,37 @@ namespace Barotrauma
{
Inventory selectedInventory = selectedSlot.ParentInventory;
int slotIndex = selectedSlot.SlotIndex;
if (selectedInventory.TryPutItem(draggingItem, slotIndex, true, true, Character.Controlled))
//if attempting to drop into an invalid slot in the same inventory, try to move to the correct slot
if (selectedInventory.Items[slotIndex] == null &&
selectedInventory == Character.Controlled.Inventory &&
!draggingItem.AllowedSlots.Any(a => a.HasFlag(Character.Controlled.Inventory.SlotTypes[slotIndex])) &&
selectedInventory.TryPutItem(draggingItem, Character.Controlled, draggingItem.AllowedSlots))
{
if (selectedInventory.slots != null) selectedInventory.slots[slotIndex].ShowBorderHighlight(Color.White, 0.1f, 0.4f);
if (selectedInventory.slots != null)
{
for (int i = 0; i < selectedInventory.slots.Length; i++)
{
if (selectedInventory.Items[i] == draggingItem)
{
selectedInventory.slots[slotIndex].ShowBorderHighlight(Color.White, 0.1f, 0.4f);
}
}
selectedInventory.slots[slotIndex].ShowBorderHighlight(Color.Red, 0.1f, 0.9f);
}
GUI.PlayUISound(GUISoundType.PickItem);
}
else if (selectedInventory.TryPutItem(draggingItem, slotIndex, true, true, Character.Controlled))
{
if (selectedInventory.slots != null) { selectedInventory.slots[slotIndex].ShowBorderHighlight(Color.White, 0.1f, 0.4f); }
GUI.PlayUISound(GUISoundType.PickItem);
}
else
{
if (selectedInventory.slots != null) selectedInventory.slots[slotIndex].ShowBorderHighlight(Color.Red, 0.1f, 0.9f);
if (selectedInventory.slots != null){ selectedInventory.slots[slotIndex].ShowBorderHighlight(Color.Red, 0.1f, 0.9f); }
GUI.PlayUISound(GUISoundType.PickItemFail);
}
selectedInventory.HideTimer = 1.0f;
selectedInventory.HideTimer = 2.0f;
if (selectedSlot.ParentInventory?.Owner is Item parentItem && parentItem.ParentInventory != null)
{
for (int i = 0; i < parentItem.ParentInventory.capacity; i++)
@@ -960,7 +980,7 @@ namespace Barotrauma
{
GUI.DrawRectangle(spriteBatch, new Rectangle(rect.X, rect.Bottom - 8, rect.Width, 8), Color.Black * 0.8f, true);
GUI.DrawRectangle(spriteBatch,
new Rectangle(rect.X, rect.Bottom - 8, (int)(rect.Width * item.Condition / item.MaxCondition), 8),
new Rectangle(rect.X, rect.Bottom - 8, (int)(rect.Width * (item.Condition / item.MaxCondition)), 8),
Color.Lerp(Color.Red, Color.Green, item.Condition / item.MaxCondition) * 0.8f, true);
}
@@ -1080,9 +1100,9 @@ namespace Barotrauma
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
receivedItemIDs = new ushort[capacity];
for (int i = 0; i < capacity; i++)
byte itemCount = msg.ReadByte();
receivedItemIDs = new ushort[itemCount];
for (int i = 0; i < itemCount; i++)
{
receivedItemIDs[i] = msg.ReadUInt16();
}

View File

@@ -930,17 +930,17 @@ namespace Barotrauma
}
NetEntityEvent.Type eventType = (NetEntityEvent.Type)extraData[0];
msg.WriteRangedIntegerDeprecated(0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1, (int)eventType);
msg.WriteRangedInteger((int)eventType, 0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1);
switch (eventType)
{
case NetEntityEvent.Type.ComponentState:
int componentIndex = (int)extraData[1];
msg.WriteRangedIntegerDeprecated(0, components.Count - 1, componentIndex);
msg.WriteRangedInteger(componentIndex, 0, components.Count - 1);
(components[componentIndex] as IClientSerializable).ClientWrite(msg, extraData);
break;
case NetEntityEvent.Type.InventoryState:
int containerIndex = (int)extraData[1];
msg.WriteRangedIntegerDeprecated(0, components.Count - 1, containerIndex);
msg.WriteRangedInteger(containerIndex, 0, components.Count - 1);
(components[containerIndex] as ItemContainer).Inventory.ClientWrite(msg, extraData);
break;
case NetEntityEvent.Type.Treatment:
@@ -1114,7 +1114,8 @@ namespace Barotrauma
MapEntityPrefab.Find(itemName, itemIdentifier, showErrorMessages: false) as ItemPrefab;
if (itemPrefab == null)
{
string errorMsg = "Failed to spawn item (name: " + (itemName ?? "null") + ", identifier: " + (itemIdentifier ?? "null");
string errorMsg = "Failed to spawn item, prefab not found (name: " + (itemName ?? "null") + ", identifier: " + (itemIdentifier ?? "null") + ")";
errorMsg += "\n" + string.Join(", ", GameMain.Config.SelectedContentPackages.Select(cp => cp.Name));
GameAnalyticsManager.AddErrorEventOnce("Item.ReadSpawnData:PrefabNotFound" + (itemName ?? "null") + (itemIdentifier ?? "null"),
GameAnalyticsSDK.Net.EGAErrorSeverity.Critical,
errorMsg);

View File

@@ -534,7 +534,7 @@ namespace Barotrauma
msg.Write(FireSources.Count > 0);
if (FireSources.Count > 0)
{
msg.WriteRangedIntegerDeprecated(0, 16, Math.Min(FireSources.Count, 16));
msg.WriteRangedInteger(Math.Min(FireSources.Count, 16), 0, 16);
for (int i = 0; i < Math.Min(FireSources.Count, 16); i++)
{
var fireSource = FireSources[i];

View File

@@ -45,7 +45,9 @@ namespace Barotrauma
if (string.IsNullOrEmpty(filename))
{
DebugConsole.ThrowError("Error when loading round sound (" + element + ") - file path not set");
string errorMsg = "Error when loading round sound (" + element + ") - file path not set";
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("Submarine.LoadRoundSound:FilePathEmpty" + element.ToString(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace);
return null;
}
@@ -69,7 +71,9 @@ namespace Barotrauma
}
catch (FileNotFoundException e)
{
DebugConsole.ThrowError("Failed to load sound file \"" + filename + "\".", e);
string errorMsg = "Failed to load sound file \"" + filename + "\".";
DebugConsole.ThrowError(errorMsg, e);
GameAnalyticsManager.AddErrorEventOnce("Submarine.LoadRoundSound:FileNotFound" + filename, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace);
return null;
}
}

View File

@@ -84,14 +84,12 @@ namespace Barotrauma.Networking
font: GUI.SmallFont);
var reasonText = new GUITextBlock(new RectTransform(new Vector2(0.6f, 0.0f), paddedPlayerFrame.RectTransform),
TextManager.Get("BanReason") +
TextManager.Get("BanReason") + " " +
(string.IsNullOrEmpty(bannedPlayer.Reason) ? TextManager.Get("None") : ToolBox.LimitString(bannedPlayer.Reason, GUI.SmallFont, 170)),
font: GUI.SmallFont, wrap: true)
{
ToolTip = bannedPlayer.Reason
};
}
return banFrame;
@@ -100,34 +98,29 @@ namespace Barotrauma.Networking
private bool RemoveBan(GUIButton button, object obj)
{
BannedPlayer banned = obj as BannedPlayer;
if (banned == null) return false;
if (banned == null) { return false; }
localRemovedBans.Add(banned.UniqueIdentifier);
RecreateBanFrame();
GameMain.Client?.ServerSettings?.ClientAdminWrite(ServerSettings.NetFlags.Properties);
return true;
}
private bool RangeBan(GUIButton button, object obj)
{
BannedPlayer banned = obj as BannedPlayer;
if (banned == null) return false;
if (banned == null) { return false; }
localRangeBans.Add(banned.UniqueIdentifier);
RecreateBanFrame();
return true;
}
private bool CloseFrame(GUIButton button, object obj)
{
banFrame = null;
GameMain.Client?.ServerSettings?.ClientAdminWrite(ServerSettings.NetFlags.Properties);
return true;
}
public void ClientAdminRead(IReadMessage incMsg)
{
bool hasPermission = incMsg.ReadBoolean();

View File

@@ -460,13 +460,13 @@ namespace Barotrauma.Networking
}
catch (Exception e)
{
ErrorMessage = "Loading received submarine ''" + fileTransfer.FileName + "'' failed! {" + e.Message + "}";
ErrorMessage = "Loading received submarine \"" + fileTransfer.FileName + "\" failed! {" + e.Message + "}";
return false;
}
if (stream == null)
{
ErrorMessage = "Decompressing received submarine file''" + fileTransfer.FilePath + "'' failed!";
ErrorMessage = "Decompressing received submarine file \"" + fileTransfer.FilePath + "\" failed!";
return false;
}
@@ -490,7 +490,7 @@ namespace Barotrauma.Networking
stream.Close();
stream.Dispose();
ErrorMessage = "Parsing file ''" + fileTransfer.FilePath + "'' failed! The file may not be a valid submarine file.";
ErrorMessage = "Parsing file \"" + fileTransfer.FilePath + "\" failed! The file may not be a valid submarine file.";
return false;
}

View File

@@ -396,15 +396,13 @@ namespace Barotrauma.Networking
private bool connectCancelled;
private void CancelConnect()
{
if (!(GameMain.ServerChildProcess?.HasExited??true))
if (!(GameMain.ServerChildProcess?.HasExited ?? true))
{
GameMain.ServerChildProcess.Kill();
GameMain.ServerChildProcess = null;
}
connectCancelled = true;
clientPeer?.Close();
clientPeer = null;
Disconnect();
}
// Before main looping starts, we loop here and wait for approval message
@@ -554,14 +552,20 @@ namespace Barotrauma.Networking
UpdateHUD(deltaTime);
base.Update(deltaTime);
try
{
clientPeer?.Update(deltaTime);
}
catch (Exception e)
{
string errorMsg = "Error while reading a message from server. {" + e + "}\n" + e.StackTrace;
string errorMsg = "Error while reading a message from server. {" + e + "}. ";
if (GameMain.Client == null) { errorMsg += "Client disposed."; }
errorMsg += "\n" + e.StackTrace;
if (e.InnerException != null)
{
errorMsg += "\nInner exception: " + e.InnerException.Message + "\n" + e.InnerException.StackTrace;
}
GameAnalyticsManager.AddErrorEventOnce("GameClient.Update:CheckServerMessagesException" + e.TargetSite.ToString(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
DebugConsole.ThrowError("Error while reading a message from server.", e);
new GUIMessageBox(TextManager.Get("Error"), TextManager.GetWithVariables("MessageReadError", new string[2] { "[message]", "[targetsite]" }, new string[2] { e.Message, e.TargetSite.ToString() }));
@@ -603,7 +607,7 @@ namespace Barotrauma.Networking
if (IsServerOwner && connected && !connectCancelled)
{
if (GameMain.ServerChildProcess?.HasExited??true)
if (GameMain.ServerChildProcess?.HasExited ?? true)
{
Disconnect();
var msgBox = new GUIMessageBox(TextManager.Get("ConnectionLost"), TextManager.Get("ServerProcessClosed"));
@@ -626,9 +630,34 @@ namespace Barotrauma.Networking
ReadLobbyUpdate(inc);
break;
case ServerPacketHeader.UPDATE_INGAME:
ReadIngameUpdate(inc);
try
{
ReadIngameUpdate(inc);
}
catch (Exception e)
{
string errorMsg = "Error while reading an ingame update message from server. {" + e + "}\n" + e.StackTrace;
if (e.InnerException != null)
{
errorMsg += "\nInner exception: " + e.InnerException.Message + "\n" + e.InnerException.StackTrace;
}
GameAnalyticsManager.AddErrorEventOnce("GameClient.ReadDataMessage:ReadIngameUpdate", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
throw;
}
break;
case ServerPacketHeader.VOICE:
if (VoipClient == null)
{
string errorMsg = "Failed to read a voice packet from the server (VoipClient == null). ";
if (GameMain.Client == null) { errorMsg += "Client disposed. "; }
errorMsg += "\n" + Environment.StackTrace;
GameAnalyticsManager.AddErrorEventOnce(
"GameClient.ReadDataMessage:VoipClientNull",
GameMain.Client == null ? GameAnalyticsSDK.Net.EGAErrorSeverity.Error : GameAnalyticsSDK.Net.EGAErrorSeverity.Warning,
errorMsg);
return;
}
VoipClient.Read(inc);
break;
case ServerPacketHeader.QUERY_STARTGAME:
@@ -728,7 +757,7 @@ namespace Barotrauma.Networking
string[] splitMsg = disconnectMsg.Split('/');
DisconnectReason disconnectReason = DisconnectReason.Unknown;
if (splitMsg.Length > 0) Enum.TryParse(splitMsg[0], out disconnectReason);
if (splitMsg.Length > 0) { Enum.TryParse(splitMsg[0], out disconnectReason); }
if (disconnectMsg == Lidgren.Network.NetConnection.NoResponseMessage)
{
@@ -737,6 +766,19 @@ namespace Barotrauma.Networking
DebugConsole.NewMessage("Received a disconnect message (" + disconnectMsg + ")");
if (disconnectReason != DisconnectReason.Banned &&
disconnectReason != DisconnectReason.ServerShutdown &&
disconnectReason != DisconnectReason.TooManyFailedLogins &&
disconnectReason != DisconnectReason.NotOnWhitelist &&
disconnectReason != DisconnectReason.MissingContentPackage &&
disconnectReason != DisconnectReason.InvalidVersion)
{
GameAnalyticsManager.AddErrorEventOnce(
"GameClient.HandleDisconnectMessage",
GameAnalyticsSDK.Net.EGAErrorSeverity.Debug,
"Client received a disconnect message. Reason: " + disconnectReason.ToString() + ", message: " + disconnectMsg);
}
if (disconnectReason == DisconnectReason.ServerFull)
{
CoroutineManager.StopCoroutines("WaitForStartingInfo");
@@ -1059,6 +1101,28 @@ namespace Barotrauma.Networking
if (campaign == null)
{
//this shouldn't happen, TrySelectSub should stop the coroutine if the correct sub/shuttle cannot be found
if (GameMain.NetLobbyScreen.SelectedSub == null ||
GameMain.NetLobbyScreen.SelectedSub.Name != subName ||
GameMain.NetLobbyScreen.SelectedSub.MD5Hash?.Hash != subHash)
{
string errorMsg = "Failed to select submarine \"" + subName + "\" (hash: " + subHash + ").";
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:FailedToSelectSub" + subName, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
CoroutineManager.StartCoroutine(EndGame(""));
yield return CoroutineStatus.Failure;
}
if (GameMain.NetLobbyScreen.SelectedShuttle == null ||
GameMain.NetLobbyScreen.SelectedShuttle.Name != shuttleName ||
GameMain.NetLobbyScreen.SelectedShuttle.MD5Hash?.Hash != shuttleHash)
{
string errorMsg = "Failed to select shuttle \"" + shuttleName + "\" (hash: " + shuttleHash + ").";
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:FailedToSelectShuttle" + shuttleName, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
CoroutineManager.StartCoroutine(EndGame(""));
yield return CoroutineStatus.Failure;
}
GameMain.GameSession = missionIndex < 0 ?
new GameSession(GameMain.NetLobbyScreen.SelectedSub, "", gameMode, MissionType.None) :
new GameSession(GameMain.NetLobbyScreen.SelectedSub, "", gameMode, MissionPrefab.List[missionIndex]);
@@ -1252,7 +1316,8 @@ namespace Barotrauma.Networking
{
existingClient.SetPermissions(permissions, permittedConsoleCommands);
name = tc.Name;
if (GameMain.NetLobbyScreen.CharacterNameBox != null)
if (GameMain.NetLobbyScreen.CharacterNameBox != null &&
!GameMain.NetLobbyScreen.CharacterNameBox.Selected)
{
GameMain.NetLobbyScreen.CharacterNameBox.Text = name;
}

View File

@@ -9,6 +9,11 @@ namespace Barotrauma
{
public void CreateSettingsFrame(GUIComponent parent)
{
if (TextManager.ContainsTag("Karma.ResetKarmaBetweenRounds"))
{
CreateLabeledTickBox(parent, "ResetKarmaBetweenRounds");
}
CreateLabeledSlider(parent, 0.0f, 40.0f, 1.0f, "KickBanThreshold");
if (TextManager.ContainsTag("Karma.KicksBeforeBan"))
{
@@ -102,5 +107,14 @@ namespace Barotrauma
};
GameMain.NetworkMember.ServerSettings.AssignGUIComponent(propertyName, numInput);
}
private void CreateLabeledTickBox(GUIComponent parent, string propertyName)
{
var tickBox = new GUITickBox(new RectTransform(new Vector2(0.3f, 0.1f), parent.RectTransform), TextManager.Get("Karma." + propertyName))
{
ToolTip = TextManager.Get("Karma." + propertyName + "ToolTip", returnNull: true) ?? ""
};
GameMain.NetworkMember.ServerSettings.AssignGUIComponent(propertyName, tickBox);
}
}
}

View File

@@ -96,7 +96,7 @@ namespace Barotrauma.Networking
//find the first event that hasn't been sent in roundtriptime or at all
eventLastSent.TryGetValue(events[i].ID, out float lastSent);
if (lastSent > Lidgren.Network.NetTime.Now - 50) //TODO: reimplement serverConnection.AverageRoundtripTime
if (lastSent > Lidgren.Network.NetTime.Now - 0.2) //TODO: reimplement serverConnection.AverageRoundtripTime
{
continue;
}

View File

@@ -176,7 +176,11 @@ namespace Barotrauma.Networking
outMsg.Write(contentPackage.MD5hash.Hash);
}
netClient.SendMessage(outMsg, NetDeliveryMethod.ReliableUnordered);
NetSendResult result = netClient.SendMessage(outMsg, NetDeliveryMethod.ReliableUnordered);
if (result != NetSendResult.Queued && result != NetSendResult.Sent)
{
DebugConsole.NewMessage("Failed to send "+initializationStep.ToString()+" message to host: " + result);
}
break;
case ConnectionInitialization.Password:
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion) { initializationStep = ConnectionInitialization.Password; }
@@ -207,7 +211,11 @@ namespace Barotrauma.Networking
byte[] saltedPw = ServerSettings.SaltPassword(NetUtility.ComputeSHAHash(Encoding.UTF8.GetBytes(password)), passwordSalt);
outMsg.Write((byte)saltedPw.Length);
outMsg.Write(saltedPw, 0, saltedPw.Length);
netClient.SendMessage(outMsg, NetDeliveryMethod.ReliableUnordered);
NetSendResult result = netClient.SendMessage(outMsg, NetDeliveryMethod.ReliableUnordered);
if (result != NetSendResult.Queued && result != NetSendResult.Sent)
{
DebugConsole.NewMessage("Failed to send " + initializationStep.ToString() + " message to host: " + result);
}
}
public override void Close(string msg = null)
@@ -247,7 +255,11 @@ namespace Barotrauma.Networking
lidgrenMsg.Write((UInt16)length);
lidgrenMsg.Write(msgData, 0, length);
netClient.SendMessage(lidgrenMsg, lidgrenDeliveryMethod);
NetSendResult result = netClient.SendMessage(lidgrenMsg, lidgrenDeliveryMethod);
if (result != NetSendResult.Queued && result != NetSendResult.Sent)
{
DebugConsole.NewMessage("Failed to send message to host: " + result);
}
}
}
}

View File

@@ -66,7 +66,7 @@ namespace Barotrauma.Networking
initializationStep = ConnectionInitialization.SteamTicketAndVersion;
timeout = 20.0;
timeout = NetworkConnection.TimeoutThreshold;
heartbeatTimer = 1.0;
isActive = true;
@@ -83,7 +83,7 @@ namespace Barotrauma.Networking
if (!isActive) { return; }
if (steamId != hostSteamId) { return; }
timeout = 20.0;
timeout = NetworkConnection.TimeoutThreshold;
byte incByte = data[0];
bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;

View File

@@ -87,7 +87,7 @@ namespace Barotrauma.Networking
private void OnAuthChange(ulong steamID, ulong ownerID, ClientAuthStatus status)
{
RemotePeer remotePeer = remotePeers.Find(p => p.SteamID == steamID);
DebugConsole.NewMessage(steamID + " validation: " + status + ", " + (remotePeer != null));
DebugConsole.Log(steamID + " validation: " + status + ", " + (remotePeer != null));
if (remotePeer == null) { return; }
@@ -106,7 +106,11 @@ namespace Barotrauma.Networking
remotePeer.Authenticating = false;
foreach (var msg in remotePeer.UnauthedMessages)
{
netClient.SendMessage(msg.Second, msg.First);
NetSendResult result = netClient.SendMessage(msg.Second, msg.First);
if (result != NetSendResult.Queued && result != NetSendResult.Sent)
{
DebugConsole.NewMessage("Failed to send unauthed message to host: " + result);
}
}
remotePeer.UnauthedMessages.Clear();
}
@@ -200,7 +204,11 @@ namespace Barotrauma.Networking
}
else
{
netClient.SendMessage(outMsg, lidgrenDeliveryMethod);
NetSendResult result = netClient.SendMessage(outMsg, lidgrenDeliveryMethod);
if (result != NetSendResult.Queued && result != NetSendResult.Sent)
{
DebugConsole.NewMessage("Failed to send message from "+SteamManager.SteamIDUInt64ToString(remotePeer.SteamID)+" to host: " + result);
}
}
}
@@ -344,7 +352,11 @@ namespace Barotrauma.Networking
outMsg.Write(selfSteamID);
outMsg.Write((byte)(PacketHeader.IsConnectionInitializationStep));
outMsg.Write(Name);
netClient.SendMessage(outMsg, NetDeliveryMethod.ReliableUnordered);
NetSendResult result = netClient.SendMessage(outMsg, NetDeliveryMethod.ReliableUnordered);
if (result != NetSendResult.Queued && result != NetSendResult.Sent)
{
DebugConsole.NewMessage("Failed to send initialization message to host: " + result);
}
return;
}
@@ -466,7 +478,11 @@ namespace Barotrauma.Networking
lidgrenMsg.Write((UInt16)length);
lidgrenMsg.Write(msgData, 0, length);
netClient.SendMessage(lidgrenMsg, lidgrenDeliveryMethod);
NetSendResult result = netClient.SendMessage(lidgrenMsg, lidgrenDeliveryMethod);
if (result != NetSendResult.Queued && result != NetSendResult.Sent)
{
DebugConsole.NewMessage("Failed to send own message to host: " + result);
}
}
}
}

View File

@@ -218,9 +218,9 @@ namespace Barotrauma.Steam
instance.client.Lobby.CurrentLobbyData.SetData("allowrespawn", serverSettings.AllowRespawn.ToString());
instance.client.Lobby.CurrentLobbyData.SetData("traitors", serverSettings.TraitorsEnabled.ToString());
instance.client.Lobby.CurrentLobbyData.SetData("gamestarted", GameMain.Client.GameStarted.ToString());
instance.client.Lobby.CurrentLobbyData.SetData("gamemode", serverSettings.GameModeIdentifier);
instance.client.Lobby.CurrentLobbyData.SetData("gamemode", GameMain.NetLobbyScreen?.SelectedMode?.Identifier??"");
DebugConsole.NewMessage("Lobby updated!", Microsoft.Xna.Framework.Color.Lime);
DebugConsole.Log("Lobby updated!");
}
public static void LeaveLobby()
@@ -770,6 +770,14 @@ namespace Barotrauma.Steam
ContentPackage tempContentPackage = new ContentPackage(Path.Combine(existingItem.Directory.FullName, MetadataFileName));
string installedContentPackagePath = Path.GetFullPath(GetWorkshopItemContentPackagePath(tempContentPackage));
contentPackage = ContentPackage.List.Find(cp => Path.GetFullPath(cp.Path) == installedContentPackagePath);
if (contentPackage == null && tempContentPackage.GameVersion <= new Version(0, 9, 1, 0))
{
//try finding the content package in the lega
installedContentPackagePath = Path.GetFullPath(GetWorkshopItemContentPackagePath(tempContentPackage, legacy: false));
contentPackage = ContentPackage.List.Find(cp => Path.GetFullPath(cp.Path) == installedContentPackagePath);
}
if (tempContentPackage.GameVersion > new Version(0, 9, 1, 0))
{
itemEditor.Folder = Path.GetDirectoryName(installedContentPackagePath);
@@ -784,6 +792,7 @@ namespace Barotrauma.Steam
contentPackage.Path = newPath;
itemEditor.Folder = newDir;
if (!Directory.Exists(newDir)) { Directory.CreateDirectory(newDir); }
if (File.Exists(newPath)) { File.Delete(newPath); }
File.Move(installedContentPackagePath, newPath);
//move all files inside the Mods folder
foreach (ContentFile cf in contentPackage.Files)
@@ -793,10 +802,12 @@ namespace Barotrauma.Steam
{
string destinationPath = Path.Combine(newDir, cf.Path);
if (!Directory.Exists(Path.GetDirectoryName(destinationPath))) { Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)); }
if (File.Exists(destinationPath)) { File.Delete(destinationPath); }
File.Move(cf.Path, destinationPath);
cf.Path = destinationPath;
}
}
contentPackage.GameVersion = GameMain.Version;
contentPackage.Save(contentPackage.Path);
}
catch (Exception e)
@@ -1202,7 +1213,22 @@ namespace Barotrauma.Steam
return false;
}
string metaDataPath = Path.Combine(item.Directory.FullName, MetadataFileName);
string metaDataPath = "";
try
{
metaDataPath = Path.Combine(item.Directory.FullName, MetadataFileName);
}
catch (ArgumentException e)
{
string errorMessage = "Metadata file for the Workshop item \"" + item.Title +
"\" not found. Could not combine path (" + (item.Directory.FullName ?? "directory name empty") + ").";
DebugConsole.ThrowError(errorMessage);
GameAnalyticsManager.AddErrorEventOnce("SteamManager.CheckWorkshopItemEnabled:PathCombineException" + item.Title,
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
errorMessage);
return false;
}
if (!File.Exists(metaDataPath))
{
DebugConsole.ThrowError("Metadata file for the Workshop item \"" + item.Title + "\" not found. The file may be corrupted.");
@@ -1309,12 +1335,18 @@ namespace Barotrauma.Steam
}
public static string GetWorkshopItemContentPackagePath(ContentPackage contentPackage)
{
return GetWorkshopItemContentPackagePath(contentPackage, legacy: contentPackage.GameVersion <= new Version(0, 9, 1, 0));
}
private static string GetWorkshopItemContentPackagePath(ContentPackage contentPackage, bool legacy)
{
string fileName = contentPackage.Name;
string invalidChars = ToolBox.RemoveInvalidFileNameChars(fileName);
return contentPackage.GameVersion > new Version(0, 9, 1, 0) ?
Path.Combine("Mods", fileName, MetadataFileName) :
Path.Combine("Data", "ContentPackages", fileName + ".xml"); //legacy support
fileName = ToolBox.RemoveInvalidFileNameChars(fileName);
return legacy ?
Path.Combine("Data", "ContentPackages", fileName + ".xml") :
Path.Combine("Mods", fileName, MetadataFileName);
}
#endregion

View File

@@ -94,7 +94,7 @@ namespace Barotrauma.Networking
client.VoipSound = new VoipSound(GameMain.SoundManager, client.VoipQueue);
}
if (client.Character != null && !client.Character.IsDead && client.Character.SpeechImpediment <= 100.0f)
if (client.Character != null && !client.Character.IsDead && !client.Character.Removed && client.Character.SpeechImpediment <= 100.0f)
{
var messageType = ChatMessage.CanUseRadio(client.Character, out WifiComponent radio) ? ChatMessageType.Radio : ChatMessageType.Default;
client.Character.ShowSpeechBubble(1.25f, ChatMessage.MessageColor[(int)messageType]);
@@ -119,7 +119,7 @@ namespace Barotrauma.Networking
if (client.VoipSound.CurrentAmplitude > 0.1f) //TODO: might need to tweak
{
if (client.Character != null)
if (client.Character != null && !client.Character.Removed)
{
Vector3 clientPos = new Vector3(client.Character.WorldPosition.X, client.Character.WorldPosition.Y, 0.0f);
Vector3 listenerPos = GameMain.SoundManager.ListenerPosition;

View File

@@ -859,6 +859,9 @@ namespace Barotrauma
private void FillStoreItemList()
{
float prevStoreItemScroll = storeItemList.BarScroll;
float prevMyItemScroll = myItemList.BarScroll;
int width = storeItemList.Rect.Width;
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
foreach (MapEntityPrefab mapEntityPrefab in MapEntityPrefab.List)
@@ -883,6 +886,9 @@ namespace Barotrauma
storeItemList.Content.RectTransform.SortChildren(
(x, y) => (x.GUIComponent.UserData as PurchasedItem).ItemPrefab.Name.CompareTo((y.GUIComponent.UserData as PurchasedItem).ItemPrefab.Name));
storeItemList.BarScroll = prevStoreItemScroll;
myItemList.BarScroll = prevMyItemScroll;
}
private void FilterStoreItems(MapEntityCategory? category, string filter)
@@ -904,7 +910,7 @@ namespace Barotrauma
btn.Selected = (MapEntityCategory)btn.UserData == selectedItemCategory;
}
storeItemList.UpdateScrollBarSize();
storeItemList.BarScroll = 0.0f;
//storeItemList.BarScroll = 0.0f;
}
public string GetMoney()

View File

@@ -1216,7 +1216,7 @@ namespace Barotrauma
CanBeFocused = false
};
var matchingSub = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == sub.Name && s.MD5Hash.Hash == sub.MD5Hash.Hash);
var matchingSub = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == sub.Name && s.MD5Hash?.Hash == sub.MD5Hash?.Hash);
if (matchingSub == null) matchingSub = Submarine.SavedSubmarines.FirstOrDefault(s => s.Name == sub.Name);
if (matchingSub == null)
@@ -1224,7 +1224,7 @@ namespace Barotrauma
subTextBlock.TextColor = new Color(subTextBlock.TextColor, 0.5f);
frame.ToolTip = TextManager.Get("SubNotFound");
}
else if (matchingSub.MD5Hash.Hash != sub.MD5Hash.Hash)
else if (matchingSub?.MD5Hash == null || matchingSub.MD5Hash?.Hash != sub.MD5Hash?.Hash)
{
subTextBlock.TextColor = new Color(subTextBlock.TextColor, 0.5f);
frame.ToolTip = TextManager.Get("SubDoesntMatch");
@@ -1383,25 +1383,44 @@ namespace Barotrauma
OnClicked = (btn, userdata) => { if (GUI.MouseOn == btn || GUI.MouseOn == btn.TextBlock) ClosePlayerFrame(btn, userdata); return true; }
};
Vector2 frameSize = GameMain.Client.HasPermission(ClientPermissions.ManagePermissions) ? new Vector2(.24f, .44f) : new Vector2(.24f, .24f);
Vector2 frameSize = GameMain.Client.HasPermission(ClientPermissions.ManagePermissions) ? new Vector2(.24f, .5f) : new Vector2(.24f, .24f);
var playerFrameInner = new GUIFrame(new RectTransform(frameSize, playerFrame.RectTransform, Anchor.Center));
var paddedPlayerFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.85f), playerFrameInner.RectTransform, Anchor.Center))
var playerFrameInner = new GUIFrame(new RectTransform(frameSize, playerFrame.RectTransform, Anchor.Center) { MinSize = new Point(550, 0) });
var paddedPlayerFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.88f), playerFrameInner.RectTransform, Anchor.Center))
{
Stretch = true,
RelativeSpacing = 0.05f
RelativeSpacing = 0.03f
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), paddedPlayerFrame.RectTransform),
var headerContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), paddedPlayerFrame.RectTransform), isHorizontal: true)
{
Stretch = true
};
var nameText = new GUITextBlock(new RectTransform(new Vector2(0.75f, 1.0f), headerContainer.RectTransform),
text: selectedClient.Name, font: GUI.LargeFont);
//TODO: UI for client permission management
if (selectedClient.SteamID != 0 && Steam.SteamManager.IsInitialized)
{
var viewSteamProfileButton = new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), headerContainer.RectTransform, Anchor.TopCenter),
TextManager.Get("ViewSteamProfile"))
{
UserData = selectedClient
};
GUITextBlock.AutoScaleAndNormalize(nameText, viewSteamProfileButton.TextBlock);
viewSteamProfileButton.OnClicked = (bt, userdata) =>
{
Steam.SteamManager.Instance.Overlay.OpenUrl("https://steamcommunity.com/profiles/" + selectedClient.SteamID.ToString());
return true;
};
}
if (GameMain.Client.HasPermission(ClientPermissions.ManagePermissions))
{
playerFrame.UserData = selectedClient;
//new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), paddedPlayerFrame.RectTransform), selectedClient.Connection.RemoteEndPoint.Address.ToString());
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), paddedPlayerFrame.RectTransform),
TextManager.Get("Rank"));
var rankDropDown = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.1f), paddedPlayerFrame.RectTransform),
@@ -1441,16 +1460,45 @@ namespace Barotrauma
Stretch = true,
RelativeSpacing = 0.05f
};
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), permissionLabels.RectTransform), TextManager.Get("Permissions"));
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), permissionLabels.RectTransform), TextManager.Get("PermittedConsoleCommands"));
var permissionLabel = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), permissionLabels.RectTransform), TextManager.Get("Permissions"));
var consoleCommandLabel = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), permissionLabels.RectTransform), TextManager.Get("PermittedConsoleCommands"));
GUITextBlock.AutoScaleAndNormalize(permissionLabel, consoleCommandLabel);
var permissionContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.4f), paddedPlayerFrame.RectTransform), isHorizontal: true)
{
Stretch = true,
RelativeSpacing = 0.05f
};
var permissionsBox = new GUIListBox(new RectTransform(new Vector2(0.5f, 1.0f), permissionContainer.RectTransform))
var listBoxContainerLeft = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), permissionContainer.RectTransform))
{
Stretch = true,
RelativeSpacing = 0.05f
};
new GUITickBox(new RectTransform(new Vector2(0.15f, 0.15f), listBoxContainerLeft.RectTransform), TextManager.Get("all", fallBackTag: "clientpermission.all"))
{
Enabled = !myClient,
OnSelected = (tickbox) =>
{
//reset rank to custom
rankDropDown.SelectItem(null);
var client = playerFrame.UserData as Client;
if (client == null) { return false; }
foreach (GUIComponent child in tickbox.Parent.GetChild<GUIListBox>().Content.Children)
{
var permissionTickBox = child as GUITickBox;
permissionTickBox.Enabled = false;
permissionTickBox.Selected = tickbox.Selected;
permissionTickBox.Enabled = true;
}
GameMain.Client.UpdateClientPermissions(client);
return true;
}
};
var permissionsBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 1.0f), listBoxContainerLeft.RectTransform))
{
UserData = selectedClient
};
@@ -1471,10 +1519,9 @@ namespace Barotrauma
rankDropDown.SelectItem(null);
var client = playerFrame.UserData as Client;
if (client == null) return false;
if (client == null) { return false; }
var thisPermission = (ClientPermissions)tickBox.UserData;
if (tickBox.Selected)
{
client.GivePermission(thisPermission);
@@ -1483,15 +1530,44 @@ namespace Barotrauma
{
client.RemovePermission(thisPermission);
}
GameMain.Client.UpdateClientPermissions(client);
if (tickBox.Enabled)
{
GameMain.Client.UpdateClientPermissions(client);
}
return true;
}
};
}
var commandList = new GUIListBox(new RectTransform(new Vector2(0.5f, 1.0f), permissionContainer.RectTransform))
var listBoxContainerRight = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), permissionContainer.RectTransform))
{
Stretch = true,
RelativeSpacing = 0.05f
};
new GUITickBox(new RectTransform(new Vector2(0.15f, 0.15f), listBoxContainerRight.RectTransform), TextManager.Get("all", fallBackTag: "clientpermission.all"))
{
Enabled = !myClient,
OnSelected = (tickbox) =>
{
//reset rank to custom
rankDropDown.SelectItem(null);
var client = playerFrame.UserData as Client;
if (client == null) { return false; }
foreach (GUIComponent child in tickbox.Parent.GetChild<GUIListBox>().Content.Children)
{
var commandTickBox = child as GUITickBox;
commandTickBox.Enabled = false;
commandTickBox.Selected = tickbox.Selected;
commandTickBox.Enabled = true;
}
GameMain.Client.UpdateClientPermissions(client);
return true;
}
};
var commandList = new GUIListBox(new RectTransform(new Vector2(1.0f, 1.0f), listBoxContainerRight.RectTransform))
{
UserData = selectedClient
};
@@ -1522,37 +1598,23 @@ namespace Barotrauma
{
client.PermittedConsoleCommands.Add(selectedCommand);
}
GameMain.Client.UpdateClientPermissions(client);
if (tickBox.Enabled)
{
GameMain.Client.UpdateClientPermissions(client);
}
return true;
};
}
}
var buttonAreaUpper = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), paddedPlayerFrame.RectTransform), isHorizontal: true);
var buttonAreaMiddle = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), paddedPlayerFrame.RectTransform), isHorizontal: true);
var buttonAreaLower = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), paddedPlayerFrame.RectTransform), isHorizontal: true);
if (selectedClient.SteamID != 0 && Steam.SteamManager.IsInitialized)
{
var viewSteamProfileButton = new GUIButton(new RectTransform(new Vector2(0.8f, 1.0f), buttonAreaUpper.RectTransform, Anchor.TopCenter),
TextManager.Get("ViewSteamProfile"))
{
UserData = selectedClient
};
viewSteamProfileButton.OnClicked = (bt, userdata) =>
{
Steam.SteamManager.Instance.Overlay.OpenUrl("https://steamcommunity.com/profiles/" + selectedClient.SteamID.ToString());
return true;
};
}
var buttonAreaTop = myClient ? null : new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.08f), paddedPlayerFrame.RectTransform), isHorizontal: true);
var buttonAreaLower = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.08f), paddedPlayerFrame.RectTransform), isHorizontal: true);
if (!myClient)
{
if (GameMain.Client.HasPermission(ClientPermissions.Ban))
{
var banButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonAreaMiddle.RectTransform),
var banButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonAreaTop.RectTransform),
TextManager.Get("Ban"))
{
UserData = selectedClient
@@ -1560,7 +1622,7 @@ namespace Barotrauma
banButton.OnClicked = (bt, userdata) => { BanPlayer(selectedClient); return true; };
banButton.OnClicked += ClosePlayerFrame;
var rangebanButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonAreaMiddle.RectTransform),
var rangebanButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonAreaTop.RectTransform),
TextManager.Get("BanRange"))
{
UserData = selectedClient
@@ -1594,7 +1656,7 @@ namespace Barotrauma
kickButton.OnClicked += ClosePlayerFrame;
}
new GUITickBox(new RectTransform(new Vector2(0.25f, 1.0f), buttonAreaMiddle.RectTransform, Anchor.TopRight),
new GUITickBox(new RectTransform(new Vector2(0.25f, 1.0f), buttonAreaTop.RectTransform, Anchor.TopRight),
TextManager.Get("Mute"))
{
IgnoreLayoutGroups = true,
@@ -1982,24 +2044,34 @@ namespace Barotrauma
public bool TrySelectSub(string subName, string md5Hash, GUIListBox subList)
{
if (GameMain.Client == null) return false;
if (GameMain.Client == null) { return false; }
//already downloading the selected sub file
if (GameMain.Client.FileReceiver.ActiveTransfers.Any(t => t.FileName == subName + ".sub"))
{
return false;
}
Submarine sub = subList.Content.Children
.FirstOrDefault(c => c.UserData is Submarine s && s.Name == subName && s.MD5Hash?.Hash == md5Hash)?
.UserData as Submarine;
Submarine sub = Submarine.SavedSubmarines.FirstOrDefault(m => m.Name == subName && m.MD5Hash.Hash == md5Hash);
if (sub == null) sub = Submarine.SavedSubmarines.FirstOrDefault(m => m.Name == subName);
var matchingListSub = subList.Content.GetChildByUserData(sub);
if (sub != null && subList.SelectedData as Submarine == sub)
//matching sub found and already selected, all good
if (sub != null && subList.SelectedData is Submarine selectedSub && selectedSub.MD5Hash?.Hash == md5Hash)
{
return true;
}
if (matchingListSub != null)
//sub not found, see if we have a sub with the same name
if (sub == null)
{
sub = subList.Content.Children
.FirstOrDefault(c => c.UserData is Submarine s && s.Name == subName)?
.UserData as Submarine;
}
//found a sub that at least has the same name, select it
if (sub != null)
{
if (subList.Parent is GUIDropDown subDropDown)
{
@@ -2008,7 +2080,7 @@ namespace Barotrauma
else
{
subList.OnSelected -= VotableClicked;
subList.Select(subList.Content.GetChildIndex(matchingListSub), true);
subList.Select(sub, force: true);
subList.OnSelected += VotableClicked;
}
@@ -2016,58 +2088,62 @@ namespace Barotrauma
FailedSelectedSub = null;
else
FailedSelectedShuttle = null;
//hashes match, all good
if (sub.MD5Hash?.Hash == md5Hash)
{
return true;
}
}
//-------------------------------------------------------------------------------------
//if we get to this point, a matching sub was not found or it has an incorrect MD5 hash
if (subList == SubList)
FailedSelectedSub = new Pair<string, string>(subName, md5Hash);
else
FailedSelectedShuttle = new Pair<string, string>(subName, md5Hash);
string errorMsg = "";
if (sub == null)
{
errorMsg = TextManager.GetWithVariable("SubNotFoundError", "[subname]", subName) + " ";
}
else if (sub.MD5Hash?.Hash == null)
{
errorMsg = TextManager.GetWithVariable("SubLoadError", "[subname]", subName) + " ";
subList.Content.GetChildByUserData(sub).GetChild<GUITextBox>().TextColor = Color.Red;
}
else
{
errorMsg = TextManager.GetWithVariables("SubDoesntMatchError", new string[3] { "[subname]" , "[myhash]", "[serverhash]" },
new string[3] { sub.Name, sub.MD5Hash.ShortHash, Md5Hash.GetShortHash(md5Hash) }) + " ";
}
if (sub == null || sub.MD5Hash.Hash != md5Hash)
errorMsg += TextManager.Get("DownloadSubQuestion");
//already showing a message about the same sub
if (GUIMessageBox.MessageBoxes.Any(mb => mb.UserData as string == "request" + subName))
{
if (subList == SubList)
FailedSelectedSub = new Pair<string, string>(subName, md5Hash);
else
FailedSelectedShuttle = new Pair<string, string>(subName, md5Hash);
string errorMsg = "";
if (sub == null)
{
errorMsg = TextManager.GetWithVariable("SubNotFoundError", "[subname]", subName) + " ";
}
else if (sub.MD5Hash.Hash == null)
{
errorMsg = TextManager.GetWithVariable("SubLoadError", "[subname]", subName) + " ";
if (matchingListSub != null) matchingListSub.GetChild<GUITextBox>().TextColor = Color.Red;
}
else
{
errorMsg = TextManager.GetWithVariables("SubDoesntMatchError", new string[3] { "[subname]" , "[myhash]", "[serverhash]" },
new string[3] { sub.Name, sub.MD5Hash.ShortHash, Md5Hash.GetShortHash(md5Hash) }) + " ";
}
errorMsg += TextManager.Get("DownloadSubQuestion");
//already showing a message about the same sub
if (GUIMessageBox.MessageBoxes.Any(mb => mb.UserData as string == "request" + subName))
{
return false;
}
var requestFileBox = new GUIMessageBox(TextManager.Get("DownloadSubLabel"), errorMsg,
new string[] { TextManager.Get("Yes"), TextManager.Get("No") })
{
UserData = "request" + subName
};
requestFileBox.Buttons[0].UserData = new string[] { subName, md5Hash };
requestFileBox.Buttons[0].OnClicked += requestFileBox.Close;
requestFileBox.Buttons[0].OnClicked += (GUIButton button, object userdata) =>
{
string[] fileInfo = (string[])userdata;
GameMain.Client?.RequestFile(FileTransferType.Submarine, fileInfo[0], fileInfo[1]);
return true;
};
requestFileBox.Buttons[1].OnClicked += requestFileBox.Close;
return false;
}
return true;
var requestFileBox = new GUIMessageBox(TextManager.Get("DownloadSubLabel"), errorMsg,
new string[] { TextManager.Get("Yes"), TextManager.Get("No") })
{
UserData = "request" + subName
};
requestFileBox.Buttons[0].UserData = new string[] { subName, md5Hash };
requestFileBox.Buttons[0].OnClicked += requestFileBox.Close;
requestFileBox.Buttons[0].OnClicked += (GUIButton button, object userdata) =>
{
string[] fileInfo = (string[])userdata;
GameMain.Client?.RequestFile(FileTransferType.Submarine, fileInfo[0], fileInfo[1]);
return true;
};
requestFileBox.Buttons[1].OnClicked += requestFileBox.Close;
return false;
}
}

View File

@@ -1297,13 +1297,13 @@ namespace Barotrauma
string modFolder = Path.GetDirectoryName(itemContentPackage.Path);
string filePathRelativeToModFolder = UpdaterUtil.GetRelativePath(file, Path.Combine(Environment.CurrentDirectory, modFolder));
string destinationPath = Path.Combine(modFolder, Path.GetFileName(file));
string destinationPath;
//file is not inside the mod folder, we need to move it
if (filePathRelativeToModFolder.StartsWith("..") ||
Path.GetPathRoot(Environment.CurrentDirectory) != Path.GetPathRoot(file))
{
string tryPath = destinationPath;
destinationPath = Path.Combine(modFolder, Path.GetFileName(file));
//add a number to the filename if a file with the same name already exists
i = 2;
while (File.Exists(destinationPath))
@@ -1317,10 +1317,14 @@ namespace Barotrauma
}
catch (Exception e)
{
DebugConsole.ThrowError("Copying the file \""+file+"\" to the mod folder failed.", e);
DebugConsole.ThrowError("Copying the file \"" + file + "\" to the mod folder failed.", e);
return;
}
}
else
{
destinationPath = Path.Combine(modFolder, filePathRelativeToModFolder);
}
itemContentPackage.AddFile(destinationPath, ContentType.None);
}
itemContentPackage.Save(itemContentPackage.Path);

View File

@@ -23,7 +23,7 @@ namespace Barotrauma
"CrewExperienceHigh"
};
private readonly Point defaultPreviewImageSize = new Point(512, 368);
private readonly Point defaultPreviewImageSize = new Point(640, 368);
private Camera cam;
@@ -158,7 +158,26 @@ namespace Barotrauma
var button = new GUIButton(new RectTransform(new Vector2(0.07f, 0.9f), paddedTopPanel.RectTransform, Anchor.CenterLeft), TextManager.Get("Back"))
{
OnClicked = GameMain.MainMenuScreen.ReturnToMainMenu
OnClicked = (b, d) =>
{
var msgBox = new GUIMessageBox("", TextManager.Get("PauseMenuQuitVerificationEditor"), new string[] { TextManager.Get("Yes"), TextManager.Get("Cancel") })
{
UserData = "verificationprompt"
};
msgBox.Buttons[0].OnClicked = (yesBtn, userdata) =>
{
GUIMessageBox.CloseAll();
GameMain.MainMenuScreen.Select();
return true;
};
msgBox.Buttons[0].OnClicked += msgBox.Close;
msgBox.Buttons[1].OnClicked = (_, userdata) =>
{
msgBox.Close();
return true;
};
return true;
}
};
button = new GUIButton(new RectTransform(new Vector2(0.07f, 0.9f), paddedTopPanel.RectTransform, Anchor.CenterLeft) { RelativeOffset = new Vector2(0.07f, 0.0f) }, TextManager.Get("OpenSubButton"))
@@ -497,9 +516,8 @@ namespace Barotrauma
foreach (MapEntityPrefab ep in MapEntityPrefab.List)
{
var itemAssemblyPrefab = ep as ItemAssemblyPrefab;
#if !DEBUG
if (itemAssemblyPrefab != null && itemAssemblyPrefab.HideInMenus) { continue; }
if (ep.HideInMenus) { continue; }
#endif
bool legacy = ep.Category == MapEntityCategory.Legacy;
@@ -548,7 +566,7 @@ namespace Barotrauma
};
}
if (ep.Category == MapEntityCategory.ItemAssembly)
if (ep is ItemAssemblyPrefab itemAssemblyPrefab)
{
new GUICustomComponent(new RectTransform(new Vector2(1.0f, 0.75f),
paddedFrame.RectTransform, Anchor.TopCenter), onDraw: itemAssemblyPrefab.DrawIcon, onUpdate: null)
@@ -2448,7 +2466,7 @@ namespace Barotrauma
Matrix.CreateScale(new Vector3(scale, scale, 1)) *
viewMatrix;
Sprite backgroundSprite = LevelGenerationParams.LevelParams.Find(l => l.BackgroundTopSprite != null).BackgroundTopSprite;
/*Sprite backgroundSprite = LevelGenerationParams.LevelParams.Find(l => l.BackgroundTopSprite != null).BackgroundTopSprite;*/
using (RenderTarget2D rt = new RenderTarget2D(
GameMain.Instance.GraphicsDevice,
@@ -2457,14 +2475,14 @@ namespace Barotrauma
{
GameMain.Instance.GraphicsDevice.SetRenderTarget(rt);
GameMain.Instance.GraphicsDevice.Clear(Color.Black);
GameMain.Instance.GraphicsDevice.Clear(new Color(8, 13, 19));
if (backgroundSprite != null)
/*if (backgroundSprite != null)
{
spriteBatch.Begin();
backgroundSprite.DrawTiled(spriteBatch, Vector2.Zero, new Vector2(width, height), color: new Color(0.025f, 0.075f, 0.131f, 1.0f));
spriteBatch.End();
}
}*/
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, null, null, null, null, transform);
Submarine.Draw(spriteBatch, false);

View File

@@ -484,12 +484,19 @@ namespace Barotrauma
public static SoundChannel PlaySound(string soundTag, Vector2 position, float? volume = null, float? range = null, Hull hullGuess = null)
{
var sound = GetSound(soundTag);
if (sound == null) return null;
if (sound == null) { return null; }
return PlaySound(sound, position, volume ?? sound.BaseGain, range ?? sound.BaseFar, hullGuess);
}
public static SoundChannel PlaySound(Sound sound, Vector2 position, float? volume = null, float? range = null, Hull hullGuess = null)
{
if (sound == null)
{
string errorMsg = "Error in SoundPlayer.PlaySound (sound was null)\n" + Environment.StackTrace;
GameAnalyticsManager.AddErrorEventOnce("SoundPlayer.PlaySound:SoundNull" + Environment.StackTrace, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
return null;
}
float far = range ?? sound.BaseFar;
if (Vector2.DistanceSquared(new Vector2(GameMain.SoundManager.ListenerPosition.X, GameMain.SoundManager.ListenerPosition.Y), position) > far * far) return null;

View File

@@ -35,7 +35,7 @@ namespace Barotrauma
break;
case "sound":
var sound = Submarine.LoadRoundSound(subElement);
if (sound != null)
if (sound?.Sound != null)
{
loopSound = subElement.GetAttributeBool("loop", false);
if (subElement.Attribute("selectionmode") != null)

View File

@@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.9.2.1")]
[assembly: AssemblyFileVersion("0.9.2.1")]
[assembly: AssemblyVersion("0.9.3.2")]
[assembly: AssemblyFileVersion("0.9.3.2")]

View File

@@ -191,6 +191,7 @@
<Compile Include="Source\Items\Components\Door.cs" />
<Compile Include="Source\Items\Components\ItemComponent.cs" />
<Compile Include="Source\Items\Components\ItemLabel.cs" />
<Compile Include="Source\Items\Components\Machines\Controller.cs" />
<Compile Include="Source\Items\Components\Machines\Deconstructor.cs" />
<Compile Include="Source\Items\Components\Machines\Engine.cs" />
<Compile Include="Source\Items\Components\Machines\Fabricator.cs" />

View File

@@ -263,20 +263,20 @@ namespace Barotrauma
switch ((NetEntityEvent.Type)extraData[0])
{
case NetEntityEvent.Type.InventoryState:
msg.WriteRangedIntegerDeprecated(0, 3, 0);
msg.WriteRangedInteger(0, 0, 3);
Inventory.SharedWrite(msg, extraData);
break;
case NetEntityEvent.Type.Control:
msg.WriteRangedIntegerDeprecated(0, 3, 1);
msg.WriteRangedInteger(1, 0, 3);
Client owner = ((Client)extraData[1]);
msg.Write(owner == null ? (byte)0 : owner.ID);
break;
case NetEntityEvent.Type.Status:
msg.WriteRangedIntegerDeprecated(0, 3, 2);
msg.WriteRangedInteger(2, 0, 3);
WriteStatus(msg);
break;
case NetEntityEvent.Type.UpdateSkills:
msg.WriteRangedIntegerDeprecated(0, 3, 3);
msg.WriteRangedInteger(3, 0, 3);
if (Info?.Job == null)
{
msg.Write((byte)0);
@@ -411,10 +411,10 @@ namespace Barotrauma
msg.Write(IsDead);
if (IsDead)
{
msg.WriteRangedIntegerDeprecated(0, Enum.GetValues(typeof(CauseOfDeathType)).Length - 1, (int)CauseOfDeath.Type);
msg.WriteRangedInteger((int)CauseOfDeath.Type, 0, Enum.GetValues(typeof(CauseOfDeathType)).Length - 1);
if (CauseOfDeath.Type == CauseOfDeathType.Affliction)
{
msg.WriteRangedIntegerDeprecated(0, AfflictionPrefab.List.Count - 1, AfflictionPrefab.List.IndexOf(CauseOfDeath.Affliction));
msg.WriteRangedInteger(AfflictionPrefab.List.IndexOf(CauseOfDeath.Affliction), 0, AfflictionPrefab.List.Count - 1);
}
if (AnimController?.LimbJoints == null)

View File

@@ -1,177 +0,0 @@
using Barotrauma.Networking;
using System.Collections.Generic;
using System.IO;
namespace Barotrauma
{
partial class Traitor
{
public readonly Character Character;
public Character TargetCharacter; //TODO: make a modular objective system (similar to crew missions) that allows for things OTHER than assasinations.
public Traitor(Character character)
{
Character = character;
}
public void Greet(GameServer server, string codeWords, string codeResponse)
{
string greetingMessage = TextManager.GetWithVariable("TraitorStartMessage", "[targetname]", TargetCharacter.Name);
string moreAgentsMessage = TextManager.GetWithVariables("TraitorMoreAgentsMessage",
new string[2] { "[codewords]", "[coderesponse]" }, new string[2] { codeWords, codeResponse });
var greetingChatMsg = ChatMessage.Create(null, greetingMessage, ChatMessageType.Server, null);
var moreAgentsChatMsg = ChatMessage.Create(null, moreAgentsMessage, ChatMessageType.Server, null);
var moreAgentsMsgBox = ChatMessage.Create(null, moreAgentsMessage, ChatMessageType.MessageBox, null);
var greetingMsgBox = ChatMessage.Create(null, greetingMessage, ChatMessageType.MessageBox, null);
Client traitorClient = server.ConnectedClients.Find(c => c.Character == Character);
GameMain.Server.SendDirectChatMessage(greetingChatMsg, traitorClient);
GameMain.Server.SendDirectChatMessage(moreAgentsChatMsg, traitorClient);
GameMain.Server.SendDirectChatMessage(greetingMsgBox, traitorClient);
GameMain.Server.SendDirectChatMessage(moreAgentsMsgBox, traitorClient);
Client ownerClient = server.ConnectedClients.Find(c => c.Connection == server.OwnerConnection);
if (traitorClient != ownerClient && ownerClient != null && ownerClient.Character == null)
{
var ownerMsg = ChatMessage.Create(
null,//TextManager.Get("NewTraitor"),
TextManager.GetWithVariables("TraitorStartMessageServer", new string[2] { "[targetname]", "[traitorname]" }, new string[2] { TargetCharacter.Name, Character.Name }),
ChatMessageType.MessageBox,
null
);
GameMain.Server.SendDirectChatMessage(ownerMsg, ownerClient);
}
}
}
partial class TraitorManager
{
private static string wordsTxt = Path.Combine("Content", "CodeWords.txt");
public List<Traitor> TraitorList
{
get { return traitorList; }
}
private List<Traitor> traitorList = new List<Traitor>();
public string codeWords, codeResponse;
public TraitorManager(GameServer server, int traitorCount)
{
if (traitorCount < 1) //what why how
{
traitorCount = 1;
DebugConsole.ThrowError("Traitor Manager: TraitorCount somehow ended up less than 1, setting it to 1.");
}
Start(server, traitorCount);
}
private void Start(GameServer server, int traitorCount)
{
if (server == null) return;
List<Character> characters = new List<Character>(); //ANYONE can be a target.
List<Character> traitorCandidates = new List<Character>(); //Keep this to not re-pick traitors twice
foreach (Client client in server.ConnectedClients)
{
if (client.Character != null)
{
characters.Add(client.Character);
traitorCandidates.Add(client.Character);
}
}
if (server.Character != null)
{
characters.Add(server.Character); //Add host character
traitorCandidates.Add(server.Character);
}
if (characters.Count < 2)
{
return;
}
codeWords = ToolBox.GetRandomLine(wordsTxt) + ", " + ToolBox.GetRandomLine(wordsTxt);
codeResponse = ToolBox.GetRandomLine(wordsTxt) + ", " + ToolBox.GetRandomLine(wordsTxt);
while (traitorCount-- > 0)
{
if (traitorCandidates.Count <= 0) break;
int traitorIndex = Rand.Int(traitorCandidates.Count);
Character traitorCharacter = traitorCandidates[traitorIndex];
traitorCandidates.Remove(traitorCharacter);
//Add them to the list
traitorList.Add(new Traitor(traitorCharacter));
}
//Now that traitors have been decided, let's do objectives in post for deciding things like Document Exchange.
foreach (Traitor traitor in traitorList)
{
Character traitorCharacter = traitor.Character;
int targetIndex = Rand.Int(characters.Count);
while (characters[targetIndex] == traitorCharacter) //Cannot target self
{
targetIndex = Rand.Int(characters.Count);
}
Character targetCharacter = characters[targetIndex];
traitor.TargetCharacter = targetCharacter;
traitor.Greet(server, codeWords, codeResponse);
}
}
public string GetEndMessage()
{
if (GameMain.Server == null || traitorList.Count <= 0) return "";
string endMessage = "";
foreach (Traitor traitor in traitorList)
{
Character traitorCharacter = traitor.Character;
Character targetCharacter = traitor.TargetCharacter;
string messageTag;
if (targetCharacter.IsDead) //Partial or complete mission success
{
if (traitorCharacter.IsDead)
{
messageTag = "TraitorEndMessageSuccessTraitorDead";
}
else if (traitorCharacter.LockHands)
{
messageTag = "TraitorEndMessageSuccessTraitorDetained";
}
else
messageTag = "TraitorEndMessageSuccess";
}
else //Partial or complete failure
{
if (traitorCharacter.IsDead)
{
messageTag = "TraitorEndMessageFailureTraitorDead";
}
else if (traitorCharacter.LockHands)
{
messageTag = "TraitorEndMessageFailureTraitorDetained";
}
else
{
messageTag = "TraitorEndMessageFailure";
}
}
endMessage += (TextManager.ReplaceGenderPronouns(TextManager.GetWithVariables(messageTag, new string[2] { "[traitorname]", "[targetname]" },
new string[2] { traitorCharacter.Name, targetCharacter.Name }), traitorCharacter.Info.Gender) + "\n");
}
return endMessage;
}
}
}

View File

@@ -0,0 +1,12 @@
using Barotrauma.Networking;
namespace Barotrauma.Items.Components
{
partial class Controller : ItemComponent, IServerSerializable
{
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
{
msg.Write(state);
}
}
}

View File

@@ -1,8 +1,5 @@
using Microsoft.Xna.Framework;
using Barotrauma.Networking;
using System;
using System.Globalization;
using System.Xml.Linq;
using Barotrauma.Networking;
namespace Barotrauma.Items.Components
{
@@ -11,7 +8,7 @@ namespace Barotrauma.Items.Components
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
{
//force can only be adjusted at 10% intervals -> no need for more accuracy than this
msg.WriteRangedIntegerDeprecated(-10, 10, (int)(targetForce / 10.0f));
msg.WriteRangedInteger((int)(targetForce / 10.0f), -10, 10);
}
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)

View File

@@ -34,7 +34,7 @@ namespace Barotrauma.Items.Components
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
{
int itemIndex = fabricatedItem == null ? -1 : fabricationRecipes.IndexOf(fabricatedItem);
msg.WriteRangedIntegerDeprecated(-1, fabricationRecipes.Count - 1, itemIndex);
msg.WriteRangedInteger(itemIndex, -1, fabricationRecipes.Count - 1);
UInt16 userID = fabricatedItem == null || user == null ? (UInt16)0 : user.ID;
msg.Write(userID);
}

View File

@@ -35,7 +35,7 @@ namespace Barotrauma.Items.Components
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
{
//flowpercentage can only be adjusted at 10% intervals -> no need for more accuracy than this
msg.WriteRangedIntegerDeprecated(-10, 10, (int)(flowPercentage / 10.0f));
msg.WriteRangedInteger((int)(flowPercentage / 10.0f), -10, 10);
msg.Write(IsActive);
}
}

View File

@@ -22,7 +22,7 @@ namespace Barotrauma.Items.Components
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
{
msg.WriteRangedIntegerDeprecated(0, 10, (int)(rechargeSpeed / MaxRechargeSpeed * 10));
msg.WriteRangedInteger((int)(rechargeSpeed / MaxRechargeSpeed * 10), 0, 10);
float chargeRatio = MathHelper.Clamp(charge / capacity, 0.0f, 1.0f);
msg.WriteRangedSingle(chargeRatio, 0.0f, 1.0f, 8);

View File

@@ -88,7 +88,10 @@ namespace Barotrauma.Items.Components
existingWire.RemoveConnection(item);
item.GetComponent<ConnectionPanel>()?.DisconnectedWires.Add(existingWire);
GameMain.Server.KarmaManager.OnWireDisconnected(c.Character, existingWire);
if (!wires.Any(w => w.Contains(existingWire)))
{
GameMain.Server.KarmaManager.OnWireDisconnected(c.Character, existingWire);
}
if (existingWire.Connections[0] == null && existingWire.Connections[1] == null)
{

View File

@@ -28,8 +28,8 @@ namespace Barotrauma.Items.Components
int nodeStartIndex = eventIndex * MaxNodesPerNetworkEvent;
int nodeCount = MathHelper.Clamp(nodes.Count - nodeStartIndex, 0, MaxNodesPerNetworkEvent);
msg.WriteRangedIntegerDeprecated(0, (int)Math.Ceiling(MaxNodeCount / (float)MaxNodesPerNetworkEvent), eventIndex);
msg.WriteRangedIntegerDeprecated(0, MaxNodesPerNetworkEvent, nodeCount);
msg.WriteRangedInteger(eventIndex, 0, (int)Math.Ceiling(MaxNodeCount / (float)MaxNodesPerNetworkEvent));
msg.WriteRangedInteger(nodeCount, 0, MaxNodesPerNetworkEvent);
for (int i = nodeStartIndex; i < nodeStartIndex + nodeCount; i++)
{
msg.Write(nodes[i].X);

View File

@@ -11,13 +11,13 @@ namespace Barotrauma
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
{
List<Item> prevItems = new List<Item>(Items);
ushort[] newItemIDs = new ushort[capacity];
for (int i = 0; i < capacity; i++)
byte itemCount = msg.ReadByte();
ushort[] newItemIDs = new ushort[itemCount];
for (int i = 0; i < itemCount; i++)
{
newItemIDs[i] = msg.ReadUInt16();
}
if (c == null || c.Character == null) return;

View File

@@ -25,7 +25,7 @@ namespace Barotrauma
{
errorMsg = "Failed to write a network event for the item \"" + Name + "\" - event type not set.";
}
msg.WriteRangedIntegerDeprecated(0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1, (int)NetEntityEvent.Type.Invalid);
msg.WriteRangedInteger((int)NetEntityEvent.Type.Invalid, 0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1);
DebugConsole.Log(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("Item.ServerWrite:InvalidData" + Name, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
return;
@@ -34,7 +34,7 @@ namespace Barotrauma
int initialWritePos = msg.LengthBits;
NetEntityEvent.Type eventType = (NetEntityEvent.Type)extraData[0];
msg.WriteRangedIntegerDeprecated(0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1, (int)eventType);
msg.WriteRangedInteger((int)eventType, 0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1);
switch (eventType)
{
case NetEntityEvent.Type.ComponentState:
@@ -54,7 +54,7 @@ namespace Barotrauma
errorMsg = "Failed to write a component state event for the item \"" + Name + "\" - component \"" + components[componentIndex] + "\" is not server serializable.";
break;
}
msg.WriteRangedIntegerDeprecated(0, components.Count - 1, componentIndex);
msg.WriteRangedInteger(componentIndex, 0, components.Count - 1);
(components[componentIndex] as IServerSerializable).ServerWrite(msg, c, extraData);
break;
case NetEntityEvent.Type.InventoryState:
@@ -74,7 +74,7 @@ namespace Barotrauma
errorMsg = "Failed to write an inventory state event for the item \"" + Name + "\" - component \"" + components[containerIndex] + "\" is not server serializable.";
break;
}
msg.WriteRangedIntegerDeprecated(0, components.Count - 1, containerIndex);
msg.WriteRangedInteger(containerIndex, 0, components.Count - 1);
(components[containerIndex] as ItemContainer).Inventory.ServerWrite(msg, c);
break;
case NetEntityEvent.Type.Status:
@@ -91,7 +91,7 @@ namespace Barotrauma
byte targetLimbIndex = targetLimb != null && targetCharacter != null ? (byte)Array.IndexOf(targetCharacter.AnimController.Limbs, targetLimb) : (byte)255;
msg.Write((byte)components.IndexOf(targetComponent));
msg.WriteRangedIntegerDeprecated(0, Enum.GetValues(typeof(ActionType)).Length - 1, (int)actionType);
msg.WriteRangedInteger((int)actionType, 0, Enum.GetValues(typeof(ActionType)).Length - 1);
msg.Write(targetID);
msg.Write(targetLimbIndex);
}
@@ -106,7 +106,7 @@ namespace Barotrauma
Character targetCharacter = FindEntityByID(targetID) as Character;
byte targetLimbIndex = targetLimb != null && targetCharacter != null ? (byte)Array.IndexOf(targetCharacter.AnimController.Limbs, targetLimb) : (byte)255;
msg.WriteRangedIntegerDeprecated(0, Enum.GetValues(typeof(ActionType)).Length - 1, (int)actionType);
msg.WriteRangedInteger((int)actionType, 0, Enum.GetValues(typeof(ActionType)).Length - 1);
msg.Write((byte)(targetComponent == null ? 255 : components.IndexOf(targetComponent)));
msg.Write(targetID);
msg.Write(targetLimbIndex);
@@ -132,7 +132,7 @@ namespace Barotrauma
//something went wrong - rewind the write position and write invalid event type to prevent creating an unreadable event
msg.BitPosition = initialWritePos;
msg.LengthBits = initialWritePos;
msg.WriteRangedIntegerDeprecated(0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1, (int)NetEntityEvent.Type.Invalid);
msg.WriteRangedInteger((int)NetEntityEvent.Type.Invalid, 0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1);
DebugConsole.Log(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("Item.ServerWrite:" + errorMsg, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
}
@@ -345,7 +345,7 @@ namespace Barotrauma
if (!ItemList.Contains(this))
{
string errorMsg = "Attempted to create a network event for an item (" + Name + ") that hasn't been fully initialized yet.";
string errorMsg = "Attempted to create a network event for an item (" + Name + ") that hasn't been fully initialized yet.\n" + Environment.StackTrace;
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("Item.CreateServerEvent:EventForUninitializedItem" + Name + ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
return;

View File

@@ -56,7 +56,7 @@ namespace Barotrauma
message.Write(FireSources.Count > 0);
if (FireSources.Count > 0)
{
message.WriteRangedIntegerDeprecated(0, 16, Math.Min(FireSources.Count, 16));
message.WriteRangedInteger(Math.Min(FireSources.Count, 16), 0, 16);
for (int i = 0; i < Math.Min(FireSources.Count, 16); i++)
{
var fireSource = FireSources[i];

View File

@@ -18,7 +18,7 @@ namespace Barotrauma.Networking
this.ExpirationTime = expirationTime;
this.UniqueIdentifier = LastIdentifier; LastIdentifier++;
this.IsRangeBan = IP.IndexOf(".x")>-1;
this.IsRangeBan = IP.IndexOf(".x") > -1;
}
public BannedPlayer(string name, ulong steamID, string reason, DateTime? expirationTime)
@@ -30,6 +30,8 @@ namespace Barotrauma.Networking
this.UniqueIdentifier = LastIdentifier; LastIdentifier++;
this.IsRangeBan = false;
this.IP = "";
}
public bool CompareTo(string ipCompare)
@@ -276,28 +278,42 @@ namespace Barotrauma.Networking
public void ServerAdminWrite(IWriteMessage outMsg, Client c)
{
if (!c.HasPermission(ClientPermissions.Ban))
try
{
outMsg.Write(false); outMsg.WritePadBits();
return;
}
outMsg.Write(true);
outMsg.Write(c.Connection == GameMain.Server.OwnerConnection);
if (outMsg == null) { throw new ArgumentException("OutMsg was null"); }
if (GameMain.Server == null) { throw new Exception("GameMain.Server was null"); }
outMsg.WritePadBits();
outMsg.WriteVariableUInt32((UInt32)bannedPlayers.Count);
for (int i = 0; i < bannedPlayers.Count; i++)
{
BannedPlayer bannedPlayer = bannedPlayers[i];
outMsg.Write(bannedPlayer.Name);
outMsg.Write(bannedPlayer.UniqueIdentifier);
outMsg.Write(bannedPlayer.IsRangeBan); outMsg.WritePadBits();
if (c.Connection == GameMain.Server.OwnerConnection)
if (!c.HasPermission(ClientPermissions.Ban))
{
outMsg.Write(bannedPlayer.IP);
outMsg.Write(bannedPlayer.SteamID);
outMsg.Write(false); outMsg.WritePadBits();
return;
}
outMsg.Write(true);
outMsg.Write(c.Connection == GameMain.Server.OwnerConnection);
outMsg.WritePadBits();
outMsg.WriteVariableUInt32((UInt32)bannedPlayers.Count);
for (int i = 0; i < bannedPlayers.Count; i++)
{
BannedPlayer bannedPlayer = bannedPlayers[i];
outMsg.Write(bannedPlayer.Name);
outMsg.Write(bannedPlayer.UniqueIdentifier);
outMsg.Write(bannedPlayer.IsRangeBan); outMsg.WritePadBits();
if (c.Connection == GameMain.Server.OwnerConnection)
{
outMsg.Write(bannedPlayer.IP);
outMsg.Write(bannedPlayer.SteamID);
}
}
}
catch (Exception e)
{
string errorMsg = "Error while writing banlist. {" + e + "}\n" + e.StackTrace;
GameAnalyticsManager.AddErrorEventOnce("Banlist.ServerAdminWrite", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
throw;
}
}

View File

@@ -6,6 +6,11 @@ namespace Barotrauma
partial class EntitySpawner : Entity, IServerSerializable
{
public void CreateNetworkEvent(Entity entity, bool remove)
{
CreateNetworkEventProjSpecific(entity, remove);
}
partial void CreateNetworkEventProjSpecific(Entity entity, bool remove)
{
if (GameMain.Server != null && entity != null)
{

View File

@@ -264,17 +264,15 @@ namespace Barotrauma.Networking
{
newClient.GivePermission(ClientPermissions.All);
newClient.PermittedConsoleCommands.AddRange(DebugConsole.Commands);
GameMain.Server.UpdateClientPermissions(newClient);
GameMain.Server.SendConsoleMessage("Granted all permissions to " + newClient.Name + ".", newClient);
SendConsoleMessage("Granted all permissions to " + newClient.Name + ".", newClient);
}
GameMain.Server.SendChatMessage($"ServerMessage.JoinedServer~[client]={clName}", ChatMessageType.Server, null);
SendChatMessage($"ServerMessage.JoinedServer~[client]={clName}", ChatMessageType.Server, null);
serverSettings.ServerDetailsChanged = true;
if (previousPlayer != null && previousPlayer.Name != newClient.Name)
{
GameMain.Server.SendChatMessage($"ServerMessage.PreviousClientName~[client]={clName}~[previousname]={previousPlayer.Name}", ChatMessageType.Server, null);
SendChatMessage($"ServerMessage.PreviousClientName~[client]={clName}~[previousname]={previousPlayer.Name}", ChatMessageType.Server, null);
previousPlayer.Name = newClient.Name;
}
@@ -299,6 +297,8 @@ namespace Barotrauma.Networking
newClient.SetPermissions(ClientPermissions.None, new List<DebugConsole.Command>());
}
}
UpdateClientPermissions(newClient);
}
private void OnClientDisconnect(NetworkConnection connection, string disconnectMsg)
@@ -653,9 +653,18 @@ namespace Barotrauma.Networking
catch (Exception e)
{
DebugConsole.ThrowError("Failed to write a network message for the client \"" + c.Name + "\"!", e);
GameAnalyticsManager.AddErrorEventOnce("GameServer.Update:ClientWriteFailed" + e.StackTrace, GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
"Failed to write a network message for the client \"" + c.Name + "\"! (MidRoundSyncing: " + c.NeedsMidRoundSync + ")\n"
+ e.Message + "\n" + e.StackTrace);
string errorMsg = "Failed to write a network message for the client \"" + c.Name + "\"! (MidRoundSyncing: " + c.NeedsMidRoundSync + ")\n"
+ e.Message + "\n" + e.StackTrace;
if (e.InnerException != null)
{
errorMsg += "\nInner exception: " + e.InnerException.Message + "\n" + e.InnerException.StackTrace;
}
GameAnalyticsManager.AddErrorEventOnce(
"GameServer.Update:ClientWriteFailed" + e.StackTrace,
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
errorMsg);
}
}
@@ -832,7 +841,7 @@ namespace Barotrauma.Networking
}
Log(c.Name + " has reported an error: " + errorStr, ServerLog.MessageType.Error);
GameAnalyticsManager.AddErrorEventOnce("GameServer.HandleClientError:LevelsDontMatch" + error, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorStr);
GameAnalyticsManager.AddErrorEventOnce("GameServer.HandleClientError:" + errorStr, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorStr);
if (c.Connection == OwnerConnection)
{
@@ -1475,7 +1484,7 @@ namespace Barotrauma.Networking
private void WriteClientList(Client c, IWriteMessage outmsg)
{
bool hasChanged = NetIdUtils.IdMoreRecent(LastClientListUpdateID, c.LastRecvClientListUpdate);
if (!hasChanged) return;
if (!hasChanged) { return; }
outmsg.Write((byte)ServerNetObject.CLIENT_LIST);
outmsg.Write(LastClientListUpdateID);
@@ -1502,6 +1511,8 @@ namespace Barotrauma.Networking
outmsg.Write((byte)ServerNetObject.SYNC_IDS);
int settingsBytes = outmsg.LengthBytes;
if (NetIdUtils.IdMoreRecent(GameMain.NetLobbyScreen.LastUpdateID, c.LastRecvLobbyUpdate))
{
outmsg.Write(true);
@@ -1534,9 +1545,9 @@ namespace Barotrauma.Networking
outmsg.Write(serverSettings.AllowSpectating);
outmsg.WriteRangedIntegerDeprecated(0, 2, (int)serverSettings.TraitorsEnabled);
outmsg.WriteRangedInteger((int)serverSettings.TraitorsEnabled, 0, 2);
outmsg.WriteRangedIntegerDeprecated(0, Enum.GetValues(typeof(MissionType)).Length - 1, (GameMain.NetLobbyScreen.MissionTypeIndex));
outmsg.WriteRangedInteger((GameMain.NetLobbyScreen.MissionTypeIndex), 0, Enum.GetValues(typeof(MissionType)).Length - 1);
outmsg.Write((byte)GameMain.NetLobbyScreen.SelectedModeIndex);
outmsg.Write(GameMain.NetLobbyScreen.LevelSeed);
@@ -1556,9 +1567,12 @@ namespace Barotrauma.Networking
outmsg.Write(false);
outmsg.WritePadBits();
}
settingsBytes = outmsg.LengthBytes - settingsBytes;
int campaignBytes = outmsg.LengthBytes;
var campaign = GameMain.GameSession?.GameMode as MultiPlayerCampaign;
if (campaign != null && campaign.Preset == GameMain.NetLobbyScreen.SelectedMode &&
if (outmsg.LengthBytes < MsgConstants.MTU - 500 &&
campaign != null && campaign.Preset == GameMain.NetLobbyScreen.SelectedMode &&
NetIdUtils.IdMoreRecent(campaign.LastUpdateID, c.LastRecvCampaignUpdate))
{
outmsg.Write(true);
@@ -1570,12 +1584,20 @@ namespace Barotrauma.Networking
outmsg.Write(false);
outmsg.WritePadBits();
}
campaignBytes = outmsg.LengthBytes - campaignBytes;
outmsg.Write(c.LastSentChatMsgID); //send this to client so they know which chat messages weren't received by the server
WriteClientList(c, outmsg);
int clientListBytes = outmsg.LengthBytes;
if (outmsg.LengthBytes < MsgConstants.MTU - 500)
{
WriteClientList(c, outmsg);
}
clientListBytes = outmsg.LengthBytes - clientListBytes;
int chatMessageBytes = outmsg.LengthBytes;
WriteChatMessages(outmsg, c);
chatMessageBytes = outmsg.LengthBytes - outmsg.LengthBytes;
outmsg.Write((byte)ServerNetObject.END_OF_MESSAGE);
@@ -1597,7 +1619,14 @@ namespace Barotrauma.Networking
{
if (outmsg.LengthBytes > MsgConstants.MTU)
{
DebugConsole.ThrowError("Maximum packet size exceeded (" + outmsg.LengthBytes + " > " + MsgConstants.MTU + ")");
string errorMsg = "Maximum packet size exceeded (" + outmsg.LengthBytes + " > " + MsgConstants.MTU + ")";
errorMsg +=
" Client list size: " + clientListBytes + " bytes\n" +
" Chat message size: " + chatMessageBytes + " bytes\n" +
" Campaign size: " + campaignBytes + " bytes\n" +
" Settings size: " + settingsBytes + " bytes\n\n";
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameServer.ClientWriteIngame1:ClientWriteLobby" + outmsg.LengthBytes, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
}
serverPeer.Send(outmsg, c.Connection, DeliveryMethod.Unreliable);
@@ -2018,6 +2047,8 @@ namespace Barotrauma.Networking
c.PositionUpdateLastSent.Clear();
}
KarmaManager.OnRoundEnded();
#if DEBUG
messageCount.Clear();
#endif
@@ -2644,25 +2675,48 @@ namespace Barotrauma.Networking
}
}
//send the message to the client whose permissions are being modified and the clients who are allowed to modify permissions
List<Client> recipients = new List<Client>() { client };
foreach (Client otherClient in connectedClients)
{
if (otherClient.HasPermission(ClientPermissions.ManagePermissions) && !recipients.Contains(otherClient))
{
recipients.Add(otherClient);
}
}
foreach (Client recipient in recipients)
{
CoroutineManager.StartCoroutine(SendClientPermissionsAfterClientListSynced(recipient, client));
}
serverSettings.SaveClientPermissions();
}
private IEnumerable<object> SendClientPermissionsAfterClientListSynced(Client recipient, Client client)
{
DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, 10);
while (recipient.LastRecvClientListUpdate < LastClientListUpdateID)
{
if (DateTime.Now > timeOut || GameMain.Server == null || !connectedClients.Contains(recipient))
{
yield return CoroutineStatus.Success;
}
yield return null;
}
SendClientPermissions(recipient, client);
yield return CoroutineStatus.Success;
}
private void SendClientPermissions(Client recipient, Client client)
{
if (recipient?.Connection == null) { return; }
IWriteMessage msg = new WriteOnlyMessage();
msg.Write((byte)ServerPacketHeader.PERMISSIONS);
client.WritePermissions(msg);
//send the message to the client whose permissions are being modified and the clients who are allowed to modify permissions
List<NetworkConnection> recipients = new List<NetworkConnection>() { client.Connection };
foreach (Client otherClient in connectedClients)
{
if (otherClient.HasPermission(ClientPermissions.ManagePermissions) && !recipients.Contains(otherClient.Connection))
{
recipients.Add(otherClient.Connection);
}
}
foreach (NetworkConnection c in recipients)
{
serverPeer.Send(msg, c, DeliveryMethod.Reliable);
}
serverSettings.SaveClientPermissions();
serverPeer.Send(msg, recipient.Connection, DeliveryMethod.Reliable);
}
public void GiveAchievement(Character character, string achievementIdentifier)

View File

@@ -12,7 +12,6 @@ namespace Barotrauma
{
public List<Pair<Wire, float>> WireDisconnectTime = new List<Pair<Wire, float>>();
//the client's karma value when they were last sent a notification about it (e.g. "your karma is very low")
public float PreviousNotifiedKarma;
public float StructureDamageAccumulator;
@@ -23,6 +22,13 @@ namespace Barotrauma
get { return Math.Max(StructureDamageAccumulator, structureDamagePerSecond); }
set { structureDamagePerSecond = value; }
}
//when did a given character last attack this one
public Dictionary<Character, double> LastAttackTime
{
get;
private set;
} = new Dictionary<Character, double>();
}
public bool TestMode = false;
@@ -31,9 +37,7 @@ namespace Barotrauma
private readonly List<Client> bannedClients = new List<Client>();
private DateTime perSecondUpdate;
private double KarmaNotificationTime;
public void UpdateClients(IEnumerable<Client> clients, float deltaTime)
{
if (!GameMain.Server.GameStarted) { return; }
@@ -41,32 +45,34 @@ namespace Barotrauma
bannedClients.Clear();
foreach (Client client in clients)
{
var clientMemory = GetClientMemory(client);
UpdateClient(client, deltaTime);
if (perSecondUpdate < DateTime.Now)
{
var clientMemory = GetClientMemory(client);
clientMemory.StructureDamagePerSecond = clientMemory.StructureDamageAccumulator;
clientMemory.StructureDamageAccumulator = 0.0f;
var toRemove = clientMemory.LastAttackTime.Where(pair => pair.Value < Timing.TotalTime - AllowedRetaliationTime).Select(pair => pair.Key).ToList();
foreach (var lastAttacker in toRemove)
{
clientMemory.LastAttackTime.Remove(lastAttacker);
}
}
}
if (perSecondUpdate < DateTime.Now)
{
perSecondUpdate = DateTime.Now + new TimeSpan(0, 0, 1);
}
if (TestMode || Timing.TotalTime > KarmaNotificationTime)
{
foreach (Client client in clients)
{
SendKarmaNotifications(client);
}
KarmaNotificationTime = Timing.TotalTime + KarmaNotificationInterval;
perSecondUpdate = DateTime.Now + new TimeSpan(0, 0, 1);
}
foreach (Client bannedClient in bannedClients)
{
if (bannedClient.KarmaKickCount < KicksBeforeBan)
bannedClient.KarmaKickCount++;
if (bannedClient.KarmaKickCount <= KicksBeforeBan)
{
GameMain.Server.KickClient(bannedClient, $"KarmaKicked~[banthreshold]={(int)KickBanThreshold}", resetKarma: true);
}
@@ -74,15 +80,17 @@ namespace Barotrauma
{
GameMain.Server.BanClient(bannedClient, $"KarmaBanned~[banthreshold]={(int)KickBanThreshold}", duration: TimeSpan.FromSeconds(GameMain.Server.ServerSettings.AutoBanTime));
}
bannedClient.KarmaKickCount++;
}
}
private void SendKarmaNotifications(Client client, string debugKarmaChangeReason = "")
{
//send a notification about karma changing if the karma has changed by x% within the last second
var clientMemory = GetClientMemory(client);
float karmaChange = client.Karma - clientMemory.PreviousNotifiedKarma;
if (Math.Abs(karmaChange) > KarmaNotificationInterval || (TestMode && Math.Abs(karmaChange) > 2.0f))
if (Math.Abs(karmaChange) > 1.0f &&
(TestMode || Math.Abs(karmaChange) / clientMemory.PreviousNotifiedKarma > KarmaNotificationInterval / 100.0f))
{
if (TestMode)
{
@@ -102,8 +110,8 @@ namespace Barotrauma
{
GameMain.Server.SendDirectChatMessage(TextManager.Get(karmaChange < 0 ? "KarmaDecreasedUnknownAmount" : "KarmaIncreasedUnknownAmount"), client);
}
clientMemory.PreviousNotifiedKarma = client.Karma;
}
clientMemory.PreviousNotifiedKarma = client.Karma;
}
private void UpdateClient(Client client, float deltaTime)
@@ -156,7 +164,7 @@ namespace Barotrauma
AdjustKarma(client.Character, karmaDecrease, "Disconnected excessive number of wires");
}
}
if (client.Character?.Info?.Job.Prefab.Identifier == "captain" && client.Character.SelectedConstruction != null)
{
if (client.Character.SelectedConstruction.GetComponent<Steering>() != null)
@@ -180,6 +188,18 @@ namespace Barotrauma
}
}
public void OnRoundEnded()
{
if (ResetKarmaBetweenRounds)
{
clientMemories.Clear();
foreach (Client client in GameMain.Server.ConnectedClients)
{
client.Karma = Math.Max(50.0f, client.Karma);
}
}
}
public void OnClientDisconnected(Client client)
{
clientMemories.Remove(client);
@@ -210,7 +230,41 @@ namespace Barotrauma
isEnemy = true;
}
}
bool targetIsHusk = target.CharacterHealth?.GetAffliction<AfflictionHusk>("huskinfection")?.State == AfflictionHusk.InfectionState.Active;
bool attackerIsHusk = attacker.CharacterHealth?.GetAffliction<AfflictionHusk>("huskinfection")?.State == AfflictionHusk.InfectionState.Active;
//huskified characters count as enemies to healthy characters and vice versa
if (targetIsHusk != attackerIsHusk) { isEnemy = true; }
if (appliedAfflictions != null)
{
foreach (Affliction affliction in appliedAfflictions)
{
if (MathUtils.NearlyEqual(affliction.Prefab.KarmaChangeOnApplied, 0.0f)) { continue; }
damage -= affliction.Prefab.KarmaChangeOnApplied * affliction.Strength;
}
}
Client targetClient = GameMain.Server.ConnectedClients.Find(c => c.Character == target);
if (damage > 0 && targetClient != null)
{
var targetMemory = GetClientMemory(targetClient);
targetMemory.LastAttackTime[attacker] = Timing.TotalTime;
}
Client attackerClient = GameMain.Server.ConnectedClients.Find(c => c.Character == attacker);
if (attackerClient != null)
{
//if the attacker has been attacked by the target within the last x seconds, ignore the damage
//(= no karma penalty from retaliating against someone who attacked you)
var attackerMemory = GetClientMemory(attackerClient);
if (attackerMemory.LastAttackTime.ContainsKey(target) &&
attackerMemory.LastAttackTime[target] > Timing.TotalTime - AllowedRetaliationTime)
{
damage = Math.Min(damage, 0);
}
}
//attacking/healing clowns has a smaller effect on karma
if (target.HasEquippedItem("clownmask") &&
target.HasEquippedItem("clowncostume"))
@@ -218,15 +272,21 @@ namespace Barotrauma
damage *= 0.5f;
}
if (appliedAfflictions != null)
//smaller karma penalty for attacking someone who's aiming with a weapon
if (damage > 0.0f &&
target.IsKeyDown(InputType.Aim) &&
target.SelectedItems.Any(it => it != null && (it.GetComponent<MeleeWeapon>() != null || it.GetComponent<RangedWeapon>() != null)))
{
foreach (Affliction affliction in appliedAfflictions)
{
if (MathUtils.NearlyEqual(affliction.Prefab.KarmaChangeOnApplied, 0.0f)) { continue; }
damage -= affliction.Prefab.KarmaChangeOnApplied * affliction.Strength;
}
damage *= 0.5f;
}
//damage scales according to the karma of the target
//(= smaller karma penalty from attacking someone who has a low karma)
if (damage > 0 && targetClient != null)
{
damage *= MathUtils.InverseLerp(0.0f, 50.0f, targetClient.Karma);
}
if (isEnemy)
{
if (damage > 0)

View File

@@ -37,8 +37,8 @@ namespace Barotrauma.Networking
Retries = 0;
SteamID = null;
PasswordSalt = null;
UpdateTime = Timing.TotalTime;
TimeOut = 20.0;
UpdateTime = Timing.TotalTime+Timing.Step*3.0;
TimeOut = NetworkConnection.TimeoutThreshold;
AuthSessionStarted = false;
}
}
@@ -319,7 +319,7 @@ namespace Barotrauma.Networking
{
if (netServer == null) { return; }
pendingClient.TimeOut = 20.0;
pendingClient.TimeOut = NetworkConnection.TimeoutThreshold;
ConnectionInitialization initializationStep = (ConnectionInitialization)inc.ReadByte();
@@ -327,6 +327,8 @@ namespace Barotrauma.Networking
if (pendingClient.InitializationStep != initializationStep) return;
pendingClient.UpdateTime = Timing.TotalTime + Timing.Step;
switch (initializationStep)
{
case ConnectionInitialization.SteamTicketAndVersion:
@@ -522,6 +524,7 @@ namespace Barotrauma.Networking
}
OnInitializationComplete?.Invoke(newConnection);
return;
}
@@ -554,6 +557,10 @@ namespace Barotrauma.Networking
}
NetSendResult result = netServer.SendMessage(outMsg, pendingClient.Connection, NetDeliveryMethod.ReliableUnordered);
if (result != NetSendResult.Sent && result != NetSendResult.Queued)
{
DebugConsole.NewMessage("Failed to send initialization step " + pendingClient.InitializationStep.ToString() + " to pending client: " + result.ToString(), Microsoft.Xna.Framework.Color.Yellow);
}
//DebugConsole.NewMessage("sent update to pending client: "+result);
}
@@ -588,7 +595,7 @@ namespace Barotrauma.Networking
if (netServer == null) { return; }
PendingClient pendingClient = pendingClients.Find(c => c.SteamID == steamID);
DebugConsole.NewMessage(steamID + " validation: " + status+", "+(pendingClient!=null));
DebugConsole.Log(steamID + " validation: " + status+", "+(pendingClient!=null));
if (pendingClient == null)
{
@@ -653,7 +660,11 @@ namespace Barotrauma.Networking
lidgrenMsg.Write((UInt16)length);
lidgrenMsg.Write(msgData, 0, length);
netServer.SendMessage(lidgrenMsg, lidgrenConn.NetConnection, lidgrenDeliveryMethod);
NetSendResult result = netServer.SendMessage(lidgrenMsg, lidgrenConn.NetConnection, lidgrenDeliveryMethod);
if (result != NetSendResult.Sent && result != NetSendResult.Queued)
{
DebugConsole.NewMessage("Failed to send message to "+conn.Name+": " + result.ToString(), Microsoft.Xna.Framework.Color.Yellow);
}
}
public override void Disconnect(NetworkConnection conn,string msg=null)

View File

@@ -40,14 +40,14 @@ namespace Barotrauma.Networking
Retries = 0;
SteamID = steamId;
PasswordSalt = null;
UpdateTime = Timing.TotalTime;
TimeOut = 20.0;
UpdateTime = Timing.TotalTime+Timing.Step*3.0;
TimeOut = NetworkConnection.TimeoutThreshold;
AuthSessionStarted = false;
}
public void Heartbeat()
{
TimeOut = 5.0;
TimeOut = NetworkConnection.TimeoutThreshold;
}
}
@@ -228,7 +228,7 @@ namespace Barotrauma.Networking
if (isServerMessage)
{
DebugConsole.ThrowError("got server message from" + senderSteamId.ToString());
DebugConsole.ThrowError("Got server message from" + senderSteamId.ToString());
return;
}
@@ -346,7 +346,11 @@ namespace Barotrauma.Networking
NetOutgoingMessage outMsg = netServer.CreateMessage();
outMsg.Write(OwnerSteamID);
outMsg.Write((byte)(PacketHeader.IsConnectionInitializationStep | PacketHeader.IsServerMessage));
netServer.SendMessage(outMsg, netConnection, NetDeliveryMethod.ReliableUnordered);
NetSendResult result = netServer.SendMessage(outMsg, netConnection, NetDeliveryMethod.ReliableUnordered);
if (result != NetSendResult.Sent && result != NetSendResult.Queued)
{
DebugConsole.NewMessage("Failed to send connection confirmation message to owner: " + result.ToString(), Microsoft.Xna.Framework.Color.Yellow);
}
break;
case NetConnectionStatus.Disconnected:
DebugConsole.NewMessage("Owner disconnected: closing the server...");
@@ -360,7 +364,7 @@ namespace Barotrauma.Networking
{
if (netServer == null) { return; }
pendingClient.TimeOut = 20.0;
pendingClient.TimeOut = NetworkConnection.TimeoutThreshold;
ConnectionInitialization initializationStep = (ConnectionInitialization)inc.ReadByte();
@@ -368,6 +372,8 @@ namespace Barotrauma.Networking
if (pendingClient.InitializationStep != initializationStep) return;
pendingClient.UpdateTime = Timing.TotalTime+Timing.Step;
switch (initializationStep)
{
case ConnectionInitialization.SteamTicketAndVersion:
@@ -549,6 +555,10 @@ namespace Barotrauma.Networking
if (netConnection != null)
{
NetSendResult result = netServer.SendMessage(outMsg, netConnection, NetDeliveryMethod.ReliableUnordered);
if (result != NetSendResult.Sent && result != NetSendResult.Queued)
{
DebugConsole.NewMessage("Failed to send initialization step " + pendingClient.InitializationStep.ToString() + " to pending client: " + result.ToString(), Microsoft.Xna.Framework.Color.Yellow);
}
}
}
@@ -609,7 +619,11 @@ namespace Barotrauma.Networking
lidgrenMsg.Write((UInt16)length);
lidgrenMsg.Write(msgData, 0, length);
netServer.SendMessage(lidgrenMsg, netConnection, lidgrenDeliveryMethod);
NetSendResult result = netServer.SendMessage(lidgrenMsg, netConnection, lidgrenDeliveryMethod);
if (result != NetSendResult.Sent && result != NetSendResult.Queued)
{
DebugConsole.NewMessage("Failed to send message to " + conn.Name + ": " + result.ToString(), Microsoft.Xna.Framework.Color.Yellow);
}
}
private void SendDisconnectMessage(UInt64 steamId, string msg)
@@ -622,7 +636,11 @@ namespace Barotrauma.Networking
lidgrenMsg.Write((byte)(PacketHeader.IsDisconnectMessage | PacketHeader.IsServerMessage));
lidgrenMsg.Write(msg);
netServer.SendMessage(lidgrenMsg, netConnection, NetDeliveryMethod.ReliableUnordered);
NetSendResult result = netServer.SendMessage(lidgrenMsg, netConnection, NetDeliveryMethod.ReliableUnordered);
if (result != NetSendResult.Sent && result != NetSendResult.Queued)
{
DebugConsole.NewMessage("Failed to send disconnect message to " + Steam.SteamManager.SteamIDUInt64ToString(steamId) + ": " + result.ToString(), Microsoft.Xna.Framework.Color.Yellow);
}
}
private void Disconnect(NetworkConnection conn, string msg, bool sendDisconnectMessage)

View File

@@ -327,7 +327,7 @@ namespace Barotrauma.Networking
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
{
msg.WriteRangedIntegerDeprecated(0, Enum.GetNames(typeof(State)).Length, (int)CurrentState);
msg.WriteRangedInteger((int)CurrentState, 0, Enum.GetNames(typeof(State)).Length);
switch (CurrentState)
{

View File

@@ -50,7 +50,7 @@ namespace Barotrauma.Networking
outMsg.Write(HasPassword);
outMsg.Write(isPublic);
outMsg.WritePadBits();
outMsg.WriteRangedIntegerDeprecated(1, 60, TickRate);
outMsg.WriteRangedInteger(TickRate, 1, 60);
WriteExtraCargo(outMsg);
@@ -236,8 +236,8 @@ namespace Barotrauma.Networking
GameMain.NetLobbyScreen.SetLevelDifficulty(selectedLevelDifficulty);
GameMain.NetLobbyScreen.SetTraitorsEnabled(traitorsEnabled);
string[] allowedClientNameCharsStr = doc.Root.GetAttributeStringArray("AllowedClientNameChars",
string[] defaultAllowedClientNameChars =
new string[] {
"32-33",
"38-46",
@@ -248,8 +248,16 @@ namespace Barotrauma.Networking
"95-122",
"192-255",
"384-591",
"1024-1279"
});
"1024-1279",
"19968-40959","13312-19903","131072-173791","173824-178207","178208-183983","63744-64255","194560-195103" //CJK
};
string[] allowedClientNameCharsStr = doc.Root.GetAttributeStringArray("AllowedClientNameChars", defaultAllowedClientNameChars);
if (doc.Root.GetAttributeString("AllowedClientNameChars", "") == "65-90,97-122,48-59")
{
allowedClientNameCharsStr = defaultAllowedClientNameChars;
}
foreach (string allowedClientNameCharRange in allowedClientNameCharsStr)
{
string[] splitRange = allowedClientNameCharRange.Split('-');
@@ -275,7 +283,7 @@ namespace Barotrauma.Networking
}
}
if (min > -1 && max > -1) AllowedClientNameChars.Add(new Pair<int, int>(min, max));
if (min > -1 && max > -1) { AllowedClientNameChars.Add(new Pair<int, int>(min, max)); }
}
AllowedRandomMissionTypes = new List<MissionType>();

View File

@@ -24,6 +24,7 @@ namespace Barotrauma
foreach (Hull hull in Hull.hullList)
{
if (hull.Submarine == null || hull.Submarine.IsOutpost || hull.Submarine.TeamID != Traitor.Character.TeamID) { continue; }
if (hull.Submarine == GameMain.Server?.RespawnManager?.RespawnShuttle) { continue; }
++validHullsCount;
floodingAmount += hull.WaterVolume / hull.Volume;
}

View File

@@ -93,6 +93,7 @@
<Text file="Content/Texts/SimplifiedChineseVanilla.xml" />
<Text file="Content/Texts/TraditionalChineseVanilla.xml" />
<Text file="Content/Texts/CastilianSpanishVanilla.xml" />
<Text file="Content/Texts/JapaneseVanilla.xml" />
<Text file="Content/Texts/LatinamericanSpanishVanilla.xml" />
<Text file="Content/Texts/PolishVanilla.xml" />
<Text file="Content/Texts/TurkishVanilla.xml" />
@@ -117,6 +118,11 @@
<NPCConversations file="Content/NPCConversations/NpcConversations_BrazilianPortuguese.xml"/>
<NPCConversations file="Content/NPCConversations/NpcConversations_SimplifiedChinese.xml"/>
<NPCConversations file="Content/NPCConversations/NpcConversations_TraditionalChinese.xml"/>
<NPCConversations file="Content/NPCConversations/NpcConversations_CastilianSpanish.xml"/>
<NPCConversations file="Content/NPCConversations/NpcConversations_Japanese.xml"/>
<NPCConversations file="Content/NPCConversations/NpcConversations_LatinamericanSpanish.xml"/>
<NPCConversations file="Content/NPCConversations/NpcConversations_Polish.xml"/>
<NPCConversations file="Content/NPCConversations/NpcConversations_Turkish.xml"/>
<Jobs file="Content/Jobs.xml" />
<Sounds file="Content/Sounds/sounds.xml" />
<Tutorials file="Content/Tutorials/Tutorials.xml" />

View File

@@ -7,20 +7,22 @@
karmaincrease="0.1"
karmaincreasethreshold="50"
structurerepairkarmaincrease="0.05"
structuredamagekarmadecrease="0.1"
structuredamagekarmadecrease="0.08"
itemrepairkarmaincrease="0.03"
reactoroverheatkarmadecrease="0.5"
reactormeltdownkarmadecrease="30"
damageenemykarmaincrease="0.1"
damagefriendlykarmadecrease="0.2"
damagefriendlykarmadecrease="0.15"
extinguishfirekarmaincrease="1"
allowedwiredisconnectionsperminute="3"
allowedwiredisconnectionsperminute="5"
wiredisconnectionkarmadecrease="6.0"
steersubkarmaincrease="0.15"
spamfilterkarmadecrease="15"
herpesthreshold="40"
kickbanthreshold="1"
karmanotificationinterval="10" />
kicksbeforeban="3"
karmanotificationinterval="15"
resetkarmabetweenrounds="true" />
<Preset
name="Strict"
karmadecay="0.08"
@@ -35,13 +37,15 @@
damageenemykarmaincrease="0.1"
damagefriendlykarmadecrease="0.3"
extinguishfirekarmaincrease="1"
allowedwiredisconnectionsperminute="1"
allowedwiredisconnectionsperminute="3"
wiredisconnectionkarmadecrease="10.0"
steersubkarmaincrease="0.15"
spamfilterkarmadecrease="25"
herpesthreshold="40"
kickbanthreshold="1"
karmanotificationinterval="10" />
kicksbeforeban="1"
karmanotificationinterval="15"
resetkarmabetweenrounds="true" />
<Preset
name="Custom"
karmadecay="0.08"
@@ -49,18 +53,20 @@
karmaincrease="0.1"
karmaincreasethreshold="50"
structurerepairkarmaincrease="0.05"
structuredamagekarmadecrease="0.1"
structuredamagekarmadecrease="0.08"
itemrepairkarmaincrease="0.03"
reactoroverheatkarmadecrease="0.5"
reactormeltdownkarmadecrease="30"
damageenemykarmaincrease="0.1"
damagefriendlykarmadecrease="0.2"
damagefriendlykarmadecrease="0.15"
extinguishfirekarmaincrease="1"
allowedwiredisconnectionsperminute="3"
allowedwiredisconnectionsperminute="5"
wiredisconnectionkarmadecrease="6.0"
steersubkarmaincrease="0.15"
spamfilterkarmadecrease="15"
herpesthreshold="40"
kickbanthreshold="1"
karmanotificationinterval="10" />
kicksbeforeban="3"
karmanotificationinterval="15"
resetkarmabetweenrounds="true" />
</KarmaManager>

View File

@@ -592,6 +592,9 @@
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_BrazilianPortuguese.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_CastilianSpanish.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_English.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -602,6 +605,15 @@
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_German.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_Japanese.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_LatinamericanSpanish.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_Polish.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_Russian.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -611,6 +623,9 @@
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_TraditionalChinese.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\NPCConversations\NpcConversations_Turkish.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Splash_Daedalic.mp4">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -635,6 +650,9 @@
<Content Include="$(MSBuildThisFileDirectory)Content\Texts\GermanVanilla.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Texts\JapaneseVanilla.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="$(MSBuildThisFileDirectory)Content\Texts\LatinamericanSpanishVanilla.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -2399,6 +2417,12 @@
<None Include="$(MSBuildThisFileDirectory)Content\Sounds\Impact\SoftImpact3.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Sounds\RepairLoop.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Sounds\RewiringLoop.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Tutorials\Dugong_Tutorial.sub">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
@@ -2420,6 +2444,9 @@
<None Include="$(MSBuildThisFileDirectory)Content\TraitorMissions.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Submarines\Nautilus.sub">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)Content\Characters\Carrier\CARRIER_alarmLoop.ogg">
@@ -3593,4 +3620,4 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
</Project>

View File

@@ -387,14 +387,17 @@ namespace Barotrauma
private void UpdateIdle(float deltaTime)
{
if (Character.Submarine == null && SimPosition.Y < ConvertUnits.ToSimUnits(Character.CharacterHealth.CrushDepth * 0.75f))
if (Character.Submarine == null &&
SimPosition.Y < ConvertUnits.ToSimUnits(Character.CharacterHealth.CrushDepth * 0.75f))
{
//steer straight up if very deep
steeringManager.SteeringManual(deltaTime, Vector2.UnitY);
return;
}
if (wallTarget != null) return;
SteerInsideLevel(deltaTime);
if (wallTarget != null) { return; }
if (SelectedAiTarget != null)
{
@@ -451,6 +454,10 @@ namespace Barotrauma
}
}
}
else
{
SteerInsideLevel(deltaTime);
}
if (escapePoint != Vector2.Zero && Vector2.DistanceSquared(Character.SimPosition, escapePoint) > 1)
{
SteeringManager.SteeringSeek(escapePoint);
@@ -1396,6 +1403,30 @@ namespace Barotrauma
AttackingLimb = null;
}
private void SteerInsideLevel(float deltaTime)
{
if (Level.Loaded == null) { return; }
Vector2 levelSimSize = new Vector2(
ConvertUnits.ToSimUnits(Level.Loaded.Size.X),
ConvertUnits.ToSimUnits(Level.Loaded.Size.Y));
float margin = 10.0f;
if (SimPosition.Y < 0.0f)
{
steeringManager.SteeringManual(deltaTime, Vector2.UnitY * MathUtils.InverseLerp(0.0f, -margin, SimPosition.Y));
}
if (SimPosition.X < 0.0f)
{
steeringManager.SteeringManual(deltaTime, Vector2.UnitX * MathUtils.InverseLerp(0.0f, -margin, SimPosition.X));
}
if (SimPosition.X > levelSimSize.X)
{
steeringManager.SteeringManual(deltaTime, Vector2.UnitX * MathUtils.InverseLerp(levelSimSize.X, levelSimSize.X + margin, SimPosition.X));
}
}
private int GetMinimumPassableHoleCount()
{
return (int)Math.Ceiling(ConvertUnits.ToDisplayUnits(colliderSize) / Structure.WallSectionSize);

View File

@@ -81,7 +81,7 @@ namespace Barotrauma
public override void Update(float deltaTime)
{
if (DisableCrewAI || Character.IsUnconscious) return;
if (DisableCrewAI || Character.IsUnconscious || Character.Removed) { return; }
float maxDistanceToSub = 3000;
if (Character.Submarine != null || SelectedAiTarget?.Entity?.Submarine != null &&

View File

@@ -312,8 +312,10 @@ namespace Barotrauma
Vector2 colliderBottom = character.AnimController.GetColliderBottom();
Vector2 colliderSize = collider.GetSize();
Vector2 velocity = collider.LinearVelocity;
// If the character is smaller than this, it fails to use the waypoint nodes, because they are always too high.
float minHeight = 1;
// Cannot use the head position, because not all characters have head or it can be below the total height of the character
float characterHeight = colliderSize.Y + character.AnimController.ColliderHeightFromFloor;
float characterHeight = Math.Max(colliderSize.Y + character.AnimController.ColliderHeightFromFloor, minHeight);
float horizontalDistance = Math.Abs(collider.SimPosition.X - currentPath.CurrentNode.SimPosition.X);
bool isAboveFeet = currentPath.CurrentNode.SimPosition.Y > colliderBottom.Y;
bool isNotTooHigh = currentPath.CurrentNode.SimPosition.Y < colliderBottom.Y + characterHeight;

View File

@@ -132,7 +132,9 @@ namespace Barotrauma
{
if (Frozen) return;
if (MainLimb == null) { return; }
levitatingCollider = true;
if (!character.AllowInput)
{
levitatingCollider = false;
@@ -542,8 +544,6 @@ namespace Barotrauma
//limbs are disabled when simple physics is enabled, no need to move them
if (SimplePhysicsEnabled) { return; }
float mainLimbHeight = ColliderHeightFromFloor;
Vector2 colliderBottom = GetColliderBottom();
float movementAngle = 0.0f;
@@ -569,9 +569,9 @@ namespace Barotrauma
Vector2 pos = colliderBottom + Vector2.UnitY * TorsoPosition.Value;
if (torso != MainLimb)
{
pos.X = torso.SimPosition.X;
else
mainLimbHeight = TorsoPosition.Value;
}
torso.MoveToPos(pos, TorsoMoveForce);
torso.PullJointEnabled = true;
@@ -591,9 +591,9 @@ namespace Barotrauma
Vector2 pos = colliderBottom + Vector2.UnitY * HeadPosition.Value;
if (head != MainLimb)
{
pos.X = head.SimPosition.X;
else
mainLimbHeight = HeadPosition.Value;
}
head.MoveToPos(pos, HeadMoveForce);
head.PullJointEnabled = true;

View File

@@ -1298,7 +1298,8 @@ namespace Barotrauma
Vector2 colliderPos = GetColliderBottom();
bool wasCritical = target.Vitality < 0.0f;
float prevVitality = target.Vitality;
bool wasCritical = prevVitality < 0.0f;
if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient) //Serverside code
{
@@ -1357,7 +1358,7 @@ namespace Barotrauma
AfflictionPrefab.InternalDamage.Instantiate((CPRSettings.DamageSkillThreshold - skill) * CPRSettings.DamageSkillMultiplier,
source: character)
},
0.0f, true, 0.0f, character);
0.0f, true, 0.0f, attacker: null);
}
if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient) //Serverside code
{
@@ -1389,9 +1390,12 @@ namespace Barotrauma
character.Info.IncreaseSkillLevel("medical", 0.5f, character.WorldPosition + Vector2.UnitY * 150.0f);
SteamAchievementManager.OnCharacterRevived(target, character);
lastReviveTime = (float)Timing.TotalTime;
#if SERVER
GameMain.Server?.KarmaManager?.OnCharacterHealthChanged(target, character, damage: Math.Min(prevVitality - target.Vitality, 0.0f));
#endif
//reset attacker, we don't want the character to start attacking us
//because we caused a bit of damage to them during CPR
if (target.LastAttacker == character) target.LastAttacker = null;
if (target.LastAttacker == character) { target.LastAttacker = null; }
}
}
}

View File

@@ -1,150 +0,0 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace Barotrauma
{
partial class HumanoidAnimParams : ISerializableEntity
{
public string Name
{
get;
private set;
}
public Dictionary<string, SerializableProperty> SerializableProperties
{
get;
private set;
}
public HumanoidAnimParams(string file)
{
XDocument doc = XMLExtensions.TryLoadXml(file);
if (doc == null || doc.Root == null) return;
Name = doc.Root.Name.ToString();
SerializableProperties = SerializableProperty.DeserializeProperties(this, doc.Root);
}
[Serialize(0.3f, true), Editable]
public float GetUpSpeed
{
get;
set;
}
[Serialize(1.54f, true), Editable]
public float HeadPosition
{
get;
set;
}
[Serialize(1.15f, true), Editable]
public float TorsoPosition
{
get;
set;
}
[Serialize(0.25f, true), Editable]
public float HeadLeanAmount
{
get;
set;
}
[Serialize(0.25f, true), Editable]
public float TorsoLeanAmount
{
get;
set;
}
[Serialize(5.0f, true), Editable]
public float CycleSpeed
{
get;
set;
}
[Serialize(15.0f, true), Editable]
public float FootMoveStrength
{
get;
set;
}
[Serialize(20.0f, true), Editable]
public float FootRotateStrength
{
get;
set;
}
[Serialize("0.4,0.12", true), Editable]
public Vector2 StepSize
{
get;
set;
}
[Serialize("0.0, 0.0", true), Editable]
public Vector2 FootMoveOffset
{
get;
set;
}
[Serialize(10.0f, true), Editable]
public float LegCorrectionTorque
{
get;
set;
}
[Serialize(15.0f, true), Editable]
public float ThighCorrectionTorque
{
get;
set;
}
[Serialize("0.4, 0.15", true), Editable]
public Vector2 HandMoveAmount
{
get;
set;
}
[Serialize("-0.15, 0.0", true), Editable]
public Vector2 HandMoveOffset
{
get;
set;
}
[Serialize(0.7f, true), Editable]
public float HandMoveStrength
{
get;
set;
}
[Serialize(-1.0f, true), Editable]
public float HandClampY
{
get;
set;
}
}
}

View File

@@ -1252,7 +1252,7 @@ namespace Barotrauma
rayEnd.Y -= Collider.height * 0.5f + Collider.radius + ColliderHeightFromFloor*1.2f;
Vector2 colliderBottomDisplay = ConvertUnits.ToDisplayUnits(GetColliderBottom());
if (!inWater && !character.IsDead && character.Stun <= 0f && levitatingCollider && Collider.LinearVelocity.Y>-ImpactTolerance)
if (!inWater && !character.IsDead && character.Stun <= 0f && levitatingCollider && Collider.LinearVelocity.Y > -ImpactTolerance)
{
float closestFraction = 1.0f;
Fixture closestFixture = null;

View File

@@ -1484,6 +1484,9 @@ namespace Barotrauma
return (wall == null || !wall.CastShadow) && (door == null || door.IsOpen);
}
public bool HasItem(Item item, bool requireEquipped = false) =>
requireEquipped ? HasEquippedItem(item) : item.FindParentInventory(i => i.Owner == this) != null;
public bool HasEquippedItem(Item item)
{
for (int i = 0; i < Inventory.Capacity; i++)
@@ -1595,7 +1598,7 @@ namespace Barotrauma
#if CLIENT
if (Screen.Selected == GameMain.SubEditorScreen) { hidden = false; }
#endif
if (!CanInteract || hidden) return false;
if (!CanInteract || hidden || item.NonInteractable) return false;
if (item.ParentInventory != null)
{

View File

@@ -764,13 +764,13 @@ namespace Barotrauma
public void SetSkillLevel(string skillIdentifier, float level, Vector2 worldPos)
{
if (Job == null) return;
if (Job == null) { return; }
var skill = Job.Skills.Find(s => s.Identifier == skillIdentifier);
if (skill == null)
{
Job.Skills.Add(new Skill(skillIdentifier, level));
OnSkillChanged(skillIdentifier, 0.0f, skill.Level, worldPos);
OnSkillChanged(skillIdentifier, 0.0f, level, worldPos);
}
else
{

View File

@@ -1,141 +0,0 @@
using Microsoft.Xna.Framework;
using System;
using System.Linq;
namespace Barotrauma
{
class Affliction
{
public readonly AfflictionPrefab Prefab;
public float Strength;
public float DamagePerSecond;
public float DamagePerSecondTimer;
public float PreviousVitalityDecrease;
/// <summary>
/// Which character gave this affliction
/// </summary>
public Character Source;
public Affliction(AfflictionPrefab prefab, float strength)
{
Prefab = prefab;
Strength = strength;
}
public Affliction CreateMultiplied(float multiplier)
{
return Prefab.Instantiate(Strength * multiplier, Source);
}
public override string ToString()
{
return "Affliction (" + Prefab.Name + ")";
}
public float GetVitalityDecrease(CharacterHealth characterHealth)
{
if (Strength < Prefab.ActivationThreshold) return 0.0f;
AfflictionPrefab.Effect currentEffect = Prefab.GetActiveEffect(Strength);
if (currentEffect == null) return 0.0f;
if (currentEffect.MaxStrength - currentEffect.MinStrength <= 0.0f) return 0.0f;
float currVitalityDecrease = MathHelper.Lerp(
currentEffect.MinVitalityDecrease,
currentEffect.MaxVitalityDecrease,
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength));
if (currentEffect.MultiplyByMaxVitality) currVitalityDecrease *= characterHealth == null ? 100.0f : characterHealth.MaxVitality;
return currVitalityDecrease;
}
public float GetScreenDistortStrength()
{
if (Strength < Prefab.ActivationThreshold) return 0.0f;
AfflictionPrefab.Effect currentEffect = Prefab.GetActiveEffect(Strength);
if (currentEffect == null) return 0.0f;
if (currentEffect.MaxScreenDistortStrength - currentEffect.MinScreenDistortStrength <= 0.0f) return 0.0f;
return MathHelper.Lerp(
currentEffect.MinScreenDistortStrength,
currentEffect.MaxScreenDistortStrength,
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength));
}
public float GetRadialDistortStrength()
{
if (Strength < Prefab.ActivationThreshold) return 0.0f;
AfflictionPrefab.Effect currentEffect = Prefab.GetActiveEffect(Strength);
if (currentEffect == null) return 0.0f;
if (currentEffect.MaxRadialDistortStrength - currentEffect.MinRadialDistortStrength <= 0.0f) return 0.0f;
return MathHelper.Lerp(
currentEffect.MinRadialDistortStrength,
currentEffect.MaxRadialDistortStrength,
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength));
}
public float GetChromaticAberrationStrength()
{
if (Strength < Prefab.ActivationThreshold) return 0.0f;
AfflictionPrefab.Effect currentEffect = Prefab.GetActiveEffect(Strength);
if (currentEffect == null) return 0.0f;
if (currentEffect.MaxChromaticAberrationStrength - currentEffect.MinChromaticAberrationStrength <= 0.0f) return 0.0f;
return MathHelper.Lerp(
currentEffect.MinChromaticAberrationStrength,
currentEffect.MaxChromaticAberrationStrength,
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength));
}
public float GetScreenBlurStrength()
{
if (Strength < Prefab.ActivationThreshold) return 0.0f;
AfflictionPrefab.Effect currentEffect = Prefab.GetActiveEffect(Strength);
if (currentEffect == null) return 0.0f;
if (currentEffect.MaxScreenBlurStrength - currentEffect.MinScreenBlurStrength <= 0.0f) return 0.0f;
return MathHelper.Lerp(
currentEffect.MinScreenBlurStrength,
currentEffect.MaxScreenBlurStrength,
(Strength - currentEffect.MinStrength) / (currentEffect.MaxStrength - currentEffect.MinStrength));
}
public void CalculateDamagePerSecond(float currentVitalityDecrease)
{
DamagePerSecond = Math.Max(DamagePerSecond, currentVitalityDecrease - PreviousVitalityDecrease);
if (DamagePerSecondTimer >= 1.0f)
{
DamagePerSecond = currentVitalityDecrease - PreviousVitalityDecrease;
PreviousVitalityDecrease = currentVitalityDecrease;
DamagePerSecondTimer = 0.0f;
}
}
public virtual void Update(CharacterHealth characterHealth, Limb targetLimb, float deltaTime)
{
AfflictionPrefab.Effect currentEffect = Prefab.GetActiveEffect(Strength);
if (currentEffect == null) return;
Strength += currentEffect.StrengthChange * deltaTime;
foreach (StatusEffect statusEffect in currentEffect.StatusEffects)
{
if (statusEffect.HasTargetType(StatusEffect.TargetType.Character))
{
statusEffect.Apply(ActionType.OnActive, deltaTime, characterHealth.Character, characterHealth.Character);
}
if (targetLimb != null && statusEffect.HasTargetType(StatusEffect.TargetType.Limb))
{
statusEffect.Apply(ActionType.OnActive, deltaTime, characterHealth.Character, targetLimb);
}
if (targetLimb != null && statusEffect.HasTargetType(StatusEffect.TargetType.AllLimbs))
{
statusEffect.Apply(ActionType.OnActive, deltaTime, targetLimb.character, targetLimb.character.AnimController.Limbs.Cast<ISerializableEntity>().ToList());
}
}
}
}
}

View File

@@ -1,20 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Barotrauma
{
class AfflictionBleeding : Affliction
{
public AfflictionBleeding(AfflictionPrefab prefab, float strength) :
base(prefab, strength)
{
}
public override void Update(CharacterHealth characterHealth, Limb targetLimb, float deltaTime)
{
base.Update(characterHealth, targetLimb, deltaTime);
characterHealth.BloodlossAmount += Strength * (1.0f / 60.0f) * deltaTime;
}
}
}

View File

@@ -1,336 +0,0 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Xml.Linq;
namespace Barotrauma
{
public static class CPRSettings
{
public static float ReviveChancePerSkill { get; private set; }
public static float ReviveChanceExponent { get; private set; }
public static float ReviveChanceMin { get; private set; }
public static float ReviveChanceMax { get; private set; }
public static float StabilizationPerSkill { get; private set; }
public static float StabilizationMin { get; private set; }
public static float StabilizationMax { get; private set; }
public static float DamageSkillThreshold { get; private set; }
public static float DamageSkillMultiplier { get; private set; }
public static void Load(XElement element)
{
ReviveChancePerSkill = Math.Max(element.GetAttributeFloat("revivechanceperskill", 0.01f), 0.0f);
ReviveChanceExponent = Math.Max(element.GetAttributeFloat("revivechanceexponent", 2.0f), 0.0f);
ReviveChanceMin = MathHelper.Clamp(element.GetAttributeFloat("revivechancemin", 0.05f), 0.0f, 1.0f);
ReviveChanceMax = MathHelper.Clamp(element.GetAttributeFloat("revivechancemax", 0.9f), ReviveChanceMin, 1.0f);
StabilizationPerSkill = Math.Max(element.GetAttributeFloat("stabilizationperskill", 0.01f), 0.0f);
StabilizationMin = MathHelper.Max(element.GetAttributeFloat("stabilizationmin", 0.05f), 0.0f);
StabilizationMax = MathHelper.Max(element.GetAttributeFloat("stabilizationmax", 2.0f), StabilizationMin);
DamageSkillThreshold = MathHelper.Clamp(element.GetAttributeFloat("damageskillthreshold", 40.0f), 0.0f, 100.0f);
DamageSkillMultiplier = MathHelper.Clamp(element.GetAttributeFloat("damageskillmultiplier", 0.1f), 0.0f, 100.0f);
}
}
class AfflictionPrefab
{
public class Effect
{
//this effect is applied when the strength is within this range
public float MinStrength, MaxStrength;
public readonly float MinVitalityDecrease = 0.0f;
public readonly float MaxVitalityDecrease = 0.0f;
//how much the strength of the affliction changes per second
public readonly float StrengthChange = 0.0f;
public readonly bool MultiplyByMaxVitality;
public float MinScreenBlurStrength, MaxScreenBlurStrength;
public float MinScreenDistortStrength, MaxScreenDistortStrength;
public float MinRadialDistortStrength, MaxRadialDistortStrength;
public float MinChromaticAberrationStrength, MaxChromaticAberrationStrength;
public string DialogFlag;
//statuseffects applied on the character when the affliction is active
public readonly List<StatusEffect> StatusEffects = new List<StatusEffect>();
public Effect(XElement element, string parentDebugName)
{
MinStrength = element.GetAttributeFloat("minstrength", 0);
MaxStrength = element.GetAttributeFloat("maxstrength", 0);
MultiplyByMaxVitality = element.GetAttributeBool("multiplybymaxvitality", false);
MinVitalityDecrease = element.GetAttributeFloat("minvitalitydecrease", 0.0f);
MaxVitalityDecrease = element.GetAttributeFloat("maxvitalitydecrease", 0.0f);
MaxVitalityDecrease = Math.Max(MinVitalityDecrease, MaxVitalityDecrease);
MinScreenDistortStrength = element.GetAttributeFloat("minscreendistort", 0.0f);
MaxScreenDistortStrength = element.GetAttributeFloat("maxscreendistort", 0.0f);
MaxScreenDistortStrength = Math.Max(MinScreenDistortStrength, MaxScreenDistortStrength);
MinRadialDistortStrength = element.GetAttributeFloat("minradialdistort", 0.0f);
MaxRadialDistortStrength = element.GetAttributeFloat("maxradialdistort", 0.0f);
MaxRadialDistortStrength = Math.Max(MinRadialDistortStrength, MaxRadialDistortStrength);
MinChromaticAberrationStrength = element.GetAttributeFloat("minchromaticaberration", 0.0f);
MaxChromaticAberrationStrength = element.GetAttributeFloat("maxchromaticaberration", 0.0f);
MaxChromaticAberrationStrength = Math.Max(MinChromaticAberrationStrength, MaxChromaticAberrationStrength);
MinScreenBlurStrength = element.GetAttributeFloat("minscreenblur", 0.0f);
MaxScreenBlurStrength = element.GetAttributeFloat("maxscreenblur", 0.0f);
MaxScreenBlurStrength = Math.Max(MinScreenBlurStrength, MaxScreenBlurStrength);
DialogFlag = element.GetAttributeString("dialogflag", "");
StrengthChange = element.GetAttributeFloat("strengthchange", 0.0f);
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "statuseffect":
StatusEffects.Add(StatusEffect.Load(subElement, parentDebugName));
break;
}
}
}
}
public static AfflictionPrefab InternalDamage;
public static AfflictionPrefab Bleeding;
public static AfflictionPrefab Burn;
public static AfflictionPrefab OxygenLow;
public static AfflictionPrefab Bloodloss;
public static AfflictionPrefab Pressure;
public static AfflictionPrefab Stun;
public static AfflictionPrefab Husk;
public static List<AfflictionPrefab> List = new List<AfflictionPrefab>();
//Arbitrary string that is used to identify the type of the affliction.
//Afflictions with the same type stack up, and items may be configured to cure specific types of afflictions.
public readonly string AfflictionType;
//Does the affliction affect a specific limb or the whole character
public readonly bool LimbSpecific;
//If not a limb-specific affliction, which limb is the indicator shown on in the health menu
//(e.g. mental health problems on head, lack of oxygen on torso...)
public readonly LimbType IndicatorLimb;
public readonly string Identifier;
public readonly string Name, Description;
public readonly string CauseOfDeathDescription, SelfCauseOfDeathDescription;
//how high the strength has to be for the affliction to take affect
public readonly float ActivationThreshold = 0.0f;
//how high the strength has to be for the affliction icon to be shown in the UI
public readonly float ShowIconThreshold = 0.0f;
public readonly float MaxStrength = 100.0f;
public float BurnOverlayAlpha;
public float DamageOverlayAlpha;
//steam achievement given when the affliction is removed from the controlled character
public readonly string AchievementOnRemoved;
public readonly Sprite Icon;
public readonly Color IconColor;
private List<Effect> effects = new List<Effect>();
private Dictionary<string, float> treatmentSuitability = new Dictionary<string, float>();
private readonly string typeName;
private readonly ConstructorInfo constructor;
public Dictionary<string, float> TreatmentSuitability
{
get { return treatmentSuitability; }
}
public static void LoadAll(IEnumerable<string> filePaths)
{
foreach (string filePath in filePaths)
{
XDocument doc = XMLExtensions.TryLoadXml(filePath);
if (doc == null || doc.Root == null) continue;
foreach (XElement element in doc.Root.Elements())
{
switch (element.Name.ToString().ToLowerInvariant())
{
case "internaldamage":
List.Add(InternalDamage = new AfflictionPrefab(element, typeof(Affliction)));
break;
case "bleeding":
List.Add(Bleeding = new AfflictionPrefab(element, typeof(AfflictionBleeding)));
break;
case "burn":
List.Add(Burn = new AfflictionPrefab(element, typeof(Affliction)));
break;
case "oxygenlow":
List.Add(OxygenLow = new AfflictionPrefab(element, typeof(Affliction)));
break;
case "bloodloss":
List.Add(Bloodloss = new AfflictionPrefab(element, typeof(Affliction)));
break;
case "pressure":
List.Add(Pressure = new AfflictionPrefab(element, typeof(Affliction)));
break;
case "stun":
List.Add(Stun = new AfflictionPrefab(element, typeof(Affliction)));
break;
case "husk":
case "afflictionhusk":
List.Add(Husk = new AfflictionPrefab(element, typeof(AfflictionHusk)));
break;
case "cprsettings":
CPRSettings.Load(element);
break;
default:
List.Add(new AfflictionPrefab(element));
break;
}
}
}
if (InternalDamage == null) DebugConsole.ThrowError("Affliction \"Internal Damage\" not defined in the affliction prefabs.");
if (Bleeding == null) DebugConsole.ThrowError("Affliction \"Bleeding\" not defined in the affliction prefabs.");
if (Burn == null) DebugConsole.ThrowError("Affliction \"Burn\" not defined in the affliction prefabs.");
if (OxygenLow == null) DebugConsole.ThrowError("Affliction \"OxygenLow\" not defined in the affliction prefabs.");
if (Bloodloss == null) DebugConsole.ThrowError("Affliction \"Bloodloss\" not defined in the affliction prefabs.");
if (Pressure == null) DebugConsole.ThrowError("Affliction \"Pressure\" not defined in the affliction prefabs.");
if (Stun == null) DebugConsole.ThrowError("Affliction \"Stun\" not defined in the affliction prefabs.");
if (Husk == null) DebugConsole.ThrowError("Affliction \"Husk\" not defined in the affliction prefabs.");
}
public AfflictionPrefab(XElement element, Type type = null)
{
typeName = type == null ? element.Name.ToString() : type.Name;
Identifier = element.GetAttributeString("identifier", "");
AfflictionType = element.GetAttributeString("type", "");
Name = TextManager.Get("AfflictionName." + Identifier, true) ?? element.GetAttributeString("name", "");
Description = TextManager.Get("AfflictionDescription." + Identifier, true) ?? element.GetAttributeString("description", "");
LimbSpecific = element.GetAttributeBool("limbspecific", false);
if (!LimbSpecific)
{
string indicatorLimbName = element.GetAttributeString("indicatorlimb", "Torso");
if (!Enum.TryParse(indicatorLimbName, out IndicatorLimb))
{
DebugConsole.ThrowError("Error in affliction prefab " + Name + " - limb type \"" + indicatorLimbName + "\" not found.");
}
}
ActivationThreshold = element.GetAttributeFloat("activationthreshold", 0.0f);
ShowIconThreshold = element.GetAttributeFloat("showiconthreshold", ActivationThreshold);
MaxStrength = element.GetAttributeFloat("maxstrength", 100.0f);
DamageOverlayAlpha = element.GetAttributeFloat("damageoverlayalpha", 0.0f);
BurnOverlayAlpha = element.GetAttributeFloat("burnoverlayalpha", 0.0f);
CauseOfDeathDescription = TextManager.Get("AfflictionCauseOfDeath." + Identifier, true) ?? element.GetAttributeString("causeofdeathdescription", "");
SelfCauseOfDeathDescription = TextManager.Get("AfflictionCauseOfDeathSelf." + Identifier, true) ?? element.GetAttributeString("selfcauseofdeathdescription", "");
AchievementOnRemoved = element.GetAttributeString("achievementonremoved", "");
foreach (XElement subElement in element.Elements())
{
switch (subElement.Name.ToString().ToLowerInvariant())
{
case "icon":
Icon = new Sprite(subElement);
IconColor = subElement.GetAttributeColor("color", Color.White);
break;
case "effect":
effects.Add(new Effect(subElement, Name));
break;
}
}
try
{
if (type == null)
{
type = Type.GetType("Barotrauma." + typeName, true, true);
if (type == null)
{
DebugConsole.ThrowError("Could not find an affliction class of the type \"" + typeName + "\".");
return;
}
}
}
catch
{
DebugConsole.ThrowError("Could not find an affliction class of the type \"" + typeName + "\".");
return;
}
constructor = type.GetConstructor(new[] { typeof(AfflictionPrefab), typeof(float) });
}
public override string ToString()
{
return "AfflictionPrefab (" + Name + ")";
}
public Affliction Instantiate(float strength, Character source = null)
{
object instance = null;
try
{
instance = constructor.Invoke(new object[] { this, strength });
}
catch (Exception ex)
{
DebugConsole.ThrowError(ex.InnerException != null ? ex.InnerException.ToString() : ex.ToString());
}
Affliction affliction = instance as Affliction;
affliction.Source = source;
return affliction;
}
public Effect GetActiveEffect(float currentStrength)
{
foreach (Effect effect in effects)
{
if (currentStrength > effect.MinStrength && currentStrength <= effect.MaxStrength) return effect;
}
//if above the strength range of all effects, use the highest strength effect
Effect strongestEffect = null;
float largestStrength = currentStrength;
foreach (Effect effect in effects)
{
if (currentStrength > effect.MaxStrength &&
(strongestEffect == null || effect.MaxStrength > largestStrength))
{
strongestEffect = effect;
largestStrength = effect.MaxStrength;
}
}
return strongestEffect;
}
public float GetTreatmentSuitability(Item item)
{
if (item == null || !treatmentSuitability.ContainsKey(item.Prefab.Identifier.ToLowerInvariant()))
{
return 0.0f;
}
return treatmentSuitability[item.Prefab.Identifier.ToLowerInvariant()];
}
}
}

View File

@@ -1,27 +0,0 @@
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Barotrauma.Extensions;
using System.Xml.Linq;
using System;
namespace Barotrauma
{
partial class AfflictionPsychosis : Affliction
{
public AfflictionPsychosis(AfflictionPrefab prefab, float strength) : base(prefab, strength)
{
}
public override void Update(CharacterHealth characterHealth, Limb targetLimb, float deltaTime)
{
base.Update(characterHealth, targetLimb, deltaTime);
UpdateProjSpecific(characterHealth, targetLimb, deltaTime);
}
partial void UpdateProjSpecific(CharacterHealth characterHealth, Limb targetLimb, float deltaTime);
}
}

View File

@@ -739,7 +739,7 @@ namespace Barotrauma
msg.Write((byte)activeAfflictions.Count);
foreach (Affliction affliction in activeAfflictions)
{
msg.WriteRangedIntegerDeprecated(0, AfflictionPrefab.List.Count - 1, AfflictionPrefab.List.IndexOf(affliction.Prefab));
msg.WriteRangedInteger(AfflictionPrefab.List.IndexOf(affliction.Prefab), 0, AfflictionPrefab.List.Count - 1);
msg.WriteRangedSingle(
MathHelper.Clamp(affliction.Strength, 0.0f, affliction.Prefab.MaxStrength),
0.0f, affliction.Prefab.MaxStrength, 8);
@@ -758,8 +758,8 @@ namespace Barotrauma
msg.Write((byte)limbAfflictions.Count);
foreach (var limbAffliction in limbAfflictions)
{
msg.WriteRangedIntegerDeprecated(0, limbHealths.Count - 1, limbHealths.IndexOf(limbAffliction.First));
msg.WriteRangedIntegerDeprecated(0, AfflictionPrefab.List.Count - 1, AfflictionPrefab.List.IndexOf(limbAffliction.Second.Prefab));
msg.WriteRangedInteger(limbHealths.IndexOf(limbAffliction.First), 0, limbHealths.Count - 1);
msg.WriteRangedInteger(AfflictionPrefab.List.IndexOf(limbAffliction.Second.Prefab), 0, AfflictionPrefab.List.Count - 1);
msg.WriteRangedSingle(
MathHelper.Clamp(limbAffliction.Second.Strength, 0.0f, limbAffliction.Second.Prefab.MaxStrength),
0.0f, limbAffliction.Second.Prefab.MaxStrength, 8);

View File

@@ -90,6 +90,7 @@ namespace Barotrauma.Items.Components
item.body.FarseerBody.CollisionCategories = Physics.CollisionProjectile;
item.body.FarseerBody.CollidesWith = Physics.CollisionCharacter | Physics.CollisionWall;
item.body.FarseerBody.OnCollision += OnCollision;
item.body.FarseerBody.IsBullet = true;
if (!character.AnimController.InWater)
{
@@ -207,9 +208,9 @@ namespace Barotrauma.Items.Components
private void RestoreCollision()
{
item.body.FarseerBody.OnCollision -= OnCollision;
item.body.CollisionCategories = Physics.CollisionItem;
item.body.CollidesWith = Physics.CollisionWall;
item.body.FarseerBody.IsBullet = false;
}

View File

@@ -132,7 +132,7 @@ namespace Barotrauma.Items.Components
return false;
}
if (character.AnimController.InWater)
if (item.InWater)
{
if (UsableIn == UseEnvironment.Air)
{
@@ -160,7 +160,8 @@ namespace Barotrauma.Items.Components
}
else
{
rayStart = ConvertUnits.ToSimUnits(item.WorldPosition);
rayStart = Submarine.LastPickedPosition + Submarine.LastPickedNormal * 0.1f;
if (item.Submarine != null) { rayStart += item.Submarine.SimPosition; }
}
Vector2 rayEnd = rayStart +
@@ -201,12 +202,12 @@ namespace Barotrauma.Items.Components
Repair(rayStart - character.Submarine.SimPosition, rayEnd - character.Submarine.SimPosition, deltaTime, character, degreeOfSuccess, ignoredBodies);
}
UseProjSpecific(deltaTime);
UseProjSpecific(deltaTime, rayStart);
return true;
}
partial void UseProjSpecific(float deltaTime);
partial void UseProjSpecific(float deltaTime, Vector2 raystart);
private readonly HashSet<Character> hitCharacters = new HashSet<Character>();
private readonly List<FireSource> fireSourcesInRange = new List<FireSource>();

View File

@@ -1,4 +1,5 @@
using FarseerPhysics;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
@@ -19,7 +20,7 @@ namespace Barotrauma.Items.Components
}
}
partial class Controller : ItemComponent
partial class Controller : ItemComponent, IServerSerializable
{
//where the limbs of the user should be positioned when using the controller
private List<LimbPos> limbPositions;
@@ -270,17 +271,21 @@ namespace Barotrauma.Items.Components
{
if (IsToggle)
{
state = !state;
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
{
state = !state;
#if SERVER
item.CreateServerEvent(this);
#endif
}
}
else
{
item.SendSignal(0, "1", "signal_out", picker);
}
#if CLIENT
PlaySound(ActionType.OnUse, item.WorldPosition, picker);
#endif
return true;
}

View File

@@ -273,14 +273,18 @@ namespace Barotrauma.Items.Components
{
if (connection.Name == "set_rate")
{
float tempSpeed;
if (float.TryParse(signal, NumberStyles.Any, CultureInfo.InvariantCulture, out tempSpeed))
if (float.TryParse(signal, NumberStyles.Any, CultureInfo.InvariantCulture, out float tempSpeed))
{
if (!MathUtils.IsValid(tempSpeed)) return;
RechargeSpeed = MathHelper.Clamp(tempSpeed / 100.0f, 0.0f, 1.0f) * MaxRechargeSpeed;
if (!MathUtils.IsValid(tempSpeed)) { return; }
float rechargeRate = MathHelper.Clamp(tempSpeed / 100.0f, 0.0f, 1.0f);
RechargeSpeed = rechargeRate * MaxRechargeSpeed;
#if CLIENT
rechargeSpeedSlider.BarScroll = rechargeRate;
#endif
}
}
if (!connection.IsPower) return;
if (!connection.IsPower) { return; }
if (connection.Name == "power_in")
{

View File

@@ -146,6 +146,10 @@ namespace Barotrauma.Items.Components
currentFixerAction = FixActions.None;
#if SERVER
item.CreateServerEvent(this);
#endif
#if CLIENT
repairSoundChannel?.FadeOutAndDispose();
repairSoundChannel = null;
#endif
return true;
}
@@ -221,8 +225,8 @@ namespace Barotrauma.Items.Components
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; }
float successFactor = requiredSkills.Count == 0 ? 1.0f : 0.0f;
float successFactor = requiredSkills.Count == 0 ? 1.0f : DegreeOfSuccess(CurrentFixer, requiredSkills);
//item must have been below the repair threshold for the player to get an achievement or XP for repairing it
if (item.ConditionPercentage < ShowRepairUIThreshold)
{

View File

@@ -122,22 +122,7 @@ namespace Barotrauma.Items.Components
public override void Update(float deltaTime, Camera cam)
{
#if CLIENT
foreach (Wire wire in DisconnectedWires)
{
if (Rand.Range(0.0f, 500.0f) < 1.0f)
{
SoundPlayer.PlaySound("zap", item.WorldPosition, hullGuess: item.CurrentHull);
Vector2 baseVel = new Vector2(0.0f, -100.0f);
for (int i = 0; i < 5; i++)
{
var particle = GameMain.ParticleManager.CreateParticle("spark", item.WorldPosition,
baseVel + Rand.Vector(100.0f), 0.0f, item.CurrentHull);
if (particle != null) { particle.Size *= Rand.Range(0.5f, 1.0f); }
}
}
}
#endif
UpdateProjSpecific(deltaTime);
if (user == null || user.SelectedConstruction != item)
{
@@ -150,6 +135,8 @@ namespace Barotrauma.Items.Components
user.AnimController.UpdateUseItem(true, item.WorldPosition + new Vector2(0.0f, 100.0f) * (((float)Timing.TotalTime / 10.0f) % 0.1f));
}
partial void UpdateProjSpecific(float deltaTime);
public override bool Select(Character picker)
{
//attaching wires to items with a body is not allowed
@@ -260,8 +247,14 @@ namespace Barotrauma.Items.Components
}
}
}
#if CLIENT
rewireSoundChannel?.FadeOutAndDispose();
rewireSoundChannel = null;
#endif
}
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
{
foreach (Connection connection in Connections)

View File

@@ -160,6 +160,14 @@ namespace Barotrauma.Items.Components
item.AddTag("light");
}
#if CLIENT
public override void OnScaleChanged()
{
light.SpriteScale = Vector2.One * item.Scale;
light.Position = ParentBody != null ? ParentBody.Position : item.Position;
}
#endif
public override void OnItemLoaded()
{
base.OnItemLoaded();
@@ -175,7 +183,6 @@ namespace Barotrauma.Items.Components
UpdateOnActiveEffects(deltaTime);
#if CLIENT
light.SpriteScale = Vector2.One * item.Scale;
light.ParentSub = item.Submarine;
if (item.Container != null)
{

View File

@@ -336,30 +336,39 @@ namespace Barotrauma
}
}
public Item FindItemByTag(string tag)
public Item FindItem(Func<Item, bool> predicate, bool recursive)
{
if (tag == null) return null;
return Items.FirstOrDefault(i => i != null && i.HasTag(tag));
Item match = Items.FirstOrDefault(predicate);
if (match == null && recursive)
{
foreach (var item in Items)
{
if (item == null) { continue; }
if (item.OwnInventory != null)
{
match = item.OwnInventory.FindItem(predicate, true);
if (match != null)
{
return match;
}
}
}
}
return match;
}
public Item FindItemByIdentifier(string identifier)
public Item FindItemByTag(string tag, bool recursive = false)
{
if (tag == null) { return null; }
return FindItem(i => i != null && i.HasTag(tag), recursive);
}
public Item FindItemByIdentifier(string identifier, bool recursive = false)
{
if (identifier == null) return null;
return Items.FirstOrDefault(i => i != null && i.Prefab.Identifier == identifier);
return FindItem(i => i != null && i.Prefab.Identifier == identifier, recursive);
}
/*public Item FindItem(string[] itemNames)
{
if (itemNames == null) return null;
foreach (string itemName in itemNames)
{
var item = FindItem(itemName);
if (item != null) return item;
}
return null;
}*/
public virtual void RemoveItem(Item item)
{
if (item == null) return;
@@ -376,6 +385,7 @@ namespace Barotrauma
public void SharedWrite(IWriteMessage msg, object[] extraData = null)
{
msg.Write((byte)capacity);
for (int i = 0; i < capacity; i++)
{
msg.Write((ushort)(Items[i] == null ? 0 : Items[i].ID));

View File

@@ -126,24 +126,6 @@ namespace Barotrauma
}
}
public delegate bool InventoryFilter(Inventory inventory);
public Inventory FindParentInventory(InventoryFilter filter)
{
if (parentInventory != null)
{
if (filter(parentInventory))
{
return parentInventory;
}
var owner = parentInventory.Owner as Item;
if (owner != null)
{
return owner.FindParentInventory(filter);
}
}
return null;
}
private Item container;
public Item Container
{
@@ -177,6 +159,13 @@ namespace Barotrauma
set;
}
[Editable, Serialize(false, true)]
public bool NonInteractable
{
get;
set;
}
public float ImpactTolerance
{
get { return Prefab.ImpactTolerance; }
@@ -398,6 +387,7 @@ namespace Barotrauma
}
else if (!MathUtils.NearlyEqual(lastSentCondition, condition) && (condition <= 0.0f || condition >= Prefab.Health))
{
sendConditionUpdateTimer = 0.0f;
conditionUpdatePending = true;
}
}
@@ -955,7 +945,6 @@ namespace Barotrauma
return CurrentHull;
}
CurrentHull = Hull.FindHull(WorldPosition, CurrentHull);
if (body != null && body.Enabled)
{
@@ -978,7 +967,23 @@ namespace Barotrauma
return rootContainer;
}
public Inventory FindParentInventory(Func<Inventory, bool> predicate)
{
if (parentInventory != null)
{
if (predicate(parentInventory))
{
return parentInventory;
}
if (parentInventory.Owner is Item owner)
{
return owner.FindParentInventory(predicate);
}
}
return null;
}
public void SetContainedItemPositions()
{
foreach (ItemComponent component in components)
@@ -1137,6 +1142,17 @@ namespace Barotrauma
return CurrentHull.WaterVolume > 0.0f && Position.Y < surfaceY;
}
public void SendPendingNetworkUpdates()
{
if (GameMain.NetworkMember == null || !GameMain.NetworkMember.IsServer) { return; }
if (conditionUpdatePending)
{
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.Status });
lastSentCondition = condition;
sendConditionUpdateTimer = NetConfig.ItemConditionUpdateInterval;
conditionUpdatePending = false;
}
}
public override void Update(float deltaTime, Camera cam)
{
@@ -1153,16 +1169,10 @@ namespace Barotrauma
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
{
sendConditionUpdateTimer -= deltaTime;
if (conditionUpdatePending)
if (conditionUpdatePending && sendConditionUpdateTimer <= 0.0f)
{
if (sendConditionUpdateTimer <= 0.0f)
{
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.Status });
lastSentCondition = condition;
sendConditionUpdateTimer = NetConfig.ItemConditionUpdateInterval;
conditionUpdatePending = false;
}
}
SendPendingNetworkUpdates();
}
}
ApplyStatusEffects(ActionType.Always, deltaTime, null);
@@ -1878,7 +1888,7 @@ namespace Barotrauma
var propertyOwner = allProperties.Find(p => p.Second == property);
if (allProperties.Count > 1)
{
msg.WriteRangedIntegerDeprecated(0, allProperties.Count - 1, allProperties.FindIndex(p => p.Second == property));
msg.WriteRangedInteger(allProperties.FindIndex(p => p.Second == property), 0, allProperties.Count - 1);
}
object value = property.GetValue(propertyOwner.First);
@@ -2141,7 +2151,8 @@ namespace Barotrauma
if (element.GetAttributeBool("flippedx", false)) item.FlipX(false);
if (element.GetAttributeBool("flippedy", false)) item.FlipY(false);
item.condition = element.GetAttributeFloat("condition", item.Prefab.Health);
float condition = element.GetAttributeFloat("condition", item.MaxCondition);
item.condition = MathHelper.Clamp(condition, 0, item.MaxCondition);
item.lastSentCondition = item.condition;
item.SetActiveSprite();

View File

@@ -1,6 +1,7 @@
using Barotrauma.Items.Components;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
namespace Barotrauma
@@ -92,10 +93,10 @@ namespace Barotrauma
{
if (!Item.ItemList.Contains(container.Item))
{
string errorMsg = "Attempted to create a network event for an item (" + container.Item.Name + ") that hasn't been fully initialized yet.";
string errorMsg = "Attempted to create a network event for an item (" + container.Item.Name + ") that hasn't been fully initialized yet.\n" + Environment.StackTrace;
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce(
"ItemInventory.CreateServerEvent:EventForUninitializedItem" + container.Item.Name + container.Item.ID,
"ItemInventory.CreateServerEvent:EventForUninitializedItem" + container.Item.Name + container.Item.ID,
GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
return;
}

View File

@@ -12,10 +12,7 @@ namespace Barotrauma
{
private readonly XElement configElement;
private readonly string configPath;
[Serialize(false, false)]
public bool HideInMenus { get; set; }
public List<Pair<MapEntityPrefab, Rectangle>> DisplayEntities
{
get;

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