Merge branch 'dev' of https://github.com/Regalis11/Barotrauma.git into unstable-tests
This commit is contained in:
@@ -5,9 +5,7 @@ namespace Barotrauma
|
||||
{
|
||||
partial class Character
|
||||
{
|
||||
public static Character Controlled = null;
|
||||
|
||||
partial void InitProjSpecific(XElement mainElement) { }
|
||||
public static Character Controlled => null;
|
||||
|
||||
partial void OnAttackedProjSpecific(Character attacker, AttackResult attackResult, float stun)
|
||||
{
|
||||
@@ -20,7 +18,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (causeOfDeath == CauseOfDeathType.Affliction)
|
||||
{
|
||||
GameServer.Log(GameServer.CharacterLogName(this) + " has died (Cause of death: " + causeOfDeathAffliction.Prefab.Name + ")", ServerLog.MessageType.Attack);
|
||||
GameServer.Log(GameServer.CharacterLogName(this) + " has died (Cause of death: " + causeOfDeathAffliction.Prefab.Name.Value + ")", ServerLog.MessageType.Attack);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -62,7 +60,7 @@ namespace Barotrauma
|
||||
|
||||
partial void OnMoneyChanged(int prevAmount, int newAmount)
|
||||
{
|
||||
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.UpdateMoney });
|
||||
GameMain.NetworkMember.CreateEntityEvent(this, new UpdateMoneyEventData());
|
||||
}
|
||||
|
||||
partial void OnTalentGiven(TalentPrefab talentPrefab)
|
||||
|
||||
@@ -8,9 +8,9 @@ namespace Barotrauma
|
||||
{
|
||||
partial class CharacterInfo
|
||||
{
|
||||
private readonly Dictionary<string, float> prevSentSkill = new Dictionary<string, float>();
|
||||
private readonly Dictionary<Identifier, float> prevSentSkill = new Dictionary<Identifier, float>();
|
||||
|
||||
partial void OnSkillChanged(string skillIdentifier, float prevLevel, float newLevel)
|
||||
partial void OnSkillChanged(Identifier skillIdentifier, float prevLevel, float newLevel)
|
||||
{
|
||||
if (Character == null || Character.Removed) { return; }
|
||||
if (!prevSentSkill.ContainsKey(skillIdentifier))
|
||||
@@ -19,7 +19,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (Math.Abs(prevSentSkill[skillIdentifier] - newLevel) > 0.01f)
|
||||
{
|
||||
GameMain.NetworkMember.CreateEntityEvent(Character, new object[] { NetEntityEvent.Type.UpdateSkills });
|
||||
GameMain.NetworkMember.CreateEntityEvent(Character, new Character.UpdateSkillsEventData());
|
||||
prevSentSkill[skillIdentifier] = newLevel;
|
||||
}
|
||||
}
|
||||
@@ -30,14 +30,14 @@ namespace Barotrauma
|
||||
if (prevAmount != newAmount)
|
||||
{
|
||||
GameServer.Log($"{GameServer.CharacterLogName(Character)} has gained {newAmount - prevAmount} experience ({prevAmount} -> {newAmount})", ServerLog.MessageType.Talent);
|
||||
GameMain.NetworkMember.CreateEntityEvent(Character, new object[] { NetEntityEvent.Type.UpdateExperience });
|
||||
GameMain.NetworkMember.CreateEntityEvent(Character, new Character.UpdateExperienceEventData());
|
||||
}
|
||||
}
|
||||
|
||||
partial void OnPermanentStatChanged(StatTypes statType)
|
||||
{
|
||||
if (Character == null || Character.Removed) { return; }
|
||||
GameMain.NetworkMember.CreateEntityEvent(Character, new object[] { NetEntityEvent.Type.UpdatePermanentStats, statType });
|
||||
GameMain.NetworkMember.CreateEntityEvent(Character, new Character.UpdatePermanentStatsEventData());
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg)
|
||||
@@ -45,16 +45,18 @@ namespace Barotrauma
|
||||
msg.Write(ID);
|
||||
msg.Write(Name);
|
||||
msg.Write(OriginalName);
|
||||
msg.Write((byte)Gender);
|
||||
msg.Write((byte)Race);
|
||||
msg.Write((byte)HeadSpriteId);
|
||||
msg.Write((byte)HairIndex);
|
||||
msg.Write((byte)BeardIndex);
|
||||
msg.Write((byte)MoustacheIndex);
|
||||
msg.Write((byte)FaceAttachmentIndex);
|
||||
msg.WriteColorR8G8B8(SkinColor);
|
||||
msg.WriteColorR8G8B8(HairColor);
|
||||
msg.WriteColorR8G8B8(FacialHairColor);
|
||||
msg.Write((byte)Head.Preset.TagSet.Count);
|
||||
foreach (Identifier tag in Head.Preset.TagSet)
|
||||
{
|
||||
msg.Write(tag);
|
||||
}
|
||||
msg.Write((byte)Head.HairIndex);
|
||||
msg.Write((byte)Head.BeardIndex);
|
||||
msg.Write((byte)Head.MoustacheIndex);
|
||||
msg.Write((byte)Head.FaceAttachmentIndex);
|
||||
msg.WriteColorR8G8B8(Head.SkinColor);
|
||||
msg.WriteColorR8G8B8(Head.HairColor);
|
||||
msg.WriteColorR8G8B8(Head.FacialHairColor);
|
||||
msg.Write(ragdollFileName);
|
||||
|
||||
if (Job != null)
|
||||
@@ -73,20 +75,9 @@ namespace Barotrauma
|
||||
msg.Write("");
|
||||
msg.Write((byte)0);
|
||||
}
|
||||
// TODO: animations
|
||||
msg.Write((byte)SavedStatValues.SelectMany(s => s.Value).Count());
|
||||
foreach (var savedStatValuePair in SavedStatValues)
|
||||
{
|
||||
foreach (var savedStatValue in savedStatValuePair.Value)
|
||||
{
|
||||
msg.Write((byte)savedStatValuePair.Key);
|
||||
msg.Write(savedStatValue.StatIdentifier);
|
||||
msg.Write(savedStatValue.StatValue);
|
||||
msg.Write(savedStatValue.RemoveOnDeath);
|
||||
}
|
||||
}
|
||||
|
||||
msg.Write((ushort)ExperiencePoints);
|
||||
msg.Write((ushort)AdditionalTalentPoints);
|
||||
msg.WriteRangedInteger(AdditionalTalentPoints, 0, MaxAdditionalTalentPoints);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,14 +153,94 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
|
||||
public void ServerReadInput(IReadMessage msg, Client c)
|
||||
{
|
||||
if (GameMain.Server == null) return;
|
||||
|
||||
switch (type)
|
||||
if (c.Character != this)
|
||||
{
|
||||
case ClientNetObject.CHARACTER_INPUT:
|
||||
#if DEBUG
|
||||
DebugConsole.Log("Received a character update message from a client who's not controlling the character");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
UInt16 networkUpdateID = msg.ReadUInt16();
|
||||
byte inputCount = msg.ReadByte();
|
||||
|
||||
if (AllowInput) { Enabled = true; }
|
||||
|
||||
for (int i = 0; i < inputCount; i++)
|
||||
{
|
||||
InputNetFlags newInput = (InputNetFlags)msg.ReadRangedInteger(0, (int)InputNetFlags.MaxVal);
|
||||
UInt16 newAim = 0;
|
||||
UInt16 newInteract = 0;
|
||||
|
||||
if (newInput != InputNetFlags.None && newInput != InputNetFlags.FacingLeft)
|
||||
{
|
||||
c.KickAFKTimer = 0.0f;
|
||||
}
|
||||
else if (AnimController.Dir < 0.0f != newInput.HasFlag(InputNetFlags.FacingLeft))
|
||||
{
|
||||
//character changed the direction they're facing
|
||||
c.KickAFKTimer = 0.0f;
|
||||
}
|
||||
|
||||
newAim = msg.ReadUInt16();
|
||||
if (newInput.HasFlag(InputNetFlags.Select) ||
|
||||
newInput.HasFlag(InputNetFlags.Deselect) ||
|
||||
newInput.HasFlag(InputNetFlags.Use) ||
|
||||
newInput.HasFlag(InputNetFlags.Health) ||
|
||||
newInput.HasFlag(InputNetFlags.Grab))
|
||||
{
|
||||
newInteract = msg.ReadUInt16();
|
||||
}
|
||||
|
||||
if (NetIdUtils.IdMoreRecent((ushort)(networkUpdateID - i), LastNetworkUpdateID) && (i < 60))
|
||||
{
|
||||
if ((i > 0 && memInput[i - 1].intAim != newAim))
|
||||
{
|
||||
c.KickAFKTimer = 0.0f;
|
||||
}
|
||||
NetInputMem newMem = new NetInputMem
|
||||
{
|
||||
states = newInput,
|
||||
intAim = newAim,
|
||||
interact = newInteract,
|
||||
networkUpdateID = (ushort)(networkUpdateID - i)
|
||||
};
|
||||
memInput.Insert(i, newMem);
|
||||
LastInputTime = Timing.TotalTime;
|
||||
}
|
||||
}
|
||||
|
||||
if (NetIdUtils.IdMoreRecent(networkUpdateID, LastNetworkUpdateID))
|
||||
{
|
||||
LastNetworkUpdateID = networkUpdateID;
|
||||
}
|
||||
else if (NetIdUtils.Difference(networkUpdateID, LastNetworkUpdateID) > 500)
|
||||
{
|
||||
#if DEBUG || UNSTABLE
|
||||
DebugConsole.AddWarning($"Large disrepancy between a client character's network update ID server-side and client-side (client: {networkUpdateID}, server: {LastNetworkUpdateID}). Resetting the ID.");
|
||||
#endif
|
||||
LastNetworkUpdateID = networkUpdateID;
|
||||
}
|
||||
if (memInput.Count > 60)
|
||||
{
|
||||
//deleting inputs from the queue here means the server is way behind and data needs to be dropped
|
||||
//we'll make the server drop down to 30 inputs for good measure
|
||||
memInput.RemoveRange(30, memInput.Count - 30);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void ServerEventRead(IReadMessage msg, Client c)
|
||||
{
|
||||
EventType eventType = (EventType)msg.ReadRangedInteger((int)EventType.MinValue, (int)EventType.MaxValue);
|
||||
switch (eventType)
|
||||
{
|
||||
case EventType.InventoryState:
|
||||
Inventory.ServerEventRead(msg, c);
|
||||
break;
|
||||
case EventType.Treatment:
|
||||
bool doingCPR = msg.ReadBoolean();
|
||||
if (c.Character != this)
|
||||
{
|
||||
#if DEBUG
|
||||
@@ -169,416 +249,315 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
UInt16 networkUpdateID = msg.ReadUInt16();
|
||||
byte inputCount = msg.ReadByte();
|
||||
|
||||
if (AllowInput) { Enabled = true; }
|
||||
|
||||
for (int i = 0; i < inputCount; i++)
|
||||
AnimController.Anim = doingCPR ? AnimController.Animation.CPR : AnimController.Animation.None;
|
||||
break;
|
||||
case EventType.Status:
|
||||
if (c.Character != this)
|
||||
{
|
||||
InputNetFlags newInput = (InputNetFlags)msg.ReadRangedInteger(0, (int)InputNetFlags.MaxVal);
|
||||
UInt16 newAim = 0;
|
||||
UInt16 newInteract = 0;
|
||||
|
||||
if (newInput != InputNetFlags.None && newInput != InputNetFlags.FacingLeft)
|
||||
{
|
||||
c.KickAFKTimer = 0.0f;
|
||||
}
|
||||
else if (AnimController.Dir < 0.0f != newInput.HasFlag(InputNetFlags.FacingLeft))
|
||||
{
|
||||
//character changed the direction they're facing
|
||||
c.KickAFKTimer = 0.0f;
|
||||
}
|
||||
|
||||
newAim = msg.ReadUInt16();
|
||||
if (newInput.HasFlag(InputNetFlags.Select) ||
|
||||
newInput.HasFlag(InputNetFlags.Deselect) ||
|
||||
newInput.HasFlag(InputNetFlags.Use) ||
|
||||
newInput.HasFlag(InputNetFlags.Health) ||
|
||||
newInput.HasFlag(InputNetFlags.Grab))
|
||||
{
|
||||
newInteract = msg.ReadUInt16();
|
||||
}
|
||||
|
||||
if (NetIdUtils.IdMoreRecent((ushort)(networkUpdateID - i), LastNetworkUpdateID) && (i < 60))
|
||||
{
|
||||
if ((i > 0 && memInput[i - 1].intAim != newAim))
|
||||
{
|
||||
c.KickAFKTimer = 0.0f;
|
||||
}
|
||||
NetInputMem newMem = new NetInputMem
|
||||
{
|
||||
states = newInput,
|
||||
intAim = newAim,
|
||||
interact = newInteract,
|
||||
networkUpdateID = (ushort)(networkUpdateID - i)
|
||||
};
|
||||
memInput.Insert(i, newMem);
|
||||
LastInputTime = Timing.TotalTime;
|
||||
}
|
||||
}
|
||||
|
||||
if (NetIdUtils.IdMoreRecent(networkUpdateID, LastNetworkUpdateID))
|
||||
{
|
||||
LastNetworkUpdateID = networkUpdateID;
|
||||
}
|
||||
else if (NetIdUtils.Difference(networkUpdateID, LastNetworkUpdateID) > 500)
|
||||
{
|
||||
#if DEBUG || UNSTABLE
|
||||
DebugConsole.AddWarning($"Large disrepancy between a client character's network update ID server-side and client-side (client: {networkUpdateID}, server: {LastNetworkUpdateID}). Resetting the ID.");
|
||||
#if DEBUG
|
||||
DebugConsole.Log("Received a character update message from a client who's not controlling the character");
|
||||
#endif
|
||||
LastNetworkUpdateID = networkUpdateID;
|
||||
return;
|
||||
}
|
||||
if (memInput.Count > 60)
|
||||
|
||||
if (IsIncapacitated)
|
||||
{
|
||||
//deleting inputs from the queue here means the server is way behind and data needs to be dropped
|
||||
//we'll make the server drop down to 30 inputs for good measure
|
||||
memInput.RemoveRange(30, memInput.Count - 30);
|
||||
var causeOfDeath = CharacterHealth.GetCauseOfDeath();
|
||||
Kill(causeOfDeath.type, causeOfDeath.affliction);
|
||||
}
|
||||
break;
|
||||
|
||||
case ClientNetObject.ENTITY_STATE:
|
||||
int eventType = msg.ReadRangedInteger(0, 4);
|
||||
switch (eventType)
|
||||
case EventType.UpdateTalents:
|
||||
if (c.Character != this)
|
||||
{
|
||||
case 0:
|
||||
Inventory.ServerRead(type, msg, c);
|
||||
break;
|
||||
case 1:
|
||||
bool doingCPR = msg.ReadBoolean();
|
||||
if (c.Character != this)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.Log("Received a character update message from a client who's not controlling the character");
|
||||
DebugConsole.Log("Received a character update message from a client who's not controlling the character");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
AnimController.Anim = doingCPR ? AnimController.Animation.CPR : AnimController.Animation.None;
|
||||
break;
|
||||
case 2:
|
||||
if (c.Character != this)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.Log("Received a character update message from a client who's not controlling the character");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
// get the full list of talents from the player, only give the ones
|
||||
// that are not already given (or otherwise not viable)
|
||||
ushort talentCount = msg.ReadUInt16();
|
||||
List<Identifier> talentSelection = new List<Identifier>();
|
||||
for (int i = 0; i < talentCount; i++)
|
||||
{
|
||||
UInt32 talentIdentifier = msg.ReadUInt32();
|
||||
var prefab = TalentPrefab.TalentPrefabs.Find(p => p.UintIdentifier == talentIdentifier);
|
||||
if (prefab == null) { continue; }
|
||||
|
||||
if (IsIncapacitated)
|
||||
{
|
||||
var causeOfDeath = CharacterHealth.GetCauseOfDeath();
|
||||
Kill(causeOfDeath.type, causeOfDeath.affliction);
|
||||
}
|
||||
break;
|
||||
case 3: // NetEntityEvent.Type.UpdateTalents
|
||||
if (c.Character != this)
|
||||
{
|
||||
#if DEBUG
|
||||
DebugConsole.Log("Received a character update message from a client who's not controlling the character");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
// get the full list of talents from the player, only give the ones
|
||||
// that are not already given (or otherwise not viable)
|
||||
ushort talentCount = msg.ReadUInt16();
|
||||
List<string> talentSelection = new List<string>();
|
||||
for (int i = 0; i < talentCount; i++)
|
||||
{
|
||||
UInt32 talentIdentifier = msg.ReadUInt32();
|
||||
var prefab = TalentPrefab.TalentPrefabs.Find(p => p.UIntIdentifier == talentIdentifier);
|
||||
if (prefab == null) { continue; }
|
||||
|
||||
if (TalentTree.IsViableTalentForCharacter(this, prefab.Identifier, talentSelection))
|
||||
{
|
||||
GiveTalent(prefab.Identifier);
|
||||
talentSelection.Add(prefab.Identifier);
|
||||
}
|
||||
}
|
||||
if (talentSelection.Count != talentCount)
|
||||
{
|
||||
DebugConsole.AddWarning($"Failed to unlock talents: the amount of unlocked talents doesn't match (client: {talentCount}, server: {talentSelection.Count})");
|
||||
}
|
||||
break;
|
||||
if (TalentTree.IsViableTalentForCharacter(this, prefab.Identifier, talentSelection))
|
||||
{
|
||||
GiveTalent(prefab.Identifier);
|
||||
talentSelection.Add(prefab.Identifier);
|
||||
}
|
||||
}
|
||||
if (talentSelection.Count != talentCount)
|
||||
{
|
||||
DebugConsole.AddWarning($"Failed to unlock talents: the amount of unlocked talents doesn't match (client: {talentCount}, server: {talentSelection.Count})");
|
||||
}
|
||||
break;
|
||||
}
|
||||
msg.ReadPadBits();
|
||||
}
|
||||
|
||||
public virtual void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerWritePosition(IWriteMessage msg, Client c)
|
||||
{
|
||||
if (GameMain.Server == null) return;
|
||||
msg.Write(ID);
|
||||
|
||||
if (extraData != null)
|
||||
IWriteMessage tempBuffer = new WriteOnlyMessage();
|
||||
|
||||
if (this == c.Character)
|
||||
{
|
||||
const int min = 0, max = 13;
|
||||
switch ((NetEntityEvent.Type)extraData[0])
|
||||
tempBuffer.Write(true);
|
||||
if (LastNetworkUpdateID < memInput.Count + 1)
|
||||
{
|
||||
case NetEntityEvent.Type.InventoryState:
|
||||
msg.WriteRangedInteger(0, min, max);
|
||||
msg.Write(GameMain.Server.EntityEventManager.Events.Last()?.ID ?? (ushort)0);
|
||||
Inventory.ServerWrite(msg, c);
|
||||
break;
|
||||
case NetEntityEvent.Type.Control:
|
||||
msg.WriteRangedInteger(1, min, max);
|
||||
Client owner = (Client)extraData[1];
|
||||
msg.Write(owner == c && owner.Character == this);
|
||||
msg.Write(owner != null && owner.Character == this && GameMain.Server.ConnectedClients.Contains(owner) ? owner.ID : (byte)0);
|
||||
break;
|
||||
case NetEntityEvent.Type.Status:
|
||||
msg.WriteRangedInteger(2, min, max);
|
||||
WriteStatus(msg);
|
||||
break;
|
||||
case NetEntityEvent.Type.UpdateSkills:
|
||||
msg.WriteRangedInteger(3, min, max);
|
||||
if (Info?.Job == null)
|
||||
{
|
||||
msg.Write((byte)0);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.Write((byte)Info.Job.Skills.Count);
|
||||
foreach (Skill skill in Info.Job.Skills)
|
||||
{
|
||||
msg.Write(skill.Identifier);
|
||||
msg.Write(skill.Level);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NetEntityEvent.Type.SetAttackTarget:
|
||||
case NetEntityEvent.Type.ExecuteAttack:
|
||||
Limb attackLimb = extraData[1] as Limb;
|
||||
UInt16 targetEntityID = (UInt16)extraData[2];
|
||||
int targetLimbIndex = extraData.Length > 3 ? (int)extraData[3] : 0;
|
||||
msg.WriteRangedInteger(extraData[0] is NetEntityEvent.Type.SetAttackTarget ? 4 : 5, min, max);
|
||||
msg.Write((byte)(Removed ? 255 : Array.IndexOf(AnimController.Limbs, attackLimb)));
|
||||
msg.Write(targetEntityID);
|
||||
msg.Write((byte)targetLimbIndex);
|
||||
msg.Write(extraData.Length > 4 ? (float)extraData[4] : 0);
|
||||
msg.Write(extraData.Length > 5 ? (float)extraData[5] : 0);
|
||||
break;
|
||||
case NetEntityEvent.Type.AssignCampaignInteraction:
|
||||
msg.WriteRangedInteger(6, min, max);
|
||||
msg.Write((byte)CampaignInteractionType);
|
||||
msg.Write(RequireConsciousnessForCustomInteract);
|
||||
break;
|
||||
case NetEntityEvent.Type.ObjectiveManagerState:
|
||||
msg.WriteRangedInteger(7, min, max);
|
||||
int type = (extraData[1] as string) switch
|
||||
{
|
||||
"order" => 1,
|
||||
"objective" => 2,
|
||||
_ => 0
|
||||
};
|
||||
msg.WriteRangedInteger(type, 0, 2);
|
||||
if (!(AIController is HumanAIController controller))
|
||||
{
|
||||
msg.Write(false);
|
||||
break;
|
||||
}
|
||||
if (type == 1)
|
||||
{
|
||||
var currentOrderInfo = controller.ObjectiveManager.GetCurrentOrderInfo();
|
||||
bool validOrder = currentOrderInfo.HasValue;
|
||||
msg.Write(validOrder);
|
||||
if (!validOrder) { break; }
|
||||
var orderPrefab = currentOrderInfo.Value.Order.Prefab;
|
||||
int orderIndex = Order.PrefabList.IndexOf(orderPrefab);
|
||||
msg.WriteRangedInteger(orderIndex, 0, Order.PrefabList.Count);
|
||||
if (!orderPrefab.HasOptions) { break; }
|
||||
int optionIndex = orderPrefab.AllOptions.IndexOf(currentOrderInfo.Value.OrderOption);
|
||||
if (optionIndex == -1)
|
||||
{
|
||||
DebugConsole.AddWarning($"Error while writing order data. Order option \"{(currentOrderInfo.Value.OrderOption ?? null)}\" not found in the order prefab \"{orderPrefab.Name}\".");
|
||||
}
|
||||
msg.WriteRangedInteger(optionIndex, -1, orderPrefab.AllOptions.Length);
|
||||
}
|
||||
else if (type == 2)
|
||||
{
|
||||
var objective = controller.ObjectiveManager.CurrentObjective;
|
||||
bool validObjective = !string.IsNullOrEmpty(objective?.Identifier);
|
||||
msg.Write(validObjective);
|
||||
if (!validObjective) { break; }
|
||||
msg.Write(objective.Identifier);
|
||||
msg.Write(objective.Option ?? "");
|
||||
UInt16 targetEntityId = 0;
|
||||
if (objective is AIObjectiveOperateItem operateObjective && operateObjective.OperateTarget != null)
|
||||
{
|
||||
targetEntityId = operateObjective.OperateTarget.ID;
|
||||
}
|
||||
msg.Write(targetEntityId);
|
||||
}
|
||||
break;
|
||||
case NetEntityEvent.Type.TeamChange:
|
||||
msg.WriteRangedInteger(8, min, max);
|
||||
msg.Write((byte)TeamID);
|
||||
break;
|
||||
case NetEntityEvent.Type.AddToCrew:
|
||||
msg.WriteRangedInteger(9, min, max);
|
||||
msg.Write((byte)(CharacterTeamType)extraData[1]); // team id
|
||||
ushort[] inventoryItemIDs = (ushort[])extraData[2];
|
||||
msg.Write((ushort)inventoryItemIDs.Length);
|
||||
for (int i = 0; i < inventoryItemIDs.Length; i++)
|
||||
{
|
||||
msg.Write(inventoryItemIDs[i]);
|
||||
}
|
||||
break;
|
||||
case NetEntityEvent.Type.UpdateExperience:
|
||||
msg.WriteRangedInteger(10, min, max);
|
||||
msg.Write(Info.ExperiencePoints);
|
||||
break;
|
||||
case NetEntityEvent.Type.UpdateTalents:
|
||||
msg.WriteRangedInteger(11, min, max);
|
||||
msg.Write((ushort)characterTalents.Count);
|
||||
foreach (var unlockedTalent in characterTalents)
|
||||
{
|
||||
msg.Write(unlockedTalent.AddedThisRound);
|
||||
msg.Write(unlockedTalent.Prefab.UIntIdentifier);
|
||||
}
|
||||
break;
|
||||
case NetEntityEvent.Type.UpdateMoney:
|
||||
msg.WriteRangedInteger(12, min, max);
|
||||
msg.Write(GameMain.GameSession.Campaign.Money);
|
||||
break;
|
||||
case NetEntityEvent.Type.UpdatePermanentStats:
|
||||
msg.WriteRangedInteger(13, min, max);
|
||||
if (Info == null || extraData.Length < 2 || !(extraData[1] is StatTypes statType))
|
||||
{
|
||||
msg.Write((byte)0);
|
||||
msg.Write((byte)0);
|
||||
}
|
||||
else if (!Info.SavedStatValues.ContainsKey(statType))
|
||||
{
|
||||
msg.Write((byte)0);
|
||||
msg.Write((byte)statType);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.Write((byte)Info.SavedStatValues[statType].Count);
|
||||
msg.Write((byte)statType);
|
||||
foreach (var savedStatValue in Info.SavedStatValues[statType])
|
||||
{
|
||||
msg.Write(savedStatValue.StatIdentifier);
|
||||
msg.Write(savedStatValue.StatValue);
|
||||
msg.Write(savedStatValue.RemoveOnDeath);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DebugConsole.ThrowError("Invalid NetworkEvent type for entity " + ToString() + " (" + (NetEntityEvent.Type)extraData[0] + ")");
|
||||
break;
|
||||
tempBuffer.Write((UInt16)0);
|
||||
}
|
||||
else
|
||||
{
|
||||
tempBuffer.Write((UInt16)(LastNetworkUpdateID - memInput.Count - 1));
|
||||
}
|
||||
msg.WritePadBits();
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.Write(ID);
|
||||
tempBuffer.Write(false);
|
||||
|
||||
IWriteMessage tempBuffer = new WriteOnlyMessage();
|
||||
bool aiming = false;
|
||||
bool use = false;
|
||||
bool attack = false;
|
||||
bool shoot = false;
|
||||
|
||||
if (this == c.Character)
|
||||
if (IsRemotePlayer)
|
||||
{
|
||||
tempBuffer.Write(true);
|
||||
if (LastNetworkUpdateID < memInput.Count + 1)
|
||||
aiming = dequeuedInput.HasFlag(InputNetFlags.Aim);
|
||||
use = dequeuedInput.HasFlag(InputNetFlags.Use);
|
||||
attack = dequeuedInput.HasFlag(InputNetFlags.Attack);
|
||||
shoot = dequeuedInput.HasFlag(InputNetFlags.Shoot);
|
||||
}
|
||||
else if (keys != null)
|
||||
{
|
||||
aiming = keys[(int)InputType.Aim].GetHeldQueue;
|
||||
use = keys[(int)InputType.Use].GetHeldQueue;
|
||||
attack = keys[(int)InputType.Attack].GetHeldQueue;
|
||||
shoot = keys[(int)InputType.Shoot].GetHeldQueue;
|
||||
networkUpdateSent = true;
|
||||
}
|
||||
|
||||
tempBuffer.Write(aiming);
|
||||
tempBuffer.Write(shoot);
|
||||
tempBuffer.Write(use);
|
||||
if (AnimController is HumanoidAnimController)
|
||||
{
|
||||
tempBuffer.Write(((HumanoidAnimController)AnimController).Crouching);
|
||||
}
|
||||
tempBuffer.Write(attack);
|
||||
|
||||
Vector2 relativeCursorPos = cursorPosition - AimRefPosition;
|
||||
tempBuffer.Write((UInt16)(65535.0 * Math.Atan2(relativeCursorPos.Y, relativeCursorPos.X) / (2.0 * Math.PI)));
|
||||
|
||||
tempBuffer.Write(IsRagdolled || Stun > 0.0f || IsDead || IsIncapacitated);
|
||||
|
||||
tempBuffer.Write(AnimController.Dir > 0.0f);
|
||||
}
|
||||
|
||||
if (SelectedCharacter != null || SelectedConstruction != null)
|
||||
{
|
||||
tempBuffer.Write(true);
|
||||
tempBuffer.Write(SelectedCharacter != null ? SelectedCharacter.ID : NullEntityID);
|
||||
tempBuffer.Write(SelectedConstruction != null ? SelectedConstruction.ID : NullEntityID);
|
||||
if (SelectedCharacter != null)
|
||||
{
|
||||
tempBuffer.Write(AnimController.Anim == AnimController.Animation.CPR);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tempBuffer.Write(false);
|
||||
}
|
||||
|
||||
tempBuffer.Write(SimPosition.X);
|
||||
tempBuffer.Write(SimPosition.Y);
|
||||
float MaxVel = NetConfig.MaxPhysicsBodyVelocity;
|
||||
AnimController.Collider.LinearVelocity = new Vector2(
|
||||
MathHelper.Clamp(AnimController.Collider.LinearVelocity.X, -MaxVel, MaxVel),
|
||||
MathHelper.Clamp(AnimController.Collider.LinearVelocity.Y, -MaxVel, MaxVel));
|
||||
tempBuffer.WriteRangedSingle(AnimController.Collider.LinearVelocity.X, -MaxVel, MaxVel, 12);
|
||||
tempBuffer.WriteRangedSingle(AnimController.Collider.LinearVelocity.Y, -MaxVel, MaxVel, 12);
|
||||
|
||||
bool fixedRotation = AnimController.Collider.FarseerBody.FixedRotation || !AnimController.Collider.PhysEnabled;
|
||||
tempBuffer.Write(fixedRotation);
|
||||
if (!fixedRotation)
|
||||
{
|
||||
tempBuffer.Write(AnimController.Collider.Rotation);
|
||||
float MaxAngularVel = NetConfig.MaxPhysicsBodyAngularVelocity;
|
||||
AnimController.Collider.AngularVelocity = NetConfig.Quantize(AnimController.Collider.AngularVelocity, -MaxAngularVel, MaxAngularVel, 8);
|
||||
tempBuffer.WriteRangedSingle(MathHelper.Clamp(AnimController.Collider.AngularVelocity, -MaxAngularVel, MaxAngularVel), -MaxAngularVel, MaxAngularVel, 8);
|
||||
}
|
||||
|
||||
bool writeStatus = healthUpdateTimer <= 0.0f;
|
||||
tempBuffer.Write(writeStatus);
|
||||
if (writeStatus)
|
||||
{
|
||||
WriteStatus(tempBuffer);
|
||||
AIController?.ServerWrite(tempBuffer);
|
||||
HealthUpdatePending = false;
|
||||
}
|
||||
|
||||
tempBuffer.WritePadBits();
|
||||
|
||||
msg.WriteVariableUInt32((uint)tempBuffer.LengthBytes);
|
||||
msg.Write(tempBuffer.Buffer, 0, tempBuffer.LengthBytes);
|
||||
}
|
||||
|
||||
public virtual void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
if (!(extraData is IEventData eventData)) { throw new Exception($"Malformed character event: expected {nameof(Character)}.{nameof(IEventData)}, got {extraData?.GetType().Name ?? "[NULL]"}"); }
|
||||
|
||||
msg.WriteRangedInteger((int)eventData.EventType, (int)EventType.MinValue, (int)EventType.MaxValue);
|
||||
switch (eventData)
|
||||
{
|
||||
case InventoryStateEventData _:
|
||||
msg.Write(GameMain.Server.EntityEventManager.Events.Last()?.ID ?? (ushort)0);
|
||||
Inventory.ServerEventWrite(msg, c);
|
||||
break;
|
||||
case ControlEventData controlEventData:
|
||||
Client owner = controlEventData.Owner;
|
||||
msg.Write(owner == c && owner.Character == this);
|
||||
msg.Write(owner != null && owner.Character == this && GameMain.Server.ConnectedClients.Contains(owner) ? owner.ID : (byte)0);
|
||||
break;
|
||||
case CharacterStatusEventData _:
|
||||
WriteStatus(msg);
|
||||
break;
|
||||
case UpdateSkillsEventData _:
|
||||
if (Info?.Job == null)
|
||||
{
|
||||
tempBuffer.Write((UInt16)0);
|
||||
msg.Write((byte)0);
|
||||
}
|
||||
else
|
||||
{
|
||||
tempBuffer.Write((UInt16)(LastNetworkUpdateID - memInput.Count - 1));
|
||||
msg.Write((byte)Info.Job.Skills.Count);
|
||||
foreach (Skill skill in Info.Job.Skills)
|
||||
{
|
||||
msg.Write(skill.Identifier);
|
||||
msg.Write(skill.Level);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tempBuffer.Write(false);
|
||||
|
||||
bool aiming = false;
|
||||
bool use = false;
|
||||
bool attack = false;
|
||||
bool shoot = false;
|
||||
|
||||
if (IsRemotePlayer)
|
||||
break;
|
||||
case IAttackEventData attackEventData:
|
||||
{
|
||||
aiming = dequeuedInput.HasFlag(InputNetFlags.Aim);
|
||||
use = dequeuedInput.HasFlag(InputNetFlags.Use);
|
||||
attack = dequeuedInput.HasFlag(InputNetFlags.Attack);
|
||||
shoot = dequeuedInput.HasFlag(InputNetFlags.Shoot);
|
||||
int attackLimbIndex = Removed ? -1 : Array.IndexOf(AnimController.Limbs, attackEventData.AttackLimb);
|
||||
ushort targetEntityId = 0;
|
||||
int targetLimbIndex = -1;
|
||||
if (attackEventData.TargetEntity is Entity { Removed: false } targetEntity)
|
||||
{
|
||||
targetEntityId = targetEntity.ID;
|
||||
if (targetEntity is Character { AnimController: { Limbs: var targetLimbsArray } })
|
||||
{
|
||||
targetLimbIndex = targetLimbsArray.IndexOf(attackEventData.TargetLimb);
|
||||
}
|
||||
}
|
||||
msg.Write((byte)(attackLimbIndex < 0 ? 255 : attackLimbIndex));
|
||||
msg.Write((ushort)targetEntityId);
|
||||
msg.Write((byte)(targetLimbIndex < 0 ? 255 : targetLimbIndex));
|
||||
msg.Write(attackEventData.TargetSimPos.X);
|
||||
msg.Write(attackEventData.TargetSimPos.Y);
|
||||
}
|
||||
else if (keys != null)
|
||||
break;
|
||||
case AssignCampaignInteractionEventData _:
|
||||
msg.Write((byte)CampaignInteractionType);
|
||||
msg.Write(RequireConsciousnessForCustomInteract);
|
||||
break;
|
||||
case ObjectiveManagerStateEventData objectiveManagerStateEventData:
|
||||
AIObjectiveManager.ObjectiveType type = objectiveManagerStateEventData.ObjectiveType;
|
||||
msg.WriteRangedInteger((int)type, (int)AIObjectiveManager.ObjectiveType.MinValue, (int)AIObjectiveManager.ObjectiveType.MaxValue);
|
||||
if (!(AIController is HumanAIController controller))
|
||||
{
|
||||
aiming = keys[(int)InputType.Aim].GetHeldQueue;
|
||||
use = keys[(int)InputType.Use].GetHeldQueue;
|
||||
attack = keys[(int)InputType.Attack].GetHeldQueue;
|
||||
shoot = keys[(int)InputType.Shoot].GetHeldQueue;
|
||||
networkUpdateSent = true;
|
||||
msg.Write(false);
|
||||
break;
|
||||
}
|
||||
|
||||
tempBuffer.Write(aiming);
|
||||
tempBuffer.Write(shoot);
|
||||
tempBuffer.Write(use);
|
||||
if (AnimController is HumanoidAnimController)
|
||||
if (type == AIObjectiveManager.ObjectiveType.Order)
|
||||
{
|
||||
tempBuffer.Write(((HumanoidAnimController)AnimController).Crouching);
|
||||
var currentOrderInfo = controller.ObjectiveManager.GetCurrentOrderInfo();
|
||||
bool validOrder = currentOrderInfo != null;
|
||||
msg.Write(validOrder);
|
||||
if (!validOrder) { break; }
|
||||
var orderPrefab = currentOrderInfo.Prefab;
|
||||
msg.Write(orderPrefab.UintIdentifier);
|
||||
if (!orderPrefab.HasOptions) { break; }
|
||||
int optionIndex = orderPrefab.AllOptions.IndexOf(currentOrderInfo.Option);
|
||||
if (optionIndex == -1)
|
||||
{
|
||||
DebugConsole.AddWarning($"Error while writing order data. Order option \"{currentOrderInfo.Option}\" not found in the order prefab \"{orderPrefab.Name}\".");
|
||||
}
|
||||
msg.WriteRangedInteger(optionIndex, -1, orderPrefab.AllOptions.Length);
|
||||
}
|
||||
tempBuffer.Write(attack);
|
||||
|
||||
Vector2 relativeCursorPos = cursorPosition - AimRefPosition;
|
||||
tempBuffer.Write((UInt16)(65535.0 * Math.Atan2(relativeCursorPos.Y, relativeCursorPos.X) / (2.0 * Math.PI)));
|
||||
|
||||
tempBuffer.Write(IsRagdolled || Stun > 0.0f || IsDead || IsIncapacitated);
|
||||
|
||||
tempBuffer.Write(AnimController.Dir > 0.0f);
|
||||
}
|
||||
|
||||
if (SelectedCharacter != null || SelectedConstruction != null)
|
||||
{
|
||||
tempBuffer.Write(true);
|
||||
tempBuffer.Write(SelectedCharacter != null ? SelectedCharacter.ID : NullEntityID);
|
||||
tempBuffer.Write(SelectedConstruction != null ? SelectedConstruction.ID : NullEntityID);
|
||||
if (SelectedCharacter != null)
|
||||
else if (type == AIObjectiveManager.ObjectiveType.Objective)
|
||||
{
|
||||
tempBuffer.Write(AnimController.Anim == AnimController.Animation.CPR);
|
||||
var objective = controller.ObjectiveManager.CurrentObjective;
|
||||
bool validObjective = objective?.Identifier is { IsEmpty: false };
|
||||
msg.Write(validObjective);
|
||||
if (!validObjective) { break; }
|
||||
msg.Write(objective.Identifier);
|
||||
msg.Write(objective.Option);
|
||||
UInt16 targetEntityId = 0;
|
||||
if (objective is AIObjectiveOperateItem operateObjective && operateObjective.OperateTarget != null)
|
||||
{
|
||||
targetEntityId = operateObjective.OperateTarget.ID;
|
||||
}
|
||||
msg.Write(targetEntityId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tempBuffer.Write(false);
|
||||
}
|
||||
|
||||
tempBuffer.Write(SimPosition.X);
|
||||
tempBuffer.Write(SimPosition.Y);
|
||||
float MaxVel = NetConfig.MaxPhysicsBodyVelocity;
|
||||
AnimController.Collider.LinearVelocity = new Vector2(
|
||||
MathHelper.Clamp(AnimController.Collider.LinearVelocity.X, -MaxVel, MaxVel),
|
||||
MathHelper.Clamp(AnimController.Collider.LinearVelocity.Y, -MaxVel, MaxVel));
|
||||
tempBuffer.WriteRangedSingle(AnimController.Collider.LinearVelocity.X, -MaxVel, MaxVel, 12);
|
||||
tempBuffer.WriteRangedSingle(AnimController.Collider.LinearVelocity.Y, -MaxVel, MaxVel, 12);
|
||||
|
||||
bool fixedRotation = AnimController.Collider.FarseerBody.FixedRotation || !AnimController.Collider.PhysEnabled;
|
||||
tempBuffer.Write(fixedRotation);
|
||||
if (!fixedRotation)
|
||||
{
|
||||
tempBuffer.Write(AnimController.Collider.Rotation);
|
||||
float MaxAngularVel = NetConfig.MaxPhysicsBodyAngularVelocity;
|
||||
AnimController.Collider.AngularVelocity = NetConfig.Quantize(AnimController.Collider.AngularVelocity, -MaxAngularVel, MaxAngularVel, 8);
|
||||
tempBuffer.WriteRangedSingle(MathHelper.Clamp(AnimController.Collider.AngularVelocity, -MaxAngularVel, MaxAngularVel), -MaxAngularVel, MaxAngularVel, 8);
|
||||
}
|
||||
|
||||
bool writeStatus = healthUpdateTimer <= 0.0f;
|
||||
tempBuffer.Write(writeStatus);
|
||||
if (writeStatus)
|
||||
{
|
||||
WriteStatus(tempBuffer);
|
||||
AIController?.ServerWrite(tempBuffer);
|
||||
HealthUpdatePending = false;
|
||||
}
|
||||
|
||||
tempBuffer.WritePadBits();
|
||||
|
||||
msg.WriteVariableUInt32((uint)tempBuffer.LengthBytes);
|
||||
msg.Write(tempBuffer.Buffer, 0, tempBuffer.LengthBytes);
|
||||
break;
|
||||
case TeamChangeEventData _:
|
||||
msg.Write((byte)TeamID);
|
||||
break;
|
||||
case AddToCrewEventData addToCrewEventData:
|
||||
msg.Write((byte)addToCrewEventData.TeamType); // team id
|
||||
ushort[] inventoryItemIDs = addToCrewEventData.InventoryItems.Select(item => item.ID).ToArray();
|
||||
msg.Write((ushort)inventoryItemIDs.Length);
|
||||
for (int i = 0; i < inventoryItemIDs.Length; i++)
|
||||
{
|
||||
msg.Write(inventoryItemIDs[i]);
|
||||
}
|
||||
break;
|
||||
case UpdateExperienceEventData _:
|
||||
msg.Write(Info.ExperiencePoints);
|
||||
break;
|
||||
case UpdateTalentsEventData _:
|
||||
msg.Write((ushort)characterTalents.Count);
|
||||
foreach (var unlockedTalent in characterTalents)
|
||||
{
|
||||
msg.Write(unlockedTalent.AddedThisRound);
|
||||
msg.Write(unlockedTalent.Prefab.UintIdentifier);
|
||||
}
|
||||
break;
|
||||
case UpdateMoneyEventData _:
|
||||
msg.Write(GameMain.GameSession.Campaign.GetWallet(c).Balance);
|
||||
break;
|
||||
case UpdatePermanentStatsEventData updatePermanentStatsEventData:
|
||||
StatTypes statType = updatePermanentStatsEventData.StatType;
|
||||
if (Info == null)
|
||||
{
|
||||
msg.Write((byte)0);
|
||||
msg.Write((byte)0);
|
||||
}
|
||||
else if (!Info.SavedStatValues.ContainsKey(statType))
|
||||
{
|
||||
msg.Write((byte)0);
|
||||
msg.Write((byte)statType);
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.Write((byte)Info.SavedStatValues[statType].Count);
|
||||
msg.Write((byte)statType);
|
||||
foreach (var savedStatValue in Info.SavedStatValues[statType])
|
||||
{
|
||||
msg.Write(savedStatValue.StatIdentifier);
|
||||
msg.Write(savedStatValue.StatValue);
|
||||
msg.Write(savedStatValue.RemoveOnDeath);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Exception($"Malformed character event: did not expect {eventData.GetType().Name}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -623,9 +602,9 @@ namespace Barotrauma
|
||||
|
||||
public void WriteSpawnData(IWriteMessage msg, UInt16 entityId, bool restrictMessageSize)
|
||||
{
|
||||
if (GameMain.Server == null) return;
|
||||
if (GameMain.Server == null) { return; }
|
||||
|
||||
int msgLength = msg.LengthBytes;
|
||||
int initialMsgLength = msg.LengthBytes;
|
||||
|
||||
msg.Write(Info == null);
|
||||
msg.Write(entityId);
|
||||
@@ -657,6 +636,8 @@ namespace Barotrauma
|
||||
{
|
||||
msg.Write(true);
|
||||
msg.Write(ownerClient.ID);
|
||||
msg.Write(Wallet.Balance);
|
||||
msg.WriteRangedInteger(Wallet.RewardDistribution, 0, 100);
|
||||
}
|
||||
else if (GameMain.Server.Character == this)
|
||||
{
|
||||
@@ -671,43 +652,64 @@ namespace Barotrauma
|
||||
msg.Write((byte)TeamID);
|
||||
msg.Write(this is AICharacter);
|
||||
msg.Write(info.SpeciesName);
|
||||
int msgLengthBeforeInfo = msg.LengthBytes;
|
||||
info.ServerWrite(msg);
|
||||
int infoLength = msg.LengthBytes - msgLengthBeforeInfo;
|
||||
|
||||
msg.Write((byte)CampaignInteractionType);
|
||||
if (CampaignInteractionType == CampaignMode.InteractionType.Store)
|
||||
{
|
||||
msg.Write(MerchantIdentifier);
|
||||
}
|
||||
|
||||
|
||||
int msgLengthBeforeOrders = msg.LengthBytes;
|
||||
// Current orders
|
||||
msg.Write((byte)info.CurrentOrders.Count(o => o.Order != null));
|
||||
msg.Write((byte)info.CurrentOrders.Count(o => o != null));
|
||||
foreach (var orderInfo in info.CurrentOrders)
|
||||
{
|
||||
if (orderInfo.Order == null) { continue; }
|
||||
msg.Write((byte)Order.PrefabList.IndexOf(orderInfo.Order.Prefab));
|
||||
msg.Write(orderInfo.Order.TargetEntity == null ? (UInt16)0 : orderInfo.Order.TargetEntity.ID);
|
||||
var hasOrderGiver = orderInfo.Order.OrderGiver != null;
|
||||
if (orderInfo == null) { continue; }
|
||||
msg.Write(orderInfo.Prefab.UintIdentifier);
|
||||
msg.Write(orderInfo.TargetEntity == null ? (UInt16)0 : orderInfo.TargetEntity.ID);
|
||||
var hasOrderGiver = orderInfo.OrderGiver != null;
|
||||
msg.Write(hasOrderGiver);
|
||||
if (hasOrderGiver) { msg.Write(orderInfo.Order.OrderGiver.ID); }
|
||||
msg.Write((byte)(string.IsNullOrWhiteSpace(orderInfo.OrderOption) ? 0 : Array.IndexOf(orderInfo.Order.Prefab.Options, orderInfo.OrderOption)));
|
||||
if (hasOrderGiver) { msg.Write(orderInfo.OrderGiver.ID); }
|
||||
msg.Write((byte)(orderInfo.Option == Identifier.Empty ? 0 : orderInfo.Prefab.Options.IndexOf(orderInfo.Option)));
|
||||
msg.Write((byte)orderInfo.ManualPriority);
|
||||
var hasTargetPosition = orderInfo.Order.TargetPosition != null;
|
||||
var hasTargetPosition = orderInfo.TargetPosition != null;
|
||||
msg.Write(hasTargetPosition);
|
||||
if (hasTargetPosition)
|
||||
{
|
||||
msg.Write(orderInfo.Order.TargetPosition.Position.X);
|
||||
msg.Write(orderInfo.Order.TargetPosition.Position.Y);
|
||||
msg.Write(orderInfo.Order.TargetPosition.Hull == null ? (UInt16)0 : orderInfo.Order.TargetPosition.Hull.ID);
|
||||
msg.Write(orderInfo.TargetPosition.Position.X);
|
||||
msg.Write(orderInfo.TargetPosition.Position.Y);
|
||||
msg.Write(orderInfo.TargetPosition.Hull == null ? (UInt16)0 : orderInfo.TargetPosition.Hull.ID);
|
||||
}
|
||||
}
|
||||
int ordersLength = msg.LengthBytes - msgLengthBeforeOrders;
|
||||
|
||||
if (msg.LengthBytes - initialMsgLength >= 255 && restrictMessageSize)
|
||||
{
|
||||
string errorMsg = $"Error when writing character spawn data: data exceeded 255 bytes (info: {infoLength}, orders: {ordersLength}, total: {msg.LengthBytes - initialMsgLength})";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Character.WriteSpawnData:TooMuchData", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
}
|
||||
|
||||
TryWriteStatus(msg);
|
||||
|
||||
void TryWriteStatus(IWriteMessage msg)
|
||||
{
|
||||
int msgLengthBeforeStatus = msg.LengthBytes - initialMsgLength;
|
||||
|
||||
var tempBuffer = new ReadWriteMessage();
|
||||
WriteStatus(tempBuffer);
|
||||
if (msg.LengthBytes + tempBuffer.LengthBytes >= 255 && restrictMessageSize && GameMain.Lua.networking.restrictMessageSize)
|
||||
if (msgLengthBeforeStatus + tempBuffer.LengthBytes >= 255 && restrictMessageSize)
|
||||
{
|
||||
msg.Write(false);
|
||||
DebugConsole.ThrowError($"Error when writing character spawn data: status data caused the length of the message to exceed 255 bytes ({msg.LengthBytes} + {tempBuffer.LengthBytes})");
|
||||
if (msgLengthBeforeStatus < 255)
|
||||
{
|
||||
string errorMsg = $"Error when writing character spawn data: status data caused the length of the message to exceed 255 bytes ({msgLengthBeforeStatus} + {tempBuffer.LengthBytes})";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Character.WriteSpawnData:TooMuchDataForStatus", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -716,7 +718,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
DebugConsole.Log("Character spawn message length: " + (msg.LengthBytes - msgLength));
|
||||
DebugConsole.Log("Character spawn message length: " + (msg.LengthBytes - initialMsgLength));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user