305 lines
12 KiB
C#
305 lines
12 KiB
C#
using Microsoft.Xna.Framework;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Immutable;
|
|
using System.ComponentModel;
|
|
using System.Linq;
|
|
|
|
namespace Barotrauma.Networking
|
|
{
|
|
partial class ServerSettings : ISerializableEntity
|
|
{
|
|
private static readonly LocalizedString packetAmountTooltip = TextManager.Get("ServerSettingsMaxPacketAmountTooltip");
|
|
private static readonly RichString packetAmountTooltipWarning = RichString.Rich($"{packetAmountTooltip}\n\n‖color:gui.red‖{TextManager.Get("PacketLimitWarning")}‖end‖");
|
|
|
|
partial class NetPropertyData
|
|
{
|
|
public GUIComponent GUIComponent;
|
|
public object TempValue;
|
|
|
|
public void AssignGUIComponent(GUIComponent component)
|
|
{
|
|
GUIComponent = component;
|
|
GUIComponentValue = property.GetValue(parentObject);
|
|
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)
|
|
{
|
|
if (property.PropertyType == typeof(int))
|
|
{
|
|
return (int)MathF.Floor(scrollBar.BarScrollValue);
|
|
}
|
|
|
|
return scrollBar.BarScrollValue;
|
|
}
|
|
else if (GUIComponent is GUIRadioButtonGroup radioButtonGroup) { return radioButtonGroup.Selected; }
|
|
else if (GUIComponent is GUIDropDown dropdown) { return dropdown.SelectedData; }
|
|
else if (GUIComponent is GUINumberInput numInput)
|
|
{
|
|
if (numInput.InputType == NumberType.Int) { return numInput.IntValue; } else { return numInput.FloatValue; }
|
|
}
|
|
else if (GUIComponent is IGUISelectionCarouselAccessor selectionCarousel)
|
|
{
|
|
return selectionCarousel.GetSelectedElement();
|
|
}
|
|
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)
|
|
{
|
|
if (value is int i)
|
|
{
|
|
scrollBar.BarScrollValue = i;
|
|
}
|
|
else
|
|
{
|
|
scrollBar.BarScrollValue = (float)value;
|
|
}
|
|
scrollBar.OnMoved?.Invoke(scrollBar, scrollBar.BarScroll);
|
|
}
|
|
else if (GUIComponent is GUIRadioButtonGroup radioButtonGroup) { radioButtonGroup.Selected = (int)value; }
|
|
else if (GUIComponent is GUIDropDown dropdown) { dropdown.SelectItem(value); }
|
|
else if (GUIComponent is GUINumberInput numInput)
|
|
{
|
|
if (numInput.InputType == NumberType.Int)
|
|
{
|
|
numInput.IntValue = (int)value;
|
|
}
|
|
else
|
|
{
|
|
numInput.FloatValue = (float)value;
|
|
}
|
|
}
|
|
else if (GUIComponent is IGUISelectionCarouselAccessor selectionCarousel)
|
|
{
|
|
selectionCarousel.SelectElement(value);
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool ChangedLocally
|
|
{
|
|
get
|
|
{
|
|
if (GUIComponent == null) { return false; }
|
|
return !PropEquals(TempValue, GUIComponentValue);
|
|
}
|
|
}
|
|
}
|
|
private Dictionary<Identifier, bool> tempMonsterEnabled;
|
|
|
|
partial void InitProjSpecific()
|
|
{
|
|
var properties = TypeDescriptor.GetProperties(GetType()).Cast<PropertyDescriptor>();
|
|
|
|
SerializableProperties = new Dictionary<Identifier, SerializableProperty>();
|
|
|
|
foreach (var property in properties)
|
|
{
|
|
SerializableProperty objProperty = new SerializableProperty(property);
|
|
SerializableProperties.Add(property.Name.ToIdentifier(), objProperty);
|
|
}
|
|
}
|
|
|
|
public void ClientAdminRead(IReadMessage incMsg)
|
|
{
|
|
while (true)
|
|
{
|
|
UInt32 key = incMsg.ReadUInt32();
|
|
if (key == 0) { break; }
|
|
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.BitPosition += (int)(8 * size);
|
|
}
|
|
}
|
|
|
|
if (ReadMonsterEnabled(incMsg))
|
|
{
|
|
if (monstersEnabledPanel is { Visible: true })
|
|
{
|
|
//refresh panel if someone else changes it
|
|
monstersEnabledPanel.Parent?.RemoveChild(monstersEnabledPanel);
|
|
monstersEnabledPanel = CreateMonstersEnabledPanel();
|
|
monstersEnabledPanel.Visible = true;
|
|
}
|
|
}
|
|
BanList.ClientAdminRead(incMsg);
|
|
GameMain.NetLobbyScreen?.RefreshPlaystyleIcons();
|
|
}
|
|
|
|
public void ClientRead(IReadMessage incMsg)
|
|
{
|
|
NetFlags requiredFlags = (NetFlags)incMsg.ReadByte();
|
|
|
|
PlayStyle = (PlayStyle)incMsg.ReadByte();
|
|
MaxPlayers = incMsg.ReadByte();
|
|
HasPassword = incMsg.ReadBoolean();
|
|
IsPublic = incMsg.ReadBoolean();
|
|
GameClient.SetLobbyPublic(IsPublic);
|
|
AllowFileTransfers = incMsg.ReadBoolean();
|
|
incMsg.ReadPadBits();
|
|
TickRate = incMsg.ReadRangedInteger(1, 60);
|
|
|
|
if (requiredFlags.HasFlag(NetFlags.Properties))
|
|
{
|
|
if (ReadExtraCargo(incMsg))
|
|
{
|
|
if (extraCargoPanel is { Visible: true })
|
|
{
|
|
//refresh panel if someone else changes it
|
|
extraCargoPanel.Parent?.RemoveChild(extraCargoPanel);
|
|
extraCargoPanel = CreateExtraCargoPanel();
|
|
extraCargoPanel.Visible = true;
|
|
}
|
|
}
|
|
|
|
if (ReadPerks(incMsg))
|
|
{
|
|
GameMain.NetLobbyScreen?.UpdateDisembarkPointListFromServerSettings();
|
|
}
|
|
}
|
|
|
|
if (requiredFlags.HasFlag(NetFlags.HiddenSubs))
|
|
{
|
|
ReadHiddenSubs(incMsg);
|
|
}
|
|
GameMain.NetLobbyScreen.UpdateSubVisibility();
|
|
|
|
bool isAdmin = incMsg.ReadBoolean();
|
|
incMsg.ReadPadBits();
|
|
if (isAdmin)
|
|
{
|
|
ClientAdminRead(incMsg);
|
|
}
|
|
}
|
|
|
|
public static bool HasPermissionToChangePerks()
|
|
{
|
|
if (GameMain.Client.HasPermission(Networking.ClientPermissions.ManageSettings)) { return true; }
|
|
|
|
bool isPvP = GameMain.NetLobbyScreen?.SelectedMode == GameModePreset.PvP;
|
|
bool hasSelectedTeam = MultiplayerPreferences.Instance.TeamPreference is CharacterTeamType.Team1 or CharacterTeamType.Team2;
|
|
var otherClients = GameMain.Client?.ConnectedClients.Where(static c => c.SessionId != GameMain.Client.SessionId).ToImmutableArray() ?? ImmutableArray<Client>.Empty;
|
|
|
|
if (isPvP)
|
|
{
|
|
if (!hasSelectedTeam) { return false; }
|
|
|
|
return !otherClients
|
|
.Where(static c => c.PreferredTeam == MultiplayerPreferences.Instance.TeamPreference)
|
|
.Any(static c => c.HasPermission(Networking.ClientPermissions.ManageSettings));
|
|
}
|
|
else
|
|
{
|
|
return !otherClients.Any(static c => c.HasPermission(Networking.ClientPermissions.ManageSettings));
|
|
}
|
|
}
|
|
|
|
public void ClientAdminWritePerks()
|
|
{
|
|
IWriteMessage outMsg = new WriteOnlyMessage();
|
|
|
|
outMsg.WriteByte((byte)ClientPacketHeader.SERVER_SETTINGS_PERKS);
|
|
WritePerks(outMsg);
|
|
GameMain.Client?.ClientPeer?.Send(outMsg, DeliveryMethod.Reliable);
|
|
}
|
|
|
|
public void ClientAdminWrite(
|
|
NetFlags dataToSend,
|
|
Identifier addedMissionType = default,
|
|
Identifier removedMissionType = default,
|
|
int traitorDangerLevel = 0)
|
|
{
|
|
if (!GameMain.Client.HasPermission(Networking.ClientPermissions.ManageSettings)) { return; }
|
|
|
|
IWriteMessage outMsg = new WriteOnlyMessage();
|
|
|
|
outMsg.WriteByte((byte)ClientPacketHeader.SERVER_SETTINGS);
|
|
|
|
outMsg.WriteByte((byte)dataToSend);
|
|
|
|
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.WriteUInt32(count);
|
|
foreach (KeyValuePair<UInt32, NetPropertyData> prop in changedProperties)
|
|
{
|
|
DebugConsole.NewMessage($"Changed {prop.Value.Name.Value} to {prop.Value.GUIComponentValue}", Color.Lime);
|
|
outMsg.WriteUInt32(prop.Key);
|
|
prop.Value.Write(outMsg, prop.Value.GUIComponentValue);
|
|
}
|
|
|
|
outMsg.WriteBoolean(changedMonsterSettings); outMsg.WritePadBits();
|
|
if (changedMonsterSettings) WriteMonsterEnabled(outMsg, tempMonsterEnabled);
|
|
BanList.ClientAdminWrite(outMsg);
|
|
}
|
|
|
|
if (dataToSend.HasFlag(NetFlags.HiddenSubs))
|
|
{
|
|
WriteHiddenSubs(outMsg);
|
|
}
|
|
|
|
if (dataToSend.HasFlag(NetFlags.Misc))
|
|
{
|
|
outMsg.WriteIdentifier(addedMissionType);
|
|
outMsg.WriteIdentifier(removedMissionType);
|
|
outMsg.WriteByte((byte)(traitorDangerLevel + 1));
|
|
outMsg.WritePadBits();
|
|
}
|
|
|
|
if (dataToSend.HasFlag(NetFlags.LevelSeed))
|
|
{
|
|
outMsg.WriteString(GameMain.NetLobbyScreen.LevelSeedBox.Text);
|
|
}
|
|
|
|
GameMain.Client.ClientPeer.Send(outMsg, DeliveryMethod.Reliable);
|
|
}
|
|
|
|
private NetPropertyData GetPropertyData(string name)
|
|
{
|
|
var matchingProperty = netProperties.FirstOrDefault(p => p.Value.Name == name);
|
|
if (matchingProperty.Equals(default(KeyValuePair<UInt32, NetPropertyData>)))
|
|
{
|
|
throw new ArgumentException($"Could not find a {nameof(ServerSettings)} property with the name \"{name}\".");
|
|
}
|
|
else
|
|
{
|
|
return matchingProperty.Value;
|
|
}
|
|
}
|
|
}
|
|
}
|