Build 0.21.6.0
This commit is contained in:
@@ -14,6 +14,13 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public bool Discarded;
|
||||
|
||||
public void ApplyDeathEffects()
|
||||
{
|
||||
RespawnManager.ReduceCharacterSkills(this);
|
||||
RemoveSavedStatValuesOnDeath();
|
||||
CauseOfDeath = null;
|
||||
}
|
||||
|
||||
partial void OnSkillChanged(Identifier skillIdentifier, float prevLevel, float newLevel)
|
||||
{
|
||||
if (Character == null || Character.Removed) { return; }
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
internal static class HealingCooldown
|
||||
{
|
||||
private static readonly Dictionary<Client, DateTimeOffset> HealingCooldowns = new();
|
||||
|
||||
// Little bit less than client's 0.5 second cooldown to account for latency
|
||||
private const float CooldownDuration = 0.4f;
|
||||
|
||||
public static bool IsOnCooldown(Client client)
|
||||
{
|
||||
RemoveExpiredCooldowns();
|
||||
return HealingCooldowns.ContainsKey(client);
|
||||
}
|
||||
|
||||
public static void SetCooldown(Client client)
|
||||
{
|
||||
RemoveExpiredCooldowns();
|
||||
DateTimeOffset newCooldown = DateTimeOffset.UtcNow.AddSeconds(CooldownDuration);
|
||||
HealingCooldowns[client] = newCooldown;
|
||||
}
|
||||
|
||||
private static void RemoveExpiredCooldowns()
|
||||
{
|
||||
HashSet<Client>? expiredCooldowns = null;
|
||||
|
||||
DateTimeOffset now = DateTimeOffset.UtcNow;
|
||||
|
||||
foreach (var (client, cooldown) in HealingCooldowns)
|
||||
{
|
||||
if (now < cooldown) { continue; }
|
||||
|
||||
expiredCooldowns ??= new HashSet<Client>();
|
||||
expiredCooldowns.Add(client);
|
||||
}
|
||||
|
||||
if (expiredCooldowns is null) { return; }
|
||||
|
||||
foreach (Client expiredCooldown in expiredCooldowns)
|
||||
{
|
||||
HealingCooldowns.Remove(expiredCooldown);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-2
@@ -109,15 +109,22 @@ namespace Barotrauma
|
||||
return AccountId == other.AccountId && other.ClientAddress == ClientAddress;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
itemData = null;
|
||||
healthData = null;
|
||||
WalletData = null;
|
||||
}
|
||||
|
||||
public void SpawnInventoryItems(Character character, Inventory inventory)
|
||||
{
|
||||
if (character == null)
|
||||
{
|
||||
throw new System.InvalidOperationException($"Failed to spawn inventory items. Character was null.");
|
||||
throw new InvalidOperationException($"Failed to spawn inventory items. Character was null.");
|
||||
}
|
||||
if (itemData == null)
|
||||
{
|
||||
throw new System.InvalidOperationException($"Failed to spawn inventory items for the character \"{character.Name}\". No saved inventory data.");
|
||||
throw new InvalidOperationException($"Failed to spawn inventory items for the character \"{character.Name}\". No saved inventory data.");
|
||||
}
|
||||
character.SpawnInventoryItems(inventory, itemData.FromPackage(null));
|
||||
}
|
||||
|
||||
+11
-5
@@ -240,9 +240,7 @@ namespace Barotrauma
|
||||
//reduce skills if the character has died
|
||||
if (characterInfo.CauseOfDeath != null && characterInfo.CauseOfDeath.Type != CauseOfDeathType.Disconnected)
|
||||
{
|
||||
RespawnManager.ReduceCharacterSkills(characterInfo);
|
||||
characterInfo.RemoveSavedStatValuesOnDeath();
|
||||
characterInfo.CauseOfDeath = null;
|
||||
characterInfo.ApplyDeathEffects();
|
||||
}
|
||||
c.CharacterInfo = characterInfo;
|
||||
SetClientCharacterData(c);
|
||||
@@ -254,13 +252,21 @@ namespace Barotrauma
|
||||
{
|
||||
if (data.HasSpawned && !GameMain.Server.ConnectedClients.Any(c => data.MatchesClient(c)))
|
||||
{
|
||||
var character = Character.CharacterList.Find(c => c.Info == data.CharacterInfo && !c.IsHusk);
|
||||
if (character != null && (!character.IsDead || character.CauseOfDeath?.Type == CauseOfDeathType.Disconnected))
|
||||
var character = Character.CharacterList.Find(c => c.Info == data.CharacterInfo && !c.IsHusk);
|
||||
if (character != null &&
|
||||
(!character.IsDead || character.CauseOfDeath?.Type == CauseOfDeathType.Disconnected))
|
||||
{
|
||||
//character still alive (or killed by Disconnect) -> save it as-is
|
||||
characterData.RemoveAll(cd => cd.IsDuplicate(data));
|
||||
data.Refresh(character);
|
||||
characterData.Add(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
//character dead or removed -> reduce skills, remove items, health data, etc
|
||||
data.CharacterInfo.ApplyDeathEffects();
|
||||
data.Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
@@ -19,7 +20,7 @@ namespace Barotrauma
|
||||
bool accessible = c.Character.CanAccessInventory(this);
|
||||
if (this is CharacterInventory characterInventory && accessible)
|
||||
{
|
||||
if (Owner == null || !(Owner is Character ownerCharacter))
|
||||
if (Owner == null || Owner is not Character ownerCharacter)
|
||||
{
|
||||
accessible = false;
|
||||
}
|
||||
@@ -39,7 +40,7 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (ushort id in newItemIDs[i])
|
||||
{
|
||||
if (!(Entity.FindEntityByID(id) is Item item)) { continue; }
|
||||
if (Entity.FindEntityByID(id) is not Item item) { continue; }
|
||||
item.PositionUpdateInterval = 0.0f;
|
||||
if (item.ParentInventory != null && item.ParentInventory != this)
|
||||
{
|
||||
@@ -94,7 +95,15 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (ushort id in newItemIDs[i])
|
||||
{
|
||||
if (!(Entity.FindEntityByID(id) is Item item) || slots[i].Contains(item)) { continue; }
|
||||
if (Entity.FindEntityByID(id) is not Item item || slots[i].Contains(item)) { continue; }
|
||||
|
||||
if (item.GetComponent<Pickable>() is not Pickable pickable ||
|
||||
(pickable.IsAttached && !pickable.PickingDone) ||
|
||||
item.AllowedSlots.None())
|
||||
{
|
||||
DebugConsole.AddWarning($"Client {c.Name} tried to pick up a non-pickable item \"{item}\" (parent inventory: {item.ParentInventory?.Owner.ToString() ?? "null"})");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (GameMain.Server != null)
|
||||
{
|
||||
@@ -105,7 +114,7 @@ namespace Barotrauma
|
||||
(c.Character == null || item.PreviousParentInventory == null || !c.Character.CanAccessInventory(item.PreviousParentInventory)))
|
||||
{
|
||||
#if DEBUG || UNSTABLE
|
||||
DebugConsole.NewMessage($"Client {c.Name} failed to pick up item \"{item}\" (parent inventory: {(item.ParentInventory?.Owner.ToString() ?? "null")}). No access.", Color.Yellow);
|
||||
DebugConsole.NewMessage($"Client {c.Name} failed to pick up item \"{item}\" (parent inventory: {item.ParentInventory?.Owner.ToString() ?? "null"}). No access.", Color.Yellow);
|
||||
#endif
|
||||
if (item.body != null && !c.PendingPositionUpdates.Contains(item))
|
||||
{
|
||||
|
||||
@@ -153,25 +153,27 @@ namespace Barotrauma
|
||||
(components[containerIndex] as ItemContainer).Inventory.ServerEventRead(msg, c);
|
||||
break;
|
||||
case EventType.Treatment:
|
||||
if (c.Character == null || !c.Character.CanInteractWith(this)) return;
|
||||
if (c.Character == null || !c.Character.CanInteractWith(this)) { return; }
|
||||
|
||||
UInt16 characterID = msg.ReadUInt16();
|
||||
byte limbIndex = msg.ReadByte();
|
||||
|
||||
Character targetCharacter = FindEntityByID(characterID) as Character;
|
||||
if (targetCharacter == null) break;
|
||||
if (targetCharacter != c.Character && c.Character.SelectedCharacter != targetCharacter) break;
|
||||
if (HealingCooldown.IsOnCooldown(c)) { return; }
|
||||
if (FindEntityByID(characterID) is not Character targetCharacter) { break; }
|
||||
if (targetCharacter != c.Character && c.Character.SelectedCharacter != targetCharacter) { break; }
|
||||
|
||||
HealingCooldown.SetCooldown(c);
|
||||
|
||||
Limb targetLimb = limbIndex < targetCharacter.AnimController.Limbs.Length ? targetCharacter.AnimController.Limbs[limbIndex] : null;
|
||||
|
||||
if (ContainedItems == null || ContainedItems.All(i => i == null))
|
||||
if (ContainedItems == null || ContainedItems.All(static i => i == null))
|
||||
{
|
||||
GameServer.Log(GameServer.CharacterLogName(c.Character) + " used item " + Name, ServerLog.MessageType.ItemInteraction);
|
||||
GameServer.Log($"{GameServer.CharacterLogName(c.Character)} used item {Name}", ServerLog.MessageType.ItemInteraction);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameServer.Log(
|
||||
GameServer.CharacterLogName(c.Character) + " used item " + Name + " (contained items: " + string.Join(", ", ContainedItems.Select(i => i.Name)) + ")",
|
||||
$"{GameServer.CharacterLogName(c.Character)} used item {Name} (contained items: {string.Join(", ", ContainedItems.Select(i => i.Name))})",
|
||||
ServerLog.MessageType.ItemInteraction);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,10 +11,10 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
private static UInt32 LastIdentifier = 0;
|
||||
|
||||
public bool Expired => ExpirationTime is { } expirationTime && DateTime.Now > expirationTime;
|
||||
public bool Expired => ExpirationTime.TryUnwrap(out var expirationTime) && SerializableDateTime.LocalNow > expirationTime;
|
||||
|
||||
public BannedPlayer(
|
||||
string name, Either<Address, AccountId> addressOrAccountId, string reason, DateTime? expirationTime)
|
||||
string name, Either<Address, AccountId> addressOrAccountId, string reason, Option<SerializableDateTime> expirationTime)
|
||||
{
|
||||
this.Name = name;
|
||||
this.AddressOrAccountId = addressOrAccountId;
|
||||
@@ -39,6 +39,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
LoadBanList();
|
||||
}
|
||||
RemoveExpired();
|
||||
}
|
||||
|
||||
private void LoadLegacyBanList()
|
||||
@@ -69,7 +70,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (DateTime.TryParse(separatedLine[2], out DateTime parsedTime))
|
||||
{
|
||||
expirationTime = parsedTime;
|
||||
expirationTime = DateTime.SpecifyKind(parsedTime, DateTimeKind.Local);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -80,15 +81,18 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
string reason = separatedLine.Length > 3 ? string.Join(",", separatedLine.Skip(3)) : "";
|
||||
|
||||
if (expirationTime.HasValue && DateTime.Now > expirationTime.Value) { continue; }
|
||||
var serializableExpirationTime
|
||||
= expirationTime.HasValue
|
||||
? Option<SerializableDateTime>.Some(new SerializableDateTime(expirationTime.Value))
|
||||
: Option<SerializableDateTime>.None();
|
||||
|
||||
if (AccountId.Parse(endpointStr).TryUnwrap(out var accountId))
|
||||
{
|
||||
bannedPlayers.Add(new BannedPlayer(name, accountId, reason, expirationTime));
|
||||
bannedPlayers.Add(new BannedPlayer(name, accountId, reason, serializableExpirationTime));
|
||||
}
|
||||
else if (Address.Parse(endpointStr).TryUnwrap(out var address))
|
||||
{
|
||||
bannedPlayers.Add(new BannedPlayer(name, address, reason, expirationTime));
|
||||
bannedPlayers.Add(new BannedPlayer(name, address, reason, serializableExpirationTime));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,10 +113,22 @@ namespace Barotrauma.Networking
|
||||
|
||||
var name = element.GetAttributeString("name", "")!;
|
||||
var reason = element.GetAttributeString("reason", "")!;
|
||||
DateTime? expirationTime = DateTime.FromBinary(unchecked((long)element.GetAttributeUInt64("expirationtime", 0)));
|
||||
|
||||
if (expirationTime < DateTime.Now) { expirationTime = null; }
|
||||
|
||||
var expirationTime = Option<SerializableDateTime>.None();
|
||||
var expirationTimeStr = element.GetAttributeString("expirationtime", "")!;
|
||||
|
||||
if (UInt64.TryParse(expirationTimeStr, out var binaryDateTime) && binaryDateTime > 0)
|
||||
{
|
||||
// Backwards compatibility: if expirationtime is stored as an int,
|
||||
// convert to SerializableDateTime with local timezone because
|
||||
// banlists used to assume local time
|
||||
expirationTime = Option<SerializableDateTime>.Some(
|
||||
new SerializableDateTime(
|
||||
DateTime.FromBinary((long)binaryDateTime),
|
||||
SerializableTimeZone.LocalTimeZone));
|
||||
}
|
||||
|
||||
expirationTime = expirationTime.Fallback(SerializableDateTime.Parse(expirationTimeStr));
|
||||
|
||||
if (accountId.IsNone() && address.IsNone()) { return Option<BannedPlayer>.None(); }
|
||||
|
||||
Either<Address, AccountId> addressOrAccountId = accountId.TryUnwrap(out var accId)
|
||||
@@ -171,14 +187,14 @@ namespace Barotrauma.Networking
|
||||
|
||||
string logMsg = "Banned " + name;
|
||||
if (!string.IsNullOrEmpty(reason)) { logMsg += ", reason: " + reason; }
|
||||
if (duration.HasValue) { logMsg += ", duration: " + duration.Value.ToString(); }
|
||||
if (duration.HasValue) { logMsg += ", duration: " + duration.Value; }
|
||||
|
||||
DebugConsole.Log(logMsg);
|
||||
|
||||
DateTime? expirationTime = null;
|
||||
Option<SerializableDateTime> expirationTime = Option<SerializableDateTime>.None();
|
||||
if (duration.HasValue)
|
||||
{
|
||||
expirationTime = DateTime.Now + duration.Value;
|
||||
expirationTime = Option<SerializableDateTime>.Some(new SerializableDateTime(DateTime.Now + duration.Value));
|
||||
}
|
||||
|
||||
bannedPlayers.Add(new BannedPlayer(name, addressOrAccountId, reason, expirationTime));
|
||||
@@ -232,9 +248,10 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
retVal.SetAttributeValue("address", address.StringRepresentation);
|
||||
}
|
||||
if (bannedPlayer.ExpirationTime is { } expirationTime)
|
||||
if (bannedPlayer.ExpirationTime.TryUnwrap(out var expirationTime))
|
||||
{
|
||||
retVal.SetAttributeValue("expirationtime", unchecked((ulong)expirationTime.ToBinary()));
|
||||
#warning TODO: stop writing binary DateTime representation after this gets on main
|
||||
retVal.SetAttributeValue("expirationtime", expirationTime.ToLocalValue().ToBinary());
|
||||
}
|
||||
|
||||
return retVal;
|
||||
@@ -269,11 +286,11 @@ namespace Barotrauma.Networking
|
||||
|
||||
outMsg.WriteString(bannedPlayer.Name);
|
||||
outMsg.WriteUInt32(bannedPlayer.UniqueIdentifier);
|
||||
outMsg.WriteBoolean(bannedPlayer.ExpirationTime != null);
|
||||
outMsg.WriteBoolean(bannedPlayer.ExpirationTime.IsSome());
|
||||
outMsg.WritePadBits();
|
||||
if (bannedPlayer.ExpirationTime != null)
|
||||
if (bannedPlayer.ExpirationTime.TryUnwrap(out var expirationTime))
|
||||
{
|
||||
double hoursFromNow = (bannedPlayer.ExpirationTime.Value - DateTime.Now).TotalHours;
|
||||
double hoursFromNow = (expirationTime.ToUtcValue() - DateTime.UtcNow).TotalHours;
|
||||
outMsg.WriteDouble(hoursFromNow);
|
||||
}
|
||||
|
||||
|
||||
@@ -140,6 +140,7 @@ namespace Barotrauma.Networking
|
||||
ServerSettings = new ServerSettings(this, name, port, queryPort, maxPlayers, isPublic, attemptUPnP);
|
||||
KarmaManager.SelectPreset(ServerSettings.KarmaPreset);
|
||||
ServerSettings.SetPassword(password);
|
||||
ServerSettings.SaveSettings();
|
||||
|
||||
Voting = new Voting();
|
||||
|
||||
@@ -3227,16 +3228,16 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
//too far to hear the msg -> don't send
|
||||
if (string.IsNullOrWhiteSpace(modifiedMessage)) continue;
|
||||
if (string.IsNullOrWhiteSpace(modifiedMessage)) { continue; }
|
||||
}
|
||||
break;
|
||||
case ChatMessageType.Dead:
|
||||
//character still alive -> don't send
|
||||
if (client != senderClient && client.Character != null && !client.Character.IsDead) continue;
|
||||
if (client != senderClient && client.Character != null && !client.Character.IsDead) { continue; }
|
||||
break;
|
||||
case ChatMessageType.Private:
|
||||
//private msg sent to someone else than this client -> don't send
|
||||
if (client != targetClient && client != senderClient) continue;
|
||||
if (client != targetClient && client != senderClient) { continue; }
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3272,11 +3273,17 @@ namespace Barotrauma.Networking
|
||||
//too far to hear the msg -> don't send
|
||||
if (!client.Character.CanHearCharacter(message.Sender)) { continue; }
|
||||
}
|
||||
SendDirectChatMessage(new OrderChatMessage(message.Order, message.TargetCharacter, message.Sender, isNewOrder: message.IsNewOrder), client);
|
||||
SendDirectChatMessage(new OrderChatMessage(message.Order, message.Text, message.TargetCharacter, message.Sender, isNewOrder: message.IsNewOrder), client);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(message.Text))
|
||||
{
|
||||
AddChatMessage(new OrderChatMessage(message.Order, message.TargetCharacter, message.Sender, isNewOrder: message.IsNewOrder));
|
||||
AddChatMessage(new OrderChatMessage(message.Order, message.Text, message.TargetCharacter, message.Sender, isNewOrder: message.IsNewOrder));
|
||||
if (ChatMessage.CanUseRadio(message.Sender, out var senderRadio))
|
||||
{
|
||||
//send to chat-linked wifi components
|
||||
Signal s = new Signal(message.Text, sender: message.Sender, source: senderRadio.Item);
|
||||
senderRadio.TransmitSignal(s, sentFromChat: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace Barotrauma.Networking
|
||||
segmentTable.StartNewSegment(ServerNetSegment.ChatMessage);
|
||||
msg.WriteUInt16(NetStateID);
|
||||
msg.WriteRangedInteger((int)ChatMessageType.Order, 0, Enum.GetValues(typeof(ChatMessageType)).Length - 1);
|
||||
msg.WriteString(Text);
|
||||
msg.WriteString(SenderName);
|
||||
msg.WriteBoolean(SenderClient != null);
|
||||
if (SenderClient != null)
|
||||
|
||||
+1
-1
@@ -246,7 +246,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
case ConnectionInitialization.ContentPackageOrder:
|
||||
|
||||
DateTime timeNow = DateTime.UtcNow;
|
||||
SerializableDateTime timeNow = SerializableDateTime.UtcNow;
|
||||
structToSend = new ServerPeerContentPackageOrderPacket
|
||||
{
|
||||
ServerName = GameMain.Server.ServerName,
|
||||
|
||||
Reference in New Issue
Block a user