5202af9...3ea33fb
This commit is contained in:
+1
-1
@@ -13,7 +13,7 @@ bld/
|
|||||||
[Rr]elease*/
|
[Rr]elease*/
|
||||||
|
|
||||||
# Barotrauma content folder
|
# Barotrauma content folder
|
||||||
Content/
|
BarotraumaShared/Content/
|
||||||
|
|
||||||
*.v12.suo
|
*.v12.suo
|
||||||
*.suo
|
*.suo
|
||||||
|
|||||||
Binary file not shown.
@@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
|
|||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("0.8.9.4")]
|
[assembly: AssemblyVersion("0.8.9.5")]
|
||||||
[assembly: AssemblyFileVersion("0.8.9.4")]
|
[assembly: AssemblyFileVersion("0.8.9.5")]
|
||||||
|
|||||||
@@ -1051,6 +1051,102 @@ namespace Barotrauma
|
|||||||
NPCConversation.WriteToCSV();
|
NPCConversation.WriteToCSV();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
commands.Add(new Command("loadtexts", "loadtexts [sourcefile] [destinationfile]: Loads all lines of text from a given .txt file and inserts them sequientially into the elements of an xml file. If the file paths are omitted, EnglishVanilla.txt and EnglishVanilla.xml are used.", (string[] args) =>
|
||||||
|
{
|
||||||
|
string sourcePath = args.Length > 0 ? args[0] : "Content/Texts/EnglishVanilla.txt";
|
||||||
|
string destinationPath = args.Length > 1 ? args[1] : "Content/Texts/EnglishVanilla.xml";
|
||||||
|
|
||||||
|
string[] lines;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lines = File.ReadAllLines(sourcePath);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
ThrowError("Reading the file \"" + sourcePath + "\" failed.", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var doc = XMLExtensions.TryLoadXml(destinationPath);
|
||||||
|
int i = 0;
|
||||||
|
foreach (XElement element in doc.Root.Elements())
|
||||||
|
{
|
||||||
|
if (i >= lines.Length)
|
||||||
|
{
|
||||||
|
ThrowError("Error while loading texts to the xml file. The xml has more elements than the number of lines in the text file.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
element.Value = lines[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
doc.Save(destinationPath);
|
||||||
|
},
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
var files = TextManager.GetTextFiles().Select(f => f.Replace("\\", "/"));
|
||||||
|
return new string[][]
|
||||||
|
{
|
||||||
|
files.Where(f => Path.GetExtension(f)==".txt").ToArray(),
|
||||||
|
files.Where(f => Path.GetExtension(f)==".xml").ToArray()
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
|
commands.Add(new Command("updatetextfile", "updatetextfile [sourcefile] [destinationfile]: Inserts all the xml elements that are only present in the source file into the destination file. Can be used to update outdated translation files more easily.", (string[] args) =>
|
||||||
|
{
|
||||||
|
if (args.Length < 2) return;
|
||||||
|
string sourcePath = args[0];
|
||||||
|
string destinationPath = args[1];
|
||||||
|
|
||||||
|
var sourceDoc = XMLExtensions.TryLoadXml(sourcePath);
|
||||||
|
var destinationDoc = XMLExtensions.TryLoadXml(destinationPath);
|
||||||
|
|
||||||
|
XElement destinationElement = destinationDoc.Root.Elements().First();
|
||||||
|
foreach (XElement element in sourceDoc.Root.Elements())
|
||||||
|
{
|
||||||
|
if (destinationDoc.Root.Element(element.Name) == null)
|
||||||
|
{
|
||||||
|
element.Value = "!!!!!!!!!!!!!" + element.Value;
|
||||||
|
destinationElement.AddAfterSelf(element);
|
||||||
|
}
|
||||||
|
XNode nextNode = destinationElement.NextNode;
|
||||||
|
while ((!(nextNode is XElement) || nextNode == element) && nextNode != null) nextNode = nextNode.NextNode;
|
||||||
|
destinationElement = nextNode as XElement;
|
||||||
|
}
|
||||||
|
destinationDoc.Save(destinationPath);
|
||||||
|
},
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
var files = TextManager.GetTextFiles().Where(f => Path.GetExtension(f) == ".xml").Select(f => f.Replace("\\", "/")).ToArray();
|
||||||
|
return new string[][]
|
||||||
|
{
|
||||||
|
files,
|
||||||
|
files
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
|
commands.Add(new Command("dumpentitytexts", "dumpentitytexts [filepath]: gets the names and descriptions of all entity prefabs and writes them into a file along with xml tags that can be used in translation files. If the filepath is omitted, the file is written to Content/Texts/EntityTexts.txt", (string[] args) =>
|
||||||
|
{
|
||||||
|
string filePath = args.Length > 0 ? args[0] : "Content/Texts/EntityTexts.txt";
|
||||||
|
List<string> lines = new List<string>();
|
||||||
|
foreach (MapEntityPrefab me in MapEntityPrefab.List)
|
||||||
|
{
|
||||||
|
lines.Add("<EntityName." + me.Identifier + ">" + me.Name + "</" + me.Identifier + ".Name>");
|
||||||
|
lines.Add("<EntityDescription." + me.Identifier + ">" + me.Description + "</" + me.Identifier + ".Description>");
|
||||||
|
}
|
||||||
|
File.WriteAllLines(filePath, lines);
|
||||||
|
}));
|
||||||
|
#if DEBUG
|
||||||
|
commands.Add(new Command("checkduplicates", "Checks the given language for duplicate translation keys and writes to file.", (string[] args) =>
|
||||||
|
{
|
||||||
|
if (args.Length != 1) return;
|
||||||
|
TextManager.CheckForDuplicates(args[0]);
|
||||||
|
}));
|
||||||
|
|
||||||
|
commands.Add(new Command("writetocsv", "Writes the default language (English) to a .csv file.", (string[] args) =>
|
||||||
|
{
|
||||||
|
TextManager.WriteToCSV();
|
||||||
|
NPCConversation.WriteToCSV();
|
||||||
|
}));
|
||||||
|
|
||||||
commands.Add(new Command("camerasettings", "camerasettings [defaultzoom] [zoomsmoothness] [movesmoothness] [minzoom] [maxzoom]: debug command for testing camera settings. The values default to 1.1, 8.0, 8.0, 0.1 and 2.0.", (string[] args) =>
|
commands.Add(new Command("camerasettings", "camerasettings [defaultzoom] [zoomsmoothness] [movesmoothness] [minzoom] [maxzoom]: debug command for testing camera settings. The values default to 1.1, 8.0, 8.0, 0.1 and 2.0.", (string[] args) =>
|
||||||
{
|
{
|
||||||
float defaultZoom = Screen.Selected.Cam.DefaultZoom;
|
float defaultZoom = Screen.Selected.Cam.DefaultZoom;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace Barotrauma
|
|||||||
class ChatBox
|
class ChatBox
|
||||||
{
|
{
|
||||||
private static Sprite radioIcon;
|
private static Sprite radioIcon;
|
||||||
|
|
||||||
private GUIFrame guiFrame;
|
private GUIFrame guiFrame;
|
||||||
|
|
||||||
private GUIListBox chatBox;
|
private GUIListBox chatBox;
|
||||||
@@ -25,7 +25,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private bool isSinglePlayer;
|
private bool isSinglePlayer;
|
||||||
public bool IsSinglePlayer => isSinglePlayer;
|
public bool IsSinglePlayer => isSinglePlayer;
|
||||||
|
|
||||||
private bool toggleOpen = true;
|
private bool toggleOpen = true;
|
||||||
private float openState;
|
private float openState;
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ namespace Barotrauma
|
|||||||
chatBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.9f), guiFrame.RectTransform), style: "ChatBox");
|
chatBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.9f), guiFrame.RectTransform), style: "ChatBox");
|
||||||
toggleButton = new GUIButton(new RectTransform(new Point(toggleButtonWidth, HUDLayoutSettings.ChatBoxArea.Height), parent.RectTransform),
|
toggleButton = new GUIButton(new RectTransform(new Point(toggleButtonWidth, HUDLayoutSettings.ChatBoxArea.Height), parent.RectTransform),
|
||||||
style: "UIToggleButton");
|
style: "UIToggleButton");
|
||||||
|
|
||||||
toggleButton.OnClicked += (GUIButton btn, object userdata) =>
|
toggleButton.OnClicked += (GUIButton btn, object userdata) =>
|
||||||
{
|
{
|
||||||
toggleOpen = !toggleOpen;
|
toggleOpen = !toggleOpen;
|
||||||
@@ -89,13 +89,17 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
inputBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.1f), guiFrame.RectTransform, Anchor.BottomCenter),
|
inputBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.1f), guiFrame.RectTransform, Anchor.BottomCenter),
|
||||||
style: "ChatTextBox")
|
style: "ChatTextBox")
|
||||||
{
|
{
|
||||||
Font = GUI.SmallFont,
|
Font = GUI.SmallFont,
|
||||||
MaxTextLength = ChatMessage.MaxLength
|
MaxTextLength = ChatMessage.MaxLength
|
||||||
};
|
};
|
||||||
|
inputBox.OnDeselected += (gui, Keys) =>
|
||||||
|
{
|
||||||
|
gui.Text = "";
|
||||||
|
};
|
||||||
|
|
||||||
radioButton = new GUIButton(new RectTransform(new Vector2(0.1f, 2.0f), inputBox.RectTransform,
|
radioButton = new GUIButton(new RectTransform(new Vector2(0.1f, 2.0f), inputBox.RectTransform,
|
||||||
HUDLayoutSettings.ChatBoxAlignment == Alignment.Right ? Anchor.BottomRight : Anchor.BottomLeft,
|
HUDLayoutSettings.ChatBoxAlignment == Alignment.Right ? Anchor.BottomRight : Anchor.BottomLeft,
|
||||||
@@ -132,7 +136,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
command = "";
|
command = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (command)
|
switch (command)
|
||||||
{
|
{
|
||||||
@@ -169,7 +173,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
chatBox.RemoveChild(chatBox.Content.Children.First());
|
chatBox.RemoveChild(chatBox.Content.Children.First());
|
||||||
}
|
}
|
||||||
|
|
||||||
float prevSize = chatBox.BarSize;
|
float prevSize = chatBox.BarSize;
|
||||||
|
|
||||||
string displayedText = message.TranslatedText;
|
string displayedText = message.TranslatedText;
|
||||||
@@ -202,8 +206,8 @@ namespace Barotrauma
|
|||||||
CanBeFocused = true
|
CanBeFocused = true
|
||||||
};
|
};
|
||||||
|
|
||||||
if (message is OrderChatMessage orderChatMsg &&
|
if (message is OrderChatMessage orderChatMsg &&
|
||||||
Character.Controlled != null &&
|
Character.Controlled != null &&
|
||||||
orderChatMsg.TargetCharacter == Character.Controlled)
|
orderChatMsg.TargetCharacter == Character.Controlled)
|
||||||
{
|
{
|
||||||
msgHolder.Flash(Color.OrangeRed * 0.6f, flashDuration: 5.0f);
|
msgHolder.Flash(Color.OrangeRed * 0.6f, flashDuration: 5.0f);
|
||||||
@@ -237,7 +241,7 @@ namespace Barotrauma
|
|||||||
CanBeFocused = false
|
CanBeFocused = false
|
||||||
};
|
};
|
||||||
int textWidth = (int)Math.Max(
|
int textWidth = (int)Math.Max(
|
||||||
msgText.Font.MeasureString(msgText.WrappedText).X,
|
msgText.Font.MeasureString(msgText.WrappedText).X,
|
||||||
senderText.Font.MeasureString(senderText.WrappedText).X);
|
senderText.Font.MeasureString(senderText.WrappedText).X);
|
||||||
popupMsg.RectTransform.Resize(new Point(textWidth + 20, msgText.Rect.Bottom - senderText.Rect.Y), resizeChildren: false);
|
popupMsg.RectTransform.Resize(new Point(textWidth + 20, msgText.Rect.Bottom - senderText.Rect.Y), resizeChildren: false);
|
||||||
popupMessages.Enqueue(popupMsg);
|
popupMessages.Enqueue(popupMsg);
|
||||||
@@ -265,7 +269,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
timer += CoroutineManager.DeltaTime;
|
timer += CoroutineManager.DeltaTime;
|
||||||
float wavePhase = timer / animDuration * MathHelper.TwoPi;
|
float wavePhase = timer / animDuration * MathHelper.TwoPi;
|
||||||
message.RectTransform.ScreenSpaceOffset =
|
message.RectTransform.ScreenSpaceOffset =
|
||||||
new Point((int)(Math.Sin(wavePhase) * (1.0f - timer / animDuration) * 50.0f), 0);
|
new Point((int)(Math.Sin(wavePhase) * (1.0f - timer / animDuration) * 50.0f), 0);
|
||||||
yield return CoroutineStatus.Running;
|
yield return CoroutineStatus.Running;
|
||||||
}
|
}
|
||||||
@@ -294,7 +298,7 @@ namespace Barotrauma
|
|||||||
new Point(HUDLayoutSettings.ChatBoxArea.X, HUDLayoutSettings.ChatBoxArea.Y) :
|
new Point(HUDLayoutSettings.ChatBoxArea.X, HUDLayoutSettings.ChatBoxArea.Y) :
|
||||||
new Point(HUDLayoutSettings.ChatBoxArea.Right - toggleButtonWidth, HUDLayoutSettings.ChatBoxArea.Y);
|
new Point(HUDLayoutSettings.ChatBoxArea.Right - toggleButtonWidth, HUDLayoutSettings.ChatBoxArea.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(float deltaTime)
|
public void Update(float deltaTime)
|
||||||
{
|
{
|
||||||
if (GameMain.GraphicsWidth != screenResolution.X || GameMain.GraphicsHeight != screenResolution.Y || prevUIScale != GUI.Scale)
|
if (GameMain.GraphicsWidth != screenResolution.X || GameMain.GraphicsHeight != screenResolution.Y || prevUIScale != GUI.Scale)
|
||||||
@@ -305,7 +309,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (toggleOpen || (inputBox != null && inputBox.Selected))
|
if (toggleOpen || (inputBox != null && inputBox.Selected))
|
||||||
{
|
{
|
||||||
openState += deltaTime * 5.0f;
|
openState += deltaTime * 5.0f;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
@@ -24,6 +25,14 @@ namespace Barotrauma
|
|||||||
get { return barSize; }
|
get { return barSize; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
if (!MathUtils.IsValid(value))
|
||||||
|
{
|
||||||
|
GameAnalyticsManager.AddErrorEventOnce(
|
||||||
|
"GUIProgressBar.BarSize_setter",
|
||||||
|
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||||
|
"Attempted to set the BarSize of a GUIProgressBar to an invalid value (" + value + ")\n" + Environment.StackTrace);
|
||||||
|
return;
|
||||||
|
}
|
||||||
barSize = MathHelper.Clamp(value, 0.0f, 1.0f);
|
barSize = MathHelper.Clamp(value, 0.0f, 1.0f);
|
||||||
//UpdateRect();
|
//UpdateRect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ namespace Barotrauma
|
|||||||
private List<Character> characters = new List<Character>();
|
private List<Character> characters = new List<Character>();
|
||||||
|
|
||||||
private Point screenResolution;
|
private Point screenResolution;
|
||||||
|
|
||||||
#region UI
|
#region UI
|
||||||
|
|
||||||
private GUIFrame guiFrame;
|
private GUIFrame guiFrame;
|
||||||
@@ -61,9 +61,34 @@ namespace Barotrauma
|
|||||||
public CrewManager(XElement element, bool isSinglePlayer)
|
public CrewManager(XElement element, bool isSinglePlayer)
|
||||||
: this(isSinglePlayer)
|
: this(isSinglePlayer)
|
||||||
{
|
{
|
||||||
foreach (XElement subElement in element.Elements())
|
return characterListBox.Rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void InitProjectSpecific()
|
||||||
|
{
|
||||||
|
guiFrame = new GUIFrame(new RectTransform(Vector2.One, GUICanvas.Instance), null, Color.Transparent)
|
||||||
{
|
{
|
||||||
if (subElement.Name.ToString().ToLowerInvariant() != "character") continue;
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
|
||||||
|
Point scrollButtonSize = new Point((int)(200 * GUI.Scale), (int)(30 * GUI.Scale));
|
||||||
|
|
||||||
|
crewArea = new GUIFrame(HUDLayoutSettings.ToRectTransform(HUDLayoutSettings.CrewArea, guiFrame.RectTransform), "", Color.Transparent)
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
toggleCrewButton = new GUIButton(new RectTransform(new Point((int)(30 * GUI.Scale), HUDLayoutSettings.CrewArea.Height), guiFrame.RectTransform)
|
||||||
|
{ AbsoluteOffset = HUDLayoutSettings.CrewArea.Location },
|
||||||
|
"", style: "UIToggleButton");
|
||||||
|
toggleCrewButton.OnClicked += (GUIButton btn, object userdata) =>
|
||||||
|
{
|
||||||
|
toggleCrewAreaOpen = !toggleCrewAreaOpen;
|
||||||
|
foreach (GUIComponent child in btn.Children)
|
||||||
|
{
|
||||||
|
child.SpriteEffects = toggleCrewAreaOpen ? SpriteEffects.None : SpriteEffects.FlipHorizontally;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
var characterInfo = new CharacterInfo(subElement);
|
var characterInfo = new CharacterInfo(subElement);
|
||||||
characterInfos.Add(characterInfo);
|
characterInfos.Add(characterInfo);
|
||||||
@@ -75,21 +100,54 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var reports = Order.PrefabList.FindAll(o => o.TargetAllCharacters && o.SymbolSprite != null);
|
||||||
|
reportButtonFrame = new GUILayoutGroup(new RectTransform(
|
||||||
|
new Point((HUDLayoutSettings.CrewArea.Height - (int)((reports.Count - 1) * 5 * GUI.Scale)) / reports.Count, HUDLayoutSettings.CrewArea.Height), guiFrame.RectTransform))
|
||||||
|
{
|
||||||
|
AbsoluteSpacing = (int)(5 * GUI.Scale),
|
||||||
|
UserData = "reportbuttons",
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
|
||||||
|
//report buttons
|
||||||
|
foreach (Order order in reports)
|
||||||
|
{
|
||||||
|
if (!order.TargetAllCharacters || order.SymbolSprite == null) continue;
|
||||||
|
var btn = new GUIButton(new RectTransform(new Point(reportButtonFrame.Rect.Width), reportButtonFrame.RectTransform), style: null)
|
||||||
|
{
|
||||||
|
OnClicked = (GUIButton button, object userData) =>
|
||||||
|
{
|
||||||
|
if (Character.Controlled == null || Character.Controlled.SpeechImpediment >= 100.0f) return false;
|
||||||
|
SetCharacterOrder(null, order, null, Character.Controlled);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
UserData = order,
|
||||||
|
ToolTip = order.Name
|
||||||
|
};
|
||||||
|
|
||||||
|
new GUIFrame(new RectTransform(new Vector2(1.5f), btn.RectTransform, Anchor.Center), "OuterGlow")
|
||||||
|
{
|
||||||
|
Color = Color.Red * 0.8f,
|
||||||
|
HoverColor = Color.Red * 1.0f,
|
||||||
|
PressedColor = Color.Red * 0.6f,
|
||||||
|
UserData = "highlighted",
|
||||||
|
CanBeFocused = false,
|
||||||
|
Visible = false
|
||||||
|
};
|
||||||
|
|
||||||
|
var img = new GUIImage(new RectTransform(Vector2.One, btn.RectTransform), order.Prefab.SymbolSprite, scaleToFit: true)
|
||||||
|
{
|
||||||
|
Color = order.Color,
|
||||||
|
HoverColor = Color.Lerp(order.Color, Color.White, 0.5f),
|
||||||
|
ToolTip = order.Name
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
screenResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
screenResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||||
|
|
||||||
prevUIScale = GUI.Scale;
|
prevUIScale = GUI.Scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Character list management
|
|
||||||
|
|
||||||
public Rectangle GetCharacterListArea()
|
|
||||||
{
|
|
||||||
return characterListBox.Rect;
|
|
||||||
}
|
|
||||||
|
|
||||||
partial void InitProjectSpecific()
|
partial void InitProjectSpecific()
|
||||||
{
|
{
|
||||||
guiFrame = new GUIFrame(new RectTransform(Vector2.One, GUICanvas.Instance), null, Color.Transparent)
|
guiFrame = new GUIFrame(new RectTransform(Vector2.One, GUICanvas.Instance), null, Color.Transparent)
|
||||||
@@ -167,10 +225,7 @@ namespace Barotrauma
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
chatBox.InputBox.OnDeselected += (gui, Keys) =>
|
|
||||||
{
|
|
||||||
this.chatBox.InputBox.Text = "";
|
|
||||||
};
|
|
||||||
chatBox.InputBox.OnTextChanged += chatBox.TypingChatMessage;
|
chatBox.InputBox.OnTextChanged += chatBox.TypingChatMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,6 +338,7 @@ namespace Barotrauma
|
|||||||
DebugConsole.ThrowError("Tried to add the same character info to CrewManager twice.\n" + Environment.StackTrace);
|
DebugConsole.ThrowError("Tried to add the same character info to CrewManager twice.\n" + Environment.StackTrace);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
characterInfos.Add(characterInfo);
|
characterInfos.Add(characterInfo);
|
||||||
}
|
}
|
||||||
@@ -371,7 +427,7 @@ namespace Barotrauma
|
|||||||
frame.Color = character.Info.Job.Prefab.UIColor;
|
frame.Color = character.Info.Job.Prefab.UIColor;
|
||||||
frame.SelectedColor = Color.Lerp(frame.Color, Color.White, 0.5f);
|
frame.SelectedColor = Color.Lerp(frame.Color, Color.White, 0.5f);
|
||||||
frame.HoverColor = Color.Lerp(frame.Color, Color.White, 0.9f);
|
frame.HoverColor = Color.Lerp(frame.Color, Color.White, 0.9f);
|
||||||
|
|
||||||
new GUIFrame(new RectTransform(new Point(characterInfoWidth, (int)(frame.Rect.Height * 1.3f)), frame.RectTransform, Anchor.CenterLeft), style: "OuterGlow")
|
new GUIFrame(new RectTransform(new Point(characterInfoWidth, (int)(frame.Rect.Height * 1.3f)), frame.RectTransform, Anchor.CenterLeft), style: "OuterGlow")
|
||||||
{
|
{
|
||||||
UserData = "highlight",
|
UserData = "highlight",
|
||||||
@@ -396,7 +452,7 @@ namespace Barotrauma
|
|||||||
HoverColor = frame.HoverColor,
|
HoverColor = frame.HoverColor,
|
||||||
ToolTip = characterToolTip
|
ToolTip = characterToolTip
|
||||||
};
|
};
|
||||||
|
|
||||||
var soundIcon = new GUIImage(new RectTransform(new Point((int)(characterArea.Rect.Height * 0.5f)), characterArea.RectTransform, Anchor.CenterRight) { AbsoluteOffset = new Point(5, 0) },
|
var soundIcon = new GUIImage(new RectTransform(new Point((int)(characterArea.Rect.Height * 0.5f)), characterArea.RectTransform, Anchor.CenterRight) { AbsoluteOffset = new Point(5, 0) },
|
||||||
"GUISoundIcon")
|
"GUISoundIcon")
|
||||||
{
|
{
|
||||||
@@ -604,10 +660,6 @@ namespace Barotrauma
|
|||||||
characterListBox.BarScroll -= characterListBox.BarScroll % step;
|
characterListBox.BarScroll -= characterListBox.BarScroll % step;
|
||||||
characterListBox.BarScroll += dir * step;
|
characterListBox.BarScroll += dir * step;
|
||||||
|
|
||||||
child.Visible = (Character)button.UserData != character;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<object> KillCharacterAnim(GUIComponent component)
|
private IEnumerable<object> KillCharacterAnim(GUIComponent component)
|
||||||
{
|
{
|
||||||
List<GUIComponent> components = component.GetAllChildren().ToList();
|
List<GUIComponent> components = component.GetAllChildren().ToList();
|
||||||
@@ -619,6 +671,18 @@ namespace Barotrauma
|
|||||||
if (characterInfos.Contains(revivedCharacter.Info)) AddCharacter(revivedCharacter);
|
if (characterInfos.Contains(revivedCharacter.Info)) AddCharacter(revivedCharacter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IEnumerable<object> KillCharacterAnim(GUIComponent component)
|
||||||
|
{
|
||||||
|
List<GUIComponent> components = component.GetAllChildren().ToList();
|
||||||
|
components.Add(component);
|
||||||
|
components.RemoveAll(c => c.UserData as string == "soundicon" || c.UserData as string == "soundicondisabled");
|
||||||
|
|
||||||
|
foreach (GUIComponent comp in components)
|
||||||
|
{
|
||||||
|
comp.Color = Color.DarkRed;
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(text)) { return; }
|
||||||
|
|
||||||
yield return new WaitForSeconds(1.0f);
|
yield return new WaitForSeconds(1.0f);
|
||||||
|
|
||||||
float timer = 0.0f;
|
float timer = 0.0f;
|
||||||
@@ -685,7 +749,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
|
|
||||||
#region Voice chat
|
#region Voice chat
|
||||||
|
|
||||||
public void SetPlayerVoiceIconState(Client client, bool muted, bool mutedLocally)
|
public void SetPlayerVoiceIconState(Client client, bool muted, bool mutedLocally)
|
||||||
{
|
{
|
||||||
if (client?.Character == null) { return; }
|
if (client?.Character == null) { return; }
|
||||||
@@ -1101,7 +1165,7 @@ namespace Barotrauma
|
|||||||
if (child.Visible)
|
if (child.Visible)
|
||||||
{
|
{
|
||||||
child.GetChildByUserData("highlight").Visible = character == Character.Controlled;
|
child.GetChildByUserData("highlight").Visible = character == Character.Controlled;
|
||||||
|
|
||||||
var soundIcon = child.FindChild(character)?.FindChild("soundicon");
|
var soundIcon = child.FindChild(character)?.FindChild("soundicon");
|
||||||
if (soundIcon != null)
|
if (soundIcon != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -143,6 +143,9 @@ namespace Barotrauma
|
|||||||
|
|
||||||
infoFrame?.UpdateManually(deltaTime);
|
infoFrame?.UpdateManually(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
infoFrame?.UpdateManually(deltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
public void Draw(SpriteBatch spriteBatch)
|
public void Draw(SpriteBatch spriteBatch)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -79,10 +79,6 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (GUIComponent child in infoTextBox.Content.Children)
|
|
||||||
{
|
|
||||||
child.CanBeFocused = false;
|
|
||||||
}
|
|
||||||
foreach (GUIComponent child in infoTextBox.Content.Children)
|
foreach (GUIComponent child in infoTextBox.Content.Children)
|
||||||
{
|
{
|
||||||
child.CanBeFocused = false;
|
child.CanBeFocused = false;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Barotrauma.Networking;
|
using Barotrauma.Extensions;
|
||||||
|
using Barotrauma.Networking;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using Microsoft.Xna.Framework.Input;
|
using Microsoft.Xna.Framework.Input;
|
||||||
@@ -498,28 +499,43 @@ namespace Barotrauma
|
|||||||
voiceMode.OnSelect = (GUIRadioButtonGroup rbg, Enum value) =>
|
voiceMode.OnSelect = (GUIRadioButtonGroup rbg, Enum value) =>
|
||||||
{
|
{
|
||||||
if (rbg.Selected != null && rbg.Selected.Equals(value)) return;
|
if (rbg.Selected != null && rbg.Selected.Equals(value)) return;
|
||||||
VoiceMode vMode = (VoiceMode)value;
|
try
|
||||||
VoiceSetting = vMode;
|
|
||||||
|
|
||||||
if (vMode == VoiceMode.Activity)
|
|
||||||
{
|
{
|
||||||
voiceActivityGroup.Visible = true;
|
VoiceMode vMode = (VoiceMode)value;
|
||||||
if (GameMain.Client == null && VoipCapture.Instance == null)
|
VoiceSetting = vMode;
|
||||||
|
if (vMode == VoiceMode.Activity)
|
||||||
{
|
{
|
||||||
VoipCapture.Create(GameMain.Config.VoiceCaptureDevice);
|
voiceActivityGroup.Visible = true;
|
||||||
|
if (GameMain.Client == null && VoipCapture.Instance == null)
|
||||||
|
{
|
||||||
|
VoipCapture.Create(GameMain.Config.VoiceCaptureDevice);
|
||||||
|
}
|
||||||
|
if (VoipCapture.Instance == null)
|
||||||
|
{
|
||||||
|
VoiceSetting = vMode = VoiceMode.Disabled;
|
||||||
|
voiceInputContainer.Visible = false;
|
||||||
|
voiceActivityGroup.Visible = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else
|
|
||||||
{
|
|
||||||
voiceActivityGroup.Visible = false;
|
|
||||||
if (GameMain.Client == null)
|
|
||||||
{
|
{
|
||||||
VoipCapture.Instance?.Dispose();
|
voiceActivityGroup.Visible = false;
|
||||||
|
if (GameMain.Client == null)
|
||||||
|
{
|
||||||
|
VoipCapture.Instance?.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
voiceInputContainer.Visible = (vMode == VoiceMode.PushToTalk);
|
voiceInputContainer.Visible = (vMode == VoiceMode.PushToTalk);
|
||||||
UnsavedSettings = true;
|
UnsavedSettings = true;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Failed to set voice capture mode.", e);
|
||||||
|
GameAnalyticsManager.AddErrorEventOnce("SetVoiceCaptureMode", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, "Failed to set voice capture mode. " + e.Message + "\n" + e.StackTrace);
|
||||||
|
VoiceSetting = VoiceMode.Disabled;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
voiceMode.Selected = VoiceSetting;
|
voiceMode.Selected = VoiceSetting;
|
||||||
|
|
||||||
@@ -599,21 +615,38 @@ namespace Barotrauma
|
|||||||
.Replace("[missingfiletypes]", string.Join(", ", missingContentTypes));
|
.Replace("[missingfiletypes]", string.Join(", ", missingContentTypes));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GUITextBlock aimAssistText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("AimAssist"));
|
languageDD.SelectItem(TextManager.Language);
|
||||||
GUIScrollBar aimAssistSlider = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform),
|
languageDD.OnSelected = (guiComponent, obj) =>
|
||||||
barSize: 0.1f)
|
|
||||||
{
|
{
|
||||||
UserData = aimAssistText,
|
string newLanguage = obj as string;
|
||||||
BarScroll = MathUtils.InverseLerp(0.0f, 5.0f, AimAssistAmount),
|
if (newLanguage == Language) return true;
|
||||||
OnMoved = (scrollBar, scroll) =>
|
|
||||||
{
|
UnsavedSettings = true;
|
||||||
ChangeSliderText(scrollBar, scroll);
|
Language = newLanguage;
|
||||||
AimAssistAmount = MathHelper.Lerp(0.0f, 5.0f, scroll);
|
|
||||||
return true;
|
new GUIMessageBox(TextManager.Get("RestartRequiredLabel"), TextManager.Get("RestartRequiredLanguage"));
|
||||||
},
|
|
||||||
Step = 0.1f
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
//spacing
|
||||||
|
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), generalLayoutGroup.RectTransform), style: null);
|
||||||
|
|
||||||
|
new GUIButton(new RectTransform(new Vector2(0.4f, 1.0f), buttonArea.RectTransform, Anchor.BottomLeft),
|
||||||
|
TextManager.Get("Cancel"))
|
||||||
|
{
|
||||||
|
IgnoreLayoutGroups = true,
|
||||||
|
OnClicked = (x, y) =>
|
||||||
|
{
|
||||||
|
if (UnsavedSettings)
|
||||||
|
{
|
||||||
|
LoadPlayerConfig();
|
||||||
|
}
|
||||||
|
if (Screen.Selected == GameMain.MainMenuScreen) GameMain.MainMenuScreen.ReturnToMainMenu(null, null);
|
||||||
|
GUI.SettingsMenuOpen = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
aimAssistSlider.OnMoved(aimAssistSlider, aimAssistSlider.BarScroll);
|
|
||||||
|
|
||||||
//spacing
|
//spacing
|
||||||
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), generalLayoutGroup.RectTransform), style: null);
|
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), generalLayoutGroup.RectTransform), style: null);
|
||||||
|
|||||||
@@ -184,6 +184,63 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ApplyTo(RectTransform target)
|
||||||
|
{
|
||||||
|
if (RelativeOffset.HasValue)
|
||||||
|
{
|
||||||
|
target.RelativeOffset = RelativeOffset.Value;
|
||||||
|
}
|
||||||
|
else if (AbsoluteOffset.HasValue)
|
||||||
|
{
|
||||||
|
target.AbsoluteOffset = AbsoluteOffset.Value;
|
||||||
|
}
|
||||||
|
if (RelativeSize.HasValue)
|
||||||
|
{
|
||||||
|
target.RelativeSize = RelativeSize.Value;
|
||||||
|
}
|
||||||
|
else if (AbsoluteSize.HasValue)
|
||||||
|
{
|
||||||
|
target.NonScaledSize = AbsoluteSize.Value;
|
||||||
|
}
|
||||||
|
if (Anchor.HasValue)
|
||||||
|
{
|
||||||
|
target.Anchor = Anchor.Value;
|
||||||
|
}
|
||||||
|
if (Pivot.HasValue)
|
||||||
|
{
|
||||||
|
target.Pivot = Pivot.Value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
target.Pivot = RectTransform.MatchPivotToAnchor(target.Anchor);
|
||||||
|
}
|
||||||
|
target.RecalculateChildren(true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GUIFrame GuiFrame { get; protected set; }
|
||||||
|
|
||||||
|
[Serialize(false, false)]
|
||||||
|
public bool AllowUIOverlap
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ItemComponent linkToUIComponent;
|
||||||
|
[Serialize("", false)]
|
||||||
|
public string LinkUIToComponent
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serialize(0, false)]
|
||||||
|
public int HudPriority
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool shouldMuffleLooping;
|
private bool shouldMuffleLooping;
|
||||||
|
|||||||
@@ -982,7 +982,7 @@ namespace Barotrauma.Items.Components
|
|||||||
Vector2 textSize = GUI.SmallFont.MeasureString(wrappedLabel);
|
Vector2 textSize = GUI.SmallFont.MeasureString(wrappedLabel);
|
||||||
|
|
||||||
//flip the text to left side when the marker is on the left side or goes outside the right edge of the interface
|
//flip the text to left side when the marker is on the left side or goes outside the right edge of the interface
|
||||||
if (dir.X < 0.0f || labelPos.X + textSize.X + 10 > GuiFrame.Rect.X) labelPos.X -= textSize.X + 10;
|
if ((dir.X < 0.0f || labelPos.X + textSize.X + 10 > GuiFrame.Rect.X) && labelPos.X - textSize.X > 0) labelPos.X -= textSize.X + 10;
|
||||||
|
|
||||||
GUI.DrawString(spriteBatch,
|
GUI.DrawString(spriteBatch,
|
||||||
new Vector2(labelPos.X + 10, labelPos.Y),
|
new Vector2(labelPos.X + 10, labelPos.Y),
|
||||||
|
|||||||
@@ -64,6 +64,31 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public float SpriteRotation;
|
public float SpriteRotation;
|
||||||
|
|
||||||
|
private GUITextBlock itemInUseWarning;
|
||||||
|
private GUITextBlock ItemInUseWarning
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (itemInUseWarning == null)
|
||||||
|
{
|
||||||
|
itemInUseWarning = new GUITextBlock(new RectTransform(new Point(10), GUI.Canvas), "",
|
||||||
|
textColor: Color.Orange, color: Color.Black,
|
||||||
|
textAlignment:Alignment.Center, style: "OuterGlow");
|
||||||
|
}
|
||||||
|
return itemInUseWarning;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool SelectableInEditor
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return parentInventory == null && (body == null || body.Enabled) && ShowItems;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float SpriteRotation;
|
||||||
|
|
||||||
public Color GetSpriteColor()
|
public Color GetSpriteColor()
|
||||||
{
|
{
|
||||||
Color color = spriteColor;
|
Color color = spriteColor;
|
||||||
|
|||||||
@@ -544,6 +544,62 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ClientRead(ServerNetObject type, NetBuffer message, float sendingTime)
|
||||||
|
{
|
||||||
|
float newWaterVolume = message.ReadRangedSingle(0.0f, 1.5f, 8) * Volume;
|
||||||
|
float newOxygenPercentage = message.ReadRangedSingle(0.0f, 100.0f, 8);
|
||||||
|
|
||||||
|
bool hasFireSources = message.ReadBoolean();
|
||||||
|
int fireSourceCount = 0;
|
||||||
|
List<Vector3> newFireSources = new List<Vector3>();
|
||||||
|
if (hasFireSources)
|
||||||
|
{
|
||||||
|
fireSourceCount = message.ReadRangedInteger(0, 16);
|
||||||
|
for (int i = 0; i < fireSourceCount; i++)
|
||||||
|
{
|
||||||
|
newFireSources.Add(new Vector3(
|
||||||
|
MathHelper.Clamp(message.ReadRangedSingle(0.0f, 1.0f, 8), 0.05f, 0.95f),
|
||||||
|
MathHelper.Clamp(message.ReadRangedSingle(0.0f, 1.0f, 8), 0.05f, 0.95f),
|
||||||
|
message.ReadRangedSingle(0.0f, 1.0f, 8)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverUpdateDelay > 0.0f) { return; }
|
||||||
|
|
||||||
|
WaterVolume = newWaterVolume;
|
||||||
|
OxygenPercentage = newOxygenPercentage;
|
||||||
|
|
||||||
|
for (int i = 0; i < fireSourceCount; i++)
|
||||||
|
{
|
||||||
|
Vector2 pos = new Vector2(
|
||||||
|
rect.X + rect.Width * newFireSources[i].X,
|
||||||
|
rect.Y - rect.Height + (rect.Height * newFireSources[i].Y));
|
||||||
|
float size = newFireSources[i].Z * rect.Width;
|
||||||
|
|
||||||
|
var newFire = i < FireSources.Count ?
|
||||||
|
FireSources[i] :
|
||||||
|
new FireSource(Submarine == null ? pos : pos + Submarine.Position, null, true);
|
||||||
|
newFire.Position = pos;
|
||||||
|
newFire.Size = new Vector2(size, newFire.Size.Y);
|
||||||
|
|
||||||
|
//ignore if the fire wasn't added to this room (invalid position)?
|
||||||
|
if (!FireSources.Contains(newFire))
|
||||||
|
{
|
||||||
|
newFire.Remove();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = FireSources.Count - 1; i >= fireSourceCount; i--)
|
||||||
|
{
|
||||||
|
FireSources[i].Remove();
|
||||||
|
if (i < FireSources.Count)
|
||||||
|
{
|
||||||
|
FireSources.RemoveAt(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void ClientRead(ServerNetObject type, NetBuffer message, float sendingTime)
|
public void ClientRead(ServerNetObject type, NetBuffer message, float sendingTime)
|
||||||
{
|
{
|
||||||
float newWaterVolume = message.ReadRangedSingle(0.0f, 1.5f, 8) * Volume;
|
float newWaterVolume = message.ReadRangedSingle(0.0f, 1.5f, 8) * Volume;
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ namespace Barotrauma.Lights
|
|||||||
|
|
||||||
private float currLightMapScale;
|
private float currLightMapScale;
|
||||||
|
|
||||||
private float currLightMapScale;
|
|
||||||
|
|
||||||
public Color AmbientLight;
|
public Color AmbientLight;
|
||||||
|
|
||||||
public RenderTarget2D LightMap
|
public RenderTarget2D LightMap
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Lidgren.Network;
|
using Lidgren.Network;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Barotrauma.Networking
|
namespace Barotrauma.Networking
|
||||||
{
|
{
|
||||||
@@ -65,13 +66,13 @@ namespace Barotrauma.Networking
|
|||||||
if (order.TargetAllCharacters)
|
if (order.TargetAllCharacters)
|
||||||
{
|
{
|
||||||
GameMain.GameSession?.CrewManager?.AddOrder(
|
GameMain.GameSession?.CrewManager?.AddOrder(
|
||||||
new Order(order.Prefab, targetEntity, (targetEntity as Item)?.GetComponent<Items.Components.ItemComponent>()),
|
new Order(order.Prefab, targetEntity, (targetEntity as Item)?.Components.FirstOrDefault(ic => ic.GetType() == order.ItemComponentType)),
|
||||||
order.Prefab.FadeOutTime);
|
order.Prefab.FadeOutTime);
|
||||||
}
|
}
|
||||||
else if (targetCharacter != null)
|
else if (targetCharacter != null)
|
||||||
{
|
{
|
||||||
targetCharacter.SetOrder(
|
targetCharacter.SetOrder(
|
||||||
new Order(order.Prefab, targetEntity, (targetEntity as Item)?.GetComponent<Items.Components.ItemComponent>()),
|
new Order(order.Prefab, targetEntity, (targetEntity as Item)?.Components.FirstOrDefault(ic => ic.GetType() == order.ItemComponentType)),
|
||||||
orderOption, senderCharacter);
|
orderOption, senderCharacter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ namespace Barotrauma.Networking
|
|||||||
{
|
{
|
||||||
get { return entityEventManager.MidRoundSyncing; }
|
get { return entityEventManager.MidRoundSyncing; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private int ownerKey;
|
private int ownerKey;
|
||||||
|
|
||||||
public GameClient(string newName, string ip, int ownerKey=0)
|
public GameClient(string newName, string ip, int ownerKey=0)
|
||||||
@@ -146,7 +146,7 @@ namespace Barotrauma.Networking
|
|||||||
OnSelected = ToggleEndRoundVote,
|
OnSelected = ToggleEndRoundVote,
|
||||||
Visible = false
|
Visible = false
|
||||||
};
|
};
|
||||||
|
|
||||||
ShowLogButton = new GUIButton(new RectTransform(new Vector2(0.1f, 0.6f), buttonContainer.RectTransform) { MinSize = new Point(150, 0) },
|
ShowLogButton = new GUIButton(new RectTransform(new Vector2(0.1f, 0.6f), buttonContainer.RectTransform) { MinSize = new Point(150, 0) },
|
||||||
TextManager.Get("ServerLog"))
|
TextManager.Get("ServerLog"))
|
||||||
{
|
{
|
||||||
@@ -222,7 +222,7 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
// Create new instance of configs. Parameter is "application Id". It has to be same on client and server.
|
// Create new instance of configs. Parameter is "application Id". It has to be same on client and server.
|
||||||
NetPeerConfiguration = new NetPeerConfiguration("barotrauma");
|
NetPeerConfiguration = new NetPeerConfiguration("barotrauma");
|
||||||
|
|
||||||
NetPeerConfiguration.DisableMessageType(NetIncomingMessageType.DebugMessage | NetIncomingMessageType.WarningMessage | NetIncomingMessageType.Receipt
|
NetPeerConfiguration.DisableMessageType(NetIncomingMessageType.DebugMessage | NetIncomingMessageType.WarningMessage | NetIncomingMessageType.Receipt
|
||||||
| NetIncomingMessageType.ErrorMessage | NetIncomingMessageType.Error);
|
| NetIncomingMessageType.ErrorMessage | NetIncomingMessageType.Error);
|
||||||
|
|
||||||
@@ -245,7 +245,7 @@ namespace Barotrauma.Networking
|
|||||||
NetOutgoingMessage outmsg = client.CreateMessage();
|
NetOutgoingMessage outmsg = client.CreateMessage();
|
||||||
WriteAuthRequest(outmsg);
|
WriteAuthRequest(outmsg);
|
||||||
|
|
||||||
// Connect client, to ip previously requested from user
|
// Connect client, to ip previously requested from user
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
client.Connect(IPEndPoint, outmsg);
|
client.Connect(IPEndPoint, outmsg);
|
||||||
@@ -557,16 +557,16 @@ namespace Barotrauma.Networking
|
|||||||
{
|
{
|
||||||
System.Threading.Thread.Sleep(10);
|
System.Threading.Thread.Sleep(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
outmsg.Write(SteamManager.GetSteamID());
|
outmsg.Write(SteamManager.GetSteamID());
|
||||||
outmsg.Write(steamAuthTicket.Data.Length);
|
outmsg.Write(steamAuthTicket.Data.Length);
|
||||||
outmsg.Write(steamAuthTicket.Data);
|
outmsg.Write(steamAuthTicket.Data);
|
||||||
|
|
||||||
DebugConsole.Log("Sending Steam auth request");
|
DebugConsole.Log("Sending Steam auth request");
|
||||||
DebugConsole.Log(" Steam ID: " + SteamManager.GetSteamID());
|
DebugConsole.Log(" Steam ID: " + SteamManager.GetSteamID());
|
||||||
DebugConsole.Log(" Ticket data: " +
|
DebugConsole.Log(" Ticket data: " +
|
||||||
ToolBox.LimitString(string.Concat(steamAuthTicket.Data.Select(b => b.ToString("X2"))), 16));
|
ToolBox.LimitString(string.Concat(steamAuthTicket.Data.Select(b => b.ToString("X2"))), 16));
|
||||||
DebugConsole.Log(" Msg length: " + outmsg.LengthBytes);
|
DebugConsole.Log(" Msg length: " + outmsg.LengthBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -580,7 +580,7 @@ namespace Barotrauma.Networking
|
|||||||
{
|
{
|
||||||
c.UpdateSoundPosition();
|
c.UpdateSoundPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (VoipCapture.Instance != null)
|
if (VoipCapture.Instance != null)
|
||||||
{
|
{
|
||||||
if (VoipCapture.Instance.LastEnqueueAudio > DateTime.Now - new TimeSpan(0, 0, 0, 0, milliseconds: 100))
|
if (VoipCapture.Instance.LastEnqueueAudio > DateTime.Now - new TimeSpan(0, 0, 0, 0, milliseconds: 100))
|
||||||
@@ -633,7 +633,7 @@ namespace Barotrauma.Networking
|
|||||||
GameMain.MainMenuScreen.Select();
|
GameMain.MainMenuScreen.Select();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gameStarted && Screen.Selected == GameMain.GameScreen)
|
if (gameStarted && Screen.Selected == GameMain.GameScreen)
|
||||||
{
|
{
|
||||||
EndVoteTickBox.Visible = serverSettings.Voting.AllowEndVoting && HasSpawned;
|
EndVoteTickBox.Visible = serverSettings.Voting.AllowEndVoting && HasSpawned;
|
||||||
@@ -658,7 +658,7 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update current time
|
// Update current time
|
||||||
updateTimer = DateTime.Now + updateInterval;
|
updateTimer = DateTime.Now + updateInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CoroutineHandle startGameCoroutine;
|
private CoroutineHandle startGameCoroutine;
|
||||||
@@ -735,8 +735,8 @@ namespace Barotrauma.Networking
|
|||||||
GameMain.NetLobbyScreen.TrySelectSub(shuttleName, shuttleHash, GameMain.NetLobbyScreen.ShuttleList.ListBox));
|
GameMain.NetLobbyScreen.TrySelectSub(shuttleName, shuttleHash, GameMain.NetLobbyScreen.ShuttleList.ListBox));
|
||||||
|
|
||||||
WriteCharacterInfo(readyToStartMsg);
|
WriteCharacterInfo(readyToStartMsg);
|
||||||
|
|
||||||
client.SendMessage(readyToStartMsg, NetDeliveryMethod.ReliableUnordered);
|
client.SendMessage(readyToStartMsg, NetDeliveryMethod.ReliableUnordered);
|
||||||
break;
|
break;
|
||||||
case ServerPacketHeader.STARTGAME:
|
case ServerPacketHeader.STARTGAME:
|
||||||
startGameCoroutine = GameMain.Instance.ShowLoading(StartGame(inc), false);
|
startGameCoroutine = GameMain.Instance.ShowLoading(StartGame(inc), false);
|
||||||
@@ -861,9 +861,10 @@ namespace Barotrauma.Networking
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
msg = TextManager.Get("DisconnectReason." + disconnectReason.ToString());
|
msg = TextManager.Get("DisconnectReason." + disconnectReason.ToString());
|
||||||
|
|
||||||
for (int i = 1; i < splitMsg.Length; i++)
|
for (int i = 1; i < splitMsg.Length; i++)
|
||||||
{
|
{
|
||||||
msg += splitMsg[i];
|
msg += TextManager.GetServerMessage(splitMsg[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var msgBox = new GUIMessageBox(TextManager.Get(allowReconnect ? "ConnectionLost" : "CouldNotConnectToServer"), msg);
|
var msgBox = new GUIMessageBox(TextManager.Get(allowReconnect ? "ConnectionLost" : "CouldNotConnectToServer"), msg);
|
||||||
@@ -927,6 +928,15 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SetMyPermissions(ClientPermissions newPermissions, IEnumerable<string> permittedConsoleCommands)
|
||||||
|
{
|
||||||
|
if (!(this.permittedConsoleCommands.Any(c => !permittedConsoleCommands.Contains(c)) ||
|
||||||
|
permittedConsoleCommands.Any(c => !this.permittedConsoleCommands.Contains(c))))
|
||||||
|
{
|
||||||
|
if (newPermissions == permissions) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void SetMyPermissions(ClientPermissions newPermissions, IEnumerable<string> permittedConsoleCommands)
|
private void SetMyPermissions(ClientPermissions newPermissions, IEnumerable<string> permittedConsoleCommands)
|
||||||
{
|
{
|
||||||
if (!(this.permittedConsoleCommands.Any(c => !permittedConsoleCommands.Contains(c)) ||
|
if (!(this.permittedConsoleCommands.Any(c => !permittedConsoleCommands.Contains(c)) ||
|
||||||
@@ -940,7 +950,7 @@ namespace Barotrauma.Networking
|
|||||||
//don't show the "permissions changed" popup if the client owns the server
|
//don't show the "permissions changed" popup if the client owns the server
|
||||||
if (ownerKey == 0)
|
if (ownerKey == 0)
|
||||||
{
|
{
|
||||||
GUIMessageBox.MessageBoxes.RemoveAll(mb => mb.UserData as string == "permissions");
|
GUIMessageBox.MessageBoxes.RemoveAll(mb => mb.UserData as string == "permissions");
|
||||||
|
|
||||||
string msg = "";
|
string msg = "";
|
||||||
if (newPermissions == ClientPermissions.None)
|
if (newPermissions == ClientPermissions.None)
|
||||||
@@ -977,7 +987,7 @@ namespace Barotrauma.Networking
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GameMain.NetLobbyScreen.UpdatePermissions();
|
GameMain.NetLobbyScreen.UpdatePermissions();
|
||||||
}
|
}
|
||||||
@@ -986,13 +996,13 @@ namespace Barotrauma.Networking
|
|||||||
{
|
{
|
||||||
if (Character != null) Character.Remove();
|
if (Character != null) Character.Remove();
|
||||||
HasSpawned = false;
|
HasSpawned = false;
|
||||||
|
|
||||||
GameMain.LightManager.LightingEnabled = true;
|
GameMain.LightManager.LightingEnabled = true;
|
||||||
|
|
||||||
//enable spectate button in case we fail to start the round now
|
//enable spectate button in case we fail to start the round now
|
||||||
//(for example, due to a missing sub file or an error)
|
//(for example, due to a missing sub file or an error)
|
||||||
GameMain.NetLobbyScreen.ShowSpectateButton();
|
GameMain.NetLobbyScreen.ShowSpectateButton();
|
||||||
|
|
||||||
entityEventManager.Clear();
|
entityEventManager.Clear();
|
||||||
LastSentEntityEventID = 0;
|
LastSentEntityEventID = 0;
|
||||||
|
|
||||||
@@ -1063,14 +1073,14 @@ namespace Barotrauma.Networking
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (GameMain.GameSession?.CrewManager != null) GameMain.GameSession.CrewManager.Reset();
|
if (GameMain.GameSession?.CrewManager != null) GameMain.GameSession.CrewManager.Reset();
|
||||||
GameMain.GameSession.StartRound(campaign.Map.SelectedConnection.Level,
|
GameMain.GameSession.StartRound(campaign.Map.SelectedConnection.Level,
|
||||||
reloadSub: true,
|
reloadSub: true,
|
||||||
loadSecondSub: false,
|
loadSecondSub: false,
|
||||||
mirrorLevel: campaign.Map.CurrentLocation != campaign.Map.SelectedConnection.Locations[0]);
|
mirrorLevel: campaign.Map.CurrentLocation != campaign.Map.SelectedConnection.Locations[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (respawnAllowed) respawnManager = new RespawnManager(this, GameMain.NetLobbyScreen.UsingShuttle ? GameMain.NetLobbyScreen.SelectedShuttle : null);
|
if (respawnAllowed) respawnManager = new RespawnManager(this, GameMain.NetLobbyScreen.UsingShuttle ? GameMain.NetLobbyScreen.SelectedShuttle : null);
|
||||||
|
|
||||||
gameStarted = true;
|
gameStarted = true;
|
||||||
|
|
||||||
GameMain.GameScreen.Select();
|
GameMain.GameScreen.Select();
|
||||||
@@ -1137,7 +1147,7 @@ namespace Barotrauma.Networking
|
|||||||
submarines.Add(new Submarine(Path.Combine(Submarine.SavePath, subName) + ".sub", subHash, false));
|
submarines.Add(new Submarine(Path.Combine(Submarine.SavePath, subName) + ".sub", subHash, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GameMain.NetLobbyScreen.UpdateSubList(GameMain.NetLobbyScreen.SubList, submarines);
|
GameMain.NetLobbyScreen.UpdateSubList(GameMain.NetLobbyScreen.SubList, submarines);
|
||||||
GameMain.NetLobbyScreen.UpdateSubList(GameMain.NetLobbyScreen.ShuttleList.ListBox, submarines);
|
GameMain.NetLobbyScreen.UpdateSubList(GameMain.NetLobbyScreen.ShuttleList.ListBox, submarines);
|
||||||
|
|
||||||
@@ -1241,7 +1251,7 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
UInt16 settingsLen = inc.ReadUInt16();
|
UInt16 settingsLen = inc.ReadUInt16();
|
||||||
byte[] settingsData = inc.ReadBytes(settingsLen);
|
byte[] settingsData = inc.ReadBytes(settingsLen);
|
||||||
|
|
||||||
if (inc.ReadBoolean())
|
if (inc.ReadBoolean())
|
||||||
{
|
{
|
||||||
if (GameSettings.VerboseLogging)
|
if (GameSettings.VerboseLogging)
|
||||||
@@ -1272,12 +1282,15 @@ namespace Barotrauma.Networking
|
|||||||
string levelSeed = inc.ReadString();
|
string levelSeed = inc.ReadString();
|
||||||
float levelDifficulty = inc.ReadFloat();
|
float levelDifficulty = inc.ReadFloat();
|
||||||
|
|
||||||
|
byte botCount = inc.ReadByte();
|
||||||
|
BotSpawnMode botSpawnMode = inc.ReadBoolean() ? BotSpawnMode.Fill : BotSpawnMode.Normal;
|
||||||
|
|
||||||
byte botCount = inc.ReadByte();
|
byte botCount = inc.ReadByte();
|
||||||
BotSpawnMode botSpawnMode = inc.ReadBoolean() ? BotSpawnMode.Fill : BotSpawnMode.Normal;
|
BotSpawnMode botSpawnMode = inc.ReadBoolean() ? BotSpawnMode.Fill : BotSpawnMode.Normal;
|
||||||
|
|
||||||
bool autoRestartEnabled = inc.ReadBoolean();
|
bool autoRestartEnabled = inc.ReadBoolean();
|
||||||
float autoRestartTimer = autoRestartEnabled ? inc.ReadFloat() : 0.0f;
|
float autoRestartTimer = autoRestartEnabled ? inc.ReadFloat() : 0.0f;
|
||||||
|
|
||||||
//ignore the message if we already a more up-to-date one
|
//ignore the message if we already a more up-to-date one
|
||||||
if (NetIdUtils.IdMoreRecent(updateID, GameMain.NetLobbyScreen.LastUpdateID))
|
if (NetIdUtils.IdMoreRecent(updateID, GameMain.NetLobbyScreen.LastUpdateID))
|
||||||
{
|
{
|
||||||
@@ -1299,13 +1312,13 @@ namespace Barotrauma.Networking
|
|||||||
GameMain.NetLobbyScreen.SetTraitorsEnabled(traitorsEnabled);
|
GameMain.NetLobbyScreen.SetTraitorsEnabled(traitorsEnabled);
|
||||||
GameMain.NetLobbyScreen.SetMissionType(missionTypeIndex);
|
GameMain.NetLobbyScreen.SetMissionType(missionTypeIndex);
|
||||||
|
|
||||||
if (!allowModeVoting) GameMain.NetLobbyScreen.SelectMode(modeIndex);
|
if (!allowModeVoting) GameMain.NetLobbyScreen.SelectMode(modeIndex);
|
||||||
|
|
||||||
GameMain.NetLobbyScreen.SetAllowSpectating(allowSpectating);
|
GameMain.NetLobbyScreen.SetAllowSpectating(allowSpectating);
|
||||||
GameMain.NetLobbyScreen.LevelSeed = levelSeed;
|
GameMain.NetLobbyScreen.LevelSeed = levelSeed;
|
||||||
GameMain.NetLobbyScreen.SetLevelDifficulty(levelDifficulty);
|
GameMain.NetLobbyScreen.SetLevelDifficulty(levelDifficulty);
|
||||||
GameMain.NetLobbyScreen.SetBotCount(botCount);
|
GameMain.NetLobbyScreen.SetBotCount(botCount);
|
||||||
GameMain.NetLobbyScreen.SetBotSpawnMode(botSpawnMode);
|
GameMain.NetLobbyScreen.SetBotSpawnMode(botSpawnMode);
|
||||||
GameMain.NetLobbyScreen.SetAutoRestart(autoRestartEnabled, autoRestartTimer);
|
GameMain.NetLobbyScreen.SetAutoRestart(autoRestartEnabled, autoRestartTimer);
|
||||||
|
|
||||||
serverSettings.VoiceChatEnabled = voiceChatEnabled;
|
serverSettings.VoiceChatEnabled = voiceChatEnabled;
|
||||||
@@ -1373,7 +1386,7 @@ namespace Barotrauma.Networking
|
|||||||
entity.ClientRead(objHeader, inc, sendingTime);
|
entity.ClientRead(objHeader, inc, sendingTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
//force to the correct position in case the entity doesn't exist
|
//force to the correct position in case the entity doesn't exist
|
||||||
//or the message wasn't read correctly for whatever reason
|
//or the message wasn't read correctly for whatever reason
|
||||||
inc.Position = msgEndPos;
|
inc.Position = msgEndPos;
|
||||||
inc.ReadPadBits();
|
inc.ReadPadBits();
|
||||||
@@ -1409,7 +1422,7 @@ namespace Barotrauma.Networking
|
|||||||
errorLines.Add(" - " + e.ToString());
|
errorLines.Add(" - " + e.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (string line in errorLines)
|
foreach (string line in errorLines)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError(line);
|
DebugConsole.ThrowError(line);
|
||||||
@@ -1476,7 +1489,7 @@ namespace Barotrauma.Networking
|
|||||||
chatMsgQueue[i].ClientWrite(outmsg);
|
chatMsgQueue[i].ClientWrite(outmsg);
|
||||||
}
|
}
|
||||||
outmsg.Write((byte)ClientNetObject.END_OF_MESSAGE);
|
outmsg.Write((byte)ClientNetObject.END_OF_MESSAGE);
|
||||||
|
|
||||||
if (outmsg.LengthBytes > client.Configuration.MaximumTransmissionUnit)
|
if (outmsg.LengthBytes > client.Configuration.MaximumTransmissionUnit)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("Maximum packet size exceeded (" + outmsg.LengthBytes + " > " + client.Configuration.MaximumTransmissionUnit);
|
DebugConsole.ThrowError("Maximum packet size exceeded (" + outmsg.LengthBytes + " > " + client.Configuration.MaximumTransmissionUnit);
|
||||||
@@ -1509,7 +1522,7 @@ namespace Barotrauma.Networking
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
chatMsgQueue[i].ClientWrite(outmsg);
|
chatMsgQueue[i].ClientWrite(outmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
outmsg.Write((byte)ClientNetObject.END_OF_MESSAGE);
|
outmsg.Write((byte)ClientNetObject.END_OF_MESSAGE);
|
||||||
|
|
||||||
@@ -1523,7 +1536,7 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
public void SendChatMessage(ChatMessage msg)
|
public void SendChatMessage(ChatMessage msg)
|
||||||
{
|
{
|
||||||
if (client.ServerConnection == null) return;
|
if (client.ServerConnection == null) return;
|
||||||
lastQueueChatMsgID++;
|
lastQueueChatMsgID++;
|
||||||
msg.NetStateID = lastQueueChatMsgID;
|
msg.NetStateID = lastQueueChatMsgID;
|
||||||
chatMsgQueue.Add(msg);
|
chatMsgQueue.Add(msg);
|
||||||
@@ -1536,7 +1549,7 @@ namespace Barotrauma.Networking
|
|||||||
ChatMessage chatMessage = ChatMessage.Create(
|
ChatMessage chatMessage = ChatMessage.Create(
|
||||||
gameStarted && myCharacter != null ? myCharacter.Name : name,
|
gameStarted && myCharacter != null ? myCharacter.Name : name,
|
||||||
message,
|
message,
|
||||||
type,
|
type,
|
||||||
gameStarted && myCharacter != null ? myCharacter : null);
|
gameStarted && myCharacter != null ? myCharacter : null);
|
||||||
|
|
||||||
lastQueueChatMsgID++;
|
lastQueueChatMsgID++;
|
||||||
@@ -1586,12 +1599,12 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
for (int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
IEnumerable<GUIComponent> subListChildren = (i == 0) ?
|
IEnumerable<GUIComponent> subListChildren = (i == 0) ?
|
||||||
GameMain.NetLobbyScreen.ShuttleList.ListBox.Content.Children :
|
GameMain.NetLobbyScreen.ShuttleList.ListBox.Content.Children :
|
||||||
GameMain.NetLobbyScreen.SubList.Content.Children;
|
GameMain.NetLobbyScreen.SubList.Content.Children;
|
||||||
|
|
||||||
var subElement = subListChildren.FirstOrDefault(c =>
|
var subElement = subListChildren.FirstOrDefault(c =>
|
||||||
((Submarine)c.UserData).Name == newSub.Name &&
|
((Submarine)c.UserData).Name == newSub.Name &&
|
||||||
((Submarine)c.UserData).MD5Hash.Hash == newSub.MD5Hash.Hash);
|
((Submarine)c.UserData).MD5Hash.Hash == newSub.MD5Hash.Hash);
|
||||||
if (subElement == null) continue;
|
if (subElement == null) continue;
|
||||||
|
|
||||||
@@ -1613,7 +1626,7 @@ namespace Barotrauma.Networking
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GameMain.NetLobbyScreen.FailedSelectedSub != null &&
|
if (GameMain.NetLobbyScreen.FailedSelectedSub != null &&
|
||||||
GameMain.NetLobbyScreen.FailedSelectedSub.First == newSub.Name &&
|
GameMain.NetLobbyScreen.FailedSelectedSub.First == newSub.Name &&
|
||||||
GameMain.NetLobbyScreen.FailedSelectedSub.Second == newSub.MD5Hash.Hash)
|
GameMain.NetLobbyScreen.FailedSelectedSub.Second == newSub.MD5Hash.Hash)
|
||||||
{
|
{
|
||||||
@@ -1636,7 +1649,7 @@ namespace Barotrauma.Networking
|
|||||||
if (GameMain.GameSession.Submarine == null)
|
if (GameMain.GameSession.Submarine == null)
|
||||||
{
|
{
|
||||||
var gameSessionDoc = SaveUtil.LoadGameSessionDoc(GameMain.GameSession.SavePath);
|
var gameSessionDoc = SaveUtil.LoadGameSessionDoc(GameMain.GameSession.SavePath);
|
||||||
string subPath = Path.Combine(SaveUtil.TempPath, gameSessionDoc.Root.GetAttributeString("submarine", "")) + ".sub";
|
string subPath = Path.Combine(SaveUtil.TempPath, gameSessionDoc.Root.GetAttributeString("submarine", "")) + ".sub";
|
||||||
GameMain.GameSession.Submarine = new Submarine(subPath, "");
|
GameMain.GameSession.Submarine = new Submarine(subPath, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1662,7 +1675,7 @@ namespace Barotrauma.Networking
|
|||||||
if (!(entity is IClientSerializable)) throw new InvalidCastException("entity is not IClientSerializable");
|
if (!(entity is IClientSerializable)) throw new InvalidCastException("entity is not IClientSerializable");
|
||||||
entityEventManager.CreateEvent(entity as IClientSerializable, extraData);
|
entityEventManager.CreateEvent(entity as IClientSerializable, extraData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasPermission(ClientPermissions permission)
|
public bool HasPermission(ClientPermissions permission)
|
||||||
{
|
{
|
||||||
return permissions.HasFlag(permission);
|
return permissions.HasFlag(permission);
|
||||||
@@ -1675,7 +1688,7 @@ namespace Barotrauma.Networking
|
|||||||
command = command.ToLowerInvariant();
|
command = command.ToLowerInvariant();
|
||||||
return permittedConsoleCommands.Any(c => c.ToLowerInvariant() == command);
|
return permittedConsoleCommands.Any(c => c.ToLowerInvariant() == command);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Disconnect()
|
public override void Disconnect()
|
||||||
{
|
{
|
||||||
client.Shutdown("");
|
client.Shutdown("");
|
||||||
@@ -1711,7 +1724,7 @@ namespace Barotrauma.Networking
|
|||||||
VoipClient = null;
|
VoipClient = null;
|
||||||
GameMain.Client = null;
|
GameMain.Client = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WriteCharacterInfo(NetOutgoingMessage msg)
|
public void WriteCharacterInfo(NetOutgoingMessage msg)
|
||||||
{
|
{
|
||||||
msg.Write(characterInfo == null);
|
msg.Write(characterInfo == null);
|
||||||
@@ -1733,7 +1746,7 @@ namespace Barotrauma.Networking
|
|||||||
msg.Write(jobPreferences[i].Identifier);
|
msg.Write(jobPreferences[i].Identifier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Vote(VoteType voteType, object data)
|
public void Vote(VoteType voteType, object data)
|
||||||
{
|
{
|
||||||
NetOutgoingMessage msg = client.CreateMessage();
|
NetOutgoingMessage msg = client.CreateMessage();
|
||||||
@@ -1771,7 +1784,7 @@ namespace Barotrauma.Networking
|
|||||||
{
|
{
|
||||||
NetOutgoingMessage msg = client.CreateMessage();
|
NetOutgoingMessage msg = client.CreateMessage();
|
||||||
msg.Write((byte)ClientPacketHeader.SERVER_COMMAND);
|
msg.Write((byte)ClientPacketHeader.SERVER_COMMAND);
|
||||||
msg.Write((UInt16)ClientPermissions.Kick);
|
msg.Write((UInt16)ClientPermissions.Kick);
|
||||||
msg.Write(kickedName);
|
msg.Write(kickedName);
|
||||||
msg.Write(reason);
|
msg.Write(reason);
|
||||||
|
|
||||||
@@ -1926,7 +1939,7 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
msg.Write(false); msg.WritePadBits();
|
msg.Write(false); msg.WritePadBits();
|
||||||
msg.Write(saveName);
|
msg.Write(saveName);
|
||||||
|
|
||||||
client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered);
|
client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered);
|
||||||
|
|
||||||
GameMain.NetLobbyScreen.CampaignSetupUI = null;
|
GameMain.NetLobbyScreen.CampaignSetupUI = null;
|
||||||
@@ -1948,13 +1961,13 @@ namespace Barotrauma.Networking
|
|||||||
public bool SpectateClicked(GUIButton button, object userData)
|
public bool SpectateClicked(GUIButton button, object userData)
|
||||||
{
|
{
|
||||||
if (button != null) button.Enabled = false;
|
if (button != null) button.Enabled = false;
|
||||||
|
|
||||||
NetOutgoingMessage readyToStartMsg = client.CreateMessage();
|
NetOutgoingMessage readyToStartMsg = client.CreateMessage();
|
||||||
readyToStartMsg.Write((byte)ClientPacketHeader.RESPONSE_STARTGAME);
|
readyToStartMsg.Write((byte)ClientPacketHeader.RESPONSE_STARTGAME);
|
||||||
|
|
||||||
//assume we have the required sub files to start the round
|
//assume we have the required sub files to start the round
|
||||||
//(if not, we'll find out when the server sends the STARTGAME message and can initiate a file transfer)
|
//(if not, we'll find out when the server sends the STARTGAME message and can initiate a file transfer)
|
||||||
readyToStartMsg.Write(true);
|
readyToStartMsg.Write(true);
|
||||||
|
|
||||||
WriteCharacterInfo(readyToStartMsg);
|
WriteCharacterInfo(readyToStartMsg);
|
||||||
|
|
||||||
@@ -2052,9 +2065,9 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
|
|
||||||
SendChatMessage(message);
|
SendChatMessage(message);
|
||||||
|
|
||||||
textBox.Deselect();
|
textBox.Deselect();
|
||||||
textBox.Text = "";
|
textBox.Text = "";
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -2080,10 +2093,14 @@ namespace Barotrauma.Networking
|
|||||||
GUITextBox msgBox = null;
|
GUITextBox msgBox = null;
|
||||||
|
|
||||||
if (Screen.Selected == GameMain.GameScreen)
|
if (Screen.Selected == GameMain.GameScreen)
|
||||||
{ msgBox = chatBox.InputBox; }
|
{
|
||||||
|
msgBox = chatBox.InputBox;
|
||||||
|
}
|
||||||
else if (Screen.Selected == GameMain.NetLobbyScreen)
|
else if (Screen.Selected == GameMain.NetLobbyScreen)
|
||||||
{ msgBox = GameMain.NetLobbyScreen.TextBox; }
|
{
|
||||||
|
msgBox = GameMain.NetLobbyScreen.TextBox;
|
||||||
|
}
|
||||||
|
|
||||||
if (gameStarted && Screen.Selected == GameMain.GameScreen)
|
if (gameStarted && Screen.Selected == GameMain.GameScreen)
|
||||||
{
|
{
|
||||||
if (!GUI.DisableHUD && !GUI.DisableUpperHUD)
|
if (!GUI.DisableHUD && !GUI.DisableUpperHUD)
|
||||||
@@ -2112,11 +2129,11 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//tab doesn't autoselect the chatbox when debug console is open,
|
//tab doesn't autoselect the chatbox when debug console is open,
|
||||||
//because tab is used for autocompleting console commands
|
//because tab is used for autocompleting console commands
|
||||||
if (msgBox != null)
|
if (msgBox != null)
|
||||||
{
|
{
|
||||||
if ((PlayerInput.KeyHit(InputType.Chat) || PlayerInput.KeyHit(InputType.RadioChat)) &&
|
if ((PlayerInput.KeyHit(InputType.Chat) || PlayerInput.KeyHit(InputType.RadioChat)) &&
|
||||||
GUI.KeyboardDispatcher.Subscriber == null)
|
GUI.KeyboardDispatcher.Subscriber == null)
|
||||||
{
|
{
|
||||||
if (msgBox.Selected)
|
if (msgBox.Selected)
|
||||||
@@ -2182,15 +2199,15 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
GUI.DrawRectangle(spriteBatch, new Rectangle(
|
GUI.DrawRectangle(spriteBatch, new Rectangle(
|
||||||
(int)pos.X,
|
(int)pos.X,
|
||||||
(int)pos.Y,
|
(int)pos.Y,
|
||||||
fileReceiver.ActiveTransfers.Count * 210 + 10,
|
fileReceiver.ActiveTransfers.Count * 210 + 10,
|
||||||
32),
|
32),
|
||||||
Color.Black * 0.8f, true);
|
Color.Black * 0.8f, true);
|
||||||
|
|
||||||
for (int i = 0; i < fileReceiver.ActiveTransfers.Count; i++)
|
for (int i = 0; i < fileReceiver.ActiveTransfers.Count; i++)
|
||||||
{
|
{
|
||||||
var transfer = fileReceiver.ActiveTransfers[i];
|
var transfer = fileReceiver.ActiveTransfers[i];
|
||||||
|
|
||||||
GUI.DrawString(spriteBatch,
|
GUI.DrawString(spriteBatch,
|
||||||
pos,
|
pos,
|
||||||
ToolBox.LimitString(TextManager.Get("DownloadingFile").Replace("[filename]", transfer.FileName), GUI.SmallFont, 200),
|
ToolBox.LimitString(TextManager.Get("DownloadingFile").Replace("[filename]", transfer.FileName), GUI.SmallFont, 200),
|
||||||
|
|||||||
@@ -0,0 +1,808 @@
|
|||||||
|
using Lidgren.Network;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Barotrauma.Networking
|
||||||
|
{
|
||||||
|
partial class ServerSettings : ISerializableEntity
|
||||||
|
{
|
||||||
|
partial class NetPropertyData
|
||||||
|
{
|
||||||
|
public GUIComponent GUIComponent;
|
||||||
|
public object TempValue;
|
||||||
|
|
||||||
|
public void AssignGUIComponent(GUIComponent component)
|
||||||
|
{
|
||||||
|
GUIComponent = component;
|
||||||
|
GUIComponentValue = property.GetValue(serverSettings);
|
||||||
|
TempValue = GUIComponentValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GUIComponentValue
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (GUIComponent == null) return null;
|
||||||
|
else if (GUIComponent is GUITickBox tickBox) return tickBox.Selected;
|
||||||
|
else if (GUIComponent is GUITextBox textBox) return textBox.Text;
|
||||||
|
else if (GUIComponent is GUIScrollBar scrollBar) return scrollBar.BarScrollValue;
|
||||||
|
else if (GUIComponent is GUIRadioButtonGroup radioButtonGroup) return radioButtonGroup.Selected;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (GUIComponent == null) return;
|
||||||
|
else if (GUIComponent is GUITickBox tickBox) tickBox.Selected = (bool)value;
|
||||||
|
else if (GUIComponent is GUITextBox textBox) textBox.Text = (string)value;
|
||||||
|
else if (GUIComponent is GUIScrollBar scrollBar) scrollBar.BarScrollValue = (float)value;
|
||||||
|
else if (GUIComponent is GUIRadioButtonGroup radioButtonGroup) radioButtonGroup.Selected = (Enum)value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ChangedLocally
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (GUIComponent == null) return false;
|
||||||
|
return !PropEquals(TempValue, GUIComponentValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool PropEquals(object a,object b)
|
||||||
|
{
|
||||||
|
switch (typeString)
|
||||||
|
{
|
||||||
|
case "float":
|
||||||
|
if (!(a is float?)) return false;
|
||||||
|
if (!(b is float?)) return false;
|
||||||
|
return (float)a == (float)b;
|
||||||
|
case "int":
|
||||||
|
if (!(a is int?)) return false;
|
||||||
|
if (!(b is int?)) return false;
|
||||||
|
return (int)a == (int)b;
|
||||||
|
case "bool":
|
||||||
|
if (!(a is bool?)) return false;
|
||||||
|
if (!(b is bool?)) return false;
|
||||||
|
return (bool)a == (bool)b;
|
||||||
|
case "Enum":
|
||||||
|
if (!(a is Enum)) return false;
|
||||||
|
if (!(b is Enum)) return false;
|
||||||
|
return ((Enum)a).Equals((Enum)b);
|
||||||
|
default:
|
||||||
|
return a.ToString().Equals(b.ToString(),StringComparison.InvariantCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private Dictionary<string, bool> tempMonsterEnabled;
|
||||||
|
|
||||||
|
partial void InitProjSpecific()
|
||||||
|
{
|
||||||
|
var properties = TypeDescriptor.GetProperties(GetType()).Cast<PropertyDescriptor>();
|
||||||
|
|
||||||
|
SerializableProperties = new Dictionary<string, SerializableProperty>();
|
||||||
|
|
||||||
|
foreach (var property in properties)
|
||||||
|
{
|
||||||
|
SerializableProperty objProperty = new SerializableProperty(property, this);
|
||||||
|
SerializableProperties.Add(property.Name.ToLowerInvariant(), objProperty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClientAdminRead(NetBuffer incMsg)
|
||||||
|
{
|
||||||
|
int count = incMsg.ReadUInt16();
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
UInt32 key = incMsg.ReadUInt32();
|
||||||
|
if (netProperties.ContainsKey(key))
|
||||||
|
{
|
||||||
|
bool changedLocally = netProperties[key].ChangedLocally;
|
||||||
|
netProperties[key].Read(incMsg);
|
||||||
|
netProperties[key].TempValue = netProperties[key].Value;
|
||||||
|
|
||||||
|
if (netProperties[key].GUIComponent != null)
|
||||||
|
{
|
||||||
|
if (!changedLocally)
|
||||||
|
{
|
||||||
|
netProperties[key].GUIComponentValue = netProperties[key].Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UInt32 size = incMsg.ReadVariableUInt32();
|
||||||
|
incMsg.Position += 8 * size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadMonsterEnabled(incMsg);
|
||||||
|
BanList.ClientAdminRead(incMsg);
|
||||||
|
Whitelist.ClientAdminRead(incMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClientRead(NetBuffer incMsg)
|
||||||
|
{
|
||||||
|
ServerName = incMsg.ReadString();
|
||||||
|
ServerMessageText = incMsg.ReadString();
|
||||||
|
TickRate = incMsg.ReadRangedInteger(1, 60);
|
||||||
|
GameMain.NetworkMember.TickRate = TickRate;
|
||||||
|
|
||||||
|
ReadExtraCargo(incMsg);
|
||||||
|
|
||||||
|
Voting.ClientRead(incMsg);
|
||||||
|
|
||||||
|
bool isAdmin = incMsg.ReadBoolean();
|
||||||
|
incMsg.ReadPadBits();
|
||||||
|
if (isAdmin)
|
||||||
|
{
|
||||||
|
ClientAdminRead(incMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClientAdminWrite(NetFlags dataToSend, int missionType = 0, float? levelDifficulty = null, bool? autoRestart = null, int traitorSetting = 0, int botCount = 0, int botSpawnMode = 0)
|
||||||
|
{
|
||||||
|
if (!GameMain.Client.HasPermission(Networking.ClientPermissions.ManageSettings)) return;
|
||||||
|
|
||||||
|
NetOutgoingMessage outMsg = GameMain.NetworkMember.NetPeer.CreateMessage();
|
||||||
|
|
||||||
|
outMsg.Write((byte)ClientPacketHeader.SERVER_SETTINGS);
|
||||||
|
|
||||||
|
outMsg.Write((byte)dataToSend);
|
||||||
|
|
||||||
|
if (dataToSend.HasFlag(NetFlags.Name))
|
||||||
|
{
|
||||||
|
if (GameMain.NetLobbyScreen.ServerName.Text != ServerName)
|
||||||
|
{
|
||||||
|
ServerName = GameMain.NetLobbyScreen.ServerName.Text;
|
||||||
|
}
|
||||||
|
outMsg.Write(ServerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataToSend.HasFlag(NetFlags.Message))
|
||||||
|
{
|
||||||
|
if (GameMain.NetLobbyScreen.ServerMessage.Text != ServerMessageText)
|
||||||
|
{
|
||||||
|
ServerMessageText = GameMain.NetLobbyScreen.ServerMessage.Text;
|
||||||
|
}
|
||||||
|
outMsg.Write(ServerMessageText);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataToSend.HasFlag(NetFlags.Properties))
|
||||||
|
{
|
||||||
|
//TODO: split this up?
|
||||||
|
WriteExtraCargo(outMsg);
|
||||||
|
|
||||||
|
IEnumerable<KeyValuePair<UInt32, NetPropertyData>> changedProperties = netProperties.Where(kvp => kvp.Value.ChangedLocally);
|
||||||
|
UInt32 count = (UInt32)changedProperties.Count();
|
||||||
|
bool changedMonsterSettings = tempMonsterEnabled != null && tempMonsterEnabled.Any(p => p.Value != MonsterEnabled[p.Key]);
|
||||||
|
|
||||||
|
outMsg.Write(count);
|
||||||
|
foreach (KeyValuePair<UInt32, NetPropertyData> prop in changedProperties)
|
||||||
|
{
|
||||||
|
DebugConsole.NewMessage(prop.Value.Name, Color.Lime);
|
||||||
|
outMsg.Write(prop.Key);
|
||||||
|
prop.Value.Write(outMsg, prop.Value.GUIComponentValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
outMsg.Write(changedMonsterSettings); outMsg.WritePadBits();
|
||||||
|
if (changedMonsterSettings) WriteMonsterEnabled(outMsg, tempMonsterEnabled);
|
||||||
|
BanList.ClientAdminWrite(outMsg);
|
||||||
|
Whitelist.ClientAdminWrite(outMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataToSend.HasFlag(NetFlags.Misc))
|
||||||
|
{
|
||||||
|
outMsg.Write((byte)(missionType + 1));
|
||||||
|
outMsg.Write((byte)(traitorSetting + 1));
|
||||||
|
outMsg.Write((byte)(botCount + 1));
|
||||||
|
outMsg.Write((byte)(botSpawnMode + 1));
|
||||||
|
|
||||||
|
outMsg.Write(levelDifficulty ?? -1000.0f);
|
||||||
|
|
||||||
|
outMsg.Write(autoRestart != null);
|
||||||
|
outMsg.Write(autoRestart ?? false);
|
||||||
|
outMsg.WritePadBits();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataToSend.HasFlag(NetFlags.LevelSeed))
|
||||||
|
{
|
||||||
|
outMsg.Write(GameMain.NetLobbyScreen.SeedBox.Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
(GameMain.NetworkMember.NetPeer as NetClient).SendMessage(outMsg, NetDeliveryMethod.ReliableOrdered);
|
||||||
|
}
|
||||||
|
|
||||||
|
//GUI stuff
|
||||||
|
private GUIFrame settingsFrame;
|
||||||
|
private GUIFrame[] settingsTabs;
|
||||||
|
private GUIButton[] tabButtons;
|
||||||
|
private int settingsTabIndex;
|
||||||
|
|
||||||
|
enum SettingsTab
|
||||||
|
{
|
||||||
|
Rounds,
|
||||||
|
Server,
|
||||||
|
Banlist,
|
||||||
|
Whitelist
|
||||||
|
}
|
||||||
|
|
||||||
|
private NetPropertyData GetPropertyData(string name)
|
||||||
|
{
|
||||||
|
return netProperties.First(p => p.Value.Name == name).Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddToGUIUpdateList()
|
||||||
|
{
|
||||||
|
if (GUI.DisableHUD) return;
|
||||||
|
|
||||||
|
settingsFrame?.AddToGUIUpdateList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateSettingsFrame()
|
||||||
|
{
|
||||||
|
foreach (NetPropertyData prop in netProperties.Values)
|
||||||
|
{
|
||||||
|
prop.TempValue = prop.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
//background frame
|
||||||
|
settingsFrame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: null, color: Color.Black * 0.5f);
|
||||||
|
new GUIButton(new RectTransform(Vector2.One, settingsFrame.RectTransform), "", style: null).OnClicked += (btn, userData) =>
|
||||||
|
{
|
||||||
|
if (GUI.MouseOn == btn || GUI.MouseOn == btn.TextBlock) ToggleSettingsFrame(btn, userData);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
new GUIButton(new RectTransform(Vector2.One, settingsFrame.RectTransform), "", style: null)
|
||||||
|
{
|
||||||
|
OnClicked = ToggleSettingsFrame
|
||||||
|
};
|
||||||
|
|
||||||
|
//center frames
|
||||||
|
GUIFrame innerFrame = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.7f), settingsFrame.RectTransform, Anchor.Center) { MinSize = new Point(400, 430) });
|
||||||
|
GUIFrame paddedFrame = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.9f), innerFrame.RectTransform, Anchor.Center), style: null);
|
||||||
|
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), paddedFrame.RectTransform), TextManager.Get("Settings"), font: GUI.LargeFont);
|
||||||
|
|
||||||
|
var buttonArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.07f), paddedFrame.RectTransform) { RelativeOffset = new Vector2(0.0f, 0.1f) }, isHorizontal: true)
|
||||||
|
{
|
||||||
|
Stretch = true,
|
||||||
|
RelativeSpacing = 0.01f
|
||||||
|
};
|
||||||
|
|
||||||
|
//tabs
|
||||||
|
var tabValues = Enum.GetValues(typeof(SettingsTab)).Cast<SettingsTab>().ToArray();
|
||||||
|
string[] tabNames = new string[tabValues.Count()];
|
||||||
|
for (int i = 0; i < tabNames.Length; i++)
|
||||||
|
{
|
||||||
|
tabNames[i] = TextManager.Get("ServerSettings" + tabValues[i] + "Tab");
|
||||||
|
}
|
||||||
|
settingsTabs = new GUIFrame[tabNames.Length];
|
||||||
|
tabButtons = new GUIButton[tabNames.Length];
|
||||||
|
for (int i = 0; i < tabNames.Length; i++)
|
||||||
|
{
|
||||||
|
settingsTabs[i] = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.79f), paddedFrame.RectTransform, Anchor.Center) { RelativeOffset = new Vector2(0.0f, 0.05f) },
|
||||||
|
style: "InnerFrame");
|
||||||
|
|
||||||
|
tabButtons[i] = new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), buttonArea.RectTransform), tabNames[i], style: "GUITabButton")
|
||||||
|
{
|
||||||
|
UserData = i,
|
||||||
|
OnClicked = SelectSettingsTab
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectSettingsTab(tabButtons[0], 0);
|
||||||
|
|
||||||
|
//"Close"
|
||||||
|
var closeButton = new GUIButton(new RectTransform(new Vector2(0.25f, 0.05f), paddedFrame.RectTransform, Anchor.BottomRight), TextManager.Get("Close"))
|
||||||
|
{
|
||||||
|
OnClicked = ToggleSettingsFrame
|
||||||
|
};
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
// game settings
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
var roundsTab = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), settingsTabs[(int)SettingsTab.Rounds].RectTransform, Anchor.Center))
|
||||||
|
{
|
||||||
|
Stretch = true,
|
||||||
|
RelativeSpacing = 0.02f
|
||||||
|
};
|
||||||
|
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), TextManager.Get("ServerSettingsSubSelection"));
|
||||||
|
var selectionFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), isHorizontal: true)
|
||||||
|
{
|
||||||
|
Stretch = true,
|
||||||
|
RelativeSpacing = 0.05f
|
||||||
|
};
|
||||||
|
|
||||||
|
GUIRadioButtonGroup selectionMode = new GUIRadioButtonGroup();
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
var selectionTick = new GUITickBox(new RectTransform(new Vector2(0.3f, 1.0f), selectionFrame.RectTransform), TextManager.Get(((SelectionMode)i).ToString()), font: GUI.SmallFont);
|
||||||
|
selectionMode.AddRadioButton((SelectionMode)i, selectionTick);
|
||||||
|
}
|
||||||
|
DebugConsole.NewMessage(SubSelectionMode.ToString(),Color.White);
|
||||||
|
GetPropertyData("SubSelectionMode").AssignGUIComponent(selectionMode);
|
||||||
|
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), TextManager.Get("ServerSettingsModeSelection"));
|
||||||
|
selectionFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), isHorizontal: true)
|
||||||
|
{
|
||||||
|
Stretch = true,
|
||||||
|
RelativeSpacing = 0.05f
|
||||||
|
};
|
||||||
|
|
||||||
|
selectionMode = new GUIRadioButtonGroup();
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
var selectionTick = new GUITickBox(new RectTransform(new Vector2(0.3f, 1.0f), selectionFrame.RectTransform), TextManager.Get(((SelectionMode)i).ToString()), font: GUI.SmallFont);
|
||||||
|
selectionMode.AddRadioButton((SelectionMode)i, selectionTick);
|
||||||
|
}
|
||||||
|
GetPropertyData("ModeSelectionMode").AssignGUIComponent(selectionMode);
|
||||||
|
|
||||||
|
var endBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform),
|
||||||
|
TextManager.Get("ServerSettingsEndRoundWhenDestReached"));
|
||||||
|
GetPropertyData("EndRoundAtLevelEnd").AssignGUIComponent(endBox);
|
||||||
|
|
||||||
|
var endVoteBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform),
|
||||||
|
TextManager.Get("ServerSettingsEndRoundVoting"));
|
||||||
|
GetPropertyData("AllowEndVoting").AssignGUIComponent(endVoteBox);
|
||||||
|
|
||||||
|
CreateLabeledSlider(roundsTab, "ServerSettingsEndRoundVotesRequired", out GUIScrollBar slider, out GUITextBlock sliderLabel);
|
||||||
|
|
||||||
|
string endRoundLabel = sliderLabel.Text;
|
||||||
|
slider.Step = 0.2f;
|
||||||
|
slider.Range = new Vector2(0.5f, 1.0f);
|
||||||
|
GetPropertyData("EndVoteRequiredRatio").AssignGUIComponent(slider);
|
||||||
|
slider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
|
||||||
|
{
|
||||||
|
((GUITextBlock)scrollBar.UserData).Text = endRoundLabel + (int)MathUtils.Round(scrollBar.BarScrollValue * 100.0f, 10.0f) + " %";
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
slider.OnMoved(slider, slider.BarScroll);
|
||||||
|
|
||||||
|
var respawnBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform),
|
||||||
|
TextManager.Get("ServerSettingsAllowRespawning"));
|
||||||
|
GetPropertyData("AllowRespawn").AssignGUIComponent(respawnBox);
|
||||||
|
|
||||||
|
CreateLabeledSlider(roundsTab, "ServerSettingsRespawnInterval", out slider, out sliderLabel);
|
||||||
|
string intervalLabel = sliderLabel.Text;
|
||||||
|
slider.Step = 0.05f;
|
||||||
|
slider.Range = new Vector2(10.0f, 600.0f);
|
||||||
|
GetPropertyData("RespawnInterval").AssignGUIComponent(slider);
|
||||||
|
slider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
|
||||||
|
{
|
||||||
|
GUITextBlock text = scrollBar.UserData as GUITextBlock;
|
||||||
|
text.Text = intervalLabel + ToolBox.SecondsToReadableTime(scrollBar.BarScrollValue);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
slider.OnMoved(slider, slider.BarScroll);
|
||||||
|
|
||||||
|
var minRespawnText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), "")
|
||||||
|
{
|
||||||
|
ToolTip = TextManager.Get("ServerSettingsMinRespawnToolTip")
|
||||||
|
};
|
||||||
|
|
||||||
|
string minRespawnLabel = TextManager.Get("ServerSettingsMinRespawn");
|
||||||
|
CreateLabeledSlider(roundsTab, "", out slider, out sliderLabel);
|
||||||
|
slider.ToolTip = minRespawnText.ToolTip;
|
||||||
|
slider.UserData = minRespawnText;
|
||||||
|
slider.Step = 0.1f;
|
||||||
|
slider.Range = new Vector2(0.0f, 1.0f);
|
||||||
|
GetPropertyData("MinRespawnRatio").AssignGUIComponent(slider);
|
||||||
|
slider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
|
||||||
|
{
|
||||||
|
((GUITextBlock)scrollBar.UserData).Text = minRespawnLabel + (int)MathUtils.Round(scrollBar.BarScrollValue * 100.0f, 10.0f) + " %";
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
slider.OnMoved(slider, MinRespawnRatio);
|
||||||
|
|
||||||
|
var respawnDurationText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), "")
|
||||||
|
{
|
||||||
|
ToolTip = TextManager.Get("ServerSettingsRespawnDurationToolTip")
|
||||||
|
};
|
||||||
|
|
||||||
|
string respawnDurationLabel = TextManager.Get("ServerSettingsRespawnDuration");
|
||||||
|
CreateLabeledSlider(roundsTab, "", out slider, out sliderLabel);
|
||||||
|
slider.ToolTip = respawnDurationText.ToolTip;
|
||||||
|
slider.UserData = respawnDurationText;
|
||||||
|
slider.Step = 0.1f;
|
||||||
|
slider.Range = new Vector2(60.0f, 660.0f);
|
||||||
|
slider.ScrollToValue = (GUIScrollBar scrollBar, float barScroll) =>
|
||||||
|
{
|
||||||
|
return barScroll >= 1.0f ? 0.0f : barScroll * (scrollBar.Range.Y - scrollBar.Range.X) + scrollBar.Range.X;
|
||||||
|
};
|
||||||
|
slider.ValueToScroll = (GUIScrollBar scrollBar, float value) =>
|
||||||
|
{
|
||||||
|
return value <= 0.0f ? 1.0f : (value - scrollBar.Range.X) / (scrollBar.Range.Y - scrollBar.Range.X);
|
||||||
|
};
|
||||||
|
GetPropertyData("MaxTransportTime").AssignGUIComponent(slider);
|
||||||
|
slider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
|
||||||
|
{
|
||||||
|
if (barScroll == 1.0f)
|
||||||
|
{
|
||||||
|
((GUITextBlock)scrollBar.UserData).Text = respawnDurationLabel + TextManager.Get("Unlimited");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
((GUITextBlock)scrollBar.UserData).Text = respawnDurationLabel + ToolBox.SecondsToReadableTime(scrollBar.BarScrollValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
slider.OnMoved(slider, slider.BarScroll);
|
||||||
|
|
||||||
|
var buttonHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.07f), roundsTab.RectTransform), isHorizontal: true)
|
||||||
|
{
|
||||||
|
Stretch = true,
|
||||||
|
RelativeSpacing = 0.05f
|
||||||
|
};
|
||||||
|
|
||||||
|
var monsterButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), buttonHolder.RectTransform),
|
||||||
|
TextManager.Get("ServerSettingsMonsterSpawns"))
|
||||||
|
{
|
||||||
|
Enabled = !GameMain.NetworkMember.GameStarted
|
||||||
|
};
|
||||||
|
var monsterFrame = new GUIListBox(new RectTransform(new Vector2(0.6f, 0.7f), settingsTabs[(int)SettingsTab.Rounds].RectTransform, Anchor.BottomLeft, Pivot.BottomRight))
|
||||||
|
{
|
||||||
|
Visible = false
|
||||||
|
};
|
||||||
|
monsterButton.UserData = monsterFrame;
|
||||||
|
monsterButton.OnClicked = (button, obj) =>
|
||||||
|
{
|
||||||
|
if (GameMain.NetworkMember.GameStarted)
|
||||||
|
{
|
||||||
|
((GUIComponent)obj).Visible = false;
|
||||||
|
button.Enabled = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
((GUIComponent)obj).Visible = !((GUIComponent)obj).Visible;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
List<string> monsterNames = MonsterEnabled.Keys.ToList();
|
||||||
|
tempMonsterEnabled = new Dictionary<string, bool>(MonsterEnabled);
|
||||||
|
foreach (string s in monsterNames)
|
||||||
|
{
|
||||||
|
string translatedLabel = TextManager.Get($"Character.{s}", true);
|
||||||
|
var monsterEnabledBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.1f), monsterFrame.Content.RectTransform) { MinSize = new Point(0, 25) },
|
||||||
|
label: translatedLabel != null ? translatedLabel : s)
|
||||||
|
{
|
||||||
|
Selected = tempMonsterEnabled[s],
|
||||||
|
OnSelected = (GUITickBox tb) =>
|
||||||
|
{
|
||||||
|
tempMonsterEnabled[s] = tb.Selected;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var cargoButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), buttonHolder.RectTransform),
|
||||||
|
TextManager.Get("ServerSettingsAdditionalCargo"))
|
||||||
|
{
|
||||||
|
Enabled = !GameMain.NetworkMember.GameStarted
|
||||||
|
};
|
||||||
|
var cargoFrame = new GUIListBox(new RectTransform(new Vector2(0.6f, 0.7f), settingsTabs[(int)SettingsTab.Rounds].RectTransform, Anchor.BottomRight, Pivot.BottomLeft))
|
||||||
|
{
|
||||||
|
Visible = false
|
||||||
|
};
|
||||||
|
cargoButton.UserData = cargoFrame;
|
||||||
|
cargoButton.OnClicked = (button, obj) =>
|
||||||
|
{
|
||||||
|
if (GameMain.NetworkMember.GameStarted)
|
||||||
|
{
|
||||||
|
((GUIComponent)obj).Visible = false;
|
||||||
|
button.Enabled = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
((GUIComponent)obj).Visible = !((GUIComponent)obj).Visible;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (ItemPrefab ip in MapEntityPrefab.List.Where(p => p is ItemPrefab).Select(p => p as ItemPrefab))
|
||||||
|
{
|
||||||
|
if (!ip.CanBeBought && !ip.Tags.Contains("smallitem")) continue;
|
||||||
|
|
||||||
|
var itemFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.15f), cargoFrame.Content.RectTransform) { MinSize = new Point(0, 30) }, isHorizontal: true)
|
||||||
|
{
|
||||||
|
Stretch = true,
|
||||||
|
UserData = cargoFrame,
|
||||||
|
RelativeSpacing = 0.05f
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
if (ip.InventoryIcon != null || ip.sprite != null)
|
||||||
|
{
|
||||||
|
GUIImage img = new GUIImage(new RectTransform(new Point(itemFrame.Rect.Height), itemFrame.RectTransform),
|
||||||
|
ip.InventoryIcon ?? ip.sprite, scaleToFit: true)
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
img.Color = img.Sprite == ip.InventoryIcon ? ip.InventoryIconColor : ip.SpriteColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtraCargo.TryGetValue(ip, out int cargoVal);
|
||||||
|
var amountInput = new GUINumberInput(new RectTransform(new Vector2(0.3f, 1.0f), itemFrame.RectTransform),
|
||||||
|
GUINumberInput.NumberType.Int, textAlignment: Alignment.CenterLeft)
|
||||||
|
{
|
||||||
|
MinValueInt = 0,
|
||||||
|
MaxValueInt = 100,
|
||||||
|
IntValue = cargoVal
|
||||||
|
};
|
||||||
|
amountInput.OnValueChanged += (numberInput) =>
|
||||||
|
{
|
||||||
|
if (ExtraCargo.ContainsKey(ip))
|
||||||
|
{
|
||||||
|
ExtraCargo[ip] = numberInput.IntValue;
|
||||||
|
if (numberInput.IntValue <= 0) ExtraCargo.Remove(ip);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ExtraCargo.Add(ip, numberInput.IntValue);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
// server settings
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
var serverTab = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), settingsTabs[(int)SettingsTab.Server].RectTransform, Anchor.Center))
|
||||||
|
{
|
||||||
|
Stretch = true,
|
||||||
|
RelativeSpacing = 0.02f
|
||||||
|
};
|
||||||
|
|
||||||
|
//***********************************************
|
||||||
|
|
||||||
|
var voiceChatEnabled = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform),
|
||||||
|
TextManager.Get("ServerSettingsVoiceChatEnabled"));
|
||||||
|
GetPropertyData("VoiceChatEnabled").AssignGUIComponent(voiceChatEnabled);
|
||||||
|
|
||||||
|
//***********************************************
|
||||||
|
|
||||||
|
string autoRestartDelayLabel = TextManager.Get("ServerSettingsAutoRestartDelay");
|
||||||
|
var startIntervalText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), autoRestartDelayLabel);
|
||||||
|
var startIntervalSlider = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), barSize: 0.1f)
|
||||||
|
{
|
||||||
|
UserData = startIntervalText,
|
||||||
|
Step = 0.05f,
|
||||||
|
OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
|
||||||
|
{
|
||||||
|
GUITextBlock text = scrollBar.UserData as GUITextBlock;
|
||||||
|
text.Text = autoRestartDelayLabel + ToolBox.SecondsToReadableTime(scrollBar.BarScrollValue);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
startIntervalSlider.Range = new Vector2(10.0f, 300.0f);
|
||||||
|
GetPropertyData("AutoRestartInterval").AssignGUIComponent(startIntervalSlider);
|
||||||
|
startIntervalSlider.OnMoved(startIntervalSlider, startIntervalSlider.BarScroll);
|
||||||
|
|
||||||
|
//***********************************************
|
||||||
|
|
||||||
|
var startWhenClientsReady = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform),
|
||||||
|
TextManager.Get("ServerSettingsStartWhenClientsReady"));
|
||||||
|
GetPropertyData("StartWhenClientsReady").AssignGUIComponent(startWhenClientsReady);
|
||||||
|
|
||||||
|
CreateLabeledSlider(serverTab, "ServerSettingsStartWhenClientsReadyRatio", out slider, out sliderLabel);
|
||||||
|
string clientsReadyRequiredLabel = sliderLabel.Text;
|
||||||
|
slider.Step = 0.2f;
|
||||||
|
slider.Range = new Vector2(0.5f, 1.0f);
|
||||||
|
slider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
|
||||||
|
{
|
||||||
|
((GUITextBlock)scrollBar.UserData).Text = clientsReadyRequiredLabel.Replace("[percentage]", ((int)MathUtils.Round(scrollBar.BarScrollValue * 100.0f, 10.0f)).ToString());
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
GetPropertyData("StartWhenClientsReadyRatio").AssignGUIComponent(slider);
|
||||||
|
slider.OnMoved(slider, slider.BarScroll);
|
||||||
|
|
||||||
|
//***********************************************
|
||||||
|
|
||||||
|
var allowSpecBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsAllowSpectating"));
|
||||||
|
GetPropertyData("AllowSpectating").AssignGUIComponent(allowSpecBox);
|
||||||
|
|
||||||
|
var voteKickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsAllowVoteKick"));
|
||||||
|
GetPropertyData("AllowVoteKick").AssignGUIComponent(voteKickBox);
|
||||||
|
|
||||||
|
CreateLabeledSlider(serverTab, "ServerSettingsKickVotesRequired", out slider, out sliderLabel);
|
||||||
|
string votesRequiredLabel = sliderLabel.Text;
|
||||||
|
slider.Step = 0.2f;
|
||||||
|
slider.Range = new Vector2(0.5f, 1.0f);
|
||||||
|
slider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
|
||||||
|
{
|
||||||
|
((GUITextBlock)scrollBar.UserData).Text = votesRequiredLabel + (int)MathUtils.Round(scrollBar.BarScrollValue * 100.0f, 10.0f) + " %";
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
GetPropertyData("KickVoteRequiredRatio").AssignGUIComponent(slider);
|
||||||
|
slider.OnMoved(slider, slider.BarScroll);
|
||||||
|
|
||||||
|
CreateLabeledSlider(serverTab, "ServerSettingsAutobanTime", out slider, out sliderLabel);
|
||||||
|
string autobanLabel = sliderLabel.Text;
|
||||||
|
slider.Step = 0.05f;
|
||||||
|
slider.Range = new Vector2(0.0f, MaxAutoBanTime);
|
||||||
|
slider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
|
||||||
|
{
|
||||||
|
((GUITextBlock)scrollBar.UserData).Text = autobanLabel + ToolBox.SecondsToReadableTime(scrollBar.BarScrollValue);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
GetPropertyData("AutoBanTime").AssignGUIComponent(slider);
|
||||||
|
slider.OnMoved(slider, slider.BarScroll);
|
||||||
|
|
||||||
|
var shareSubsBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsShareSubFiles"));
|
||||||
|
GetPropertyData("AllowFileTransfers").AssignGUIComponent(shareSubsBox);
|
||||||
|
|
||||||
|
var randomizeLevelBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsRandomizeSeed"));
|
||||||
|
GetPropertyData("RandomizeSeed").AssignGUIComponent(randomizeLevelBox);
|
||||||
|
|
||||||
|
var saveLogsBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsSaveLogs"))
|
||||||
|
{
|
||||||
|
OnSelected = (GUITickBox) =>
|
||||||
|
{
|
||||||
|
//TODO: fix?
|
||||||
|
//showLogButton.Visible = SaveServerLogs;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
GetPropertyData("SaveServerLogs").AssignGUIComponent(saveLogsBox);
|
||||||
|
|
||||||
|
var ragdollButtonBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsAllowRagdollButton"));
|
||||||
|
GetPropertyData("AllowRagdollButton").AssignGUIComponent(ragdollButtonBox);
|
||||||
|
|
||||||
|
var traitorRatioBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsUseTraitorRatio"));
|
||||||
|
|
||||||
|
CreateLabeledSlider(serverTab, "", out slider, out sliderLabel);
|
||||||
|
/*var traitorRatioText = new GUITextBlock(new Rectangle(20, y + 20, 20, 20), "Traitor ratio: 20 %", "", settingsTabs[1], GUI.SmallFont);
|
||||||
|
var traitorRatioSlider = new GUIScrollBar(new Rectangle(150, y + 22, 100, 15), "", 0.1f, settingsTabs[1]);*/
|
||||||
|
var traitorRatioSlider = slider;
|
||||||
|
traitorRatioBox.OnSelected = (GUITickBox) =>
|
||||||
|
{
|
||||||
|
traitorRatioSlider.OnMoved(traitorRatioSlider, traitorRatioSlider.BarScroll);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (TraitorUseRatio)
|
||||||
|
{
|
||||||
|
traitorRatioSlider.Range = new Vector2(0.1f, 1.0f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
traitorRatioSlider.Range = new Vector2(1.0f, maxPlayers);
|
||||||
|
}
|
||||||
|
|
||||||
|
string traitorRatioLabel = TextManager.Get("ServerSettingsTraitorRatio");
|
||||||
|
string traitorCountLabel = TextManager.Get("ServerSettingsTraitorCount");
|
||||||
|
|
||||||
|
traitorRatioSlider.Range = new Vector2(0.1f, 1.0f);
|
||||||
|
traitorRatioSlider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
|
||||||
|
{
|
||||||
|
GUITextBlock traitorText = scrollBar.UserData as GUITextBlock;
|
||||||
|
if (traitorRatioBox.Selected)
|
||||||
|
{
|
||||||
|
scrollBar.Step = 0.01f;
|
||||||
|
scrollBar.Range = new Vector2(0.1f, 1.0f);
|
||||||
|
traitorText.Text = traitorRatioLabel + (int)MathUtils.Round(scrollBar.BarScrollValue * 100.0f, 1.0f) + " %";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scrollBar.Step = 1f / (maxPlayers - 1);
|
||||||
|
scrollBar.Range = new Vector2(1.0f, maxPlayers);
|
||||||
|
traitorText.Text = traitorCountLabel + scrollBar.BarScrollValue;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
GetPropertyData("TraitorUseRatio").AssignGUIComponent(traitorRatioBox);
|
||||||
|
GetPropertyData("TraitorRatio").AssignGUIComponent(traitorRatioSlider);
|
||||||
|
|
||||||
|
traitorRatioSlider.OnMoved(traitorRatioSlider, traitorRatioSlider.BarScroll);
|
||||||
|
traitorRatioBox.OnSelected(traitorRatioBox);
|
||||||
|
|
||||||
|
|
||||||
|
var karmaBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsUseKarma"));
|
||||||
|
GetPropertyData("KarmaEnabled").AssignGUIComponent(karmaBox);
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
// banlist
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
BanList.CreateBanFrame(settingsTabs[2]);
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
// whitelist
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Whitelist.CreateWhiteListFrame(settingsTabs[3]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateLabeledSlider(GUIComponent parent, string labelTag, out GUIScrollBar slider, out GUITextBlock label)
|
||||||
|
{
|
||||||
|
var container = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), parent.RectTransform), isHorizontal: true)
|
||||||
|
{
|
||||||
|
Stretch = true,
|
||||||
|
RelativeSpacing = 0.05f
|
||||||
|
};
|
||||||
|
|
||||||
|
slider = new GUIScrollBar(new RectTransform(new Vector2(0.5f, 0.8f), container.RectTransform), barSize: 0.1f);
|
||||||
|
label = new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.8f), container.RectTransform),
|
||||||
|
string.IsNullOrEmpty(labelTag) ? "" : TextManager.Get(labelTag), font: GUI.SmallFont);
|
||||||
|
|
||||||
|
//slider has a reference to the label to change the text when it's used
|
||||||
|
slider.UserData = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool SelectSettingsTab(GUIButton button, object obj)
|
||||||
|
{
|
||||||
|
settingsTabIndex = (int)obj;
|
||||||
|
|
||||||
|
for (int i = 0; i < settingsTabs.Length; i++)
|
||||||
|
{
|
||||||
|
settingsTabs[i].Visible = i == settingsTabIndex;
|
||||||
|
tabButtons[i].Selected = i == settingsTabIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ToggleSettingsFrame(GUIButton button, object obj)
|
||||||
|
{
|
||||||
|
if (settingsFrame == null)
|
||||||
|
{
|
||||||
|
CreateSettingsFrame();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ClientAdminWrite(NetFlags.Properties);
|
||||||
|
foreach (NetPropertyData prop in netProperties.Values)
|
||||||
|
{
|
||||||
|
prop.GUIComponent = null;
|
||||||
|
}
|
||||||
|
settingsFrame = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ManagePlayersFrame(GUIFrame infoFrame)
|
||||||
|
{
|
||||||
|
GUIListBox cList = new GUIListBox(new RectTransform(Vector2.One, infoFrame.RectTransform));
|
||||||
|
/*foreach (Client c in ConnectedClients)
|
||||||
|
{
|
||||||
|
var frame = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), cList.Content.RectTransform),
|
||||||
|
c.Name + " (" + c.Connection.RemoteEndPoint.Address.ToString() + ")", style: "ListBoxElement")
|
||||||
|
{
|
||||||
|
Color = (c.InGame && c.Character != null && !c.Character.IsDead) ? Color.Gold * 0.2f : Color.Transparent,
|
||||||
|
HoverColor = Color.LightGray * 0.5f,
|
||||||
|
SelectedColor = Color.Gold * 0.5f
|
||||||
|
};
|
||||||
|
|
||||||
|
var buttonArea = new GUILayoutGroup(new RectTransform(new Vector2(0.45f, 0.85f), frame.RectTransform, Anchor.CenterRight) { RelativeOffset = new Vector2(0.05f, 0.0f) },
|
||||||
|
isHorizontal: true);
|
||||||
|
|
||||||
|
var kickButton = new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), buttonArea.RectTransform),
|
||||||
|
TextManager.Get("Kick"))
|
||||||
|
{
|
||||||
|
UserData = c.Name,
|
||||||
|
OnClicked = GameMain.NetLobbyScreen.KickPlayer
|
||||||
|
};
|
||||||
|
|
||||||
|
var banButton = new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), buttonArea.RectTransform),
|
||||||
|
TextManager.Get("Ban"))
|
||||||
|
{
|
||||||
|
UserData = c.Name,
|
||||||
|
OnClicked = GameMain.NetLobbyScreen.BanPlayer
|
||||||
|
};
|
||||||
|
|
||||||
|
var rangebanButton = new GUIButton(new RectTransform(new Vector2(0.25f, 1.0f), buttonArea.RectTransform),
|
||||||
|
TextManager.Get("BanRange"))
|
||||||
|
{
|
||||||
|
UserData = c.Name,
|
||||||
|
OnClicked = GameMain.NetLobbyScreen.BanPlayerRange
|
||||||
|
};
|
||||||
|
}*/ //TODO: reimplement
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,7 +26,7 @@ namespace Barotrauma.Networking
|
|||||||
private set;
|
private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DateTime LastEnqueueAudio;
|
public DateTime LastEnqueueAudio;
|
||||||
|
|
||||||
public override byte QueueID
|
public override byte QueueID
|
||||||
{
|
{
|
||||||
@@ -47,10 +47,14 @@ namespace Barotrauma.Networking
|
|||||||
throw new Exception("Tried to instance more than one VoipCapture object");
|
throw new Exception("Tried to instance more than one VoipCapture object");
|
||||||
}
|
}
|
||||||
|
|
||||||
Instance = new VoipCapture(deviceName)
|
var capture = new VoipCapture(deviceName)
|
||||||
{
|
{
|
||||||
LatestBufferID = storedBufferID ?? BUFFER_COUNT - 1
|
LatestBufferID = storedBufferID ?? BUFFER_COUNT - 1
|
||||||
};
|
};
|
||||||
|
if (capture.captureDevice != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Instance = capture;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private VoipCapture(string deviceName) : base(GameMain.Client?.ID ?? 0, true, false)
|
private VoipCapture(string deviceName) : base(GameMain.Client?.ID ?? 0, true, false)
|
||||||
@@ -60,6 +64,14 @@ namespace Barotrauma.Networking
|
|||||||
//set up capture device
|
//set up capture device
|
||||||
captureDevice = Alc.CaptureOpenDevice(deviceName, VoipConfig.FREQUENCY, ALFormat.Mono16, VoipConfig.BUFFER_SIZE * 5);
|
captureDevice = Alc.CaptureOpenDevice(deviceName, VoipConfig.FREQUENCY, ALFormat.Mono16, VoipConfig.BUFFER_SIZE * 5);
|
||||||
|
|
||||||
|
if (captureDevice == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
new GUIMessageBox(TextManager.Get("Error"), TextManager.Get("VoipCaptureDeviceNotFound"));
|
||||||
|
Instance?.Dispose();
|
||||||
|
Instance = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ALError alError = AL.GetError();
|
ALError alError = AL.GetError();
|
||||||
AlcError alcError = Alc.GetError(captureDevice);
|
AlcError alcError = Alc.GetError(captureDevice);
|
||||||
if (alcError != AlcError.NoError)
|
if (alcError != AlcError.NoError)
|
||||||
@@ -70,7 +82,7 @@ namespace Barotrauma.Networking
|
|||||||
{
|
{
|
||||||
throw new Exception("Failed to open capture device: " + alError.ToString() + " (AL)");
|
throw new Exception("Failed to open capture device: " + alError.ToString() + " (AL)");
|
||||||
}
|
}
|
||||||
|
|
||||||
Alc.CaptureStart(captureDevice);
|
Alc.CaptureStart(captureDevice);
|
||||||
alcError = Alc.GetError(captureDevice);
|
alcError = Alc.GetError(captureDevice);
|
||||||
if (alcError != AlcError.NoError)
|
if (alcError != AlcError.NoError)
|
||||||
@@ -159,7 +171,7 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
else if (GameMain.Config.VoiceSetting == GameSettings.VoiceMode.PushToTalk)
|
else if (GameMain.Config.VoiceSetting == GameSettings.VoiceMode.PushToTalk)
|
||||||
{
|
{
|
||||||
if (PlayerInput.KeyDown(InputType.Voice))
|
if (PlayerInput.KeyDown(InputType.Voice) && GUI.KeyboardDispatcher.Subscriber == null)
|
||||||
{
|
{
|
||||||
allowEnqueue = true;
|
allowEnqueue = true;
|
||||||
}
|
}
|
||||||
@@ -201,7 +213,7 @@ namespace Barotrauma.Networking
|
|||||||
{
|
{
|
||||||
Instance = null;
|
Instance = null;
|
||||||
capturing = false;
|
capturing = false;
|
||||||
captureThread.Join();
|
captureThread?.Join();
|
||||||
captureThread = null;
|
captureThread = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ namespace Barotrauma.Networking
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (VoipCapture.Instance == null) VoipCapture.Create(GameMain.Config.VoiceCaptureDevice, storedBufferID);
|
if (VoipCapture.Instance == null) VoipCapture.Create(GameMain.Config.VoiceCaptureDevice, storedBufferID);
|
||||||
if (VoipCapture.Instance.EnqueuedTotalLength <= 0) return;
|
if (VoipCapture.Instance == null || VoipCapture.Instance.EnqueuedTotalLength <= 0) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DateTime.Now >= lastSendTime + VoipConfig.SEND_INTERVAL)
|
if (DateTime.Now >= lastSendTime + VoipConfig.SEND_INTERVAL)
|
||||||
|
|||||||
@@ -401,6 +401,43 @@ namespace Barotrauma
|
|||||||
UpdateSourceRect(limb, newRect);
|
UpdateSourceRect(limb, newRect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
UpdateJointCreation();
|
||||||
|
if (PlayerInput.KeyHit(Keys.Left))
|
||||||
|
{
|
||||||
|
foreach (var limb in selectedLimbs)
|
||||||
|
{
|
||||||
|
var newRect = limb.ActiveSprite.SourceRect;
|
||||||
|
newRect.X--;
|
||||||
|
UpdateSourceRect(limb, newRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (PlayerInput.KeyHit(Keys.Right))
|
||||||
|
{
|
||||||
|
foreach (var limb in selectedLimbs)
|
||||||
|
{
|
||||||
|
var newRect = limb.ActiveSprite.SourceRect;
|
||||||
|
newRect.X++;
|
||||||
|
UpdateSourceRect(limb, newRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (PlayerInput.KeyHit(Keys.Down))
|
||||||
|
{
|
||||||
|
foreach (var limb in selectedLimbs)
|
||||||
|
{
|
||||||
|
var newRect = limb.ActiveSprite.SourceRect;
|
||||||
|
newRect.Y++;
|
||||||
|
UpdateSourceRect(limb, newRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (PlayerInput.KeyHit(Keys.Up))
|
||||||
|
{
|
||||||
|
foreach (var limb in selectedLimbs)
|
||||||
|
{
|
||||||
|
var newRect = limb.ActiveSprite.SourceRect;
|
||||||
|
newRect.Y--;
|
||||||
|
UpdateSourceRect(limb, newRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!isFreezed)
|
if (!isFreezed)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -410,18 +410,6 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateTutorialList()
|
|
||||||
{
|
|
||||||
var tutorialList = menuTabs[(int)Tab.Tutorials].GetChild<GUIListBox>();
|
|
||||||
foreach (GUITextBlock tutorialText in tutorialList.Content.Children)
|
|
||||||
{
|
|
||||||
if (((Tutorial)tutorialText.UserData).Completed)
|
|
||||||
{
|
|
||||||
tutorialText.TextColor = Color.LightGreen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool ApplySettings(GUIButton button, object userData)
|
private bool ApplySettings(GUIButton button, object userData)
|
||||||
{
|
{
|
||||||
GameMain.Config.SaveNewPlayerConfig();
|
GameMain.Config.SaveNewPlayerConfig();
|
||||||
|
|||||||
@@ -78,9 +78,6 @@ namespace Barotrauma
|
|||||||
private GUIButton faceSelectionLeft;
|
private GUIButton faceSelectionLeft;
|
||||||
private GUIButton faceSelectionRight;
|
private GUIButton faceSelectionRight;
|
||||||
|
|
||||||
private GUIButton faceSelectionLeft;
|
|
||||||
private GUIButton faceSelectionRight;
|
|
||||||
|
|
||||||
private float autoRestartTimer;
|
private float autoRestartTimer;
|
||||||
|
|
||||||
//persistent characterinfo provided by the server
|
//persistent characterinfo provided by the server
|
||||||
@@ -125,12 +122,6 @@ namespace Barotrauma
|
|||||||
private set;
|
private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GUIButton ShowLogButton
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
private set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GUIListBox SubList
|
public GUIListBox SubList
|
||||||
{
|
{
|
||||||
get { return subList; }
|
get { return subList; }
|
||||||
|
|||||||
@@ -64,10 +64,6 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private readonly string containerDeleteTag = "containerdelete";
|
private readonly string containerDeleteTag = "containerdelete";
|
||||||
|
|
||||||
private DateTime editorSelectedTime;
|
|
||||||
|
|
||||||
private readonly string containerDeleteTag = "containerdelete";
|
|
||||||
|
|
||||||
public override Camera Cam
|
public override Camera Cam
|
||||||
{
|
{
|
||||||
get { return cam; }
|
get { return cam; }
|
||||||
|
|||||||
Binary file not shown.
@@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
|
|||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("0.8.9.4")]
|
[assembly: AssemblyVersion("0.8.9.5")]
|
||||||
[assembly: AssemblyFileVersion("0.8.9.4")]
|
[assembly: AssemblyFileVersion("0.8.9.5")]
|
||||||
|
|||||||
@@ -116,22 +116,12 @@ namespace Barotrauma.Networking
|
|||||||
ChatMessageType messageType = CanUseRadio(orderMsg.Sender) ? ChatMessageType.Radio : ChatMessageType.Default;
|
ChatMessageType messageType = CanUseRadio(orderMsg.Sender) ? ChatMessageType.Radio : ChatMessageType.Default;
|
||||||
if (orderMsg.Order.TargetAllCharacters)
|
if (orderMsg.Order.TargetAllCharacters)
|
||||||
{
|
{
|
||||||
#if CLIENT
|
//do nothing
|
||||||
//add the order to the crewmanager only if the host is not controlling a character
|
|
||||||
//OR the character is close enough to hear it
|
|
||||||
if (Character.Controlled == null ||
|
|
||||||
!string.IsNullOrEmpty(ApplyDistanceEffect(orderMsg.Text, messageType, orderMsg.Sender, Character.Controlled)))
|
|
||||||
{
|
|
||||||
GameMain.GameSession?.CrewManager?.AddOrder(
|
|
||||||
new Order(orderMsg.Order.Prefab, orderTargetEntity, (orderTargetEntity as Item)?.GetComponent<ItemComponent>()),
|
|
||||||
orderMsg.Order.Prefab.FadeOutTime);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else if (orderTargetCharacter != null)
|
else if (orderTargetCharacter != null)
|
||||||
{
|
{
|
||||||
orderTargetCharacter.SetOrder(
|
orderTargetCharacter.SetOrder(
|
||||||
new Order(orderMsg.Order.Prefab, orderTargetEntity, (orderTargetEntity as Item)?.GetComponent<ItemComponent>()),
|
new Order(orderMsg.Order.Prefab, orderTargetEntity, (orderTargetEntity as Item)?.Components.FirstOrDefault(ic => ic.GetType() == orderMsg.Order.ItemComponentType)),
|
||||||
orderMsg.OrderOption, orderMsg.Sender);
|
orderMsg.OrderOption, orderMsg.Sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -483,7 +483,7 @@ namespace Barotrauma.Networking
|
|||||||
(OwnerConnection == null || c.Connection != OwnerConnection));
|
(OwnerConnection == null || c.Connection != OwnerConnection));
|
||||||
foreach (Client c in kickAFK)
|
foreach (Client c in kickAFK)
|
||||||
{
|
{
|
||||||
KickClient(c, TextManager.Get("DisconnectMessage.AFK"));
|
KickClient(c, "DisconnectMessage.AFK");
|
||||||
}
|
}
|
||||||
|
|
||||||
NetIncomingMessage inc = null;
|
NetIncomingMessage inc = null;
|
||||||
@@ -956,11 +956,11 @@ namespace Barotrauma.Networking
|
|||||||
Log("Client \"" + sender.Name + "\" banned \"" + bannedClient.Name + "\".", ServerLog.MessageType.ServerMessage);
|
Log("Client \"" + sender.Name + "\" banned \"" + bannedClient.Name + "\".", ServerLog.MessageType.ServerMessage);
|
||||||
if (durationSeconds > 0)
|
if (durationSeconds > 0)
|
||||||
{
|
{
|
||||||
BanClient(bannedClient, string.IsNullOrEmpty(banReason) ? "Banned by " + sender.Name : banReason, range, TimeSpan.FromSeconds(durationSeconds));
|
BanClient(bannedClient, string.IsNullOrEmpty(banReason) ? $"ServerMessage.BannedBy_[initiator]={sender.Name}" : banReason, range, TimeSpan.FromSeconds(durationSeconds));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BanClient(bannedClient, string.IsNullOrEmpty(banReason) ? "Banned by " + sender.Name : banReason, range);
|
BanClient(bannedClient, string.IsNullOrEmpty(banReason) ? $"ServerMessage.BannedBy_[initiator]={sender.Name}" : banReason, range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1981,14 +1981,14 @@ namespace Barotrauma.Networking
|
|||||||
client.HasSpawned = false;
|
client.HasSpawned = false;
|
||||||
client.InGame = false;
|
client.InGame = false;
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(msg))
|
if (string.IsNullOrWhiteSpace(msg)) msg = $"ServerMessage.ClientLeftServer_[client]={client.Name}";
|
||||||
|
if (string.IsNullOrWhiteSpace(targetmsg)) targetmsg = "ServerMessage.YouLeftServer";
|
||||||
|
if (!string.IsNullOrWhiteSpace(reason))
|
||||||
{
|
{
|
||||||
msg = $"ServerMessage.ClientLeftServer_[client]={client.Name}";
|
msg += $"; ;ServerMessage.Reason;: ;{reason}";
|
||||||
|
targetmsg += $";\n;ServerMessage.Reason;: ;{reason}";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(targetmsg)) targetmsg = "ServerMessage.YouLeftServer";
|
|
||||||
if (!string.IsNullOrWhiteSpace(reason)) msg += $";ServerMessage.Reason;{reason}";
|
|
||||||
|
|
||||||
Log(msg, ServerLog.MessageType.ServerMessage);
|
Log(msg, ServerLog.MessageType.ServerMessage);
|
||||||
|
|
||||||
if (client.SteamID > 0) { SteamManager.StopAuthSession(client.SteamID); }
|
if (client.SteamID > 0) { SteamManager.StopAuthSession(client.SteamID); }
|
||||||
@@ -2236,7 +2236,7 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
if (type.Value != ChatMessageType.MessageBox)
|
if (type.Value != ChatMessageType.MessageBox)
|
||||||
{
|
{
|
||||||
string myReceivedMessage = message;
|
string myReceivedMessage = TextManager.GetServerMessage(message);
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(myReceivedMessage) &&
|
if (!string.IsNullOrWhiteSpace(myReceivedMessage) &&
|
||||||
(targetClient == null || senderClient == null))
|
(targetClient == null || senderClient == null))
|
||||||
|
|||||||
@@ -0,0 +1,511 @@
|
|||||||
|
using Lidgren.Network;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Barotrauma.Networking
|
||||||
|
{
|
||||||
|
class UnauthenticatedClient
|
||||||
|
{
|
||||||
|
public readonly NetConnection Connection;
|
||||||
|
public readonly ulong SteamID;
|
||||||
|
public Facepunch.Steamworks.ServerAuth.Status? SteamAuthStatus = null;
|
||||||
|
public readonly int Nonce;
|
||||||
|
|
||||||
|
public int FailedAttempts;
|
||||||
|
|
||||||
|
public float AuthTimer;
|
||||||
|
|
||||||
|
public UnauthenticatedClient(NetConnection connection, int nonce, ulong steamID = 0)
|
||||||
|
{
|
||||||
|
Connection = connection;
|
||||||
|
SteamID = steamID;
|
||||||
|
Nonce = nonce;
|
||||||
|
AuthTimer = 10.0f;
|
||||||
|
FailedAttempts = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
partial class GameServer : NetworkMember
|
||||||
|
{
|
||||||
|
private Int32 ownerKey = 0;
|
||||||
|
|
||||||
|
List<UnauthenticatedClient> unauthenticatedClients = new List<UnauthenticatedClient>();
|
||||||
|
|
||||||
|
private void ReadClientSteamAuthRequest(NetIncomingMessage inc, NetConnection senderConnection, out ulong clientSteamID)
|
||||||
|
{
|
||||||
|
clientSteamID = 0;
|
||||||
|
if (!Steam.SteamManager.USE_STEAM)
|
||||||
|
{
|
||||||
|
DebugConsole.Log("Received a Steam auth request from " + senderConnection.RemoteEndPoint + ". Steam authentication not required, handling auth normally.");
|
||||||
|
//not using steam, handle auth normally
|
||||||
|
HandleClientAuthRequest(senderConnection, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (senderConnection == OwnerConnection)
|
||||||
|
{
|
||||||
|
//the client is the owner of the server, no need for authentication
|
||||||
|
//(it would fail with a "duplicate request" error anyway)
|
||||||
|
HandleClientAuthRequest(senderConnection, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clientSteamID = inc.ReadUInt64();
|
||||||
|
int authTicketLength = inc.ReadInt32();
|
||||||
|
inc.ReadBytes(authTicketLength, out byte[] authTicketData);
|
||||||
|
|
||||||
|
DebugConsole.Log("Received a Steam auth request");
|
||||||
|
DebugConsole.Log(" Steam ID: "+ clientSteamID);
|
||||||
|
DebugConsole.Log(" Auth ticket length: " + authTicketLength);
|
||||||
|
DebugConsole.Log(" Auth ticket data: " +
|
||||||
|
((authTicketData == null) ? "null" : ToolBox.LimitString(string.Concat(authTicketData.Select(b => b.ToString("X2"))), 16)));
|
||||||
|
|
||||||
|
if (senderConnection != OwnerConnection &&
|
||||||
|
serverSettings.BanList.IsBanned(senderConnection.RemoteEndPoint.Address, clientSteamID))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ulong steamID = clientSteamID;
|
||||||
|
if (unauthenticatedClients.Any(uc => uc.Connection == inc.SenderConnection))
|
||||||
|
{
|
||||||
|
var steamAuthedClient = unauthenticatedClients.Find(uc =>
|
||||||
|
uc.Connection == inc.SenderConnection &&
|
||||||
|
uc.SteamID == steamID &&
|
||||||
|
uc.SteamAuthStatus == Facepunch.Steamworks.ServerAuth.Status.OK);
|
||||||
|
if (steamAuthedClient != null)
|
||||||
|
{
|
||||||
|
DebugConsole.Log("Client already authenticated, sending AUTH_RESPONSE again...");
|
||||||
|
HandleClientAuthRequest(inc.SenderConnection, steamID);
|
||||||
|
}
|
||||||
|
DebugConsole.Log("Steam authentication already pending...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authTicketData == null)
|
||||||
|
{
|
||||||
|
DebugConsole.Log("Invalid request");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unauthenticatedClients.RemoveAll(uc => uc.Connection == senderConnection);
|
||||||
|
int nonce = CryptoRandom.Instance.Next();
|
||||||
|
var unauthClient = new UnauthenticatedClient(senderConnection, nonce, clientSteamID)
|
||||||
|
{
|
||||||
|
AuthTimer = 20
|
||||||
|
};
|
||||||
|
unauthenticatedClients.Add(unauthClient);
|
||||||
|
|
||||||
|
if (!Steam.SteamManager.StartAuthSession(authTicketData, clientSteamID))
|
||||||
|
{
|
||||||
|
unauthenticatedClients.Remove(unauthClient);
|
||||||
|
if (GameMain.Config.RequireSteamAuthentication)
|
||||||
|
{
|
||||||
|
unauthClient.Connection.Disconnect(DisconnectReason.SteamAuthenticationFailed.ToString());
|
||||||
|
Log("Disconnected unauthenticated client (Steam ID: " + steamID + "). Steam authentication failed.", ServerLog.MessageType.ServerMessage);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DebugConsole.Log("Steam authentication failed, skipping to basic auth...");
|
||||||
|
HandleClientAuthRequest(senderConnection);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnAuthChange(ulong steamID, ulong ownerID, Facepunch.Steamworks.ServerAuth.Status status)
|
||||||
|
{
|
||||||
|
DebugConsole.Log("************ OnAuthChange");
|
||||||
|
DebugConsole.Log(" Steam ID: " + steamID);
|
||||||
|
DebugConsole.Log(" Owner ID: " + ownerID);
|
||||||
|
DebugConsole.Log(" Status: " + status);
|
||||||
|
|
||||||
|
UnauthenticatedClient unauthClient = unauthenticatedClients.Find(uc => uc.SteamID == ownerID);
|
||||||
|
if (unauthClient != null)
|
||||||
|
{
|
||||||
|
unauthClient.SteamAuthStatus = status;
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case Facepunch.Steamworks.ServerAuth.Status.OK:
|
||||||
|
////steam authentication done, check password next
|
||||||
|
Log("Successfully authenticated client via Steam (Steam ID: " + steamID + ").", ServerLog.MessageType.ServerMessage);
|
||||||
|
HandleClientAuthRequest(unauthClient.Connection, unauthClient.SteamID);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
unauthenticatedClients.Remove(unauthClient);
|
||||||
|
if (GameMain.Config.RequireSteamAuthentication)
|
||||||
|
{
|
||||||
|
Log("Disconnected unauthenticated client (Steam ID: " + steamID + "). Steam authentication failed, (" + status + ").", ServerLog.MessageType.ServerMessage);
|
||||||
|
unauthClient.Connection.Disconnect(DisconnectReason.SteamAuthenticationFailed.ToString() + "; (" + status.ToString() + ")");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DebugConsole.Log("Steam authentication failed (" + status.ToString() + "), skipping to basic auth...");
|
||||||
|
HandleClientAuthRequest(unauthClient.Connection);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DebugConsole.Log(" No unauthenticated clients found with the Steam ID " + steamID);
|
||||||
|
}
|
||||||
|
|
||||||
|
//kick connected client if status becomes invalid (e.g. VAC banned, not connected to steam)
|
||||||
|
if (status != Facepunch.Steamworks.ServerAuth.Status.OK && GameMain.Config.RequireSteamAuthentication)
|
||||||
|
{
|
||||||
|
var connectedClient = connectedClients.Find(c => c.SteamID == ownerID);
|
||||||
|
if (connectedClient != null)
|
||||||
|
{
|
||||||
|
Log("Disconnecting client " + connectedClient.Name + " (Steam ID: " + steamID + "). Steam authentication no longer valid (" + status + ").", ServerLog.MessageType.ServerMessage);
|
||||||
|
KickClient(connectedClient, $"DisconnectMessage.SteamAuthNoLongerValid_[status]={status.ToString()}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsServerOwner(NetIncomingMessage inc, NetConnection senderConnection)
|
||||||
|
{
|
||||||
|
string address = senderConnection.RemoteEndPoint.Address.MapToIPv4().ToString();
|
||||||
|
int incKey = inc.ReadInt32();
|
||||||
|
|
||||||
|
if (ownerKey == 0)
|
||||||
|
{
|
||||||
|
return false; //ownership key has been destroyed or has never existed
|
||||||
|
}
|
||||||
|
if (address.ToString() != "127.0.0.1")
|
||||||
|
{
|
||||||
|
return false; //not localhost
|
||||||
|
}
|
||||||
|
|
||||||
|
if (incKey != ownerKey)
|
||||||
|
{
|
||||||
|
return false; //incorrect owner key, how did this even happen
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleOwnership(NetIncomingMessage inc, NetConnection senderConnection)
|
||||||
|
{
|
||||||
|
DebugConsole.Log("HandleOwnership (" + senderConnection.RemoteEndPoint.Address + ")");
|
||||||
|
if (IsServerOwner(inc, senderConnection))
|
||||||
|
{
|
||||||
|
ownerKey = 0; //destroy owner key so nobody else can take ownership of the server
|
||||||
|
OwnerConnection = senderConnection;
|
||||||
|
DebugConsole.NewMessage("Successfully set up server owner", Color.Lime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleClientAuthRequest(NetConnection connection, ulong steamID = 0)
|
||||||
|
{
|
||||||
|
DebugConsole.Log("HandleClientAuthRequest (steamID " + steamID + ")");
|
||||||
|
|
||||||
|
if (GameMain.Config.RequireSteamAuthentication && connection != OwnerConnection && steamID == 0)
|
||||||
|
{
|
||||||
|
DebugConsole.Log("Disconnecting " + connection.RemoteEndPoint + ", Steam authentication required.");
|
||||||
|
connection.Disconnect(DisconnectReason.SteamAuthenticationRequired.ToString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//client wants to know if server requires password
|
||||||
|
if (ConnectedClients.Find(c => c.Connection == connection) != null)
|
||||||
|
{
|
||||||
|
//this client has already been authenticated
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnauthenticatedClient unauthClient = unauthenticatedClients.Find(uc => uc.Connection == connection);
|
||||||
|
if (unauthClient == null)
|
||||||
|
{
|
||||||
|
DebugConsole.Log("Unauthed client, generating a nonce...");
|
||||||
|
//new client, generate nonce and add to unauth queue
|
||||||
|
if (ConnectedClients.Count >= serverSettings.MaxPlayers)
|
||||||
|
{
|
||||||
|
//server is full, can't allow new connection
|
||||||
|
connection.Disconnect(DisconnectReason.ServerFull.ToString());
|
||||||
|
if (steamID > 0) { Steam.SteamManager.StopAuthSession(steamID); }
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nonce = CryptoRandom.Instance.Next();
|
||||||
|
unauthClient = new UnauthenticatedClient(connection, nonce, steamID);
|
||||||
|
unauthenticatedClients.Add(unauthClient);
|
||||||
|
}
|
||||||
|
unauthClient.AuthTimer = 10.0f;
|
||||||
|
//if the client is already in the queue, getting another unauth request means that our response was lost; resend
|
||||||
|
NetOutgoingMessage nonceMsg = server.CreateMessage();
|
||||||
|
nonceMsg.Write((byte)ServerPacketHeader.AUTH_RESPONSE);
|
||||||
|
if (serverSettings.HasPassword && connection != OwnerConnection)
|
||||||
|
{
|
||||||
|
nonceMsg.Write(true); //true = password
|
||||||
|
nonceMsg.Write((Int32)unauthClient.Nonce); //here's nonce, encrypt with this
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nonceMsg.Write(false); //false = no password
|
||||||
|
}
|
||||||
|
CompressOutgoingMessage(nonceMsg);
|
||||||
|
DebugConsole.Log("Sending auth response...");
|
||||||
|
server.SendMessage(nonceMsg, connection, NetDeliveryMethod.Unreliable);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClientInitRequest(NetIncomingMessage inc)
|
||||||
|
{
|
||||||
|
DebugConsole.Log("Received client init request");
|
||||||
|
if (ConnectedClients.Find(c => c.Connection == inc.SenderConnection) != null)
|
||||||
|
{
|
||||||
|
//this client was already authenticated
|
||||||
|
//another init request means they didn't get any update packets yet
|
||||||
|
DebugConsole.Log("Client already connected, ignoring...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnauthenticatedClient unauthClient = unauthenticatedClients.Find(uc => uc.Connection == inc.SenderConnection);
|
||||||
|
if (unauthClient == null)
|
||||||
|
{
|
||||||
|
//client did not ask for nonce first, can't authorize
|
||||||
|
inc.SenderConnection.Disconnect(DisconnectReason.AuthenticationRequired.ToString());
|
||||||
|
if (unauthClient.SteamID > 0) { Steam.SteamManager.StopAuthSession(unauthClient.SteamID); }
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverSettings.HasPassword && inc.SenderConnection != OwnerConnection)
|
||||||
|
{
|
||||||
|
//decrypt message and compare password
|
||||||
|
string clPw = inc.ReadString();
|
||||||
|
if (!serverSettings.IsPasswordCorrect(clPw, unauthClient.Nonce))
|
||||||
|
{
|
||||||
|
unauthClient.FailedAttempts++;
|
||||||
|
if (unauthClient.FailedAttempts > 3)
|
||||||
|
{
|
||||||
|
//disconnect and ban after too many failed attempts
|
||||||
|
serverSettings.BanList.BanPlayer("Unnamed", unauthClient.Connection.RemoteEndPoint.Address, "DisconnectMessage.TooManyFailedLogins", duration: null);
|
||||||
|
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.TooManyFailedLogins, "");
|
||||||
|
|
||||||
|
Log(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " has been banned from the server (too many wrong passwords)", ServerLog.MessageType.Error);
|
||||||
|
DebugConsole.NewMessage(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " has been banned from the server (too many wrong passwords)", Color.Red);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//not disconnecting the player here, because they'll still use the same connection and nonce if they try logging in again
|
||||||
|
NetOutgoingMessage reject = server.CreateMessage();
|
||||||
|
reject.Write((byte)ServerPacketHeader.AUTH_FAILURE);
|
||||||
|
reject.Write("Wrong password! You have " + Convert.ToString(4 - unauthClient.FailedAttempts) + " more attempts before you're banned from the server.");
|
||||||
|
Log(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " failed to join the server (incorrect password)", ServerLog.MessageType.Error);
|
||||||
|
DebugConsole.NewMessage(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " failed to join the server (incorrect password)", Color.Red);
|
||||||
|
CompressOutgoingMessage(reject);
|
||||||
|
server.SendMessage(reject, unauthClient.Connection, NetDeliveryMethod.Unreliable);
|
||||||
|
unauthClient.AuthTimer = 10.0f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string clVersion = inc.ReadString();
|
||||||
|
|
||||||
|
UInt16 contentPackageCount = inc.ReadUInt16();
|
||||||
|
List<string> contentPackageNames = new List<string>();
|
||||||
|
List<string> contentPackageHashes = new List<string>();
|
||||||
|
for (int i = 0; i < contentPackageCount; i++)
|
||||||
|
{
|
||||||
|
string packageName = inc.ReadString();
|
||||||
|
string packageHash = inc.ReadString();
|
||||||
|
contentPackageNames.Add(packageName);
|
||||||
|
contentPackageHashes.Add(packageHash);
|
||||||
|
if (contentPackageCount == 0)
|
||||||
|
{
|
||||||
|
DebugConsole.Log("Client is using content package " +
|
||||||
|
(packageName ?? "null") + " (" + (packageHash ?? "null" + ")"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contentPackageCount == 0)
|
||||||
|
{
|
||||||
|
DebugConsole.Log("Client did not list any content packages.");
|
||||||
|
}
|
||||||
|
|
||||||
|
string clName = Client.SanitizeName(inc.ReadString());
|
||||||
|
if (string.IsNullOrWhiteSpace(clName))
|
||||||
|
{
|
||||||
|
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.NoName, "");
|
||||||
|
|
||||||
|
Log(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " couldn't join the server (no name given)", ServerLog.MessageType.Error);
|
||||||
|
DebugConsole.NewMessage(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " couldn't join the server (no name given)", Color.Red);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clVersion != GameMain.Version.ToString())
|
||||||
|
{
|
||||||
|
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.InvalidVersion,
|
||||||
|
$"DisconnectMessage.InvalidVersion_[version]={GameMain.Version.ToString()}_[clientversion]={clVersion}");
|
||||||
|
|
||||||
|
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong game version)", ServerLog.MessageType.Error);
|
||||||
|
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong game version)", Color.Red);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//check if the client is missing any of the content packages the server requires
|
||||||
|
List<ContentPackage> missingPackages = new List<ContentPackage>();
|
||||||
|
foreach (ContentPackage contentPackage in GameMain.SelectedPackages)
|
||||||
|
{
|
||||||
|
if (!contentPackage.HasMultiplayerIncompatibleContent) continue;
|
||||||
|
bool packageFound = false;
|
||||||
|
for (int i = 0; i < contentPackageCount; i++)
|
||||||
|
{
|
||||||
|
if (contentPackageNames[i] == contentPackage.Name && contentPackageHashes[i] == contentPackage.MD5hash.Hash)
|
||||||
|
{
|
||||||
|
packageFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!packageFound) missingPackages.Add(contentPackage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (missingPackages.Count == 1)
|
||||||
|
{
|
||||||
|
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.MissingContentPackage, $"DisconnectMessage.MissingContentPackage_[missingcontentpackage]={GetPackageStr(missingPackages[0])}");
|
||||||
|
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (missing content package " + GetPackageStr(missingPackages[0]) + ")", ServerLog.MessageType.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (missingPackages.Count > 1)
|
||||||
|
{
|
||||||
|
List<string> packageStrs = new List<string>();
|
||||||
|
missingPackages.ForEach(cp => packageStrs.Add(GetPackageStr(cp)));
|
||||||
|
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.MissingContentPackage, $"DisconnectMessage.MissingContentPackages_[missingcontentpackages]={string.Join(", ", packageStrs)}");
|
||||||
|
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (missing content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string GetPackageStr(ContentPackage contentPackage)
|
||||||
|
{
|
||||||
|
return "\"" + contentPackage.Name + "\" (hash " + contentPackage.MD5hash.ShortHash + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
//check if the client is using any contentpackages that are not compatible with the server
|
||||||
|
List<Pair<string, string>> incompatiblePackages = new List<Pair<string, string>>();
|
||||||
|
for (int i = 0; i < contentPackageNames.Count; i++)
|
||||||
|
{
|
||||||
|
if (!GameMain.Config.SelectedContentPackages.Any(cp => cp.Name == contentPackageNames[i] && cp.MD5hash.Hash == contentPackageHashes[i]))
|
||||||
|
{
|
||||||
|
incompatiblePackages.Add(new Pair<string, string>(contentPackageNames[i], contentPackageHashes[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (incompatiblePackages.Count == 1)
|
||||||
|
{
|
||||||
|
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.IncompatibleContentPackage,
|
||||||
|
$"DisconnectMessage.IncompatibleContentPackage_[incompatiblecontentpackage]={GetPackageStr2(incompatiblePackages[0])}");
|
||||||
|
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible content package " + GetPackageStr2(incompatiblePackages[0]) + ")", ServerLog.MessageType.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (incompatiblePackages.Count > 1)
|
||||||
|
{
|
||||||
|
List<string> packageStrs = new List<string>();
|
||||||
|
incompatiblePackages.ForEach(cp => packageStrs.Add(GetPackageStr2(cp)));
|
||||||
|
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.IncompatibleContentPackage,
|
||||||
|
$"DisconnectMessage.IncompatibleContentPackages_[incompatiblecontentpackages]={string.Join(", ", packageStrs)}");
|
||||||
|
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string GetPackageStr2(Pair<string, string> nameAndHash)
|
||||||
|
{
|
||||||
|
return "\"" + nameAndHash.First + "\" (hash " + Md5Hash.GetShortHash(nameAndHash.Second) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!serverSettings.Whitelist.IsWhiteListed(clName, inc.SenderConnection.RemoteEndPoint.Address))
|
||||||
|
{
|
||||||
|
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.NotOnWhitelist, "");
|
||||||
|
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (not in whitelist)", ServerLog.MessageType.Error);
|
||||||
|
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (not in whitelist)", Color.Red);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!Client.IsValidName(clName, this))
|
||||||
|
{
|
||||||
|
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.InvalidName, "");
|
||||||
|
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (invalid name)", ServerLog.MessageType.Error);
|
||||||
|
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (invalid name)", Color.Red);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (inc.SenderConnection != OwnerConnection && Homoglyphs.Compare(clName.ToLower(),Name.ToLower()))
|
||||||
|
{
|
||||||
|
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.NameTaken, "");
|
||||||
|
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name taken by the server)", ServerLog.MessageType.Error);
|
||||||
|
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name taken by the server)", Color.Red);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Client nameTaken = ConnectedClients.Find(c => Homoglyphs.Compare(c.Name.ToLower(), clName.ToLower()));
|
||||||
|
if (nameTaken != null)
|
||||||
|
{
|
||||||
|
if (nameTaken.Connection.RemoteEndPoint.Address.ToString() == inc.SenderEndPoint.Address.ToString())
|
||||||
|
{
|
||||||
|
//both name and IP address match, replace this player's connection
|
||||||
|
nameTaken.Connection.Disconnect(DisconnectReason.SessionTaken.ToString());
|
||||||
|
nameTaken.Connection = unauthClient.Connection;
|
||||||
|
nameTaken.InitClientSync(); //reinitialize sync ids because this is a new connection
|
||||||
|
unauthenticatedClients.Remove(unauthClient);
|
||||||
|
unauthClient = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//can't authorize this client
|
||||||
|
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.NameTaken, "");
|
||||||
|
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name already taken)", ServerLog.MessageType.Error);
|
||||||
|
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name already taken)", Color.Red);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//new client
|
||||||
|
Client newClient = new Client(clName, GetNewClientID());
|
||||||
|
newClient.InitClientSync();
|
||||||
|
newClient.Connection = unauthClient.Connection;
|
||||||
|
newClient.SteamID = unauthClient.SteamID;
|
||||||
|
unauthenticatedClients.Remove(unauthClient);
|
||||||
|
unauthClient = null;
|
||||||
|
ConnectedClients.Add(newClient);
|
||||||
|
LastClientListUpdateID++;
|
||||||
|
|
||||||
|
if (newClient.Connection == OwnerConnection)
|
||||||
|
{
|
||||||
|
newClient.GivePermission(ClientPermissions.All);
|
||||||
|
newClient.PermittedConsoleCommands.AddRange(DebugConsole.Commands);
|
||||||
|
|
||||||
|
GameMain.Server.UpdateClientPermissions(newClient);
|
||||||
|
GameMain.Server.SendConsoleMessage("Granted all permissions to " + newClient.Name + ".", newClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
GameMain.Server.SendChatMessage($"ServerMessage.JoinedServer_[client]={clName}", ChatMessageType.Server, null);
|
||||||
|
|
||||||
|
var savedPermissions = serverSettings.ClientPermissions.Find(cp =>
|
||||||
|
cp.SteamID > 0 ?
|
||||||
|
cp.SteamID == newClient.SteamID :
|
||||||
|
newClient.IPMatches(cp.IP));
|
||||||
|
|
||||||
|
if (savedPermissions != null)
|
||||||
|
{
|
||||||
|
newClient.SetPermissions(savedPermissions.Permissions, savedPermissions.PermittedCommands);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newClient.SetPermissions(ClientPermissions.None, new List<DebugConsole.Command>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DisconnectUnauthClient(NetIncomingMessage inc, UnauthenticatedClient unauthClient, DisconnectReason reason, string message)
|
||||||
|
{
|
||||||
|
inc.SenderConnection.Disconnect(reason.ToString() + "; " + message);
|
||||||
|
if (unauthClient.SteamID > 0) { Steam.SteamManager.StopAuthSession(unauthClient.SteamID); }
|
||||||
|
if (unauthClient != null)
|
||||||
|
{
|
||||||
|
unauthenticatedClients.Remove(unauthClient);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,482 @@
|
|||||||
|
using Lidgren.Network;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Xml;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
namespace Barotrauma.Networking
|
||||||
|
{
|
||||||
|
partial class ServerSettings
|
||||||
|
{
|
||||||
|
public const string SettingsFile = "serversettings.xml";
|
||||||
|
public static readonly string ClientPermissionsFile = "Data" + Path.DirectorySeparatorChar + "clientpermissions.xml";
|
||||||
|
|
||||||
|
partial void InitProjSpecific()
|
||||||
|
{
|
||||||
|
LoadSettings();
|
||||||
|
LoadClientPermissions();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteNetProperties(NetBuffer outMsg)
|
||||||
|
{
|
||||||
|
outMsg.Write((UInt16)netProperties.Keys.Count);
|
||||||
|
foreach (UInt32 key in netProperties.Keys)
|
||||||
|
{
|
||||||
|
outMsg.Write(key);
|
||||||
|
netProperties[key].Write(outMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ServerAdminWrite(NetBuffer outMsg, Client c)
|
||||||
|
{
|
||||||
|
//outMsg.Write(isPublic);
|
||||||
|
//outMsg.Write(EnableUPnP);
|
||||||
|
//outMsg.WritePadBits();
|
||||||
|
//outMsg.Write((UInt16)QueryPort);
|
||||||
|
|
||||||
|
WriteNetProperties(outMsg);
|
||||||
|
WriteMonsterEnabled(outMsg);
|
||||||
|
BanList.ServerAdminWrite(outMsg, c);
|
||||||
|
Whitelist.ServerAdminWrite(outMsg, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ServerWrite(NetBuffer outMsg,Client c)
|
||||||
|
{
|
||||||
|
outMsg.Write(ServerName);
|
||||||
|
outMsg.Write(ServerMessageText);
|
||||||
|
outMsg.WriteRangedInteger(1, 60, TickRate);
|
||||||
|
|
||||||
|
WriteExtraCargo(outMsg);
|
||||||
|
|
||||||
|
Voting.ServerWrite(outMsg);
|
||||||
|
|
||||||
|
if (c.HasPermission(Networking.ClientPermissions.ManageSettings))
|
||||||
|
{
|
||||||
|
outMsg.Write(true);
|
||||||
|
outMsg.WritePadBits();
|
||||||
|
|
||||||
|
ServerAdminWrite(outMsg, c);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
outMsg.Write(false);
|
||||||
|
outMsg.WritePadBits();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ServerRead(NetIncomingMessage incMsg,Client c)
|
||||||
|
{
|
||||||
|
if (!c.HasPermission(Networking.ClientPermissions.ManageSettings)) return;
|
||||||
|
|
||||||
|
NetFlags flags = (NetFlags)incMsg.ReadByte();
|
||||||
|
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
|
if (flags.HasFlag(NetFlags.Name))
|
||||||
|
{
|
||||||
|
string serverName = incMsg.ReadString();
|
||||||
|
if (ServerName != serverName) changed = true;
|
||||||
|
ServerName = serverName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags.HasFlag(NetFlags.Message))
|
||||||
|
{
|
||||||
|
string serverMessageText = incMsg.ReadString();
|
||||||
|
if (ServerMessageText != serverMessageText) changed = true;
|
||||||
|
ServerMessageText = serverMessageText;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags.HasFlag(NetFlags.Properties))
|
||||||
|
{
|
||||||
|
changed |= ReadExtraCargo(incMsg);
|
||||||
|
|
||||||
|
UInt32 count = incMsg.ReadUInt32();
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
UInt32 key = incMsg.ReadUInt32();
|
||||||
|
|
||||||
|
if (netProperties.ContainsKey(key))
|
||||||
|
{
|
||||||
|
netProperties[key].Read(incMsg);
|
||||||
|
GameServer.Log(c.Name + " changed " + netProperties[key].Name + " to " + netProperties[key].Value.ToString(), ServerLog.MessageType.ServerMessage);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UInt32 size = incMsg.ReadVariableUInt32();
|
||||||
|
incMsg.Position += 8 * size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool changedMonsterSettings = incMsg.ReadBoolean(); incMsg.ReadPadBits();
|
||||||
|
changed |= changedMonsterSettings;
|
||||||
|
if (changedMonsterSettings) ReadMonsterEnabled(incMsg);
|
||||||
|
changed |= BanList.ServerAdminRead(incMsg, c);
|
||||||
|
changed |= Whitelist.ServerAdminRead(incMsg, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags.HasFlag(NetFlags.Misc))
|
||||||
|
{
|
||||||
|
int missionType = GameMain.NetLobbyScreen.MissionTypeIndex + incMsg.ReadByte() - 1;
|
||||||
|
while (missionType < 0) missionType += Enum.GetValues(typeof(MissionType)).Length;
|
||||||
|
while (missionType >= Enum.GetValues(typeof(MissionType)).Length) missionType -= Enum.GetValues(typeof(MissionType)).Length;
|
||||||
|
GameMain.NetLobbyScreen.MissionTypeIndex = missionType;
|
||||||
|
|
||||||
|
int traitorSetting = (int)TraitorsEnabled + incMsg.ReadByte() - 1;
|
||||||
|
if (traitorSetting < 0) traitorSetting = 2;
|
||||||
|
if (traitorSetting > 2) traitorSetting = 0;
|
||||||
|
TraitorsEnabled = (YesNoMaybe)traitorSetting;
|
||||||
|
|
||||||
|
int botCount = BotCount + incMsg.ReadByte() - 1;
|
||||||
|
if (botCount < 0) botCount = MaxBotCount;
|
||||||
|
if (botCount > MaxBotCount) botCount = 0;
|
||||||
|
BotCount = botCount;
|
||||||
|
|
||||||
|
int botSpawnMode = (int)BotSpawnMode + incMsg.ReadByte() - 1;
|
||||||
|
if (botSpawnMode < 0) botSpawnMode = 1;
|
||||||
|
if (botSpawnMode > 1) botSpawnMode = 0;
|
||||||
|
BotSpawnMode = (BotSpawnMode)botSpawnMode;
|
||||||
|
|
||||||
|
float levelDifficulty = incMsg.ReadFloat();
|
||||||
|
if (levelDifficulty >= 0.0f) SelectedLevelDifficulty = levelDifficulty;
|
||||||
|
|
||||||
|
bool changedAutoRestart = incMsg.ReadBoolean();
|
||||||
|
bool autoRestart = incMsg.ReadBoolean();
|
||||||
|
if (changedAutoRestart)
|
||||||
|
{
|
||||||
|
AutoRestart = autoRestart;
|
||||||
|
}
|
||||||
|
|
||||||
|
changed |= true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags.HasFlag(NetFlags.LevelSeed))
|
||||||
|
{
|
||||||
|
GameMain.NetLobbyScreen.LevelSeed = incMsg.ReadString();
|
||||||
|
changed |= true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed) GameMain.NetLobbyScreen.LastUpdateID++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveSettings()
|
||||||
|
{
|
||||||
|
XDocument doc = new XDocument(new XElement("serversettings"));
|
||||||
|
|
||||||
|
SerializableProperty.SerializeProperties(this, doc.Root, true);
|
||||||
|
|
||||||
|
doc.Root.SetAttributeValue("name", ServerName);
|
||||||
|
doc.Root.SetAttributeValue("public", isPublic);
|
||||||
|
doc.Root.SetAttributeValue("port", GameMain.Server.NetPeerConfiguration.Port);
|
||||||
|
if (Steam.SteamManager.USE_STEAM) doc.Root.SetAttributeValue("queryport", QueryPort);
|
||||||
|
doc.Root.SetAttributeValue("maxplayers", maxPlayers);
|
||||||
|
doc.Root.SetAttributeValue("enableupnp", GameMain.Server.NetPeerConfiguration.EnableUPnP);
|
||||||
|
|
||||||
|
doc.Root.SetAttributeValue("autorestart", autoRestart);
|
||||||
|
|
||||||
|
doc.Root.SetAttributeValue("SubSelection", SubSelectionMode.ToString());
|
||||||
|
doc.Root.SetAttributeValue("ModeSelection", ModeSelectionMode.ToString());
|
||||||
|
doc.Root.SetAttributeValue("LevelDifficulty", ((int)selectedLevelDifficulty).ToString());
|
||||||
|
doc.Root.SetAttributeValue("TraitorsEnabled", TraitorsEnabled.ToString());
|
||||||
|
|
||||||
|
/*doc.Root.SetAttributeValue("BotCount", BotCount);
|
||||||
|
doc.Root.SetAttributeValue("MaxBotCount", MaxBotCount);*/
|
||||||
|
doc.Root.SetAttributeValue("BotSpawnMode", BotSpawnMode.ToString());
|
||||||
|
|
||||||
|
doc.Root.SetAttributeValue("AllowedRandomMissionTypes", string.Join(",", AllowedRandomMissionTypes));
|
||||||
|
|
||||||
|
doc.Root.SetAttributeValue("AllowedClientNameChars", string.Join(",", AllowedClientNameChars.Select(c => c.First + "-" + c.Second)));
|
||||||
|
|
||||||
|
doc.Root.SetAttributeValue("ServerMessage", ServerMessageText);
|
||||||
|
|
||||||
|
XmlWriterSettings settings = new XmlWriterSettings
|
||||||
|
{
|
||||||
|
Indent = true,
|
||||||
|
NewLineOnAttributes = true
|
||||||
|
};
|
||||||
|
|
||||||
|
using (var writer = XmlWriter.Create(SettingsFile, settings))
|
||||||
|
{
|
||||||
|
doc.Save(writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadSettings()
|
||||||
|
{
|
||||||
|
XDocument doc = null;
|
||||||
|
if (File.Exists(SettingsFile))
|
||||||
|
{
|
||||||
|
doc = XMLExtensions.TryLoadXml(SettingsFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doc == null || doc.Root == null)
|
||||||
|
{
|
||||||
|
doc = new XDocument(new XElement("serversettings"));
|
||||||
|
}
|
||||||
|
|
||||||
|
SerializableProperties = SerializableProperty.DeserializeProperties(this, doc.Root);
|
||||||
|
|
||||||
|
AutoRestart = doc.Root.GetAttributeBool("autorestart", false);
|
||||||
|
|
||||||
|
Voting.AllowSubVoting = SubSelectionMode == SelectionMode.Vote;
|
||||||
|
Voting.AllowModeVoting = ModeSelectionMode == SelectionMode.Vote;
|
||||||
|
|
||||||
|
selectedLevelDifficulty = doc.Root.GetAttributeFloat("LevelDifficulty", 20.0f);
|
||||||
|
GameMain.NetLobbyScreen.SetLevelDifficulty(selectedLevelDifficulty);
|
||||||
|
|
||||||
|
var traitorsEnabled = TraitorsEnabled;
|
||||||
|
Enum.TryParse(doc.Root.GetAttributeString("TraitorsEnabled", "No"), out traitorsEnabled);
|
||||||
|
TraitorsEnabled = traitorsEnabled;
|
||||||
|
GameMain.NetLobbyScreen.SetTraitorsEnabled(traitorsEnabled);
|
||||||
|
|
||||||
|
var botSpawnMode = BotSpawnMode.Fill;
|
||||||
|
Enum.TryParse(doc.Root.GetAttributeString("BotSpawnMode", "Fill"), out botSpawnMode);
|
||||||
|
BotSpawnMode = botSpawnMode;
|
||||||
|
|
||||||
|
//"65-90", "97-122", "48-59" = upper and lower case english alphabet and numbers
|
||||||
|
string[] allowedClientNameCharsStr = doc.Root.GetAttributeStringArray("AllowedClientNameChars", new string[] { "65-90", "97-122", "48-59" });
|
||||||
|
foreach (string allowedClientNameCharRange in allowedClientNameCharsStr)
|
||||||
|
{
|
||||||
|
string[] splitRange = allowedClientNameCharRange.Split('-');
|
||||||
|
if (splitRange.Length == 0 || splitRange.Length > 2)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Error in server settings - " + allowedClientNameCharRange + " is not a valid range for characters allowed in client names.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int min = -1;
|
||||||
|
if (!int.TryParse(splitRange[0], out min))
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Error in server settings - " + allowedClientNameCharRange + " is not a valid range for characters allowed in client names.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int max = min;
|
||||||
|
if (splitRange.Length == 2)
|
||||||
|
{
|
||||||
|
if (!int.TryParse(splitRange[1], out max))
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Error in server settings - " + allowedClientNameCharRange + " is not a valid range for characters allowed in client names.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (min > -1 && max > -1) AllowedClientNameChars.Add(new Pair<int, int>(min, max));
|
||||||
|
}
|
||||||
|
|
||||||
|
AllowedRandomMissionTypes = new List<MissionType>();
|
||||||
|
string[] allowedMissionTypeNames = doc.Root.GetAttributeStringArray(
|
||||||
|
"AllowedRandomMissionTypes", Enum.GetValues(typeof(MissionType)).Cast<MissionType>().Select(m => m.ToString()).ToArray());
|
||||||
|
foreach (string missionTypeName in allowedMissionTypeNames)
|
||||||
|
{
|
||||||
|
if (Enum.TryParse(missionTypeName, out MissionType missionType))
|
||||||
|
{
|
||||||
|
if (missionType == Barotrauma.MissionType.None) continue;
|
||||||
|
AllowedRandomMissionTypes.Add(missionType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerName = doc.Root.GetAttributeString("name", "");
|
||||||
|
ServerMessageText = doc.Root.GetAttributeString("ServerMessage", "");
|
||||||
|
|
||||||
|
GameMain.NetLobbyScreen.SelectedModeIdentifier = GameModeIdentifier;
|
||||||
|
GameMain.NetLobbyScreen.MissionTypeName = MissionType;
|
||||||
|
|
||||||
|
GameMain.NetLobbyScreen.SetBotSpawnMode(BotSpawnMode);
|
||||||
|
GameMain.NetLobbyScreen.SetBotCount(BotCount);
|
||||||
|
|
||||||
|
List<string> monsterNames = GameMain.Instance.GetFilesOfType(ContentType.Character).ToList();
|
||||||
|
for (int i = 0; i < monsterNames.Count; i++)
|
||||||
|
{
|
||||||
|
monsterNames[i] = Path.GetFileName(Path.GetDirectoryName(monsterNames[i]));
|
||||||
|
}
|
||||||
|
MonsterEnabled = new Dictionary<string, bool>();
|
||||||
|
foreach (string s in monsterNames)
|
||||||
|
{
|
||||||
|
if (!MonsterEnabled.ContainsKey(s)) MonsterEnabled.Add(s, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
AutoBanTime = doc.Root.GetAttributeFloat("autobantime", 60);
|
||||||
|
MaxAutoBanTime = doc.Root.GetAttributeFloat("maxautobantime", 360);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadClientPermissions()
|
||||||
|
{
|
||||||
|
ClientPermissions.Clear();
|
||||||
|
|
||||||
|
if (!File.Exists(ClientPermissionsFile))
|
||||||
|
{
|
||||||
|
if (File.Exists("Data/clientpermissions.txt"))
|
||||||
|
{
|
||||||
|
LoadClientPermissionsOld("Data/clientpermissions.txt");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
XDocument doc = XMLExtensions.TryLoadXml(ClientPermissionsFile);
|
||||||
|
foreach (XElement clientElement in doc.Root.Elements())
|
||||||
|
{
|
||||||
|
string clientName = clientElement.GetAttributeString("name", "");
|
||||||
|
string clientIP = clientElement.GetAttributeString("ip", "");
|
||||||
|
string steamIdStr = clientElement.GetAttributeString("steamid", "");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(clientName))
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - all clients must have a name and an IP address.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (string.IsNullOrWhiteSpace(clientIP) && string.IsNullOrWhiteSpace(steamIdStr))
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - all clients must have an IP address or a Steam ID.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
string permissionsStr = clientElement.GetAttributeString("permissions", "");
|
||||||
|
ClientPermissions permissions = Networking.ClientPermissions.None;
|
||||||
|
if (permissionsStr.ToLowerInvariant() == "all")
|
||||||
|
{
|
||||||
|
foreach (ClientPermissions permission in Enum.GetValues(typeof(ClientPermissions)))
|
||||||
|
{
|
||||||
|
permissions |= permission;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!Enum.TryParse(permissionsStr, out permissions))
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - \"" + permissionsStr + "\" is not a valid client permission.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<DebugConsole.Command> permittedCommands = new List<DebugConsole.Command>();
|
||||||
|
if (permissions.HasFlag(Networking.ClientPermissions.ConsoleCommands))
|
||||||
|
{
|
||||||
|
foreach (XElement commandElement in clientElement.Elements())
|
||||||
|
{
|
||||||
|
if (commandElement.Name.ToString().ToLowerInvariant() != "command") continue;
|
||||||
|
|
||||||
|
string commandName = commandElement.GetAttributeString("name", "");
|
||||||
|
DebugConsole.Command command = DebugConsole.FindCommand(commandName);
|
||||||
|
if (command == null)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - \"" + commandName + "\" is not a valid console command.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
permittedCommands.Add(command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(steamIdStr))
|
||||||
|
{
|
||||||
|
if (ulong.TryParse(steamIdStr, out ulong steamID))
|
||||||
|
{
|
||||||
|
ClientPermissions.Add(new SavedClientPermission(clientName, steamID, permissions, permittedCommands));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - \"" + steamIdStr + "\" is not a valid Steam ID.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ClientPermissions.Add(new SavedClientPermission(clientName, clientIP, permissions, permittedCommands));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Method for loading old .txt client permission files to provide backwards compatibility
|
||||||
|
/// </summary>
|
||||||
|
private void LoadClientPermissionsOld(string file)
|
||||||
|
{
|
||||||
|
if (!File.Exists(file)) return;
|
||||||
|
|
||||||
|
string[] lines;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lines = File.ReadAllLines(file);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Failed to open client permission file " + ClientPermissionsFile, e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientPermissions.Clear();
|
||||||
|
|
||||||
|
foreach (string line in lines)
|
||||||
|
{
|
||||||
|
string[] separatedLine = line.Split('|');
|
||||||
|
if (separatedLine.Length < 3) continue;
|
||||||
|
|
||||||
|
string name = string.Join("|", separatedLine.Take(separatedLine.Length - 2));
|
||||||
|
string ip = separatedLine[separatedLine.Length - 2];
|
||||||
|
|
||||||
|
ClientPermissions permissions = Networking.ClientPermissions.None;
|
||||||
|
if (Enum.TryParse(separatedLine.Last(), out permissions))
|
||||||
|
{
|
||||||
|
ClientPermissions.Add(new SavedClientPermission(name, ip, permissions, new List<DebugConsole.Command>()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveClientPermissions()
|
||||||
|
{
|
||||||
|
//delete old client permission file
|
||||||
|
if (File.Exists("Data/clientpermissions.txt"))
|
||||||
|
{
|
||||||
|
File.Delete("Data/clientpermissions.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
GameServer.Log("Saving client permissions", ServerLog.MessageType.ServerMessage);
|
||||||
|
|
||||||
|
XDocument doc = new XDocument(new XElement("ClientPermissions"));
|
||||||
|
|
||||||
|
foreach (SavedClientPermission clientPermission in ClientPermissions)
|
||||||
|
{
|
||||||
|
XElement clientElement = new XElement("Client",
|
||||||
|
new XAttribute("name", clientPermission.Name),
|
||||||
|
new XAttribute("permissions", clientPermission.Permissions.ToString()));
|
||||||
|
|
||||||
|
if (clientPermission.SteamID > 0)
|
||||||
|
{
|
||||||
|
clientElement.Add(new XAttribute("steamid", clientPermission.SteamID));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
clientElement.Add(new XAttribute("ip", clientPermission.IP));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clientPermission.Permissions.HasFlag(Barotrauma.Networking.ClientPermissions.ConsoleCommands))
|
||||||
|
{
|
||||||
|
foreach (DebugConsole.Command command in clientPermission.PermittedCommands)
|
||||||
|
{
|
||||||
|
clientElement.Add(new XElement("command", new XAttribute("name", command.names[0])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
doc.Root.Add(clientElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
XmlWriterSettings settings = new XmlWriterSettings();
|
||||||
|
settings.Indent = true;
|
||||||
|
settings.NewLineOnAttributes = true;
|
||||||
|
|
||||||
|
using (var writer = XmlWriter.Create(ClientPermissionsFile, settings))
|
||||||
|
{
|
||||||
|
doc.Save(writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Saving client permissions to " + ClientPermissionsFile + " failed", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2908,7 +2908,7 @@
|
|||||||
<None Include="$(MSBuildThisFileDirectory)Content\Sounds\Damage\HitClown2.ogg">
|
<None Include="$(MSBuildThisFileDirectory)Content\Sounds\Damage\HitClown2.ogg">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Include="$(MSBuildThisFileDirectory)Content\Sounds\Damage\implode.ogg">
|
<None Include="$(MSBuildThisFileDirectory)Content\Sounds\Damage\Implode.ogg">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<None Include="$(MSBuildThisFileDirectory)Content\Sounds\Damage\LimbSlash1.ogg">
|
<None Include="$(MSBuildThisFileDirectory)Content\Sounds\Damage\LimbSlash1.ogg">
|
||||||
@@ -3322,4 +3322,4 @@
|
|||||||
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\HireManager.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\HireManager.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Animation\HumanoidAnimParams.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Animation\HumanoidAnimParams.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -188,45 +188,6 @@ namespace Barotrauma
|
|||||||
newOrder = new Order(orderPrefab, Character.CurrentHull, null);
|
newOrder = new Order(orderPrefab, Character.CurrentHull, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Character.CurrentHull.ConnectedGaps.Any(g => !g.IsRoomToRoom && g.ConnectedDoor == null && g.Open > 0.0f))
|
|
||||||
{
|
|
||||||
var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportbreach");
|
|
||||||
newOrder = new Order(orderPrefab, Character.CurrentHull, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (Character c in Character.CharacterList)
|
|
||||||
{
|
|
||||||
if (c.CurrentHull == Character.CurrentHull && !c.IsDead &&
|
|
||||||
(c.AIController is EnemyAIController || c.TeamID != Character.TeamID))
|
|
||||||
{
|
|
||||||
var orderPrefab = Order.PrefabList.Find(o => o.AITag == "reportintruders");
|
|
||||||
newOrder = new Order(orderPrefab, Character.CurrentHull, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Character.CurrentHull != null && (Character.Bleeding > 1.0f || Character.Vitality < Character.MaxVitality * 0.1f))
|
|
||||||
{
|
|
||||||
var orderPrefab = Order.PrefabList.Find(o => o.AITag == "requestfirstaid");
|
|
||||||
newOrder = new Order(orderPrefab, Character.CurrentHull, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newOrder != null)
|
|
||||||
{
|
|
||||||
if (GameMain.GameSession?.CrewManager != null && GameMain.GameSession.CrewManager.AddOrder(newOrder, newOrder.FadeOutTime))
|
|
||||||
{
|
|
||||||
Character.Speak(
|
|
||||||
newOrder.GetChatMessage("", Character.CurrentHull?.RoomName), ChatMessageType.Order);
|
|
||||||
|
|
||||||
if (GameMain.Server != null)
|
|
||||||
{
|
|
||||||
OrderChatMessage msg = new OrderChatMessage(newOrder, "", Character.CurrentHull, null, Character);
|
|
||||||
GameMain.Server.SendOrderChatMessage(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
partial void ReportProblems();
|
partial void ReportProblems();
|
||||||
|
|
||||||
private void UpdateSpeaking()
|
private void UpdateSpeaking()
|
||||||
@@ -299,21 +260,5 @@ namespace Barotrauma
|
|||||||
float minCeilingDist = Character.AnimController.Collider.height / 2 + Character.AnimController.Collider.radius + 0.1f;
|
float minCeilingDist = Character.AnimController.Collider.height / 2 + Character.AnimController.Collider.radius + 0.1f;
|
||||||
shouldCrouch = Submarine.PickBody(startPos, startPos + Vector2.UnitY * minCeilingDist, null, Physics.CollisionWall) != null;
|
shouldCrouch = Submarine.PickBody(startPos, startPos + Vector2.UnitY * minCeilingDist, null, Physics.CollisionWall) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CheckCrouching(float deltaTime)
|
|
||||||
{
|
|
||||||
crouchRaycastTimer -= deltaTime;
|
|
||||||
if (crouchRaycastTimer > 0.0f) return;
|
|
||||||
|
|
||||||
crouchRaycastTimer = CrouchRaycastInterval;
|
|
||||||
|
|
||||||
//start the raycast in front of the character in the direction it's heading to
|
|
||||||
Vector2 startPos = Character.SimPosition;
|
|
||||||
startPos.X += MathHelper.Clamp(Character.AnimController.TargetMovement.X, -1.0f, 1.0f);
|
|
||||||
|
|
||||||
//do a raycast upwards to find any walls
|
|
||||||
float minCeilingDist = Character.AnimController.Collider.height / 2 + Character.AnimController.Collider.radius + 0.1f;
|
|
||||||
shouldCrouch = Submarine.PickBody(startPos, startPos + Vector2.UnitY * minCeilingDist, null, Physics.CollisionWall) != null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -697,6 +697,22 @@ namespace Barotrauma
|
|||||||
limb?.body.SmoothRotate(angle, torque, wrapAngle: false);
|
limb?.body.SmoothRotate(angle, torque, wrapAngle: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SmoothRotateWithoutWrapping(Limb limb, float angle, Limb referenceLimb, float torque)
|
||||||
|
{
|
||||||
|
//make sure the angle "has the same number of revolutions" as the reference limb
|
||||||
|
//(e.g. we don't want to rotate the legs to 0 if the torso is at 360, because that'd blow up the hip joints)
|
||||||
|
while (referenceLimb.Rotation - angle > MathHelper.TwoPi)
|
||||||
|
{
|
||||||
|
angle += MathHelper.TwoPi;
|
||||||
|
}
|
||||||
|
while (referenceLimb.Rotation - angle < -MathHelper.TwoPi)
|
||||||
|
{
|
||||||
|
angle -= MathHelper.TwoPi;
|
||||||
|
}
|
||||||
|
|
||||||
|
limb?.body.SmoothRotate(angle, torque, wrapAngle: false);
|
||||||
|
}
|
||||||
|
|
||||||
public override void Flip()
|
public override void Flip()
|
||||||
{
|
{
|
||||||
base.Flip();
|
base.Flip();
|
||||||
|
|||||||
@@ -1297,6 +1297,7 @@ namespace Barotrauma
|
|||||||
CheckValidity(Collider);
|
CheckValidity(Collider);
|
||||||
foreach (Limb limb in limbs)
|
foreach (Limb limb in limbs)
|
||||||
{
|
{
|
||||||
|
if (limb.body == null || !limb.body.Enabled) { continue; }
|
||||||
CheckValidity(limb.body);
|
CheckValidity(limb.body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1323,7 +1324,11 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
if (errorMsg != null)
|
if (errorMsg != null)
|
||||||
{
|
{
|
||||||
|
#if DEBUG
|
||||||
DebugConsole.ThrowError(errorMsg);
|
DebugConsole.ThrowError(errorMsg);
|
||||||
|
#else
|
||||||
|
DebugConsole.NewMessage(errorMsg, Color.Red);
|
||||||
|
#endif
|
||||||
GameAnalyticsManager.AddErrorEventOnce("Ragdoll.CheckValidity:" + character.ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
GameAnalyticsManager.AddErrorEventOnce("Ragdoll.CheckValidity:" + character.ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||||
|
|
||||||
if (!MathUtils.IsValid(Collider.SimPosition) || Math.Abs(Collider.SimPosition.X) > 1e10f || Math.Abs(Collider.SimPosition.Y) > 1e10f)
|
if (!MathUtils.IsValid(Collider.SimPosition) || Math.Abs(Collider.SimPosition.X) > 1e10f || Math.Abs(Collider.SimPosition.Y) > 1e10f)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using System.Xml.Linq;
|
|||||||
using Barotrauma.Items.Components;
|
using Barotrauma.Items.Components;
|
||||||
using FarseerPhysics.Dynamics;
|
using FarseerPhysics.Dynamics;
|
||||||
using Barotrauma.Extensions;
|
using Barotrauma.Extensions;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
@@ -529,37 +530,6 @@ namespace Barotrauma
|
|||||||
set { canInventoryBeAccessed = value; }
|
set { canInventoryBeAccessed = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool canBeDragged = true;
|
|
||||||
public bool CanBeDragged
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (!canBeDragged) { return false; }
|
|
||||||
if (Removed || !AnimController.Draggable) { return false; }
|
|
||||||
return IsDead || Stun > 0.0f || LockHands || IsUnconscious;
|
|
||||||
}
|
|
||||||
set { canBeDragged = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
//can other characters access the inventory of this character
|
|
||||||
private bool canInventoryBeAccessed = true;
|
|
||||||
public bool CanInventoryBeAccessed
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (!canInventoryBeAccessed || Removed || Inventory == null) { return false; }
|
|
||||||
if (!Inventory.AccessibleWhenAlive)
|
|
||||||
{
|
|
||||||
return IsDead;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return (IsDead || Stun > 0.0f || LockHands || IsUnconscious);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
set { canInventoryBeAccessed = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Vector2 SimPosition
|
public override Vector2 SimPosition
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -1017,10 +987,6 @@ namespace Barotrauma
|
|||||||
public Vector2? OverrideMovement { get; set; }
|
public Vector2? OverrideMovement { get; set; }
|
||||||
public bool ForceRun { get; set; }
|
public bool ForceRun { get; set; }
|
||||||
|
|
||||||
// TODO: reposition? there's also the overrideTargetMovement variable, but it's not in the same manner
|
|
||||||
public Vector2? OverrideMovement { get; set; }
|
|
||||||
public bool ForceRun { get; set; }
|
|
||||||
|
|
||||||
public Vector2 GetTargetMovement()
|
public Vector2 GetTargetMovement()
|
||||||
{
|
{
|
||||||
Vector2 targetMovement = Vector2.Zero;
|
Vector2 targetMovement = Vector2.Zero;
|
||||||
@@ -1069,7 +1035,24 @@ namespace Barotrauma
|
|||||||
|
|
||||||
ResetSpeedMultiplier(); // Reset, items will set the value before the next update
|
ResetSpeedMultiplier(); // Reset, items will set the value before the next update
|
||||||
|
|
||||||
return targetMovement;
|
//?
|
||||||
|
//currMaxSpeed *= 1.5f;
|
||||||
|
|
||||||
|
var leftFoot = AnimController.GetLimb(LimbType.LeftFoot);
|
||||||
|
if (leftFoot != null)
|
||||||
|
{
|
||||||
|
float footAfflictionStrength = CharacterHealth.GetAfflictionStrength("damage", leftFoot, true);
|
||||||
|
currMaxSpeed *= MathHelper.Lerp(1.0f, 0.25f, MathHelper.Clamp(footAfflictionStrength / 100.0f, 0.0f, 1.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
var rightFoot = AnimController.GetLimb(LimbType.RightFoot);
|
||||||
|
if (rightFoot != null)
|
||||||
|
{
|
||||||
|
float footAfflictionStrength = CharacterHealth.GetAfflictionStrength("damage", rightFoot, true);
|
||||||
|
currMaxSpeed *= MathHelper.Lerp(1.0f, 0.25f, MathHelper.Clamp(footAfflictionStrength / 100.0f, 0.0f, 1.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
return currMaxSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -2202,16 +2185,17 @@ namespace Barotrauma
|
|||||||
#if SERVER
|
#if SERVER
|
||||||
if (attacker is Character attackingCharacter && attackingCharacter.AIController == null)
|
if (attacker is Character attackingCharacter && attackingCharacter.AIController == null)
|
||||||
{
|
{
|
||||||
string logMsg = LogName + " attacked by " + attackingCharacter.LogName + ".";
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.Append(LogName + " attacked by " + attackingCharacter.LogName + ".");
|
||||||
if (attackResult.Afflictions != null)
|
if (attackResult.Afflictions != null)
|
||||||
{
|
{
|
||||||
foreach (Affliction affliction in attackResult.Afflictions)
|
foreach (Affliction affliction in attackResult.Afflictions)
|
||||||
{
|
{
|
||||||
if (affliction.Strength == 0.0f) continue;
|
if (affliction.Strength == 0.0f) continue;
|
||||||
logMsg += affliction.Prefab.Name + ": " + affliction.Strength;
|
sb.Append($" {affliction.Prefab.Name}: {affliction.Strength}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GameServer.Log(logMsg, ServerLog.MessageType.Attack);
|
GameServer.Log(sb.ToString(), ServerLog.MessageType.Attack);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -980,68 +980,6 @@ namespace Barotrauma
|
|||||||
NewMessage("Set packet duplication to " + (int)(duplicates * 100) + "%.", Color.White);
|
NewMessage("Set packet duplication to " + (int)(duplicates * 100) + "%.", Color.White);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
commands.Add(new Command("simulatedlatency", "simulatedlatency [minimumlatencyseconds] [randomlatencyseconds]: applies a simulated latency to network messages. Useful for simulating real network conditions when testing the multiplayer locally.", (string[] args) =>
|
|
||||||
{
|
|
||||||
if (args.Count() < 2 || (GameMain.Client == null && GameMain.Server == null)) return;
|
|
||||||
if (!float.TryParse(args[0], NumberStyles.Any, CultureInfo.InvariantCulture, out float minimumLatency))
|
|
||||||
{
|
|
||||||
ThrowError(args[0] + " is not a valid latency value.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!float.TryParse(args[0], NumberStyles.Any, CultureInfo.InvariantCulture, out float randomLatency))
|
|
||||||
{
|
|
||||||
ThrowError(args[1] + " is not a valid latency value.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (GameMain.Client != null)
|
|
||||||
{
|
|
||||||
GameMain.Client.NetPeerConfiguration.SimulatedMinimumLatency = minimumLatency;
|
|
||||||
GameMain.Client.NetPeerConfiguration.SimulatedRandomLatency = randomLatency;
|
|
||||||
}
|
|
||||||
else if (GameMain.Server != null)
|
|
||||||
{
|
|
||||||
GameMain.Server.NetPeerConfiguration.SimulatedMinimumLatency = minimumLatency;
|
|
||||||
GameMain.Server.NetPeerConfiguration.SimulatedRandomLatency = randomLatency;
|
|
||||||
}
|
|
||||||
NewMessage("Set simulated minimum latency to " + minimumLatency + " and random latency to " + randomLatency + ".", Color.White);
|
|
||||||
}));
|
|
||||||
commands.Add(new Command("simulatedloss", "simulatedloss [lossratio]: applies simulated packet loss to network messages. For example, a value of 0.1 would mean 10% of the packets are dropped. Useful for simulating real network conditions when testing the multiplayer locally.", (string[] args) =>
|
|
||||||
{
|
|
||||||
if (args.Count() < 1 || (GameMain.Client == null && GameMain.Server == null)) return;
|
|
||||||
if (!float.TryParse(args[0], NumberStyles.Any, CultureInfo.InvariantCulture, out float loss))
|
|
||||||
{
|
|
||||||
ThrowError(args[0] + " is not a valid loss ratio.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (GameMain.Client != null)
|
|
||||||
{
|
|
||||||
GameMain.Client.NetPeerConfiguration.SimulatedLoss = loss;
|
|
||||||
}
|
|
||||||
else if (GameMain.Server != null)
|
|
||||||
{
|
|
||||||
GameMain.Server.NetPeerConfiguration.SimulatedLoss = loss;
|
|
||||||
}
|
|
||||||
NewMessage("Set simulated packet loss to " + (int)(loss * 100) + "%.", Color.White);
|
|
||||||
}));
|
|
||||||
commands.Add(new Command("simulatedduplicateschance", "simulatedduplicateschance [duplicateratio]: simulates packet duplication in network messages. For example, a value of 0.1 would mean there's a 10% chance a packet gets sent twice. Useful for simulating real network conditions when testing the multiplayer locally.", (string[] args) =>
|
|
||||||
{
|
|
||||||
if (args.Count() < 1 || (GameMain.Client == null && GameMain.Server == null)) return;
|
|
||||||
if (!float.TryParse(args[0], NumberStyles.Any, CultureInfo.InvariantCulture, out float duplicates))
|
|
||||||
{
|
|
||||||
ThrowError(args[0] + " is not a valid duplicate ratio.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (GameMain.Client != null)
|
|
||||||
{
|
|
||||||
GameMain.Client.NetPeerConfiguration.SimulatedDuplicatesChance = duplicates;
|
|
||||||
}
|
|
||||||
else if (GameMain.Server != null)
|
|
||||||
{
|
|
||||||
GameMain.Server.NetPeerConfiguration.SimulatedDuplicatesChance = duplicates;
|
|
||||||
}
|
|
||||||
NewMessage("Set packet duplication to " + (int)(duplicates * 100) + "%.", Color.White);
|
|
||||||
}));
|
|
||||||
|
|
||||||
commands.Add(new Command("flipx", "flipx: mirror the main submarine horizontally", (string[] args) =>
|
commands.Add(new Command("flipx", "flipx: mirror the main submarine horizontally", (string[] args) =>
|
||||||
{
|
{
|
||||||
Submarine.MainSub?.FlipX();
|
Submarine.MainSub?.FlipX();
|
||||||
|
|||||||
@@ -116,11 +116,6 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GameMain.Server.Character != null)
|
|
||||||
{
|
|
||||||
c.Inventory?.DeleteAllItems();
|
|
||||||
}
|
|
||||||
|
|
||||||
//remove all items that are in someone's inventory
|
//remove all items that are in someone's inventory
|
||||||
foreach (Character c in Character.CharacterList)
|
foreach (Character c in Character.CharacterList)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -45,6 +45,12 @@ namespace Barotrauma
|
|||||||
public bool SpecularityEnabled { get; set; }
|
public bool SpecularityEnabled { get; set; }
|
||||||
public bool ChromaticAberrationEnabled { get; set; }
|
public bool ChromaticAberrationEnabled { get; set; }
|
||||||
|
|
||||||
|
public int ParticleLimit { get; set; }
|
||||||
|
|
||||||
|
public float LightMapScale { get; set; }
|
||||||
|
public bool SpecularityEnabled { get; set; }
|
||||||
|
public bool ChromaticAberrationEnabled { get; set; }
|
||||||
|
|
||||||
public bool MuteOnFocusLost { get; set; }
|
public bool MuteOnFocusLost { get; set; }
|
||||||
|
|
||||||
public enum VoiceMode
|
public enum VoiceMode
|
||||||
@@ -304,11 +310,6 @@ namespace Barotrauma
|
|||||||
VerboseLogging = doc.Root.GetAttributeBool("verboselogging", false);
|
VerboseLogging = doc.Root.GetAttributeBool("verboselogging", false);
|
||||||
SaveDebugConsoleLogs = doc.Root.GetAttributeBool("savedebugconsolelogs", false);
|
SaveDebugConsoleLogs = doc.Root.GetAttributeBool("savedebugconsolelogs", false);
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
UseSteam = doc.Root.GetAttributeBool("usesteam", true);
|
|
||||||
#endif
|
|
||||||
QuickStartSubmarineName = doc.Root.GetAttributeString("quickstartsub", "");
|
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
UseSteam = doc.Root.GetAttributeBool("usesteam", true);
|
UseSteam = doc.Root.GetAttributeBool("usesteam", true);
|
||||||
#endif
|
#endif
|
||||||
@@ -376,6 +377,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
AimAssistAmount = doc.Root.GetAttributeFloat("aimassistamount", 0.5f);
|
AimAssistAmount = doc.Root.GetAttributeFloat("aimassistamount", 0.5f);
|
||||||
|
|
||||||
|
AimAssistAmount = doc.Root.GetAttributeFloat("aimassistamount", 0.5f);
|
||||||
|
|
||||||
AimAssistAmount = doc.Root.GetAttributeFloat("aimassistamount", 0.5f);
|
AimAssistAmount = doc.Root.GetAttributeFloat("aimassistamount", 0.5f);
|
||||||
|
|
||||||
keyMapping = new KeyOrMouse[Enum.GetNames(typeof(InputType)).Length];
|
keyMapping = new KeyOrMouse[Enum.GetNames(typeof(InputType)).Length];
|
||||||
@@ -519,6 +522,34 @@ namespace Barotrauma
|
|||||||
|
|
||||||
TextManager.LoadTextPacks(SelectedContentPackages);
|
TextManager.LoadTextPacks(SelectedContentPackages);
|
||||||
|
|
||||||
|
//display error messages after all content packages have been loaded
|
||||||
|
//to make sure the package that contains text files has been loaded before we attempt to use TextManager
|
||||||
|
foreach (string missingPackagePath in missingPackagePaths)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError(TextManager.Get("ContentPackageNotFound").Replace("[packagepath]", missingPackagePath));
|
||||||
|
}
|
||||||
|
foreach (ContentPackage incompatiblePackage in incompatiblePackages)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError(TextManager.Get(incompatiblePackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage")
|
||||||
|
.Replace("[packagename]", incompatiblePackage.Name)
|
||||||
|
.Replace("[packageversion]", incompatiblePackage.GameVersion.ToString())
|
||||||
|
.Replace("[gameversion]", GameMain.Version.ToString()));
|
||||||
|
}
|
||||||
|
foreach (ContentPackage contentPackage in SelectedContentPackages)
|
||||||
|
{
|
||||||
|
foreach (ContentFile file in contentPackage.Files)
|
||||||
|
{
|
||||||
|
if (!System.IO.File.Exists(file.Path))
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Error in content package \"" + contentPackage.Name + "\" - file \"" + file.Path + "\" not found.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ToolBox.IsProperFilenameCase(file.Path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextManager.LoadTextPacks(SelectedContentPackages);
|
||||||
|
|
||||||
//display error messages after all content packages have been loaded
|
//display error messages after all content packages have been loaded
|
||||||
//to make sure the package that contains text files has been loaded before we attempt to use TextManager
|
//to make sure the package that contains text files has been loaded before we attempt to use TextManager
|
||||||
foreach (string missingPackagePath in missingPackagePaths)
|
foreach (string missingPackagePath in missingPackagePaths)
|
||||||
@@ -1071,6 +1102,32 @@ namespace Barotrauma
|
|||||||
NewLineOnAttributes = true
|
NewLineOnAttributes = true
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if CLIENT
|
||||||
|
if (Tutorial.Tutorials != null)
|
||||||
|
{
|
||||||
|
foreach (Tutorial tutorial in Tutorial.Tutorials)
|
||||||
|
{
|
||||||
|
if (tutorial.Completed && !CompletedTutorialNames.Contains(tutorial.Name))
|
||||||
|
{
|
||||||
|
CompletedTutorialNames.Add(tutorial.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
var tutorialElement = new XElement("tutorials");
|
||||||
|
foreach (string tutorialName in CompletedTutorialNames)
|
||||||
|
{
|
||||||
|
tutorialElement.Add(new XElement("Tutorial", new XAttribute("name", tutorialName)));
|
||||||
|
}
|
||||||
|
doc.Root.Add(tutorialElement);
|
||||||
|
|
||||||
|
XmlWriterSettings settings = new XmlWriterSettings
|
||||||
|
{
|
||||||
|
Indent = true,
|
||||||
|
OmitXmlDeclaration = true,
|
||||||
|
NewLineOnAttributes = true
|
||||||
|
};
|
||||||
|
|
||||||
#if CLIENT
|
#if CLIENT
|
||||||
if (Tutorial.Tutorials != null)
|
if (Tutorial.Tutorials != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -24,9 +24,6 @@ namespace Barotrauma.Items.Components
|
|||||||
private bool createdNewGap;
|
private bool createdNewGap;
|
||||||
private bool autoOrientGap;
|
private bool autoOrientGap;
|
||||||
|
|
||||||
private bool createdNewGap;
|
|
||||||
private bool autoOrientGap;
|
|
||||||
|
|
||||||
private bool isStuck;
|
private bool isStuck;
|
||||||
private float resetPredictionTimer;
|
private float resetPredictionTimer;
|
||||||
|
|
||||||
|
|||||||
@@ -252,10 +252,6 @@ namespace Barotrauma.Items.Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
partial void FixStructureProjSpecific(Character user, float deltaTime, Structure targetStructure, int sectionIndex);
|
|
||||||
partial void FixCharacterProjSpecific(Character user, float deltaTime, Character targetCharacter);
|
|
||||||
partial void FixItemProjSpecific(Character user, float deltaTime, Item targetItem, float prevCondition);
|
|
||||||
|
|
||||||
partial void FixStructureProjSpecific(Character user, float deltaTime, Structure targetStructure, int sectionIndex);
|
partial void FixStructureProjSpecific(Character user, float deltaTime, Structure targetStructure, int sectionIndex);
|
||||||
partial void FixCharacterProjSpecific(Character user, float deltaTime, Character targetCharacter);
|
partial void FixCharacterProjSpecific(Character user, float deltaTime, Character targetCharacter);
|
||||||
partial void FixItemProjSpecific(Character user, float deltaTime, Item targetItem, float prevCondition);
|
partial void FixItemProjSpecific(Character user, float deltaTime, Item targetItem, float prevCondition);
|
||||||
|
|||||||
@@ -187,6 +187,24 @@ namespace Barotrauma.Items.Components
|
|||||||
return base.Select(character);
|
return base.Select(character);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool Select(Character character)
|
||||||
|
{
|
||||||
|
if (item.Container != null) { return false; }
|
||||||
|
|
||||||
|
if (AutoInteractWithContained)
|
||||||
|
{
|
||||||
|
foreach (Item contained in Inventory.Items)
|
||||||
|
{
|
||||||
|
if (contained == null) continue;
|
||||||
|
if (contained.TryInteract(character))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return base.Select(character);
|
||||||
|
}
|
||||||
|
|
||||||
public override bool Pick(Character picker)
|
public override bool Pick(Character picker)
|
||||||
{
|
{
|
||||||
if (AutoInteractWithContained)
|
if (AutoInteractWithContained)
|
||||||
|
|||||||
@@ -105,6 +105,8 @@ namespace Barotrauma.Items.Components
|
|||||||
progressTimer = 0.0f;
|
progressTimer = 0.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
voltage -= deltaTime * 10.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PutItemsToLinkedContainer()
|
private void PutItemsToLinkedContainer()
|
||||||
@@ -162,8 +164,6 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
if (!IsActive) { progressState = 0.0f; }
|
if (!IsActive) { progressState = 0.0f; }
|
||||||
|
|
||||||
if (!IsActive) { progressState = 0.0f; }
|
|
||||||
|
|
||||||
#if CLIENT
|
#if CLIENT
|
||||||
if (!IsActive)
|
if (!IsActive)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -493,7 +493,6 @@ namespace Barotrauma.Items.Components
|
|||||||
AutoTemp = false;
|
AutoTemp = false;
|
||||||
unsentChanges = true;
|
unsentChanges = true;
|
||||||
UpdateAutoTemp(2.0f + degreeOfSuccess * 5.0f, 1.0f);
|
UpdateAutoTemp(2.0f + degreeOfSuccess * 5.0f, 1.0f);
|
||||||
|
|
||||||
}
|
}
|
||||||
#if CLIENT
|
#if CLIENT
|
||||||
onOffSwitch.BarScroll = 0.0f;
|
onOffSwitch.BarScroll = 0.0f;
|
||||||
@@ -505,6 +504,11 @@ namespace Barotrauma.Items.Components
|
|||||||
#if CLIENT
|
#if CLIENT
|
||||||
onOffSwitch.BarScroll = 1.0f;
|
onOffSwitch.BarScroll = 1.0f;
|
||||||
#endif
|
#endif
|
||||||
|
if (AutoTemp || !shutDown || targetFissionRate > 0.0f || targetTurbineOutput > 0.0f)
|
||||||
|
{
|
||||||
|
unsentChanges = true;
|
||||||
|
}
|
||||||
|
|
||||||
AutoTemp = false;
|
AutoTemp = false;
|
||||||
shutDown = true;
|
shutDown = true;
|
||||||
targetFissionRate = 0.0f;
|
targetFissionRate = 0.0f;
|
||||||
|
|||||||
@@ -32,11 +32,6 @@ namespace Barotrauma.Items.Components
|
|||||||
//a list of powered devices connected directly to this item
|
//a list of powered devices connected directly to this item
|
||||||
private readonly List<Pair<Powered, Connection>> directlyConnected = new List<Pair<Powered, Connection>>(10);
|
private readonly List<Pair<Powered, Connection>> directlyConnected = new List<Pair<Powered, Connection>>(10);
|
||||||
|
|
||||||
//charge indicator description
|
|
||||||
protected Vector2 indicatorPosition, indicatorSize;
|
|
||||||
|
|
||||||
protected bool isHorizontal;
|
|
||||||
|
|
||||||
public float CurrPowerOutput
|
public float CurrPowerOutput
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
|
|||||||
@@ -178,9 +178,6 @@ namespace Barotrauma.Items.Components
|
|||||||
//items in a bad condition are more sensitive to overvoltage
|
//items in a bad condition are more sensitive to overvoltage
|
||||||
float maxOverVoltage = MathHelper.Lerp(Math.Min(OverloadVoltage, 1.0f), OverloadVoltage, item.Condition / item.Prefab.Health);
|
float maxOverVoltage = MathHelper.Lerp(Math.Min(OverloadVoltage, 1.0f), OverloadVoltage, item.Condition / item.Prefab.Health);
|
||||||
|
|
||||||
//items in a bad condition are more sensitive to overvoltage
|
|
||||||
float maxOverVoltage = MathHelper.Lerp(Math.Min(OverloadVoltage, 1.0f), OverloadVoltage, item.Condition / 100.0f);
|
|
||||||
|
|
||||||
//if the item can't be fixed, don't allow it to break
|
//if the item can't be fixed, don't allow it to break
|
||||||
if (!item.Repairables.Any() || !CanBeOverloaded) continue;
|
if (!item.Repairables.Any() || !CanBeOverloaded) continue;
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private LocationType(XElement element)
|
private LocationType(XElement element)
|
||||||
{
|
{
|
||||||
Identifier = element.Name.ToString();
|
Identifier = element.GetAttributeString("identifier", element.Name.ToString());
|
||||||
Name = TextManager.Get("LocationName." + Identifier);
|
Name = TextManager.Get("LocationName." + Identifier);
|
||||||
nameFormats = TextManager.GetAll("LocationNameFormat." + Identifier);
|
nameFormats = TextManager.GetAll("LocationNameFormat." + Identifier);
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("Failed to read name file for location type \""+Identifier+"\"!", e);
|
DebugConsole.ThrowError("Failed to read name file for location type \"" + Identifier + "\"!", e);
|
||||||
names = new List<string>() { "Name file not found" };
|
names = new List<string>() { "Name file not found" };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,9 +82,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
CommonnessPerZone[zoneIndex] = zoneCommonness;
|
CommonnessPerZone[zoneIndex] = zoneCommonness;
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
string nameFile = element.GetAttributeString("namefile", "Content/Map/locationNames.txt");
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -430,6 +430,13 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
CurrentLocation.SelectedMissionIndex = missionIndex;
|
CurrentLocation.SelectedMissionIndex = missionIndex;
|
||||||
|
|
||||||
|
//the destination must be the same as the destination of the mission
|
||||||
|
if (CurrentLocation.SelectedMission != null &&
|
||||||
|
CurrentLocation.SelectedMission.Locations[1] != SelectedLocation)
|
||||||
|
{
|
||||||
|
SelectLocation(CurrentLocation.SelectedMission.Locations[1]);
|
||||||
|
}
|
||||||
|
|
||||||
SelectedLocation = location;
|
SelectedLocation = location;
|
||||||
SelectedConnection = connections.Find(c => c.Locations.Contains(CurrentLocation) && c.Locations.Contains(SelectedLocation));
|
SelectedConnection = connections.Find(c => c.Locations.Contains(CurrentLocation) && c.Locations.Contains(SelectedLocation));
|
||||||
OnLocationSelected?.Invoke(SelectedLocation, SelectedConnection);
|
OnLocationSelected?.Invoke(SelectedLocation, SelectedConnection);
|
||||||
|
|||||||
@@ -518,6 +518,10 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
maxX = Math.Min(maxX, ruin.Area.X - 100.0f);
|
maxX = Math.Min(maxX, ruin.Area.X - 100.0f);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
maxX = Math.Min(maxX, ruin.Area.X - 100.0f);
|
||||||
|
}
|
||||||
|
|
||||||
if (entity.IsVisible(worldView)) { visibleEntities.Add(entity); }
|
if (entity.IsVisible(worldView)) { visibleEntities.Add(entity); }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,16 +40,19 @@ namespace Barotrauma.Networking
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (!Type.HasFlag(ChatMessageType.Server | ChatMessageType.Error))
|
if (Type.HasFlag(ChatMessageType.Server) || Type.HasFlag(ChatMessageType.Error) || Type.HasFlag(ChatMessageType.ServerLog))
|
||||||
|
{
|
||||||
|
if (translatedText == null || translatedText.Length == 0)
|
||||||
|
{
|
||||||
|
translatedText = TextManager.GetServerMessage(Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
return translatedText;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
return Text;
|
return Text;
|
||||||
}
|
}
|
||||||
if (translatedText == null || translatedText.Length == 0)
|
|
||||||
{
|
|
||||||
translatedText = TextManager.GetServerMessage(Text);
|
|
||||||
}
|
|
||||||
|
|
||||||
return translatedText;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,8 +72,6 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
public HashSet<string> GivenAchievements = new HashSet<string>();
|
public HashSet<string> GivenAchievements = new HashSet<string>();
|
||||||
|
|
||||||
public HashSet<string> GivenAchievements = new HashSet<string>();
|
|
||||||
|
|
||||||
public ClientPermissions Permissions = ClientPermissions.None;
|
public ClientPermissions Permissions = ClientPermissions.None;
|
||||||
public List<DebugConsole.Command> PermittedConsoleCommands
|
public List<DebugConsole.Command> PermittedConsoleCommands
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
public LogMessage(string text, MessageType type)
|
public LogMessage(string text, MessageType type)
|
||||||
{
|
{
|
||||||
Text = "[" + DateTime.Now.ToString() + "] " + text;
|
Text = "[" + DateTime.Now.ToString() + "] " + TextManager.GetServerMessage(text);
|
||||||
Type = type;
|
Type = type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,6 +145,16 @@ namespace Barotrauma
|
|||||||
get { return binding; }
|
get { return binding; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetState()
|
||||||
|
{
|
||||||
|
hit = binding.IsHit();
|
||||||
|
if (hit) hitQueue = true;
|
||||||
|
|
||||||
|
held = binding.IsDown();
|
||||||
|
if (held) heldQueue = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
public void SetState()
|
public void SetState()
|
||||||
{
|
{
|
||||||
hit = binding.IsHit();
|
hit = binding.IsHit();
|
||||||
|
|||||||
@@ -82,33 +82,6 @@ namespace Barotrauma
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetBotCount(int botCount)
|
|
||||||
{
|
|
||||||
if (GameMain.Server != null)
|
|
||||||
{
|
|
||||||
if (botCount < 0) botCount = GameMain.Server.MaxBotCount;
|
|
||||||
if (botCount > GameMain.Server.MaxBotCount) botCount = 0;
|
|
||||||
|
|
||||||
GameMain.Server.BotCount = botCount;
|
|
||||||
lastUpdateID++;
|
|
||||||
}
|
|
||||||
#if CLIENT
|
|
||||||
(botCountText as GUITextBlock).Text = botCount.ToString();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetBotSpawnMode(BotSpawnMode botSpawnMode)
|
|
||||||
{
|
|
||||||
if (GameMain.Server != null)
|
|
||||||
{
|
|
||||||
GameMain.Server.BotSpawnMode = botSpawnMode;
|
|
||||||
lastUpdateID++;
|
|
||||||
}
|
|
||||||
#if CLIENT
|
|
||||||
(botSpawnModeText as GUITextBlock).Text = botSpawnMode.ToString();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetTraitorsEnabled(YesNoMaybe enabled)
|
public void SetTraitorsEnabled(YesNoMaybe enabled)
|
||||||
{
|
{
|
||||||
#if SERVER
|
#if SERVER
|
||||||
|
|||||||
@@ -89,11 +89,6 @@ namespace Barotrauma
|
|||||||
public readonly AttributeCollection Attributes;
|
public readonly AttributeCollection Attributes;
|
||||||
public readonly Type PropertyType;
|
public readonly Type PropertyType;
|
||||||
|
|
||||||
public object ParentObject
|
|
||||||
{
|
|
||||||
get { return obj; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public SerializableProperty(PropertyDescriptor property, object obj)
|
public SerializableProperty(PropertyDescriptor property, object obj)
|
||||||
{
|
{
|
||||||
Name = property.Name;
|
Name = property.Name;
|
||||||
@@ -187,9 +182,6 @@ namespace Barotrauma
|
|||||||
case "point":
|
case "point":
|
||||||
propertyInfo.SetValue(parentObject, XMLExtensions.ParsePoint(value));
|
propertyInfo.SetValue(parentObject, XMLExtensions.ParsePoint(value));
|
||||||
break;
|
break;
|
||||||
case "point":
|
|
||||||
propertyInfo.SetValue(obj, XMLExtensions.ParsePoint(value));
|
|
||||||
break;
|
|
||||||
case "vector2":
|
case "vector2":
|
||||||
propertyInfo.SetValue(parentObject, XMLExtensions.ParseVector2(value));
|
propertyInfo.SetValue(parentObject, XMLExtensions.ParseVector2(value));
|
||||||
break;
|
break;
|
||||||
@@ -262,9 +254,6 @@ namespace Barotrauma
|
|||||||
case "point":
|
case "point":
|
||||||
propertyInfo.SetValue(parentObject, XMLExtensions.ParsePoint((string)value));
|
propertyInfo.SetValue(parentObject, XMLExtensions.ParsePoint((string)value));
|
||||||
return true;
|
return true;
|
||||||
case "point":
|
|
||||||
propertyInfo.SetValue(obj, XMLExtensions.ParsePoint((string)value));
|
|
||||||
return true;
|
|
||||||
case "vector2":
|
case "vector2":
|
||||||
propertyInfo.SetValue(parentObject, XMLExtensions.ParseVector2((string)value));
|
propertyInfo.SetValue(parentObject, XMLExtensions.ParseVector2((string)value));
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -486,38 +486,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
protected bool IsValidTarget(ISerializableEntity entity)
|
protected bool IsValidTarget(ISerializableEntity entity)
|
||||||
{
|
{
|
||||||
if (entity is Item item)
|
if (targetIdentifiers == null) { return true; }
|
||||||
{
|
|
||||||
if (item.HasTag(targetIdentifiers)) return true;
|
|
||||||
if (targetIdentifiers.Any(id => id == item.Prefab.Identifier)) return true;
|
|
||||||
}
|
|
||||||
else if (entity is ItemComponent itemComponent)
|
|
||||||
{
|
|
||||||
if (itemComponent.Item.HasTag(targetIdentifiers)) return true;
|
|
||||||
if (targetIdentifiers.Any(id => id == itemComponent.Item.Prefab.Identifier)) return true;
|
|
||||||
}
|
|
||||||
else if (entity is Structure structure)
|
|
||||||
{
|
|
||||||
if (targetIdentifiers.Any(id => id == structure.Prefab.Identifier)) return true;
|
|
||||||
}
|
|
||||||
else if (entity is Character character)
|
|
||||||
{
|
|
||||||
if (targetIdentifiers.Any(id => id == character.SpeciesName)) return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return targetIdentifiers.Any(id => id == entity.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetUser(Character user)
|
|
||||||
{
|
|
||||||
foreach (Affliction affliction in Afflictions)
|
|
||||||
{
|
|
||||||
affliction.Source = user;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected bool IsValidTarget(ISerializableEntity entity)
|
|
||||||
{
|
|
||||||
if (entity is Item item)
|
if (entity is Item item)
|
||||||
{
|
{
|
||||||
if (item.HasTag(targetIdentifiers)) return true;
|
if (item.HasTag(targetIdentifiers)) return true;
|
||||||
@@ -744,6 +714,11 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isNotClient = true;
|
||||||
|
#if CLIENT
|
||||||
|
isNotClient = GameMain.Client == null;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (FireSize > 0.0f && entity != null)
|
if (FireSize > 0.0f && entity != null)
|
||||||
{
|
{
|
||||||
@@ -812,62 +787,6 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GameMain.Client == null && entity != null && Entity.Spawner != null) //clients are not allowed to spawn items
|
|
||||||
{
|
|
||||||
foreach (ItemSpawnInfo itemSpawnInfo in spawnItems)
|
|
||||||
{
|
|
||||||
switch (itemSpawnInfo.SpawnPosition)
|
|
||||||
{
|
|
||||||
case ItemSpawnInfo.SpawnPositionType.This:
|
|
||||||
Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, entity.WorldPosition);
|
|
||||||
break;
|
|
||||||
case ItemSpawnInfo.SpawnPositionType.ThisInventory:
|
|
||||||
{
|
|
||||||
if (entity is Character character)
|
|
||||||
{
|
|
||||||
if (character.Inventory != null && character.Inventory.Items.Any(it => it == null))
|
|
||||||
{
|
|
||||||
Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, character.Inventory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (entity is Item item)
|
|
||||||
{
|
|
||||||
var inventory = item?.GetComponent<ItemContainer>()?.Inventory;
|
|
||||||
if (inventory != null && inventory.Items.Any(it => it == null))
|
|
||||||
{
|
|
||||||
Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, inventory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ItemSpawnInfo.SpawnPositionType.ContainedInventory:
|
|
||||||
{
|
|
||||||
Inventory thisInventory = null;
|
|
||||||
if (entity is Character character)
|
|
||||||
{
|
|
||||||
thisInventory = character.Inventory;
|
|
||||||
}
|
|
||||||
else if (entity is Item item)
|
|
||||||
{
|
|
||||||
thisInventory = item?.GetComponent<ItemContainer>()?.Inventory;
|
|
||||||
}
|
|
||||||
if (thisInventory != null)
|
|
||||||
{
|
|
||||||
foreach (Item item in thisInventory.Items)
|
|
||||||
{
|
|
||||||
if (item == null) continue;
|
|
||||||
Inventory containedInventory = item.GetComponent<ItemContainer>()?.Inventory;
|
|
||||||
if (containedInventory == null || !containedInventory.Items.Any(i => i == null)) continue;
|
|
||||||
Entity.Spawner.AddToSpawnQueue(itemSpawnInfo.ItemPrefab, containedInventory);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if CLIENT
|
#if CLIENT
|
||||||
if (entity != null)
|
if (entity != null)
|
||||||
{
|
{
|
||||||
@@ -983,30 +902,6 @@ namespace Barotrauma
|
|||||||
limb.character.CharacterHealth.ReduceAffliction(limb, reduceAffliction.First, reduceAffliction.Second * deltaTime);
|
limb.character.CharacterHealth.ReduceAffliction(limb, reduceAffliction.First, reduceAffliction.Second * deltaTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Affliction affliction in element.Parent.Afflictions)
|
|
||||||
{
|
|
||||||
if (target is Character)
|
|
||||||
{
|
|
||||||
((Character)target).CharacterHealth.ApplyAffliction(null, affliction.CreateMultiplied(deltaTime));
|
|
||||||
}
|
|
||||||
else if (target is Limb limb)
|
|
||||||
{
|
|
||||||
limb.character.CharacterHealth.ApplyAffliction(limb, affliction.CreateMultiplied(deltaTime));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (Pair<string, float> reduceAffliction in element.Parent.ReduceAffliction)
|
|
||||||
{
|
|
||||||
if (target is Character)
|
|
||||||
{
|
|
||||||
((Character)target).CharacterHealth.ReduceAffliction(null, reduceAffliction.First, reduceAffliction.Second * deltaTime);
|
|
||||||
}
|
|
||||||
else if (target is Limb limb)
|
|
||||||
{
|
|
||||||
limb.character.CharacterHealth.ReduceAffliction(limb, reduceAffliction.First, reduceAffliction.Second * deltaTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
element.Timer -= deltaTime;
|
element.Timer -= deltaTime;
|
||||||
|
|||||||
@@ -155,18 +155,29 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (!messages[i].Contains("_")) // No variables, just translate
|
if (!messages[i].Contains("_")) // No variables, just translate
|
||||||
{
|
{
|
||||||
messages[i] = Get(messages[i]);
|
string msg = Get(messages[i], true);
|
||||||
continue;
|
|
||||||
|
if (msg != null) // If a translation was found, otherwise use the original
|
||||||
|
{
|
||||||
|
messages[i] = msg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
string[] messageWithVariables = messages[i].Split('_');
|
|
||||||
messages[i] = Get(messageWithVariables[0]);
|
|
||||||
|
|
||||||
// First index is always the message identifier -> start at 1
|
|
||||||
for (int j = 1; j < messageWithVariables.Length; j++)
|
|
||||||
{
|
{
|
||||||
string[] variableAndValue = messageWithVariables[j].Split('=');
|
string[] messageWithVariables = messages[i].Split('_');
|
||||||
messages[i] = messages[i].Replace(variableAndValue[0], variableAndValue[1]);
|
string msg = Get(messageWithVariables[0], true);
|
||||||
|
|
||||||
|
if (msg != null) // If a translation was found, otherwise use the original
|
||||||
|
{
|
||||||
|
messages[i] = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// First index is always the message identifier -> start at 1
|
||||||
|
for (int j = 1; j < messageWithVariables.Length; j++)
|
||||||
|
{
|
||||||
|
string[] variableAndValue = messageWithVariables[j].Split('=');
|
||||||
|
messages[i] = messages[i].Replace(variableAndValue[0], variableAndValue[1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,12 +39,6 @@ namespace Barotrauma
|
|||||||
return (sync == RandSync.Unsynced ? localRandom : (syncedRandom[(int)sync])).NextDouble() * (maximum - minimum) + minimum;
|
return (sync == RandSync.Unsynced ? localRandom : (syncedRandom[(int)sync])).NextDouble() * (maximum - minimum) + minimum;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double Range(double minimum, double maximum, RandSync sync = RandSync.Unsynced)
|
|
||||||
{
|
|
||||||
Assert(sync);
|
|
||||||
return (sync == RandSync.Unsynced ? localRandom : (syncedRandom[(int)sync])).NextDouble() * (maximum - minimum) + minimum;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int Range(int minimum, int maximum, RandSync sync = RandSync.Unsynced)
|
public static int Range(int minimum, int maximum, RandSync sync = RandSync.Unsynced)
|
||||||
{
|
{
|
||||||
return (sync == RandSync.Unsynced ? localRandom : (syncedRandom[(int)sync])).Next(maximum - minimum) + minimum;
|
return (sync == RandSync.Unsynced ? localRandom : (syncedRandom[(int)sync])).Next(maximum - minimum) + minimum;
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,3 +1,26 @@
|
|||||||
|
---------------------------------------------------------------------------------------------------------
|
||||||
|
v0.8.9.5
|
||||||
|
---------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
- Fixed alien vents crashing the game when there's a character nearby.
|
||||||
|
- Fixed chatbox retaining the radio message prefix after being deselected.
|
||||||
|
- Push-to-talk doesn't trigger when typin in a text box.
|
||||||
|
- Fixed some server log messages and texts sent to clients being incorrect (= showing the tags that are
|
||||||
|
used to fetch the texts from the language files instead of the actual texts).
|
||||||
|
- Fixed AI orders that target a specific item (such as the order to power up the reactor) not working in
|
||||||
|
multiplayer.
|
||||||
|
- Fixed crashes when attempting to use voice capture or change voice capture settings when there are no
|
||||||
|
suitable capture devices available.
|
||||||
|
- Fixed clients not being notified when an AI character shuts down the reactor.
|
||||||
|
- Fixed deconstructors staying active without power in multiplayer.
|
||||||
|
- Fixed sonar labels going outside the screen when at the left side of the display.
|
||||||
|
|
||||||
|
Additions & changes:
|
||||||
|
- Added some supplies to vanilla submarines.
|
||||||
|
- Balanced item deterioration rates and adjusted neutral ballast settings in vanilla subs.
|
||||||
|
- Increased the impact tolerance of crawlers to prevent them from killing themselves by bumping into walls.
|
||||||
|
|
||||||
---------------------------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------------------------
|
||||||
v0.8.9.4
|
v0.8.9.4
|
||||||
---------------------------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------------------------
|
||||||
@@ -56,6 +79,7 @@ Additions:
|
|||||||
- Some new random events.
|
- Some new random events.
|
||||||
- A bunch of new afflictions and medical items.
|
- A bunch of new afflictions and medical items.
|
||||||
- Some new item sprites.
|
- Some new item sprites.
|
||||||
|
- A couple of new cargo missions.
|
||||||
- Added some new items that can be crafted from alien materials.
|
- Added some new items that can be crafted from alien materials.
|
||||||
- Display linked hulls as one room on the status monitor.
|
- Display linked hulls as one room on the status monitor.
|
||||||
- Tons of new sound effects.
|
- Tons of new sound effects.
|
||||||
|
|||||||
Reference in New Issue
Block a user