5202af9...3ea33fb

This commit is contained in:
Joonas Rikkonen
2019-03-18 21:46:09 +02:00
parent 044fd3344b
commit 97f31d0c94
61 changed files with 2585 additions and 558 deletions

2
.gitignore vendored
View File

@@ -13,7 +13,7 @@ bld/
[Rr]elease*/
# Barotrauma content folder
Content/
BarotraumaShared/Content/
*.v12.suo
*.suo

Binary file not shown.

View File

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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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)
{

View File

@@ -143,6 +143,9 @@ namespace Barotrauma
infoFrame?.UpdateManually(deltaTime);
}
infoFrame?.UpdateManually(deltaTime);
}
public void Draw(SpriteBatch spriteBatch)
{

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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),

View File

@@ -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;

View File

@@ -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;

View File

@@ -26,8 +26,6 @@ namespace Barotrauma.Lights
private float currLightMapScale;
private float currLightMapScale;
public Color AmbientLight;
public RenderTarget2D LightMap

View File

@@ -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);
}

View File

@@ -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),

View 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
}
}
}

View File

@@ -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;
}
}

View File

@@ -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)

View File

@@ -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)
{

View File

@@ -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();

View File

@@ -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; }

View File

@@ -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; }

View File

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

View File

@@ -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);
}

View File

@@ -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))

View 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);
}
}
}
}

View 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);
}
}
}
}

View File

@@ -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>

View File

@@ -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;
}
}
}

View File

@@ -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();

View File

@@ -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)

View File

@@ -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

View File

@@ -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();

View File

@@ -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)
{

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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);

View File

@@ -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)

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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())
{

View File

@@ -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);

View File

@@ -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); }
}

View File

@@ -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;
}
}

View File

@@ -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
{

View File

@@ -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;
}
}

View File

@@ -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();

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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]);
}
}
}

View File

@@ -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;

View File

@@ -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.