Unstable v0.19.5.0
This commit is contained in:
@@ -205,15 +205,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
votes[(int)voteType] = value;
|
||||
}
|
||||
|
||||
public void ResetVotes()
|
||||
{
|
||||
for (int i = 0; i < votes.Length; i++)
|
||||
{
|
||||
votes[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool SessionOrAccountIdMatches(string userId)
|
||||
=> (AccountId.IsSome() && Networking.AccountId.Parse(userId) == AccountId)
|
||||
|| (byte.TryParse(userId, out byte sessionId) && SessionId == sessionId);
|
||||
|
||||
@@ -131,28 +131,29 @@ namespace Barotrauma.Networking
|
||||
|
||||
enum DisconnectReason
|
||||
{
|
||||
//do not attempt reconnecting with these reasons
|
||||
Unknown,
|
||||
Disconnected,
|
||||
Banned,
|
||||
Kicked,
|
||||
ServerShutdown,
|
||||
ServerCrashed,
|
||||
ServerFull,
|
||||
AuthenticationRequired,
|
||||
SteamAuthenticationRequired,
|
||||
SteamAuthenticationFailed,
|
||||
SessionTaken,
|
||||
TooManyFailedLogins,
|
||||
NoName,
|
||||
InvalidName,
|
||||
NameTaken,
|
||||
InvalidVersion,
|
||||
MissingContentPackage,
|
||||
IncompatibleContentPackage,
|
||||
SteamP2PError,
|
||||
|
||||
//attempt reconnecting with these reasons
|
||||
Timeout,
|
||||
ExcessiveDesyncOldEvent,
|
||||
ExcessiveDesyncRemovedEvent,
|
||||
SyncTimeout,
|
||||
SteamP2PError,
|
||||
SteamP2PTimeOut,
|
||||
SteamP2PTimeOut
|
||||
}
|
||||
|
||||
abstract partial class NetworkMember
|
||||
@@ -163,71 +164,38 @@ namespace Barotrauma.Networking
|
||||
set;
|
||||
}
|
||||
|
||||
public virtual bool IsServer
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
public abstract bool IsServer { get; }
|
||||
|
||||
public virtual bool IsClient
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
public abstract bool IsClient { get; }
|
||||
|
||||
public abstract void CreateEntityEvent(INetSerializable entity, NetEntityEvent.IData extraData = null);
|
||||
|
||||
#if DEBUG
|
||||
public Dictionary<string, long> messageCount = new Dictionary<string, long>();
|
||||
#endif
|
||||
|
||||
protected ServerSettings serverSettings;
|
||||
public abstract Voting Voting { get; }
|
||||
|
||||
public Voting Voting { get; protected set; }
|
||||
|
||||
protected TimeSpan updateInterval;
|
||||
protected DateTime updateTimer;
|
||||
|
||||
protected bool gameStarted;
|
||||
|
||||
protected RespawnManager respawnManager;
|
||||
|
||||
public bool ShowNetStats;
|
||||
|
||||
public float SimulatedRandomLatency, SimulatedMinimumLatency;
|
||||
public float SimulatedLoss;
|
||||
public float SimulatedDuplicatesChance;
|
||||
|
||||
public int TickRate
|
||||
{
|
||||
get { return serverSettings.TickRate; }
|
||||
set
|
||||
{
|
||||
serverSettings.TickRate = MathHelper.Clamp(value, 1, 60);
|
||||
updateInterval = new TimeSpan(0, 0, 0, 0, MathHelper.Clamp(1000 / serverSettings.TickRate, 1, 500));
|
||||
}
|
||||
}
|
||||
|
||||
public KarmaManager KarmaManager
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = new KarmaManager();
|
||||
|
||||
public bool GameStarted
|
||||
{
|
||||
get { return gameStarted; }
|
||||
}
|
||||
public bool GameStarted { get; protected set; }
|
||||
|
||||
public abstract IReadOnlyList<Client> ConnectedClients { get; }
|
||||
|
||||
public RespawnManager RespawnManager
|
||||
{
|
||||
get { return respawnManager; }
|
||||
}
|
||||
public RespawnManager RespawnManager { get; protected set; }
|
||||
|
||||
public ServerSettings ServerSettings { get; protected set; }
|
||||
|
||||
public TimeSpan UpdateInterval => new TimeSpan(0, 0, 0, 0, MathHelper.Clamp(1000 / ServerSettings.TickRate, 1, 500));
|
||||
|
||||
public ServerSettings ServerSettings
|
||||
{
|
||||
get { return serverSettings; }
|
||||
}
|
||||
|
||||
public bool CanUseRadio(Character sender)
|
||||
{
|
||||
@@ -277,24 +245,6 @@ namespace Barotrauma.Networking
|
||||
|
||||
public abstract void UnbanPlayer(Endpoint endpoint);
|
||||
|
||||
public virtual void Update(float deltaTime) { }
|
||||
|
||||
public virtual void Quit() { }
|
||||
|
||||
/// <summary>
|
||||
/// Check if the two version are compatible (= if they can play together in multiplayer).
|
||||
/// Returns null if compatibility could not be determined (invalid/unknown version number).
|
||||
/// </summary>
|
||||
public static bool? IsCompatible(string myVersion, string remoteVersion)
|
||||
{
|
||||
if (string.IsNullOrEmpty(myVersion) || string.IsNullOrEmpty(remoteVersion)) { return null; }
|
||||
|
||||
if (!Version.TryParse(myVersion, out Version myVersionNumber)) { return null; }
|
||||
if (!Version.TryParse(remoteVersion, out Version remoteVersionNumber)) { return null; }
|
||||
|
||||
return IsCompatible(myVersionNumber, remoteVersionNumber);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the two version are compatible (= if they can play together in multiplayer).
|
||||
/// </summary>
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ namespace Barotrauma.Networking
|
||||
public abstract string StringRepresentation { get; }
|
||||
|
||||
public static Option<AccountId> Parse(string str)
|
||||
=> ReflectionUtils.ParseDerived<AccountId>(str);
|
||||
=> ReflectionUtils.ParseDerived<AccountId, string>(str);
|
||||
|
||||
public abstract override bool Equals(object? obj);
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Barotrauma.Networking
|
||||
public abstract string StringRepresentation { get; }
|
||||
|
||||
public static Option<Address> Parse(string str)
|
||||
=> ReflectionUtils.ParseDerived<Address>(str);
|
||||
=> ReflectionUtils.ParseDerived<Address, string>(str);
|
||||
|
||||
public abstract bool IsLocalHost { get; }
|
||||
|
||||
|
||||
+14
-18
@@ -17,31 +17,27 @@ namespace Barotrauma.Networking
|
||||
|
||||
public LidgrenAddress(IPAddress netAddress)
|
||||
{
|
||||
NetAddress = netAddress;
|
||||
if (IPAddress.IsLoopback(netAddress))
|
||||
{
|
||||
NetAddress = IPAddress.Loopback;
|
||||
}
|
||||
else
|
||||
{
|
||||
NetAddress = netAddress;
|
||||
}
|
||||
}
|
||||
|
||||
public new static Option<LidgrenAddress> Parse(string endpointStr)
|
||||
{
|
||||
if (IPAddress.TryParse(endpointStr, out IPAddress? netEndpoint))
|
||||
if (endpointStr.Equals("localhost", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return Option<LidgrenAddress>.Some(new LidgrenAddress(IPAddress.Loopback));
|
||||
}
|
||||
else if (IPAddress.TryParse(endpointStr, out IPAddress? netEndpoint))
|
||||
{
|
||||
return Option<LidgrenAddress>.Some(new LidgrenAddress(netEndpoint!));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var resolvedAddresses = Dns.GetHostAddresses(endpointStr);
|
||||
return resolvedAddresses.Any()
|
||||
? Option<LidgrenAddress>.Some(new LidgrenAddress(resolvedAddresses.First()))
|
||||
: Option<LidgrenAddress>.None();
|
||||
}
|
||||
catch (SocketException)
|
||||
{
|
||||
return Option<LidgrenAddress>.None();
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
{
|
||||
return Option<LidgrenAddress>.None();
|
||||
}
|
||||
return Option<LidgrenAddress>.None();
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
|
||||
+13
-4
@@ -22,12 +22,21 @@ namespace Barotrauma.Networking
|
||||
public override string ToString() => StringRepresentation;
|
||||
|
||||
public static Option<Endpoint> Parse(string str)
|
||||
=> ReflectionUtils.ParseDerived<Endpoint>(str);
|
||||
=> ReflectionUtils.ParseDerived<Endpoint, string>(str);
|
||||
|
||||
public static bool operator ==(Endpoint a, Endpoint b)
|
||||
=> a.Equals(b);
|
||||
public static bool operator ==(Endpoint? a, Endpoint? b)
|
||||
{
|
||||
if (a is null)
|
||||
{
|
||||
return b is null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return a.Equals(b);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator !=(Endpoint a, Endpoint b)
|
||||
public static bool operator !=(Endpoint? a, Endpoint? b)
|
||||
=> !(a == b);
|
||||
}
|
||||
}
|
||||
|
||||
+13
-14
@@ -24,24 +24,23 @@ namespace Barotrauma.Networking
|
||||
|
||||
public new static Option<LidgrenEndpoint> Parse(string endpointStr)
|
||||
{
|
||||
if (IPEndPoint.TryParse(endpointStr, out IPEndPoint? netEndpoint))
|
||||
{
|
||||
return Option<LidgrenEndpoint>.Some(new LidgrenEndpoint(netEndpoint!));
|
||||
}
|
||||
|
||||
string hostName = endpointStr;
|
||||
int port = NetConfig.DefaultPort;
|
||||
if (endpointStr.Count(c => c == ':') == 1)
|
||||
{
|
||||
string[] split = endpointStr.Split(':');
|
||||
string hostName = split[0];
|
||||
if (LidgrenAddress.Parse(hostName).TryUnwrap(out var adr)
|
||||
&& int.TryParse(split[1], out var port))
|
||||
{
|
||||
return Option<LidgrenEndpoint>.Some(new LidgrenEndpoint(adr.NetAddress, port));
|
||||
}
|
||||
hostName = split[0];
|
||||
port = int.TryParse(split[1], out var tmpPort) ? tmpPort : port;
|
||||
}
|
||||
|
||||
return LidgrenAddress.Parse(endpointStr)
|
||||
.Select(adr => new LidgrenEndpoint(adr.NetAddress, NetConfig.DefaultPort));
|
||||
|
||||
if (LidgrenAddress.Parse(hostName).TryUnwrap(out var adr))
|
||||
{
|
||||
return Option<LidgrenEndpoint>.Some(new LidgrenEndpoint(adr.NetAddress, port));
|
||||
}
|
||||
|
||||
return IPEndPoint.TryParse(endpointStr, out IPEndPoint? netEndpoint)
|
||||
? Option<LidgrenEndpoint>.Some(new LidgrenEndpoint(netEndpoint))
|
||||
: Option<LidgrenEndpoint>.None();
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
|
||||
+168
-7
@@ -1,8 +1,8 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
@@ -68,7 +68,7 @@ namespace Barotrauma.Networking
|
||||
public byte[] Buffer;
|
||||
public readonly int Length => Buffer.Length;
|
||||
|
||||
public readonly IReadMessage GetReadMessage() => new ReadWriteMessage(Buffer, 0, Length, copyBuf: false);
|
||||
public readonly IReadMessage GetReadMessageUncompressed() => new ReadWriteMessage(Buffer, 0, Length, copyBuf: false);
|
||||
public readonly IReadMessage GetReadMessage(bool isCompressed, NetworkConnection conn) => new ReadOnlyMessage(Buffer, isCompressed, 0, Length, conn);
|
||||
}
|
||||
|
||||
@@ -86,9 +86,164 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
[NetworkSerialize]
|
||||
internal struct PeerDisconnectPacket : INetSerializableStruct
|
||||
internal readonly struct PeerDisconnectPacket : INetSerializableStruct
|
||||
{
|
||||
public string Message;
|
||||
public readonly DisconnectReason DisconnectReason;
|
||||
|
||||
public readonly string AdditionalInformation;
|
||||
|
||||
private PeerDisconnectPacket(
|
||||
DisconnectReason disconnectReason,
|
||||
string additionalInformation = "")
|
||||
{
|
||||
DisconnectReason = disconnectReason;
|
||||
AdditionalInformation = additionalInformation;
|
||||
}
|
||||
|
||||
public LocalizedString ChatMessage(Client c)
|
||||
=> DisconnectReason switch
|
||||
{
|
||||
DisconnectReason.Disconnected => TextManager.GetWithVariable("ServerMessage.ClientLeftServer",
|
||||
"[client]", c.Name),
|
||||
_ => TextManager.GetWithVariables("ChatMsg.DisconnectedWithReason",
|
||||
("[client]", c.Name),
|
||||
("[reason]", TextManager.Get($"ChatMsg.DisconnectReason.{DisconnectReason}")))
|
||||
};
|
||||
|
||||
private LocalizedString msgWithReason
|
||||
=> TextManager.Get($"DisconnectReason.{DisconnectReason}")
|
||||
+ "\n\n"
|
||||
+ TextManager.Get("banreason") + " " + AdditionalInformation;
|
||||
|
||||
private LocalizedString serverMessage
|
||||
=> TextManager.Get($"ServerMessage.{DisconnectReason}");
|
||||
|
||||
public LocalizedString PopupMessage
|
||||
=> DisconnectReason switch
|
||||
{
|
||||
DisconnectReason.Banned => msgWithReason,
|
||||
DisconnectReason.Kicked => msgWithReason,
|
||||
DisconnectReason.InvalidVersion => TextManager.GetWithVariables("DisconnectMessage.InvalidVersion",
|
||||
("[version]", AdditionalInformation),
|
||||
("[clientversion]", GameMain.Version.ToString())),
|
||||
DisconnectReason.ExcessiveDesyncOldEvent => serverMessage,
|
||||
DisconnectReason.ExcessiveDesyncRemovedEvent => serverMessage,
|
||||
DisconnectReason.SyncTimeout => serverMessage,
|
||||
_ => TextManager.Get($"DisconnectReason.{DisconnectReason}").Fallback(TextManager.Get("ConnectionLost"))
|
||||
};
|
||||
|
||||
public LocalizedString ReconnectMessage
|
||||
=> PopupMessage + "\n\n" + TextManager.Get("ConnectionLostReconnecting");
|
||||
|
||||
public PlayerConnectionChangeType ConnectionChangeType
|
||||
=> DisconnectReason switch
|
||||
{
|
||||
DisconnectReason.Banned => PlayerConnectionChangeType.Banned,
|
||||
DisconnectReason.Kicked => PlayerConnectionChangeType.Kicked,
|
||||
_ => PlayerConnectionChangeType.Disconnected
|
||||
};
|
||||
|
||||
public bool ShouldAttemptReconnect
|
||||
=> DisconnectReason
|
||||
is DisconnectReason.ExcessiveDesyncOldEvent
|
||||
or DisconnectReason.ExcessiveDesyncRemovedEvent
|
||||
or DisconnectReason.Timeout
|
||||
or DisconnectReason.SyncTimeout
|
||||
or DisconnectReason.SteamP2PTimeOut;
|
||||
|
||||
public bool IsEventSyncError
|
||||
=> DisconnectReason
|
||||
is DisconnectReason.ExcessiveDesyncOldEvent
|
||||
or DisconnectReason.ExcessiveDesyncRemovedEvent
|
||||
or DisconnectReason.SyncTimeout;
|
||||
|
||||
public bool ShouldCreateAnalyticsEvent
|
||||
=> DisconnectReason is not (
|
||||
DisconnectReason.Disconnected
|
||||
or DisconnectReason.Banned
|
||||
or DisconnectReason.Kicked
|
||||
or DisconnectReason.TooManyFailedLogins
|
||||
or DisconnectReason.InvalidVersion);
|
||||
|
||||
public bool ShouldShowMessage
|
||||
=> DisconnectReason is not DisconnectReason.Disconnected;
|
||||
|
||||
private const string lidgrenSeparator = ":hankey:";
|
||||
|
||||
/// <summary>
|
||||
/// This exists because Lidgren is a piece of shit and
|
||||
/// doesn't readily support sending anything other than
|
||||
/// a string through a disconnect packet, so this thing
|
||||
/// needs a sufficiently nasty string representation that
|
||||
/// can be decoded with some certainty that it won't get
|
||||
/// mangled by user input.
|
||||
/// </summary>
|
||||
public string ToLidgrenStringRepresentation()
|
||||
{
|
||||
static string strToBase64(string str)
|
||||
=> Convert.ToBase64String(Encoding.UTF8.GetBytes(str));
|
||||
|
||||
return DisconnectReason
|
||||
+ lidgrenSeparator
|
||||
+ strToBase64(AdditionalInformation);
|
||||
}
|
||||
|
||||
public static Option<PeerDisconnectPacket> FromLidgrenStringRepresentation(string str)
|
||||
{
|
||||
// Lidgren has some hardcoded disconnect strings that it uses
|
||||
// when it detects that a connection has failed. We can handle
|
||||
// timeouts, so let's look for strings related to that and return
|
||||
// an appropriate PeerDisconnectPacket.
|
||||
switch (str)
|
||||
{
|
||||
case Lidgren.Network.NetConnection.NoResponseMessage:
|
||||
case "Connection timed out":
|
||||
case "Reconnecting":
|
||||
return Option<PeerDisconnectPacket>.Some(WithReason(DisconnectReason.Timeout));
|
||||
}
|
||||
|
||||
static string base64ToStr(string base64)
|
||||
=> Encoding.UTF8.GetString(Convert.FromBase64String(base64));
|
||||
|
||||
string[] split = str.Split(lidgrenSeparator);
|
||||
if (split.Length != 2) { return Option<PeerDisconnectPacket>.None(); }
|
||||
if (!Enum.TryParse(split[0], out DisconnectReason disconnectReason)) { return Option<PeerDisconnectPacket>.None(); }
|
||||
return Option<PeerDisconnectPacket>.Some(new PeerDisconnectPacket(disconnectReason, base64ToStr(split[1])));
|
||||
}
|
||||
|
||||
public static PeerDisconnectPacket Custom(string customMessage)
|
||||
=> new PeerDisconnectPacket(
|
||||
DisconnectReason.Unknown,
|
||||
customMessage);
|
||||
|
||||
public static PeerDisconnectPacket WithReason(DisconnectReason disconnectReason)
|
||||
=> new PeerDisconnectPacket(disconnectReason);
|
||||
|
||||
public static PeerDisconnectPacket Kicked(string? msg)
|
||||
=> new PeerDisconnectPacket(DisconnectReason.Kicked, msg ?? "");
|
||||
|
||||
public static PeerDisconnectPacket Banned(string? msg)
|
||||
=> new PeerDisconnectPacket(DisconnectReason.Banned, msg ?? "");
|
||||
|
||||
public static PeerDisconnectPacket InvalidVersion()
|
||||
=> new PeerDisconnectPacket(
|
||||
DisconnectReason.InvalidVersion,
|
||||
GameMain.Version.ToString());
|
||||
|
||||
public static PeerDisconnectPacket SteamP2PError(Steamworks.P2PSessionError error)
|
||||
=> new PeerDisconnectPacket(
|
||||
DisconnectReason.SteamP2PError,
|
||||
error.ToString());
|
||||
|
||||
public static PeerDisconnectPacket SteamAuthError(Steamworks.BeginAuthResult error)
|
||||
=> new PeerDisconnectPacket(
|
||||
DisconnectReason.SteamAuthenticationFailed,
|
||||
$"{nameof(Steamworks.BeginAuthResult)}.{error}");
|
||||
|
||||
public static PeerDisconnectPacket SteamAuthError(Steamworks.AuthResponse error)
|
||||
=> new PeerDisconnectPacket(
|
||||
DisconnectReason.SteamAuthenticationFailed,
|
||||
$"{nameof(Steamworks.AuthResponse)}.{error}");
|
||||
}
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global, FieldCanBeMadeReadOnly.Global, UnassignedField.Global
|
||||
@@ -101,11 +256,14 @@ namespace Barotrauma.Networking
|
||||
public byte[] HashBytes = Array.Empty<byte>();
|
||||
|
||||
[NetworkSerialize]
|
||||
public ulong WorkshopId;
|
||||
public string UgcId = "";
|
||||
|
||||
[NetworkSerialize]
|
||||
public uint InstallTimeDiffInSeconds;
|
||||
|
||||
[NetworkSerialize]
|
||||
public bool IsMandatory;
|
||||
|
||||
private Md5Hash? cachedHash;
|
||||
private DateTime? cachedDateTime;
|
||||
|
||||
@@ -130,9 +288,12 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
Name = contentPackage.Name;
|
||||
Hash = contentPackage.Hash;
|
||||
WorkshopId = contentPackage.SteamWorkshopId;
|
||||
UgcId = contentPackage.UgcId.TryUnwrap(out var ugcId)
|
||||
? ugcId.StringRepresentation
|
||||
: "";
|
||||
IsMandatory = !contentPackage.Files.All(f => f is SubmarineFile);
|
||||
InstallTimeDiffInSeconds =
|
||||
contentPackage.InstallTime is { } installTime
|
||||
contentPackage.InstallTime.TryUnwrap(out var installTime)
|
||||
? (uint)(installTime - referenceTime).TotalSeconds
|
||||
: 0;
|
||||
}
|
||||
|
||||
@@ -333,10 +333,14 @@ namespace Barotrauma.Networking
|
||||
RespawnCharactersProjSpecific(shuttlePos);
|
||||
}
|
||||
|
||||
public static AfflictionPrefab GetRespawnPenaltyAfflictionPrefab()
|
||||
{
|
||||
return AfflictionPrefab.Prefabs.First(a => a.AfflictionType == "respawnpenalty");
|
||||
}
|
||||
|
||||
public static Affliction GetRespawnPenaltyAffliction()
|
||||
{
|
||||
var respawnPenaltyAffliction = AfflictionPrefab.Prefabs.First(a => a.AfflictionType == "respawnpenalty");
|
||||
return respawnPenaltyAffliction?.Instantiate(10.0f);
|
||||
return GetRespawnPenaltyAfflictionPrefab()?.Instantiate(10.0f);
|
||||
}
|
||||
|
||||
public static void GiveRespawnPenaltyAffliction(Character character)
|
||||
|
||||
@@ -388,11 +388,12 @@ namespace Barotrauma.Networking
|
||||
|
||||
public List<SavedClientPermission> ClientPermissions { get; private set; } = new List<SavedClientPermission>();
|
||||
|
||||
private int tickRate = 20;
|
||||
[Serialize(20, IsPropertySaveable.Yes)]
|
||||
public int TickRate
|
||||
{
|
||||
get;
|
||||
set;
|
||||
get { return tickRate; }
|
||||
set { tickRate = MathHelper.Clamp(value, 1, 60); }
|
||||
}
|
||||
|
||||
[Serialize(true, IsPropertySaveable.Yes)]
|
||||
|
||||
@@ -56,23 +56,5 @@ namespace Barotrauma
|
||||
|
||||
return selected;
|
||||
}
|
||||
|
||||
public void ResetVotes(IEnumerable<Client> connectedClients)
|
||||
{
|
||||
foreach (Client client in connectedClients)
|
||||
{
|
||||
client.ResetVotes();
|
||||
}
|
||||
#if CLIENT
|
||||
foreach (VoteType voteType in Enum.GetValues(typeof(VoteType)))
|
||||
{
|
||||
SetVoteCountYes(voteType, 0);
|
||||
SetVoteCountNo(voteType, 0);
|
||||
SetVoteCountMax(voteType, 0);
|
||||
}
|
||||
UpdateVoteTexts(connectedClients, VoteType.Mode);
|
||||
UpdateVoteTexts(connectedClients, VoteType.Sub);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user