commit 7245c721339885d062567befc052a592391b3b4a Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Sun Mar 10 15:22:31 2019 +0200 Fixed StatusEffects only applying afflictions to one limb even if the target is "Character" instead of "Limb", added a subtle screen distortion effect to heavy radiation sickness. Closes #1256 commit e0db27e62ec9546fd4b182a0cc97f7e5830645ae Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Sat Mar 9 21:53:51 2019 +0200 Fixed WrapText adding unnecessary spaces after every line break. Closes #1215 commit 988bc58d51c195ad9265b84a1e97e0101cd3f808 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Sat Mar 9 21:12:50 2019 +0200 Fixed crashing when attempting to create a body for a wall section that's less than 1 unit long (e.g. if a wall that's just slightly longer than the wall section size receives damage). commit 8c31157425a9e2ec02312618d1bfa359ab3ee87d Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Sat Mar 9 20:30:44 2019 +0200 Fixed clients being unable to toggle the respawn shuttle on/off commit a4ccb039219830efe9cd305c26942dda1bd04e9c Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Sat Mar 9 19:33:22 2019 +0200 Fixed inability to select the respawn shuttle as a client host commit b89b2d2c282d8c74d7ccd37b3f29dcab51eff680 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Sat Mar 9 19:32:41 2019 +0200 Made it possible to edit the style of the ListBox under GUIDropDowns, increased the opacity of the listbox to make the contents more readable when there's text behind it commit 8f6d9aef3d637fe37a18c78f4b15ef8fd266374e Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Sat Mar 9 18:11:23 2019 +0200 Fixed NetLobbyScreen not showing the names of the submarines the client doesn't have
711 lines
20 KiB
C#
711 lines
20 KiB
C#
using Lidgren.Network;
|
|
using Microsoft.Xna.Framework;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using System.Xml;
|
|
using System.Xml.Linq;
|
|
|
|
namespace Barotrauma.Networking
|
|
{
|
|
enum SelectionMode
|
|
{
|
|
Manual = 0, Random = 1, Vote = 2
|
|
}
|
|
|
|
enum YesNoMaybe
|
|
{
|
|
No = 0, Maybe = 1, Yes = 2
|
|
}
|
|
|
|
enum BotSpawnMode
|
|
{
|
|
Normal, Fill
|
|
}
|
|
|
|
partial class ServerSettings : ISerializableEntity
|
|
{
|
|
[Flags]
|
|
public enum NetFlags : byte
|
|
{
|
|
Name = 0x1,
|
|
Message = 0x2,
|
|
Properties = 0x4,
|
|
Misc = 0x8,
|
|
LevelSeed = 0x10
|
|
}
|
|
|
|
public static readonly string PermissionPresetFile = "Data" + Path.DirectorySeparatorChar + "permissionpresets.xml";
|
|
|
|
public string Name
|
|
{
|
|
get { return "ServerSettings"; }
|
|
}
|
|
|
|
public class SavedClientPermission
|
|
{
|
|
public readonly string IP;
|
|
public readonly ulong SteamID;
|
|
public readonly string Name;
|
|
public List<DebugConsole.Command> PermittedCommands;
|
|
|
|
public ClientPermissions Permissions;
|
|
|
|
public SavedClientPermission(string name, IPAddress ip, ClientPermissions permissions, List<DebugConsole.Command> permittedCommands)
|
|
{
|
|
this.Name = name;
|
|
this.IP = ip.IsIPv4MappedToIPv6 ? ip.MapToIPv4().ToString() : ip.ToString();
|
|
this.Permissions = permissions;
|
|
this.PermittedCommands = permittedCommands;
|
|
}
|
|
public SavedClientPermission(string name, string ip, ClientPermissions permissions, List<DebugConsole.Command> permittedCommands)
|
|
{
|
|
this.Name = name;
|
|
this.IP = ip;
|
|
|
|
this.Permissions = permissions;
|
|
this.PermittedCommands = permittedCommands;
|
|
}
|
|
public SavedClientPermission(string name, ulong steamID, ClientPermissions permissions, List<DebugConsole.Command> permittedCommands)
|
|
{
|
|
this.Name = name;
|
|
this.SteamID = steamID;
|
|
|
|
this.Permissions = permissions;
|
|
this.PermittedCommands = permittedCommands;
|
|
}
|
|
}
|
|
|
|
partial class NetPropertyData
|
|
{
|
|
private SerializableProperty property;
|
|
private string typeString;
|
|
|
|
private ServerSettings serverSettings;
|
|
|
|
public string Name
|
|
{
|
|
get { return property.Name; }
|
|
}
|
|
|
|
public object Value
|
|
{
|
|
get { return property.GetValue(serverSettings); }
|
|
}
|
|
|
|
public NetPropertyData(ServerSettings serverSettings, SerializableProperty property, string typeString)
|
|
{
|
|
this.property = property;
|
|
this.typeString = typeString;
|
|
this.serverSettings = serverSettings;
|
|
}
|
|
|
|
public void Read(NetBuffer msg)
|
|
{
|
|
long oldPos = msg.Position;
|
|
UInt32 size = msg.ReadVariableUInt32();
|
|
|
|
float x; float y; float z; float w;
|
|
byte r; byte g; byte b; byte a;
|
|
int ix; int iy; int width; int height;
|
|
|
|
switch (typeString)
|
|
{
|
|
case "float":
|
|
if (size != 4) break;
|
|
property.SetValue(serverSettings, msg.ReadFloat());
|
|
return;
|
|
case "vector2":
|
|
if (size != 8) break;
|
|
x = msg.ReadFloat();
|
|
y = msg.ReadFloat();
|
|
property.SetValue(serverSettings, new Vector2(x, y));
|
|
return;
|
|
case "vector3":
|
|
if (size != 12) break;
|
|
x = msg.ReadFloat();
|
|
y = msg.ReadFloat();
|
|
z = msg.ReadFloat();
|
|
property.SetValue(serverSettings, new Vector3(x, y, z));
|
|
return;
|
|
case "vector4":
|
|
if (size != 16) break;
|
|
x = msg.ReadFloat();
|
|
y = msg.ReadFloat();
|
|
z = msg.ReadFloat();
|
|
w = msg.ReadFloat();
|
|
property.SetValue(serverSettings, new Vector4(x, y, z, w));
|
|
return;
|
|
case "color":
|
|
if (size != 4) break;
|
|
r = msg.ReadByte();
|
|
g = msg.ReadByte();
|
|
b = msg.ReadByte();
|
|
a = msg.ReadByte();
|
|
property.SetValue(serverSettings, new Color(r, g, b, a));
|
|
return;
|
|
case "rectangle":
|
|
if (size != 16) break;
|
|
ix = msg.ReadInt32();
|
|
iy = msg.ReadInt32();
|
|
width = msg.ReadInt32();
|
|
height = msg.ReadInt32();
|
|
property.SetValue(serverSettings, new Rectangle(ix, iy, width, height));
|
|
return;
|
|
default:
|
|
msg.Position = oldPos; //reset position to properly read the string
|
|
string incVal = msg.ReadString();
|
|
property.TrySetValue(serverSettings, incVal);
|
|
return;
|
|
}
|
|
|
|
//size didn't match: skip this
|
|
msg.Position += 8 * size;
|
|
}
|
|
|
|
public void Write(NetBuffer msg, object overrideValue = null)
|
|
{
|
|
if (overrideValue == null) overrideValue = property.GetValue(serverSettings);
|
|
switch (typeString)
|
|
{
|
|
case "float":
|
|
msg.WriteVariableUInt32(4);
|
|
msg.Write((float)overrideValue);
|
|
break;
|
|
case "vector2":
|
|
msg.WriteVariableUInt32(8);
|
|
msg.Write(((Vector2)overrideValue).X);
|
|
msg.Write(((Vector2)overrideValue).Y);
|
|
break;
|
|
case "vector3":
|
|
msg.WriteVariableUInt32(12);
|
|
msg.Write(((Vector3)overrideValue).X);
|
|
msg.Write(((Vector3)overrideValue).Y);
|
|
msg.Write(((Vector3)overrideValue).Z);
|
|
break;
|
|
case "vector4":
|
|
msg.WriteVariableUInt32(16);
|
|
msg.Write(((Vector4)overrideValue).X);
|
|
msg.Write(((Vector4)overrideValue).Y);
|
|
msg.Write(((Vector4)overrideValue).Z);
|
|
msg.Write(((Vector4)overrideValue).W);
|
|
break;
|
|
case "color":
|
|
msg.WriteVariableUInt32(4);
|
|
msg.Write(((Color)overrideValue).R);
|
|
msg.Write(((Color)overrideValue).G);
|
|
msg.Write(((Color)overrideValue).B);
|
|
msg.Write(((Color)overrideValue).A);
|
|
break;
|
|
case "rectangle":
|
|
msg.WriteVariableUInt32(16);
|
|
msg.Write(((Rectangle)overrideValue).X);
|
|
msg.Write(((Rectangle)overrideValue).Y);
|
|
msg.Write(((Rectangle)overrideValue).Width);
|
|
msg.Write(((Rectangle)overrideValue).Height);
|
|
break;
|
|
default:
|
|
string strVal = overrideValue.ToString();
|
|
|
|
msg.Write(strVal);
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
public Dictionary<string, SerializableProperty> SerializableProperties
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
Dictionary<UInt32,NetPropertyData> netProperties;
|
|
|
|
partial void InitProjSpecific();
|
|
|
|
public ServerSettings(string serverName, int port, int queryPort, int maxPlayers, bool isPublic, bool enableUPnP)
|
|
{
|
|
ServerLog = new ServerLog(serverName);
|
|
|
|
Voting = new Voting();
|
|
|
|
Whitelist = new WhiteList();
|
|
BanList = new BanList();
|
|
|
|
ExtraCargo = new Dictionary<ItemPrefab, int>();
|
|
|
|
PermissionPreset.LoadAll(PermissionPresetFile);
|
|
InitProjSpecific();
|
|
|
|
ServerName = serverName;
|
|
Port = port;
|
|
QueryPort = queryPort;
|
|
//EnableUPnP = enableUPnP;
|
|
this.maxPlayers = maxPlayers;
|
|
this.isPublic = isPublic;
|
|
|
|
netProperties = new Dictionary<UInt32, NetPropertyData>();
|
|
|
|
using (MD5 md5 = MD5.Create())
|
|
{
|
|
var saveProperties = SerializableProperty.GetProperties<Serialize>(this);
|
|
foreach (var property in saveProperties)
|
|
{
|
|
object value = property.GetValue(this);
|
|
if (value == null) continue;
|
|
|
|
string typeName = SerializableProperty.GetSupportedTypeName(value.GetType());
|
|
if (typeName != null || property.PropertyType.IsEnum)
|
|
{
|
|
NetPropertyData netPropertyData = new NetPropertyData(this, property, typeName);
|
|
|
|
UInt32 key = ToolBox.StringToUInt32Hash(property.Name, md5);
|
|
|
|
if (netProperties.ContainsKey(key)) throw new Exception("Hashing collision in ServerSettings.netProperties: " + netProperties[key] + " has same key as " + property.Name + " (" + key.ToString() + ")");
|
|
|
|
netProperties.Add(key, netPropertyData);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public string ServerName;
|
|
|
|
public string ServerMessageText;
|
|
|
|
public int Port;
|
|
|
|
public int QueryPort;
|
|
|
|
public ServerLog ServerLog;
|
|
|
|
public Voting Voting;
|
|
|
|
public Dictionary<string, bool> MonsterEnabled { get; private set; }
|
|
|
|
public Dictionary<ItemPrefab, int> ExtraCargo { get; private set; }
|
|
|
|
private TimeSpan sparseUpdateInterval = new TimeSpan(0, 0, 0, 3);
|
|
private float selectedLevelDifficulty;
|
|
private string password;
|
|
|
|
public float AutoRestartTimer;
|
|
|
|
private bool autoRestart;
|
|
|
|
public bool isPublic;
|
|
|
|
private int maxPlayers;
|
|
|
|
public List<SavedClientPermission> ClientPermissions { get; private set; } = new List<SavedClientPermission>();
|
|
|
|
public WhiteList Whitelist { get; private set; }
|
|
|
|
[Serialize(20, true)]
|
|
public int TickRate
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
[Serialize(true, true)]
|
|
public bool RandomizeSeed
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
[Serialize(true, true)]
|
|
public bool UseRespawnShuttle
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
[Serialize(300.0f, true)]
|
|
public float RespawnInterval
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
[Serialize(180.0f, true)]
|
|
public float MaxTransportTime
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
[Serialize(0.2f, true)]
|
|
public float MinRespawnRatio
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
[Serialize(60.0f, true)]
|
|
public float AutoRestartInterval
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
[Serialize(false, true)]
|
|
public bool StartWhenClientsReady
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
[Serialize(0.8f, true)]
|
|
public float StartWhenClientsReadyRatio
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
[Serialize(true, true)]
|
|
public bool AllowSpectating
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
[Serialize(true, true)]
|
|
public bool EndRoundAtLevelEnd
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
[Serialize(true, true)]
|
|
public bool SaveServerLogs
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
[Serialize(true, true)]
|
|
public bool AllowRagdollButton
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
[Serialize(true, true)]
|
|
public bool AllowFileTransfers
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
[Serialize(true, true)]
|
|
public bool VoiceChatEnabled
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
[Serialize(800, true)]
|
|
private int LinesPerLogFile
|
|
{
|
|
get
|
|
{
|
|
return ServerLog.LinesPerFile;
|
|
}
|
|
set
|
|
{
|
|
ServerLog.LinesPerFile = value;
|
|
}
|
|
}
|
|
|
|
public bool AutoRestart
|
|
{
|
|
get { return autoRestart; }
|
|
set
|
|
{
|
|
autoRestart = value;
|
|
|
|
AutoRestartTimer = autoRestart ? AutoRestartInterval : 0.0f;
|
|
}
|
|
}
|
|
|
|
public bool HasPassword
|
|
{
|
|
get { return !string.IsNullOrEmpty(password); }
|
|
}
|
|
|
|
[Serialize(true, true)]
|
|
public bool AllowVoteKick
|
|
{
|
|
get
|
|
{
|
|
return Voting.AllowVoteKick;
|
|
}
|
|
set
|
|
{
|
|
Voting.AllowVoteKick = value;
|
|
}
|
|
}
|
|
|
|
[Serialize(true, true)]
|
|
public bool AllowEndVoting
|
|
{
|
|
get
|
|
{
|
|
return Voting.AllowEndVoting;
|
|
}
|
|
set
|
|
{
|
|
Voting.AllowEndVoting = value;
|
|
}
|
|
}
|
|
|
|
[Serialize(true, true)]
|
|
public bool AllowRespawn
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
[Serialize(0, true)]
|
|
public int BotCount
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
[Serialize(16, true)]
|
|
public int MaxBotCount
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public BotSpawnMode BotSpawnMode
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public float SelectedLevelDifficulty
|
|
{
|
|
get { return selectedLevelDifficulty; }
|
|
set { selectedLevelDifficulty = MathHelper.Clamp(value, 0.0f, 100.0f); }
|
|
}
|
|
|
|
[Serialize(true, true)]
|
|
public bool AllowDisguises
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public YesNoMaybe TraitorsEnabled
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
[Serialize(SelectionMode.Manual, true)]
|
|
public SelectionMode SubSelectionMode { get; private set; }
|
|
|
|
[Serialize(SelectionMode.Manual, true)]
|
|
public SelectionMode ModeSelectionMode { get; private set; }
|
|
|
|
public BanList BanList { get; private set; }
|
|
|
|
[Serialize(0.6f, true)]
|
|
public float EndVoteRequiredRatio
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
[Serialize(0.6f, true)]
|
|
public float KickVoteRequiredRatio
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
[Serialize(30.0f, true)]
|
|
public float KillDisconnectedTime
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
[Serialize(120.0f, true)]
|
|
public float KickAFKTime
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
[Serialize(true, true)]
|
|
public bool TraitorUseRatio
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
[Serialize(0.2f, true)]
|
|
public float TraitorRatio
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
[Serialize(false, true)]
|
|
public bool KarmaEnabled
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
[Serialize("sandbox", true)]
|
|
public string GameModeIdentifier
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
[Serialize("Random", true)]
|
|
public string MissionType
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
public int MaxPlayers
|
|
{
|
|
get { return maxPlayers; }
|
|
}
|
|
|
|
public List<MissionType> AllowedRandomMissionTypes
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
[Serialize(60f, true)]
|
|
public float AutoBanTime
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
[Serialize(360f, true)]
|
|
public float MaxAutoBanTime
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
public void SetPassword(string password)
|
|
{
|
|
this.password = Encoding.UTF8.GetString(NetUtility.ComputeSHAHash(Encoding.UTF8.GetBytes(password)));
|
|
}
|
|
|
|
public bool IsPasswordCorrect(string input, int nonce)
|
|
{
|
|
if (!HasPassword) return true;
|
|
string saltedPw = password;
|
|
saltedPw = saltedPw + Convert.ToString(nonce);
|
|
saltedPw = Encoding.UTF8.GetString(NetUtility.ComputeSHAHash(Encoding.UTF8.GetBytes(saltedPw)));
|
|
return input == saltedPw;
|
|
}
|
|
|
|
/// <summary>
|
|
/// A list of int pairs that represent the ranges of UTF-16 codes allowed in client names
|
|
/// </summary>
|
|
public List<Pair<int, int>> AllowedClientNameChars
|
|
{
|
|
get;
|
|
private set;
|
|
} = new List<Pair<int, int>>();
|
|
|
|
public void ReadMonsterEnabled(NetBuffer inc)
|
|
{
|
|
//monster spawn settings
|
|
if (MonsterEnabled == null)
|
|
{
|
|
List<string> monsterNames1 = GameMain.Instance.GetFilesOfType(ContentType.Character).ToList();
|
|
for (int i = 0; i < monsterNames1.Count; i++)
|
|
{
|
|
monsterNames1[i] = Path.GetFileName(Path.GetDirectoryName(monsterNames1[i]));
|
|
}
|
|
|
|
MonsterEnabled = new Dictionary<string, bool>();
|
|
foreach (string s in monsterNames1)
|
|
{
|
|
if (!MonsterEnabled.ContainsKey(s)) MonsterEnabled.Add(s, true);
|
|
}
|
|
}
|
|
|
|
List<string> monsterNames = MonsterEnabled.Keys.ToList();
|
|
foreach (string s in monsterNames)
|
|
{
|
|
MonsterEnabled[s] = inc.ReadBoolean();
|
|
}
|
|
inc.ReadPadBits();
|
|
}
|
|
|
|
public void WriteMonsterEnabled(NetBuffer msg, Dictionary<string, bool> monsterEnabled = null)
|
|
{
|
|
//monster spawn settings
|
|
if (monsterEnabled == null) monsterEnabled = MonsterEnabled;
|
|
|
|
List<string> monsterNames = monsterEnabled.Keys.ToList();
|
|
foreach (string s in monsterNames)
|
|
{
|
|
msg.Write(monsterEnabled[s]);
|
|
}
|
|
msg.WritePadBits();
|
|
}
|
|
|
|
public bool ReadExtraCargo(NetBuffer msg)
|
|
{
|
|
bool changed = false;
|
|
UInt32 count = msg.ReadUInt32();
|
|
if (ExtraCargo == null || count != ExtraCargo.Count) changed = true;
|
|
Dictionary<ItemPrefab, int> extraCargo = new Dictionary<ItemPrefab, int>();
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
string prefabName = msg.ReadString();
|
|
byte amount = msg.ReadByte();
|
|
ItemPrefab ip = MapEntityPrefab.List.Find(p => p is ItemPrefab && p.Name.Equals(prefabName, StringComparison.InvariantCulture)) as ItemPrefab;
|
|
if (ip != null && amount > 0)
|
|
{
|
|
if (changed || !ExtraCargo.ContainsKey(ip) || ExtraCargo[ip] != amount) changed = true;
|
|
extraCargo.Add(ip, amount);
|
|
}
|
|
}
|
|
if (changed) ExtraCargo = extraCargo;
|
|
return changed;
|
|
}
|
|
|
|
public void WriteExtraCargo(NetBuffer msg)
|
|
{
|
|
if (ExtraCargo == null)
|
|
{
|
|
msg.Write((UInt32)0);
|
|
return;
|
|
}
|
|
|
|
msg.Write((UInt32)ExtraCargo.Count);
|
|
foreach (KeyValuePair<ItemPrefab, int> kvp in ExtraCargo)
|
|
{
|
|
msg.Write(kvp.Key.Name); msg.Write((byte)kvp.Value);
|
|
}
|
|
}
|
|
}
|
|
}
|