5202af9...3ea33fb
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -13,7 +13,7 @@ bld/
|
||||
[Rr]elease*/
|
||||
|
||||
# Barotrauma content folder
|
||||
Content/
|
||||
BarotraumaShared/Content/
|
||||
|
||||
*.v12.suo
|
||||
*.suo
|
||||
|
||||
BIN
Barotrauma/BarotraumaClient/OpenAL32.dll
Normal file
BIN
Barotrauma/BarotraumaClient/OpenAL32.dll
Normal file
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
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("0.8.9.4")]
|
||||
[assembly: AssemblyFileVersion("0.8.9.4")]
|
||||
[assembly: AssemblyVersion("0.8.9.5")]
|
||||
[assembly: AssemblyFileVersion("0.8.9.5")]
|
||||
|
||||
@@ -1051,6 +1051,102 @@ namespace Barotrauma
|
||||
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) =>
|
||||
{
|
||||
float defaultZoom = Screen.Selected.Cam.DefaultZoom;
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Barotrauma
|
||||
class ChatBox
|
||||
{
|
||||
private static Sprite radioIcon;
|
||||
|
||||
|
||||
private GUIFrame guiFrame;
|
||||
|
||||
private GUIListBox chatBox;
|
||||
@@ -25,7 +25,7 @@ namespace Barotrauma
|
||||
|
||||
private bool isSinglePlayer;
|
||||
public bool IsSinglePlayer => isSinglePlayer;
|
||||
|
||||
|
||||
private bool toggleOpen = true;
|
||||
private float openState;
|
||||
|
||||
@@ -78,7 +78,7 @@ namespace Barotrauma
|
||||
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),
|
||||
style: "UIToggleButton");
|
||||
|
||||
|
||||
toggleButton.OnClicked += (GUIButton btn, object userdata) =>
|
||||
{
|
||||
toggleOpen = !toggleOpen;
|
||||
@@ -89,13 +89,17 @@ namespace Barotrauma
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
inputBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.1f), guiFrame.RectTransform, Anchor.BottomCenter),
|
||||
style: "ChatTextBox")
|
||||
{
|
||||
Font = GUI.SmallFont,
|
||||
MaxTextLength = ChatMessage.MaxLength
|
||||
};
|
||||
inputBox.OnDeselected += (gui, Keys) =>
|
||||
{
|
||||
gui.Text = "";
|
||||
};
|
||||
|
||||
radioButton = new GUIButton(new RectTransform(new Vector2(0.1f, 2.0f), inputBox.RectTransform,
|
||||
HUDLayoutSettings.ChatBoxAlignment == Alignment.Right ? Anchor.BottomRight : Anchor.BottomLeft,
|
||||
@@ -132,7 +136,7 @@ namespace Barotrauma
|
||||
{
|
||||
command = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (command)
|
||||
{
|
||||
@@ -169,7 +173,7 @@ namespace Barotrauma
|
||||
{
|
||||
chatBox.RemoveChild(chatBox.Content.Children.First());
|
||||
}
|
||||
|
||||
|
||||
float prevSize = chatBox.BarSize;
|
||||
|
||||
string displayedText = message.TranslatedText;
|
||||
@@ -202,8 +206,8 @@ namespace Barotrauma
|
||||
CanBeFocused = true
|
||||
};
|
||||
|
||||
if (message is OrderChatMessage orderChatMsg &&
|
||||
Character.Controlled != null &&
|
||||
if (message is OrderChatMessage orderChatMsg &&
|
||||
Character.Controlled != null &&
|
||||
orderChatMsg.TargetCharacter == Character.Controlled)
|
||||
{
|
||||
msgHolder.Flash(Color.OrangeRed * 0.6f, flashDuration: 5.0f);
|
||||
@@ -237,7 +241,7 @@ namespace Barotrauma
|
||||
CanBeFocused = false
|
||||
};
|
||||
int textWidth = (int)Math.Max(
|
||||
msgText.Font.MeasureString(msgText.WrappedText).X,
|
||||
msgText.Font.MeasureString(msgText.WrappedText).X,
|
||||
senderText.Font.MeasureString(senderText.WrappedText).X);
|
||||
popupMsg.RectTransform.Resize(new Point(textWidth + 20, msgText.Rect.Bottom - senderText.Rect.Y), resizeChildren: false);
|
||||
popupMessages.Enqueue(popupMsg);
|
||||
@@ -265,7 +269,7 @@ namespace Barotrauma
|
||||
{
|
||||
timer += CoroutineManager.DeltaTime;
|
||||
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);
|
||||
yield return CoroutineStatus.Running;
|
||||
}
|
||||
@@ -294,7 +298,7 @@ namespace Barotrauma
|
||||
new Point(HUDLayoutSettings.ChatBoxArea.X, HUDLayoutSettings.ChatBoxArea.Y) :
|
||||
new Point(HUDLayoutSettings.ChatBoxArea.Right - toggleButtonWidth, HUDLayoutSettings.ChatBoxArea.Y);
|
||||
}
|
||||
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
if (GameMain.GraphicsWidth != screenResolution.X || GameMain.GraphicsHeight != screenResolution.Y || prevUIScale != GUI.Scale)
|
||||
@@ -305,7 +309,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (toggleOpen || (inputBox != null && inputBox.Selected))
|
||||
{
|
||||
openState += deltaTime * 5.0f;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -24,6 +25,14 @@ namespace Barotrauma
|
||||
get { return barSize; }
|
||||
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);
|
||||
//UpdateRect();
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Barotrauma
|
||||
private List<Character> characters = new List<Character>();
|
||||
|
||||
private Point screenResolution;
|
||||
|
||||
|
||||
#region UI
|
||||
|
||||
private GUIFrame guiFrame;
|
||||
@@ -61,9 +61,34 @@ namespace Barotrauma
|
||||
public CrewManager(XElement element, bool 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);
|
||||
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);
|
||||
|
||||
prevUIScale = GUI.Scale;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Character list management
|
||||
|
||||
public Rectangle GetCharacterListArea()
|
||||
{
|
||||
return characterListBox.Rect;
|
||||
}
|
||||
|
||||
partial void InitProjectSpecific()
|
||||
{
|
||||
guiFrame = new GUIFrame(new RectTransform(Vector2.One, GUICanvas.Instance), null, Color.Transparent)
|
||||
@@ -167,10 +225,7 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
};
|
||||
chatBox.InputBox.OnDeselected += (gui, Keys) =>
|
||||
{
|
||||
this.chatBox.InputBox.Text = "";
|
||||
};
|
||||
|
||||
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);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
characterInfos.Add(characterInfo);
|
||||
}
|
||||
@@ -371,7 +427,7 @@ namespace Barotrauma
|
||||
frame.Color = character.Info.Job.Prefab.UIColor;
|
||||
frame.SelectedColor = Color.Lerp(frame.Color, Color.White, 0.5f);
|
||||
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")
|
||||
{
|
||||
UserData = "highlight",
|
||||
@@ -396,7 +452,7 @@ namespace Barotrauma
|
||||
HoverColor = frame.HoverColor,
|
||||
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) },
|
||||
"GUISoundIcon")
|
||||
{
|
||||
@@ -604,10 +660,6 @@ namespace Barotrauma
|
||||
characterListBox.BarScroll -= characterListBox.BarScroll % step;
|
||||
characterListBox.BarScroll += dir * step;
|
||||
|
||||
child.Visible = (Character)button.UserData != character;
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<object> KillCharacterAnim(GUIComponent component)
|
||||
{
|
||||
List<GUIComponent> components = component.GetAllChildren().ToList();
|
||||
@@ -619,6 +671,18 @@ namespace Barotrauma
|
||||
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);
|
||||
|
||||
float timer = 0.0f;
|
||||
@@ -685,7 +749,7 @@ namespace Barotrauma
|
||||
|
||||
|
||||
#region Voice chat
|
||||
|
||||
|
||||
public void SetPlayerVoiceIconState(Client client, bool muted, bool mutedLocally)
|
||||
{
|
||||
if (client?.Character == null) { return; }
|
||||
@@ -1101,7 +1165,7 @@ namespace Barotrauma
|
||||
if (child.Visible)
|
||||
{
|
||||
child.GetChildByUserData("highlight").Visible = character == Character.Controlled;
|
||||
|
||||
|
||||
var soundIcon = child.FindChild(character)?.FindChild("soundicon");
|
||||
if (soundIcon != null)
|
||||
{
|
||||
|
||||
@@ -143,6 +143,9 @@ namespace Barotrauma
|
||||
|
||||
infoFrame?.UpdateManually(deltaTime);
|
||||
}
|
||||
|
||||
infoFrame?.UpdateManually(deltaTime);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
child.CanBeFocused = false;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
@@ -498,28 +499,43 @@ namespace Barotrauma
|
||||
voiceMode.OnSelect = (GUIRadioButtonGroup rbg, Enum value) =>
|
||||
{
|
||||
if (rbg.Selected != null && rbg.Selected.Equals(value)) return;
|
||||
VoiceMode vMode = (VoiceMode)value;
|
||||
VoiceSetting = vMode;
|
||||
|
||||
if (vMode == VoiceMode.Activity)
|
||||
try
|
||||
{
|
||||
voiceActivityGroup.Visible = true;
|
||||
if (GameMain.Client == null && VoipCapture.Instance == null)
|
||||
VoiceMode vMode = (VoiceMode)value;
|
||||
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
|
||||
{
|
||||
voiceActivityGroup.Visible = false;
|
||||
if (GameMain.Client == null)
|
||||
else
|
||||
{
|
||||
VoipCapture.Instance?.Dispose();
|
||||
voiceActivityGroup.Visible = false;
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
VoipCapture.Instance?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
voiceInputContainer.Visible = (vMode == VoiceMode.PushToTalk);
|
||||
UnsavedSettings = true;
|
||||
voiceInputContainer.Visible = (vMode == VoiceMode.PushToTalk);
|
||||
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;
|
||||
|
||||
@@ -599,21 +615,38 @@ namespace Barotrauma
|
||||
.Replace("[missingfiletypes]", string.Join(", ", missingContentTypes));
|
||||
}
|
||||
}
|
||||
GUITextBlock aimAssistText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), TextManager.Get("AimAssist"));
|
||||
GUIScrollBar aimAssistSlider = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform),
|
||||
barSize: 0.1f)
|
||||
languageDD.SelectItem(TextManager.Language);
|
||||
languageDD.OnSelected = (guiComponent, obj) =>
|
||||
{
|
||||
UserData = aimAssistText,
|
||||
BarScroll = MathUtils.InverseLerp(0.0f, 5.0f, AimAssistAmount),
|
||||
OnMoved = (scrollBar, scroll) =>
|
||||
{
|
||||
ChangeSliderText(scrollBar, scroll);
|
||||
AimAssistAmount = MathHelper.Lerp(0.0f, 5.0f, scroll);
|
||||
return true;
|
||||
},
|
||||
Step = 0.1f
|
||||
string newLanguage = obj as string;
|
||||
if (newLanguage == Language) return true;
|
||||
|
||||
UnsavedSettings = true;
|
||||
Language = newLanguage;
|
||||
|
||||
new GUIMessageBox(TextManager.Get("RestartRequiredLabel"), TextManager.Get("RestartRequiredLanguage"));
|
||||
|
||||
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
|
||||
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;
|
||||
|
||||
@@ -982,7 +982,7 @@ namespace Barotrauma.Items.Components
|
||||
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
|
||||
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,
|
||||
new Vector2(labelPos.X + 10, labelPos.Y),
|
||||
|
||||
@@ -64,6 +64,31 @@ namespace Barotrauma
|
||||
|
||||
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()
|
||||
{
|
||||
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)
|
||||
{
|
||||
float newWaterVolume = message.ReadRangedSingle(0.0f, 1.5f, 8) * Volume;
|
||||
|
||||
@@ -26,8 +26,6 @@ namespace Barotrauma.Lights
|
||||
|
||||
private float currLightMapScale;
|
||||
|
||||
private float currLightMapScale;
|
||||
|
||||
public Color AmbientLight;
|
||||
|
||||
public RenderTarget2D LightMap
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
@@ -65,13 +66,13 @@ namespace Barotrauma.Networking
|
||||
if (order.TargetAllCharacters)
|
||||
{
|
||||
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);
|
||||
}
|
||||
else if (targetCharacter != null)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
get { return entityEventManager.MidRoundSyncing; }
|
||||
}
|
||||
|
||||
|
||||
private int ownerKey;
|
||||
|
||||
public GameClient(string newName, string ip, int ownerKey=0)
|
||||
@@ -146,7 +146,7 @@ namespace Barotrauma.Networking
|
||||
OnSelected = ToggleEndRoundVote,
|
||||
Visible = false
|
||||
};
|
||||
|
||||
|
||||
ShowLogButton = new GUIButton(new RectTransform(new Vector2(0.1f, 0.6f), buttonContainer.RectTransform) { MinSize = new Point(150, 0) },
|
||||
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.
|
||||
NetPeerConfiguration = new NetPeerConfiguration("barotrauma");
|
||||
|
||||
|
||||
NetPeerConfiguration.DisableMessageType(NetIncomingMessageType.DebugMessage | NetIncomingMessageType.WarningMessage | NetIncomingMessageType.Receipt
|
||||
| NetIncomingMessageType.ErrorMessage | NetIncomingMessageType.Error);
|
||||
|
||||
@@ -245,7 +245,7 @@ namespace Barotrauma.Networking
|
||||
NetOutgoingMessage outmsg = client.CreateMessage();
|
||||
WriteAuthRequest(outmsg);
|
||||
|
||||
// Connect client, to ip previously requested from user
|
||||
// Connect client, to ip previously requested from user
|
||||
try
|
||||
{
|
||||
client.Connect(IPEndPoint, outmsg);
|
||||
@@ -557,16 +557,16 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
System.Threading.Thread.Sleep(10);
|
||||
}
|
||||
|
||||
|
||||
outmsg.Write(SteamManager.GetSteamID());
|
||||
outmsg.Write(steamAuthTicket.Data.Length);
|
||||
outmsg.Write(steamAuthTicket.Data);
|
||||
|
||||
DebugConsole.Log("Sending Steam auth request");
|
||||
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));
|
||||
DebugConsole.Log(" Msg length: " + outmsg.LengthBytes);
|
||||
DebugConsole.Log(" Msg length: " + outmsg.LengthBytes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -580,7 +580,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
c.UpdateSoundPosition();
|
||||
}
|
||||
|
||||
|
||||
if (VoipCapture.Instance != null)
|
||||
{
|
||||
if (VoipCapture.Instance.LastEnqueueAudio > DateTime.Now - new TimeSpan(0, 0, 0, 0, milliseconds: 100))
|
||||
@@ -633,7 +633,7 @@ namespace Barotrauma.Networking
|
||||
GameMain.MainMenuScreen.Select();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (gameStarted && Screen.Selected == GameMain.GameScreen)
|
||||
{
|
||||
EndVoteTickBox.Visible = serverSettings.Voting.AllowEndVoting && HasSpawned;
|
||||
@@ -658,7 +658,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
// Update current time
|
||||
updateTimer = DateTime.Now + updateInterval;
|
||||
updateTimer = DateTime.Now + updateInterval;
|
||||
}
|
||||
|
||||
private CoroutineHandle startGameCoroutine;
|
||||
@@ -735,8 +735,8 @@ namespace Barotrauma.Networking
|
||||
GameMain.NetLobbyScreen.TrySelectSub(shuttleName, shuttleHash, GameMain.NetLobbyScreen.ShuttleList.ListBox));
|
||||
|
||||
WriteCharacterInfo(readyToStartMsg);
|
||||
|
||||
client.SendMessage(readyToStartMsg, NetDeliveryMethod.ReliableUnordered);
|
||||
|
||||
client.SendMessage(readyToStartMsg, NetDeliveryMethod.ReliableUnordered);
|
||||
break;
|
||||
case ServerPacketHeader.STARTGAME:
|
||||
startGameCoroutine = GameMain.Instance.ShowLoading(StartGame(inc), false);
|
||||
@@ -861,9 +861,10 @@ namespace Barotrauma.Networking
|
||||
else
|
||||
{
|
||||
msg = TextManager.Get("DisconnectReason." + disconnectReason.ToString());
|
||||
|
||||
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);
|
||||
@@ -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)
|
||||
{
|
||||
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
|
||||
if (ownerKey == 0)
|
||||
{
|
||||
GUIMessageBox.MessageBoxes.RemoveAll(mb => mb.UserData as string == "permissions");
|
||||
GUIMessageBox.MessageBoxes.RemoveAll(mb => mb.UserData as string == "permissions");
|
||||
|
||||
string msg = "";
|
||||
if (newPermissions == ClientPermissions.None)
|
||||
@@ -977,7 +987,7 @@ namespace Barotrauma.Networking
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GameMain.NetLobbyScreen.UpdatePermissions();
|
||||
}
|
||||
@@ -986,13 +996,13 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (Character != null) Character.Remove();
|
||||
HasSpawned = false;
|
||||
|
||||
|
||||
GameMain.LightManager.LightingEnabled = true;
|
||||
|
||||
//enable spectate button in case we fail to start the round now
|
||||
//(for example, due to a missing sub file or an error)
|
||||
GameMain.NetLobbyScreen.ShowSpectateButton();
|
||||
|
||||
|
||||
entityEventManager.Clear();
|
||||
LastSentEntityEventID = 0;
|
||||
|
||||
@@ -1063,14 +1073,14 @@ namespace Barotrauma.Networking
|
||||
else
|
||||
{
|
||||
if (GameMain.GameSession?.CrewManager != null) GameMain.GameSession.CrewManager.Reset();
|
||||
GameMain.GameSession.StartRound(campaign.Map.SelectedConnection.Level,
|
||||
reloadSub: true,
|
||||
GameMain.GameSession.StartRound(campaign.Map.SelectedConnection.Level,
|
||||
reloadSub: true,
|
||||
loadSecondSub: false,
|
||||
mirrorLevel: campaign.Map.CurrentLocation != campaign.Map.SelectedConnection.Locations[0]);
|
||||
}
|
||||
|
||||
|
||||
if (respawnAllowed) respawnManager = new RespawnManager(this, GameMain.NetLobbyScreen.UsingShuttle ? GameMain.NetLobbyScreen.SelectedShuttle : null);
|
||||
|
||||
|
||||
gameStarted = true;
|
||||
|
||||
GameMain.GameScreen.Select();
|
||||
@@ -1137,7 +1147,7 @@ namespace Barotrauma.Networking
|
||||
submarines.Add(new Submarine(Path.Combine(Submarine.SavePath, subName) + ".sub", subHash, false));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GameMain.NetLobbyScreen.UpdateSubList(GameMain.NetLobbyScreen.SubList, submarines);
|
||||
GameMain.NetLobbyScreen.UpdateSubList(GameMain.NetLobbyScreen.ShuttleList.ListBox, submarines);
|
||||
|
||||
@@ -1241,7 +1251,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
UInt16 settingsLen = inc.ReadUInt16();
|
||||
byte[] settingsData = inc.ReadBytes(settingsLen);
|
||||
|
||||
|
||||
if (inc.ReadBoolean())
|
||||
{
|
||||
if (GameSettings.VerboseLogging)
|
||||
@@ -1272,12 +1282,15 @@ namespace Barotrauma.Networking
|
||||
string levelSeed = inc.ReadString();
|
||||
float levelDifficulty = inc.ReadFloat();
|
||||
|
||||
byte botCount = inc.ReadByte();
|
||||
BotSpawnMode botSpawnMode = inc.ReadBoolean() ? BotSpawnMode.Fill : BotSpawnMode.Normal;
|
||||
|
||||
byte botCount = inc.ReadByte();
|
||||
BotSpawnMode botSpawnMode = inc.ReadBoolean() ? BotSpawnMode.Fill : BotSpawnMode.Normal;
|
||||
|
||||
bool autoRestartEnabled = inc.ReadBoolean();
|
||||
float autoRestartTimer = autoRestartEnabled ? inc.ReadFloat() : 0.0f;
|
||||
|
||||
|
||||
//ignore the message if we already a more up-to-date one
|
||||
if (NetIdUtils.IdMoreRecent(updateID, GameMain.NetLobbyScreen.LastUpdateID))
|
||||
{
|
||||
@@ -1299,13 +1312,13 @@ namespace Barotrauma.Networking
|
||||
GameMain.NetLobbyScreen.SetTraitorsEnabled(traitorsEnabled);
|
||||
GameMain.NetLobbyScreen.SetMissionType(missionTypeIndex);
|
||||
|
||||
if (!allowModeVoting) GameMain.NetLobbyScreen.SelectMode(modeIndex);
|
||||
|
||||
if (!allowModeVoting) GameMain.NetLobbyScreen.SelectMode(modeIndex);
|
||||
|
||||
GameMain.NetLobbyScreen.SetAllowSpectating(allowSpectating);
|
||||
GameMain.NetLobbyScreen.LevelSeed = levelSeed;
|
||||
GameMain.NetLobbyScreen.SetLevelDifficulty(levelDifficulty);
|
||||
GameMain.NetLobbyScreen.SetBotCount(botCount);
|
||||
GameMain.NetLobbyScreen.SetBotSpawnMode(botSpawnMode);
|
||||
GameMain.NetLobbyScreen.SetBotSpawnMode(botSpawnMode);
|
||||
GameMain.NetLobbyScreen.SetAutoRestart(autoRestartEnabled, autoRestartTimer);
|
||||
|
||||
serverSettings.VoiceChatEnabled = voiceChatEnabled;
|
||||
@@ -1373,7 +1386,7 @@ namespace Barotrauma.Networking
|
||||
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
|
||||
inc.Position = msgEndPos;
|
||||
inc.ReadPadBits();
|
||||
@@ -1409,7 +1422,7 @@ namespace Barotrauma.Networking
|
||||
errorLines.Add(" - " + e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach (string line in errorLines)
|
||||
{
|
||||
DebugConsole.ThrowError(line);
|
||||
@@ -1476,7 +1489,7 @@ namespace Barotrauma.Networking
|
||||
chatMsgQueue[i].ClientWrite(outmsg);
|
||||
}
|
||||
outmsg.Write((byte)ClientNetObject.END_OF_MESSAGE);
|
||||
|
||||
|
||||
if (outmsg.LengthBytes > client.Configuration.MaximumTransmissionUnit)
|
||||
{
|
||||
DebugConsole.ThrowError("Maximum packet size exceeded (" + outmsg.LengthBytes + " > " + client.Configuration.MaximumTransmissionUnit);
|
||||
@@ -1509,7 +1522,7 @@ namespace Barotrauma.Networking
|
||||
return;
|
||||
}
|
||||
chatMsgQueue[i].ClientWrite(outmsg);
|
||||
}
|
||||
}
|
||||
|
||||
outmsg.Write((byte)ClientNetObject.END_OF_MESSAGE);
|
||||
|
||||
@@ -1523,7 +1536,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
public void SendChatMessage(ChatMessage msg)
|
||||
{
|
||||
if (client.ServerConnection == null) return;
|
||||
if (client.ServerConnection == null) return;
|
||||
lastQueueChatMsgID++;
|
||||
msg.NetStateID = lastQueueChatMsgID;
|
||||
chatMsgQueue.Add(msg);
|
||||
@@ -1536,7 +1549,7 @@ namespace Barotrauma.Networking
|
||||
ChatMessage chatMessage = ChatMessage.Create(
|
||||
gameStarted && myCharacter != null ? myCharacter.Name : name,
|
||||
message,
|
||||
type,
|
||||
type,
|
||||
gameStarted && myCharacter != null ? myCharacter : null);
|
||||
|
||||
lastQueueChatMsgID++;
|
||||
@@ -1586,12 +1599,12 @@ namespace Barotrauma.Networking
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
IEnumerable<GUIComponent> subListChildren = (i == 0) ?
|
||||
GameMain.NetLobbyScreen.ShuttleList.ListBox.Content.Children :
|
||||
IEnumerable<GUIComponent> subListChildren = (i == 0) ?
|
||||
GameMain.NetLobbyScreen.ShuttleList.ListBox.Content.Children :
|
||||
GameMain.NetLobbyScreen.SubList.Content.Children;
|
||||
|
||||
var subElement = subListChildren.FirstOrDefault(c =>
|
||||
((Submarine)c.UserData).Name == newSub.Name &&
|
||||
var subElement = subListChildren.FirstOrDefault(c =>
|
||||
((Submarine)c.UserData).Name == newSub.Name &&
|
||||
((Submarine)c.UserData).MD5Hash.Hash == newSub.MD5Hash.Hash);
|
||||
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.Second == newSub.MD5Hash.Hash)
|
||||
{
|
||||
@@ -1636,7 +1649,7 @@ namespace Barotrauma.Networking
|
||||
if (GameMain.GameSession.Submarine == null)
|
||||
{
|
||||
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, "");
|
||||
}
|
||||
|
||||
@@ -1662,7 +1675,7 @@ namespace Barotrauma.Networking
|
||||
if (!(entity is IClientSerializable)) throw new InvalidCastException("entity is not IClientSerializable");
|
||||
entityEventManager.CreateEvent(entity as IClientSerializable, extraData);
|
||||
}
|
||||
|
||||
|
||||
public bool HasPermission(ClientPermissions permission)
|
||||
{
|
||||
return permissions.HasFlag(permission);
|
||||
@@ -1675,7 +1688,7 @@ namespace Barotrauma.Networking
|
||||
command = command.ToLowerInvariant();
|
||||
return permittedConsoleCommands.Any(c => c.ToLowerInvariant() == command);
|
||||
}
|
||||
|
||||
|
||||
public override void Disconnect()
|
||||
{
|
||||
client.Shutdown("");
|
||||
@@ -1711,7 +1724,7 @@ namespace Barotrauma.Networking
|
||||
VoipClient = null;
|
||||
GameMain.Client = null;
|
||||
}
|
||||
|
||||
|
||||
public void WriteCharacterInfo(NetOutgoingMessage msg)
|
||||
{
|
||||
msg.Write(characterInfo == null);
|
||||
@@ -1733,7 +1746,7 @@ namespace Barotrauma.Networking
|
||||
msg.Write(jobPreferences[i].Identifier);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Vote(VoteType voteType, object data)
|
||||
{
|
||||
NetOutgoingMessage msg = client.CreateMessage();
|
||||
@@ -1771,7 +1784,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
NetOutgoingMessage msg = client.CreateMessage();
|
||||
msg.Write((byte)ClientPacketHeader.SERVER_COMMAND);
|
||||
msg.Write((UInt16)ClientPermissions.Kick);
|
||||
msg.Write((UInt16)ClientPermissions.Kick);
|
||||
msg.Write(kickedName);
|
||||
msg.Write(reason);
|
||||
|
||||
@@ -1926,7 +1939,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
msg.Write(false); msg.WritePadBits();
|
||||
msg.Write(saveName);
|
||||
|
||||
|
||||
client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered);
|
||||
|
||||
GameMain.NetLobbyScreen.CampaignSetupUI = null;
|
||||
@@ -1948,13 +1961,13 @@ namespace Barotrauma.Networking
|
||||
public bool SpectateClicked(GUIButton button, object userData)
|
||||
{
|
||||
if (button != null) button.Enabled = false;
|
||||
|
||||
|
||||
NetOutgoingMessage readyToStartMsg = client.CreateMessage();
|
||||
readyToStartMsg.Write((byte)ClientPacketHeader.RESPONSE_STARTGAME);
|
||||
|
||||
//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)
|
||||
readyToStartMsg.Write(true);
|
||||
readyToStartMsg.Write(true);
|
||||
|
||||
WriteCharacterInfo(readyToStartMsg);
|
||||
|
||||
@@ -2052,9 +2065,9 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
SendChatMessage(message);
|
||||
|
||||
|
||||
textBox.Deselect();
|
||||
textBox.Text = "";
|
||||
textBox.Text = "";
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -2080,10 +2093,14 @@ namespace Barotrauma.Networking
|
||||
GUITextBox msgBox = null;
|
||||
|
||||
if (Screen.Selected == GameMain.GameScreen)
|
||||
{ msgBox = chatBox.InputBox; }
|
||||
{
|
||||
msgBox = chatBox.InputBox;
|
||||
}
|
||||
else if (Screen.Selected == GameMain.NetLobbyScreen)
|
||||
{ msgBox = GameMain.NetLobbyScreen.TextBox; }
|
||||
|
||||
{
|
||||
msgBox = GameMain.NetLobbyScreen.TextBox;
|
||||
}
|
||||
|
||||
if (gameStarted && Screen.Selected == GameMain.GameScreen)
|
||||
{
|
||||
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
|
||||
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)
|
||||
{
|
||||
if (msgBox.Selected)
|
||||
@@ -2182,15 +2199,15 @@ namespace Barotrauma.Networking
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle(
|
||||
(int)pos.X,
|
||||
(int)pos.Y,
|
||||
fileReceiver.ActiveTransfers.Count * 210 + 10,
|
||||
32),
|
||||
(int)pos.Y,
|
||||
fileReceiver.ActiveTransfers.Count * 210 + 10,
|
||||
32),
|
||||
Color.Black * 0.8f, true);
|
||||
|
||||
|
||||
for (int i = 0; i < fileReceiver.ActiveTransfers.Count; i++)
|
||||
{
|
||||
var transfer = fileReceiver.ActiveTransfers[i];
|
||||
|
||||
|
||||
GUI.DrawString(spriteBatch,
|
||||
pos,
|
||||
ToolBox.LimitString(TextManager.Get("DownloadingFile").Replace("[filename]", transfer.FileName), GUI.SmallFont, 200),
|
||||
|
||||
808
Barotrauma/BarotraumaClient/Source/Networking/ServerSettings.cs
Normal file
808
Barotrauma/BarotraumaClient/Source/Networking/ServerSettings.cs
Normal file
@@ -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;
|
||||
}
|
||||
|
||||
public DateTime LastEnqueueAudio;
|
||||
public DateTime LastEnqueueAudio;
|
||||
|
||||
public override byte QueueID
|
||||
{
|
||||
@@ -47,10 +47,14 @@ namespace Barotrauma.Networking
|
||||
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
|
||||
};
|
||||
if (capture.captureDevice != IntPtr.Zero)
|
||||
{
|
||||
Instance = capture;
|
||||
}
|
||||
}
|
||||
|
||||
private VoipCapture(string deviceName) : base(GameMain.Client?.ID ?? 0, true, false)
|
||||
@@ -60,6 +64,14 @@ namespace Barotrauma.Networking
|
||||
//set up capture device
|
||||
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();
|
||||
AlcError alcError = Alc.GetError(captureDevice);
|
||||
if (alcError != AlcError.NoError)
|
||||
@@ -70,7 +82,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
throw new Exception("Failed to open capture device: " + alError.ToString() + " (AL)");
|
||||
}
|
||||
|
||||
|
||||
Alc.CaptureStart(captureDevice);
|
||||
alcError = Alc.GetError(captureDevice);
|
||||
if (alcError != AlcError.NoError)
|
||||
@@ -159,7 +171,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else if (GameMain.Config.VoiceSetting == GameSettings.VoiceMode.PushToTalk)
|
||||
{
|
||||
if (PlayerInput.KeyDown(InputType.Voice))
|
||||
if (PlayerInput.KeyDown(InputType.Voice) && GUI.KeyboardDispatcher.Subscriber == null)
|
||||
{
|
||||
allowEnqueue = true;
|
||||
}
|
||||
@@ -201,7 +213,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
Instance = null;
|
||||
capturing = false;
|
||||
captureThread.Join();
|
||||
captureThread?.Join();
|
||||
captureThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace Barotrauma.Networking
|
||||
else
|
||||
{
|
||||
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)
|
||||
|
||||
@@ -401,6 +401,43 @@ namespace Barotrauma
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
GameMain.Config.SaveNewPlayerConfig();
|
||||
|
||||
@@ -78,9 +78,6 @@ namespace Barotrauma
|
||||
private GUIButton faceSelectionLeft;
|
||||
private GUIButton faceSelectionRight;
|
||||
|
||||
private GUIButton faceSelectionLeft;
|
||||
private GUIButton faceSelectionRight;
|
||||
|
||||
private float autoRestartTimer;
|
||||
|
||||
//persistent characterinfo provided by the server
|
||||
@@ -125,12 +122,6 @@ namespace Barotrauma
|
||||
private set;
|
||||
}
|
||||
|
||||
public GUIButton ShowLogButton
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public GUIListBox SubList
|
||||
{
|
||||
get { return subList; }
|
||||
|
||||
@@ -64,10 +64,6 @@ namespace Barotrauma
|
||||
|
||||
private readonly string containerDeleteTag = "containerdelete";
|
||||
|
||||
private DateTime editorSelectedTime;
|
||||
|
||||
private readonly string containerDeleteTag = "containerdelete";
|
||||
|
||||
public override Camera Cam
|
||||
{
|
||||
get { return cam; }
|
||||
|
||||
BIN
Barotrauma/BarotraumaClient/plugins/codec/libavcodec_plugin.dll
Normal file
BIN
Barotrauma/BarotraumaClient/plugins/codec/libavcodec_plugin.dll
Normal file
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
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("0.8.9.4")]
|
||||
[assembly: AssemblyFileVersion("0.8.9.4")]
|
||||
[assembly: AssemblyVersion("0.8.9.5")]
|
||||
[assembly: AssemblyFileVersion("0.8.9.5")]
|
||||
|
||||
@@ -116,22 +116,12 @@ namespace Barotrauma.Networking
|
||||
ChatMessageType messageType = CanUseRadio(orderMsg.Sender) ? ChatMessageType.Radio : ChatMessageType.Default;
|
||||
if (orderMsg.Order.TargetAllCharacters)
|
||||
{
|
||||
#if CLIENT
|
||||
//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
|
||||
//do nothing
|
||||
}
|
||||
else if (orderTargetCharacter != null)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -483,7 +483,7 @@ namespace Barotrauma.Networking
|
||||
(OwnerConnection == null || c.Connection != OwnerConnection));
|
||||
foreach (Client c in kickAFK)
|
||||
{
|
||||
KickClient(c, TextManager.Get("DisconnectMessage.AFK"));
|
||||
KickClient(c, "DisconnectMessage.AFK");
|
||||
}
|
||||
|
||||
NetIncomingMessage inc = null;
|
||||
@@ -956,11 +956,11 @@ namespace Barotrauma.Networking
|
||||
Log("Client \"" + sender.Name + "\" banned \"" + bannedClient.Name + "\".", ServerLog.MessageType.ServerMessage);
|
||||
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
|
||||
{
|
||||
BanClient(bannedClient, string.IsNullOrEmpty(banReason) ? "Banned by " + sender.Name : banReason, range);
|
||||
BanClient(bannedClient, string.IsNullOrEmpty(banReason) ? $"ServerMessage.BannedBy_[initiator]={sender.Name}" : banReason, range);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1981,14 +1981,14 @@ namespace Barotrauma.Networking
|
||||
client.HasSpawned = 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);
|
||||
|
||||
if (client.SteamID > 0) { SteamManager.StopAuthSession(client.SteamID); }
|
||||
@@ -2236,7 +2236,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (type.Value != ChatMessageType.MessageBox)
|
||||
{
|
||||
string myReceivedMessage = message;
|
||||
string myReceivedMessage = TextManager.GetServerMessage(message);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(myReceivedMessage) &&
|
||||
(targetClient == null || senderClient == null))
|
||||
|
||||
511
Barotrauma/BarotraumaServer/Source/Networking/GameServerLogin.cs
Normal file
511
Barotrauma/BarotraumaServer/Source/Networking/GameServerLogin.cs
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
482
Barotrauma/BarotraumaServer/Source/Networking/ServerSettings.cs
Normal file
482
Barotrauma/BarotraumaServer/Source/Networking/ServerSettings.cs
Normal file
@@ -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">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="$(MSBuildThisFileDirectory)Content\Sounds\Damage\implode.ogg">
|
||||
<None Include="$(MSBuildThisFileDirectory)Content\Sounds\Damage\Implode.ogg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="$(MSBuildThisFileDirectory)Content\Sounds\Damage\LimbSlash1.ogg">
|
||||
@@ -3322,4 +3322,4 @@
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\HireManager.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Characters\Animation\HumanoidAnimParams.cs" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -188,45 +188,6 @@ namespace Barotrauma
|
||||
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();
|
||||
|
||||
private void UpdateSpeaking()
|
||||
@@ -299,21 +260,5 @@ namespace Barotrauma
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
base.Flip();
|
||||
|
||||
@@ -1297,6 +1297,7 @@ namespace Barotrauma
|
||||
CheckValidity(Collider);
|
||||
foreach (Limb limb in limbs)
|
||||
{
|
||||
if (limb.body == null || !limb.body.Enabled) { continue; }
|
||||
CheckValidity(limb.body);
|
||||
}
|
||||
}
|
||||
@@ -1323,7 +1324,11 @@ namespace Barotrauma
|
||||
}
|
||||
if (errorMsg != null)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
#else
|
||||
DebugConsole.NewMessage(errorMsg, Color.Red);
|
||||
#endif
|
||||
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)
|
||||
|
||||
@@ -10,6 +10,7 @@ using System.Xml.Linq;
|
||||
using Barotrauma.Items.Components;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using Barotrauma.Extensions;
|
||||
using System.Text;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -529,37 +530,6 @@ namespace Barotrauma
|
||||
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
|
||||
{
|
||||
get
|
||||
@@ -1017,10 +987,6 @@ namespace Barotrauma
|
||||
public Vector2? OverrideMovement { 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()
|
||||
{
|
||||
Vector2 targetMovement = Vector2.Zero;
|
||||
@@ -1069,7 +1035,24 @@ namespace Barotrauma
|
||||
|
||||
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>
|
||||
@@ -2202,16 +2185,17 @@ namespace Barotrauma
|
||||
#if SERVER
|
||||
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)
|
||||
{
|
||||
foreach (Affliction affliction in attackResult.Afflictions)
|
||||
{
|
||||
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
|
||||
|
||||
|
||||
@@ -980,68 +980,6 @@ namespace Barotrauma
|
||||
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) =>
|
||||
{
|
||||
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
|
||||
foreach (Character c in Character.CharacterList)
|
||||
{
|
||||
|
||||
@@ -45,6 +45,12 @@ namespace Barotrauma
|
||||
public bool SpecularityEnabled { 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 enum VoiceMode
|
||||
@@ -304,11 +310,6 @@ namespace Barotrauma
|
||||
VerboseLogging = doc.Root.GetAttributeBool("verboselogging", false);
|
||||
SaveDebugConsoleLogs = doc.Root.GetAttributeBool("savedebugconsolelogs", false);
|
||||
|
||||
#if DEBUG
|
||||
UseSteam = doc.Root.GetAttributeBool("usesteam", true);
|
||||
#endif
|
||||
QuickStartSubmarineName = doc.Root.GetAttributeString("quickstartsub", "");
|
||||
|
||||
#if DEBUG
|
||||
UseSteam = doc.Root.GetAttributeBool("usesteam", true);
|
||||
#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);
|
||||
|
||||
keyMapping = new KeyOrMouse[Enum.GetNames(typeof(InputType)).Length];
|
||||
@@ -519,6 +522,34 @@ namespace Barotrauma
|
||||
|
||||
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
|
||||
//to make sure the package that contains text files has been loaded before we attempt to use TextManager
|
||||
foreach (string missingPackagePath in missingPackagePaths)
|
||||
@@ -1071,6 +1102,32 @@ namespace Barotrauma
|
||||
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 (Tutorial.Tutorials != null)
|
||||
{
|
||||
|
||||
@@ -24,9 +24,6 @@ namespace Barotrauma.Items.Components
|
||||
private bool createdNewGap;
|
||||
private bool autoOrientGap;
|
||||
|
||||
private bool createdNewGap;
|
||||
private bool autoOrientGap;
|
||||
|
||||
private bool isStuck;
|
||||
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 FixCharacterProjSpecific(Character user, float deltaTime, Character targetCharacter);
|
||||
partial void FixItemProjSpecific(Character user, float deltaTime, Item targetItem, float prevCondition);
|
||||
|
||||
@@ -187,6 +187,24 @@ namespace Barotrauma.Items.Components
|
||||
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)
|
||||
{
|
||||
if (AutoInteractWithContained)
|
||||
|
||||
@@ -105,6 +105,8 @@ namespace Barotrauma.Items.Components
|
||||
progressTimer = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
voltage -= deltaTime * 10.0f;
|
||||
}
|
||||
|
||||
private void PutItemsToLinkedContainer()
|
||||
@@ -162,8 +164,6 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (!IsActive) { progressState = 0.0f; }
|
||||
|
||||
if (!IsActive) { progressState = 0.0f; }
|
||||
|
||||
#if CLIENT
|
||||
if (!IsActive)
|
||||
{
|
||||
|
||||
@@ -493,7 +493,6 @@ namespace Barotrauma.Items.Components
|
||||
AutoTemp = false;
|
||||
unsentChanges = true;
|
||||
UpdateAutoTemp(2.0f + degreeOfSuccess * 5.0f, 1.0f);
|
||||
|
||||
}
|
||||
#if CLIENT
|
||||
onOffSwitch.BarScroll = 0.0f;
|
||||
@@ -505,6 +504,11 @@ namespace Barotrauma.Items.Components
|
||||
#if CLIENT
|
||||
onOffSwitch.BarScroll = 1.0f;
|
||||
#endif
|
||||
if (AutoTemp || !shutDown || targetFissionRate > 0.0f || targetTurbineOutput > 0.0f)
|
||||
{
|
||||
unsentChanges = true;
|
||||
}
|
||||
|
||||
AutoTemp = false;
|
||||
shutDown = true;
|
||||
targetFissionRate = 0.0f;
|
||||
|
||||
@@ -32,11 +32,6 @@ namespace Barotrauma.Items.Components
|
||||
//a list of powered devices connected directly to this item
|
||||
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
|
||||
{
|
||||
get;
|
||||
|
||||
@@ -178,9 +178,6 @@ namespace Barotrauma.Items.Components
|
||||
//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);
|
||||
|
||||
//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 (!item.Repairables.Any() || !CanBeOverloaded) continue;
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace Barotrauma
|
||||
|
||||
private LocationType(XElement element)
|
||||
{
|
||||
Identifier = element.Name.ToString();
|
||||
Identifier = element.GetAttributeString("identifier", element.Name.ToString());
|
||||
Name = TextManager.Get("LocationName." + Identifier);
|
||||
nameFormats = TextManager.GetAll("LocationNameFormat." + Identifier);
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace Barotrauma
|
||||
}
|
||||
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" };
|
||||
}
|
||||
|
||||
@@ -82,9 +82,7 @@ namespace Barotrauma
|
||||
}
|
||||
CommonnessPerZone[zoneIndex] = zoneCommonness;
|
||||
}
|
||||
|
||||
string nameFile = element.GetAttributeString("namefile", "Content/Map/locationNames.txt");
|
||||
try
|
||||
catch (Exception e)
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
|
||||
@@ -430,6 +430,13 @@ namespace Barotrauma
|
||||
}
|
||||
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;
|
||||
SelectedConnection = connections.Find(c => c.Locations.Contains(CurrentLocation) && c.Locations.Contains(SelectedLocation));
|
||||
OnLocationSelected?.Invoke(SelectedLocation, SelectedConnection);
|
||||
|
||||
@@ -518,6 +518,10 @@ namespace Barotrauma
|
||||
{
|
||||
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); }
|
||||
}
|
||||
|
||||
@@ -40,16 +40,19 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
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;
|
||||
}
|
||||
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 ClientPermissions Permissions = ClientPermissions.None;
|
||||
public List<DebugConsole.Command> PermittedConsoleCommands
|
||||
{
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
public LogMessage(string text, MessageType type)
|
||||
{
|
||||
Text = "[" + DateTime.Now.ToString() + "] " + text;
|
||||
Text = "[" + DateTime.Now.ToString() + "] " + TextManager.GetServerMessage(text);
|
||||
Type = type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,6 +145,16 @@ namespace Barotrauma
|
||||
get { return binding; }
|
||||
}
|
||||
|
||||
public void SetState()
|
||||
{
|
||||
hit = binding.IsHit();
|
||||
if (hit) hitQueue = true;
|
||||
|
||||
held = binding.IsDown();
|
||||
if (held) heldQueue = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
public void SetState()
|
||||
{
|
||||
hit = binding.IsHit();
|
||||
|
||||
@@ -82,33 +82,6 @@ namespace Barotrauma
|
||||
#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)
|
||||
{
|
||||
#if SERVER
|
||||
|
||||
@@ -89,11 +89,6 @@ namespace Barotrauma
|
||||
public readonly AttributeCollection Attributes;
|
||||
public readonly Type PropertyType;
|
||||
|
||||
public object ParentObject
|
||||
{
|
||||
get { return obj; }
|
||||
}
|
||||
|
||||
public SerializableProperty(PropertyDescriptor property, object obj)
|
||||
{
|
||||
Name = property.Name;
|
||||
@@ -187,9 +182,6 @@ namespace Barotrauma
|
||||
case "point":
|
||||
propertyInfo.SetValue(parentObject, XMLExtensions.ParsePoint(value));
|
||||
break;
|
||||
case "point":
|
||||
propertyInfo.SetValue(obj, XMLExtensions.ParsePoint(value));
|
||||
break;
|
||||
case "vector2":
|
||||
propertyInfo.SetValue(parentObject, XMLExtensions.ParseVector2(value));
|
||||
break;
|
||||
@@ -262,9 +254,6 @@ namespace Barotrauma
|
||||
case "point":
|
||||
propertyInfo.SetValue(parentObject, XMLExtensions.ParsePoint((string)value));
|
||||
return true;
|
||||
case "point":
|
||||
propertyInfo.SetValue(obj, XMLExtensions.ParsePoint((string)value));
|
||||
return true;
|
||||
case "vector2":
|
||||
propertyInfo.SetValue(parentObject, XMLExtensions.ParseVector2((string)value));
|
||||
return true;
|
||||
|
||||
@@ -486,38 +486,8 @@ namespace Barotrauma
|
||||
|
||||
protected bool IsValidTarget(ISerializableEntity entity)
|
||||
{
|
||||
if (entity is Item item)
|
||||
{
|
||||
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;
|
||||
}
|
||||
if (targetIdentifiers == null) { 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 (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)
|
||||
{
|
||||
@@ -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 (entity != null)
|
||||
{
|
||||
@@ -983,30 +902,6 @@ namespace Barotrauma
|
||||
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;
|
||||
|
||||
@@ -155,18 +155,29 @@ namespace Barotrauma
|
||||
{
|
||||
if (!messages[i].Contains("_")) // No variables, just translate
|
||||
{
|
||||
messages[i] = Get(messages[i]);
|
||||
continue;
|
||||
string msg = Get(messages[i], true);
|
||||
|
||||
if (msg != null) // If a translation was found, otherwise use the original
|
||||
{
|
||||
messages[i] = msg;
|
||||
}
|
||||
}
|
||||
|
||||
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++)
|
||||
else
|
||||
{
|
||||
string[] variableAndValue = messageWithVariables[j].Split('=');
|
||||
messages[i] = messages[i].Replace(variableAndValue[0], variableAndValue[1]);
|
||||
string[] messageWithVariables = messages[i].Split('_');
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
@@ -56,6 +79,7 @@ Additions:
|
||||
- Some new random events.
|
||||
- A bunch of new afflictions and medical items.
|
||||
- Some new item sprites.
|
||||
- A couple of new cargo missions.
|
||||
- Added some new items that can be crafted from alien materials.
|
||||
- Display linked hulls as one room on the status monitor.
|
||||
- Tons of new sound effects.
|
||||
|
||||
Reference in New Issue
Block a user