Files
LuaCsForBarotraumaEP/Barotrauma/BarotraumaServer/ServerSource/Characters/Character.cs
T
Eero 7b8275100d Improve thread safety and performance in core systems
Refactors event, entity, and physics management to use thread-safe and lock-free data structures (Immutable collections, ConcurrentQueue, ConcurrentDictionary, Channel) for improved concurrency and performance. Replaces O(n) queue lookups with O(1) set/dictionary checks, ensures atomic updates for shared state, and optimizes queue draining and deferred action processing. Updates related code to use new APIs and patterns, and adds documentation for thread safety and workflow.
2025-12-29 16:47:10 +08:00

105 lines
4.2 KiB
C#

using Barotrauma.Networking;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.Items.Components;
namespace Barotrauma
{
partial class Character
{
public static Character Controlled => null;
partial void OnAttackedProjSpecific(Character attacker, AttackResult attackResult, float stun)
{
GameMain.Server.KarmaManager.OnCharacterHealthChanged(this, attacker, attackResult.Damage, stun, attackResult.Afflictions);
}
partial void KillProjSpecific(CauseOfDeathType causeOfDeath, Affliction causeOfDeathAffliction, bool log)
{
if (log)
{
if (causeOfDeath == CauseOfDeathType.Affliction)
{
GameServer.Log(GameServer.CharacterLogName(this) + " has died (Cause of death: " + causeOfDeathAffliction.Prefab.Name.Value + ")", ServerLog.MessageType.Attack);
}
else
{
GameServer.Log(GameServer.CharacterLogName(this) + " has died (Cause of death: " + causeOfDeath + ")", ServerLog.MessageType.Attack);
}
}
if (GameMain.Server is { ServerSettings.RespawnMode: RespawnMode.Permadeath } &&
GameMain.GameSession?.Campaign is MultiPlayerCampaign mpCampaign &&
causeOfDeath != CauseOfDeathType.Disconnected)
{
Client ownerClient = GameMain.Server.ConnectedClients.FirstOrDefault(c => c.Character == this);
if (ownerClient != null)
{
ownerClient.SpectateOnly = true;
CharacterCampaignData matchingData = mpCampaign.GetClientCharacterData(ownerClient);
if (matchingData != null)
{
matchingData.ApplyPermadeath();
if (GameMain.Server?.ServerSettings is { IronmanModeActive: true })
{
mpCampaign.SaveSingleCharacter(matchingData);
}
}
}
}
if (HasAbilityFlag(AbilityFlags.RetainExperienceForNewCharacter))
{
var ownerClient = GameMain.Server.ConnectedClients.Find(c => c.Character == this);
if (ownerClient != null)
{
(GameMain.GameSession?.GameMode as MultiPlayerCampaign)?.SaveExperiencePoints(ownerClient);
}
}
healthUpdateTimer = 0.0f;
if (CauseOfDeath.Killer != null && CauseOfDeath.Killer.IsTraitor && CauseOfDeath.Killer != this)
{
var owner = GameMain.Server.ConnectedClients.Find(c => c.Character == this);
if (owner != null)
{
if (!GameMain.LuaCs.Game.overrideTraitors)
{
GameMain.Server.SendDirectChatMessage(TextManager.FormatServerMessage("KilledByTraitorNotification"), owner, ChatMessageType.ServerMessageBoxInGame);
}
}
}
foreach (Client client in GameMain.Server.ConnectedClients)
{
if (client.InGame)
{
client.TryEnqueuePositionUpdate(this);
}
}
}
partial void OnMoneyChanged(int prevAmount, int newAmount)
{
GameMain.NetworkMember.CreateEntityEvent(this, new UpdateMoneyEventData());
}
partial void OnTalentGiven(TalentPrefab talentPrefab)
{
GameServer.Log($"{GameServer.CharacterLogName(this)} has gained the talent '{talentPrefab.DisplayName}'", ServerLog.MessageType.Talent);
}
private void SyncInGameEditables(Item item)
{
foreach (ItemComponent itemComponent in item.Components)
{
foreach (var serializableProperty in SerializableProperty.GetProperties<InGameEditable>(itemComponent))
{
GameMain.Server.CreateEntityEvent(item, new Item.ChangePropertyEventData(serializableProperty, itemComponent));
}
}
}
}
}