Unstable 0.17.1.0
This commit is contained in:
@@ -56,7 +56,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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,415 +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<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 (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 != 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);
|
||||
}
|
||||
else if (type == 2)
|
||||
{
|
||||
var objective = controller.ObjectiveManager.CurrentObjective;
|
||||
bool validObjective = objective != null && objective.Identifier != Identifier.Empty;
|
||||
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 StatusEventData _:
|
||||
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}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -656,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)
|
||||
{
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using FarseerPhysics;
|
||||
using Barotrauma.Items.Components;
|
||||
using System.Threading;
|
||||
using Barotrauma.IO;
|
||||
using System.Text;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -1187,7 +1183,7 @@ namespace Barotrauma
|
||||
NewMessage("*****************", Color.Lime);
|
||||
GameServer.Log("Console command \"restart\" executed: closing the server...", ServerLog.MessageType.ServerMessage);
|
||||
GameMain.Instance.CloseServer();
|
||||
GameMain.Instance.TryStartChildServerRelay();
|
||||
Program.TryStartChildServerRelay(GameMain.Instance.CommandLineArgs);
|
||||
GameMain.Instance.StartServer();
|
||||
}));
|
||||
|
||||
@@ -1400,17 +1396,71 @@ namespace Barotrauma
|
||||
commands.Add(new Command("eventdata", "", (string[] args) =>
|
||||
{
|
||||
if (args.Length == 0) { return; }
|
||||
if (!UInt16.TryParse(args[0], NumberStyles.Any, CultureInfo.InvariantCulture, out ushort eventId)) { return; }
|
||||
ServerEntityEvent ev = GameMain.Server.EntityEventManager.Events.Find(ev => ev.ID == eventId);
|
||||
if (ev != null)
|
||||
|
||||
string indentStr(string s)
|
||||
=> string.Join('\n', s.Split('\n').Select(sub => $" {sub}"));
|
||||
|
||||
string eventDataRip(object data)
|
||||
{
|
||||
if (data is null) { return "[NULL]"; }
|
||||
var type = data.GetType();
|
||||
|
||||
string retVal = $"{type.FullName} ";
|
||||
|
||||
if (type.IsPrimitive
|
||||
|| type.IsEnum
|
||||
|| type.IsClass)
|
||||
{
|
||||
retVal += data.ToString();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
retVal += "{\n";
|
||||
var fields = data.GetType().GetFields();
|
||||
foreach (var field in fields)
|
||||
{
|
||||
retVal += indentStr($"{field.Name}: {eventDataRip(field.GetValue(data))}")+"\n";
|
||||
}
|
||||
|
||||
retVal += "}";
|
||||
retVal = retVal.Replace("{\n}", "{ }");
|
||||
return retVal;
|
||||
}
|
||||
|
||||
string eventDebugStr(ServerEntityEvent ev)
|
||||
{
|
||||
ushort eventId = ev.ID;
|
||||
|
||||
string entityData = "";
|
||||
if (ev.Entity is { ID: var entityId, Removed: var removed, IdFreed: var idFreed })
|
||||
{
|
||||
entityData = $"Entity ID: {entityId}; Entity removed: {removed}; Entity ID freed: {idFreed}";
|
||||
entityData = $"Entity ID: {entityId}\n" +
|
||||
$"Entity type {ev.Entity.GetType().Name}\n" +
|
||||
$"Entity removed: {removed}\n" +
|
||||
$"Entity ID freed: {idFreed}\n" +
|
||||
$"Event data: {eventDataRip(ev.Data)}\n";
|
||||
}
|
||||
NewMessage($"EventData {eventId}\n{entityData}", Color.Lime);
|
||||
//NewMessage(ev.StackTrace.CleanupStackTrace(), Color.Lime);
|
||||
|
||||
return $"EventData {eventId}\n{indentStr(entityData)}";
|
||||
}
|
||||
|
||||
IReadOnlyList<ServerEntityEvent> events = GameMain.Server.EntityEventManager.Events;
|
||||
ushort? eventId = null;
|
||||
if (args[0].Equals("latest", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
eventId = events.Max(e => e.ID);
|
||||
}
|
||||
else if (UInt16.TryParse(args[0], NumberStyles.Any, CultureInfo.InvariantCulture, out ushort id))
|
||||
{
|
||||
eventId = id;
|
||||
}
|
||||
IEnumerable<ServerEntityEvent> matchedEvents = GameMain.Server.EntityEventManager.Events.Where(ev
|
||||
=> eventId.HasValue
|
||||
? ev.ID == eventId
|
||||
: eventDebugStr(ev).Contains(args[0], StringComparison.OrdinalIgnoreCase));
|
||||
foreach (var ev in matchedEvents)
|
||||
{
|
||||
NewMessage(eventDebugStr(ev), Color.Lime);
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -1665,28 +1715,27 @@ namespace Barotrauma
|
||||
(Client client, Vector2 cursorWorldPos, string[] args) =>
|
||||
{
|
||||
if (args.Length < 2) return;
|
||||
|
||||
AfflictionPrefab afflictionPrefab = AfflictionPrefab.List.FirstOrDefault(a =>
|
||||
a.Name.Equals(args[0], StringComparison.OrdinalIgnoreCase) ||
|
||||
a.Identifier == args[0]);
|
||||
string affliction = args[0];
|
||||
AfflictionPrefab afflictionPrefab = AfflictionPrefab.List.FirstOrDefault(a => a.Identifier == affliction);
|
||||
if (afflictionPrefab == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Affliction \"" + args[0] + "\" not found.", client, Color.Red);
|
||||
afflictionPrefab = AfflictionPrefab.List.FirstOrDefault(a => a.Name.Equals(affliction, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
if (afflictionPrefab == null)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Affliction \"" + affliction + "\" not found.", client, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!float.TryParse(args[1], out float afflictionStrength))
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("\"" + args[1] + "\" is not a valid affliction strength.", client, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
bool relativeStrength = false;
|
||||
if (args.Length > 4)
|
||||
{
|
||||
bool.TryParse(args[4], out relativeStrength);
|
||||
}
|
||||
|
||||
Character targetCharacter = (args.Length <= 2) ? client.Character : FindMatchingCharacter(args.Skip(2).ToArray());
|
||||
if (targetCharacter != null)
|
||||
{
|
||||
@@ -2217,18 +2266,50 @@ namespace Barotrauma
|
||||
GameMain.Server.SendConsoleMessage("No campaign active!", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
Character targetCharacter = null;
|
||||
|
||||
if (args.Length >= 2)
|
||||
{
|
||||
targetCharacter = FindMatchingCharacter(args.Skip(1).ToArray());
|
||||
}
|
||||
|
||||
if (int.TryParse(args[0], out int money))
|
||||
{
|
||||
campaign.Money += money;
|
||||
Wallet wallet = targetCharacter is null ? campaign.Bank : targetCharacter.Wallet;
|
||||
wallet.Give(money);
|
||||
GameAnalyticsManager.AddMoneyGainedEvent(money, GameAnalyticsManager.MoneySource.Cheat, "console");
|
||||
campaign.LastUpdateID++;
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage($"\"{args[0]}\" is not a valid numeric value.", senderClient, Color.Red);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
AssignOnClientRequestExecute(
|
||||
"showmoney",
|
||||
(Client senderClient, Vector2 cursorWorldPos, string[] args) =>
|
||||
{
|
||||
if (!(GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign))
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("No campaign active!", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append($"Bank: {campaign.Bank.Balance}");
|
||||
foreach (Client client in GameMain.Server.ConnectedClients)
|
||||
{
|
||||
if (client.Character is null) { continue; }
|
||||
sb.Append(Environment.NewLine);
|
||||
sb.Append($"{client.Name}: {client.Character.Wallet.Balance}");
|
||||
}
|
||||
GameMain.Server.SendConsoleMessage(sb.ToString(), senderClient);
|
||||
}
|
||||
);
|
||||
|
||||
AssignOnClientRequestExecute(
|
||||
"campaigndestination|setcampaigndestination",
|
||||
(Client senderClient, Vector2 cursorWorldPos, string[] args) =>
|
||||
@@ -2327,7 +2408,7 @@ namespace Barotrauma
|
||||
GameMain.Server.SendConsoleMessage($"Set {character.Name}'s {skillIdentifier} level to {level}", senderClient);
|
||||
}
|
||||
|
||||
GameMain.NetworkMember.CreateEntityEvent(character, new object[] { NetEntityEvent.Type.UpdateSkills });
|
||||
GameMain.NetworkMember.CreateEntityEvent(character, new Character.UpdateSkillsEventData());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -141,20 +141,6 @@ namespace Barotrauma
|
||||
}*/
|
||||
}
|
||||
|
||||
public bool TryStartChildServerRelay()
|
||||
{
|
||||
for (int i = 0; i < CommandLineArgs.Length; i++)
|
||||
{
|
||||
switch (CommandLineArgs[i].Trim())
|
||||
{
|
||||
case "-pipes":
|
||||
ChildServerRelay.Start(CommandLineArgs[i + 2], CommandLineArgs[i + 1]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void StartServer()
|
||||
{
|
||||
string name = "Server";
|
||||
@@ -299,7 +285,6 @@ namespace Barotrauma
|
||||
Hyper.ComponentModel.HyperTypeDescriptionProvider.Add(typeof(Items.Components.ItemComponent));
|
||||
Hyper.ComponentModel.HyperTypeDescriptionProvider.Add(typeof(Hull));
|
||||
|
||||
TryStartChildServerRelay();
|
||||
Init();
|
||||
StartServer();
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
using Barotrauma.Extensions;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class CargoManager
|
||||
{
|
||||
public void SellBackPurchasedItems(List<PurchasedItem> itemsToSell)
|
||||
public void SellBackPurchasedItems(List<PurchasedItem> itemsToSell, Client client = null)
|
||||
{
|
||||
// Check all the prices before starting the transaction
|
||||
// to make sure the modifiers stay the same for the whole transaction
|
||||
@@ -15,12 +16,12 @@ namespace Barotrauma
|
||||
{
|
||||
var itemValue = item.Quantity * buyValues[item.ItemPrefab];
|
||||
Location.StoreCurrentBalance -= itemValue;
|
||||
campaign.Money += itemValue;
|
||||
campaign.GetWallet(client).Give(itemValue);
|
||||
PurchasedItems.Remove(item);
|
||||
}
|
||||
}
|
||||
|
||||
public void BuyBackSoldItems(List<SoldItem> itemsToBuy)
|
||||
public void BuyBackSoldItems(List<SoldItem> itemsToBuy, Client client)
|
||||
{
|
||||
// Check all the prices before starting the transaction
|
||||
// to make sure the modifiers stay the same for the whole transaction
|
||||
@@ -30,12 +31,12 @@ namespace Barotrauma
|
||||
int itemValue = sellValues[item.ItemPrefab];
|
||||
if (Location.StoreCurrentBalance < itemValue || item.Removed) { continue; }
|
||||
Location.StoreCurrentBalance += itemValue;
|
||||
campaign.Money -= itemValue;
|
||||
campaign.Bank.TryDeduct(itemValue);
|
||||
SoldItems.Remove(item);
|
||||
}
|
||||
}
|
||||
|
||||
public void SellItems(List<SoldItem> itemsToSell)
|
||||
public void SellItems(List<SoldItem> itemsToSell, Client client)
|
||||
{
|
||||
bool canAddToRemoveQueue = (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer) && Entity.Spawner != null;
|
||||
IEnumerable<Item> sellableItemsInSub = Enumerable.Empty<Item>();
|
||||
@@ -67,7 +68,7 @@ namespace Barotrauma
|
||||
}
|
||||
SoldItems.Add(item);
|
||||
Location.StoreCurrentBalance -= itemValue;
|
||||
campaign.Money += itemValue;
|
||||
campaign.Bank.Give(itemValue);
|
||||
GameAnalyticsManager.AddMoneyGainedEvent(itemValue, GameAnalyticsManager.MoneySource.Store, item.ItemPrefab.Identifier.Value);
|
||||
}
|
||||
OnSoldItemsChanged?.Invoke();
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
internal partial class Wallet
|
||||
{
|
||||
private readonly Queue<WalletChangedData> transactions = new Queue<WalletChangedData>();
|
||||
|
||||
partial void SettingsChanged(Option<int> balanceChanged, Option<int> rewardChanged)
|
||||
{
|
||||
transactions.Enqueue(new WalletChangedData
|
||||
{
|
||||
BalanceChanged = balanceChanged,
|
||||
RewardDistributionChanged = rewardChanged
|
||||
});
|
||||
}
|
||||
|
||||
public bool HasTransactions() => transactions.Count > 0;
|
||||
|
||||
public NetWalletTransaction DequeueAndMergeTransactions(ushort id)
|
||||
{
|
||||
Option<ushort> targetCharacterID = id == Entity.NullEntityID ? Option<ushort>.None() : Option<ushort>.Some(id);
|
||||
|
||||
WalletChangedData changedData = new WalletChangedData
|
||||
{
|
||||
BalanceChanged = Option<int>.None(),
|
||||
RewardDistributionChanged = Option<int>.None()
|
||||
};
|
||||
|
||||
while (transactions.TryDequeue(out WalletChangedData transactionOut))
|
||||
{
|
||||
changedData = changedData.MergeInto(transactionOut);
|
||||
}
|
||||
|
||||
return new NetWalletTransaction
|
||||
{
|
||||
CharacterID = targetCharacterID,
|
||||
ChangedData = changedData,
|
||||
Info = CreateWalletInfo()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
+43
-2
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Networking;
|
||||
using System.Globalization;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
@@ -32,8 +31,26 @@ namespace Barotrauma
|
||||
{
|
||||
CharacterInfo.SaveOrderData(client.CharacterInfo, OrderData);
|
||||
}
|
||||
|
||||
if (client.Character?.Wallet.Save() is { } walletSave)
|
||||
{
|
||||
WalletData = walletSave;
|
||||
}
|
||||
}
|
||||
|
||||
public void Refresh(Character character)
|
||||
{
|
||||
healthData = new XElement("health");
|
||||
character.CharacterHealth.Save(healthData);
|
||||
if (character.Inventory != null)
|
||||
{
|
||||
itemData = new XElement("inventory");
|
||||
Character.SaveInventory(character.Inventory, itemData);
|
||||
}
|
||||
OrderData = new XElement("orders");
|
||||
CharacterInfo.SaveOrderData(character.Info, OrderData);
|
||||
WalletData = character.Wallet.Save();
|
||||
}
|
||||
|
||||
public CharacterCampaignData(XElement element)
|
||||
{
|
||||
@@ -63,6 +80,9 @@ namespace Barotrauma
|
||||
case "orders":
|
||||
OrderData = subElement;
|
||||
break;
|
||||
case Wallet.LowerCaseSaveElementName:
|
||||
WalletData = subElement;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -98,7 +118,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
public void ApplyHealthData(Character character)
|
||||
{
|
||||
{
|
||||
CharacterInfo.ApplyHealthData(character, healthData);
|
||||
}
|
||||
|
||||
@@ -106,5 +126,26 @@ namespace Barotrauma
|
||||
{
|
||||
CharacterInfo.ApplyOrderData(character, OrderData);
|
||||
}
|
||||
|
||||
public void ApplyWalletData(Character character)
|
||||
{
|
||||
character.Wallet = new Wallet(WalletData);
|
||||
}
|
||||
|
||||
public XElement Save()
|
||||
{
|
||||
XElement element = new XElement("CharacterCampaignData",
|
||||
new XAttribute("name", Name),
|
||||
new XAttribute("endpoint", ClientEndPoint),
|
||||
new XAttribute("steamid", SteamID));
|
||||
|
||||
CharacterInfo?.Save(element);
|
||||
if (itemData != null) { element.Add(itemData); }
|
||||
if (healthData != null) { element.Add(healthData); }
|
||||
if (OrderData != null) { element.Add(OrderData); }
|
||||
if (WalletData != null) { element.Add(WalletData); }
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+176
-50
@@ -12,6 +12,22 @@ namespace Barotrauma
|
||||
partial class MultiPlayerCampaign : CampaignMode
|
||||
{
|
||||
private readonly List<CharacterCampaignData> characterData = new List<CharacterCampaignData>();
|
||||
private readonly Dictionary<ushort, Wallet> walletsToCheck = new Dictionary<ushort, Wallet>();
|
||||
private readonly HashSet<NetWalletTransaction> transactions = new HashSet<NetWalletTransaction>();
|
||||
private const float clientCheckInterval = 10;
|
||||
private float clientCheckTimer = clientCheckInterval;
|
||||
|
||||
public override Wallet GetWallet(Client client = null)
|
||||
{
|
||||
if (client is null) { throw new ArgumentNullException(nameof(client), "Client should not be null in multiplayer"); }
|
||||
|
||||
if (client.Character is { } character)
|
||||
{
|
||||
return character.Wallet;
|
||||
}
|
||||
|
||||
return Wallet.Invalid;
|
||||
}
|
||||
|
||||
private bool forceMapUI;
|
||||
public bool ForceMapUI
|
||||
@@ -229,8 +245,7 @@ namespace Barotrauma
|
||||
characterInfo.CauseOfDeath = null;
|
||||
}
|
||||
c.CharacterInfo = characterInfo;
|
||||
characterData.RemoveAll(cd => cd.MatchesClient(c));
|
||||
characterData.Add(new CharacterCampaignData(c));
|
||||
SetClientCharacterData(c);
|
||||
}
|
||||
|
||||
//refresh the character data of clients who aren't in the server anymore
|
||||
@@ -412,8 +427,8 @@ namespace Barotrauma
|
||||
LastSaveID++;
|
||||
}
|
||||
|
||||
public bool CanPurchaseSub(SubmarineInfo info)
|
||||
=> info.Price <= Money && GetCampaignSubs().Contains(info);
|
||||
public bool CanPurchaseSub(SubmarineInfo info, Client client)
|
||||
=> GetWallet(client).CanAfford(info.Price) && GetCampaignSubs().Contains(info);
|
||||
|
||||
public void DiscardClientCharacterData(Client client)
|
||||
{
|
||||
@@ -487,6 +502,54 @@ namespace Barotrauma
|
||||
KeepCharactersCloseToOutpost(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateClientsToCheck(deltaTime);
|
||||
UpdateWallets();
|
||||
}
|
||||
|
||||
private void UpdateClientsToCheck(float deltaTime)
|
||||
{
|
||||
if (clientCheckTimer < clientCheckInterval)
|
||||
{
|
||||
clientCheckTimer += deltaTime;
|
||||
return;
|
||||
}
|
||||
|
||||
clientCheckTimer = 0;
|
||||
walletsToCheck.Clear();
|
||||
walletsToCheck.Add(0, Bank);
|
||||
|
||||
foreach (Character character in Mission.GetSalaryEligibleCrew())
|
||||
{
|
||||
walletsToCheck.Add(character.ID, character.Wallet);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateWallets()
|
||||
{
|
||||
foreach (var (id, wallet) in walletsToCheck)
|
||||
{
|
||||
if (wallet.HasTransactions())
|
||||
{
|
||||
transactions.Add(wallet.DequeueAndMergeTransactions(id));
|
||||
}
|
||||
}
|
||||
|
||||
if (transactions.Count == 0) { return; }
|
||||
|
||||
NetWalletUpdate walletUpdate = new NetWalletUpdate
|
||||
{
|
||||
Transactions = transactions.ToArray()
|
||||
};
|
||||
|
||||
transactions.Clear();
|
||||
|
||||
foreach (Client client in GameMain.Server.ConnectedClients)
|
||||
{
|
||||
IWriteMessage msg = new WriteOnlyMessage().WithHeader(ServerPacketHeader.MONEY);
|
||||
((INetSerializableStruct)walletUpdate).Write(msg);
|
||||
GameMain.Server?.ServerPeer?.Send(msg, client.Connection, DeliveryMethod.Reliable);
|
||||
}
|
||||
}
|
||||
|
||||
public override void End(TransitionType transitionType = TransitionType.None)
|
||||
@@ -530,7 +593,6 @@ namespace Barotrauma
|
||||
|
||||
msg.Write(ForceMapUI);
|
||||
|
||||
msg.Write(Money);
|
||||
msg.Write(PurchasedHullRepairs);
|
||||
msg.Write(PurchasedItemRepairs);
|
||||
msg.Write(PurchasedLostShuttles);
|
||||
@@ -644,7 +706,7 @@ namespace Barotrauma
|
||||
{
|
||||
string itemPrefabIdentifier = msg.ReadString();
|
||||
int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
|
||||
buyCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
|
||||
buyCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity, sender));
|
||||
}
|
||||
|
||||
UInt16 subSellCrateItemCount = msg.ReadUInt16();
|
||||
@@ -653,7 +715,7 @@ namespace Barotrauma
|
||||
{
|
||||
string itemPrefabIdentifier = msg.ReadString();
|
||||
int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
|
||||
subSellCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
|
||||
subSellCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity, sender));
|
||||
}
|
||||
|
||||
UInt16 purchasedItemCount = msg.ReadUInt16();
|
||||
@@ -662,7 +724,7 @@ namespace Barotrauma
|
||||
{
|
||||
string itemPrefabIdentifier = msg.ReadString();
|
||||
int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
|
||||
purchasedItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
|
||||
purchasedItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity, sender));
|
||||
}
|
||||
|
||||
UInt16 soldItemCount = msg.ReadUInt16();
|
||||
@@ -711,57 +773,63 @@ namespace Barotrauma
|
||||
int hullRepairCost = location?.GetAdjustedMechanicalCost(HullRepairCost) ?? HullRepairCost;
|
||||
int itemRepairCost = location?.GetAdjustedMechanicalCost(ItemRepairCost) ?? ItemRepairCost;
|
||||
int shuttleRetrieveCost = location?.GetAdjustedMechanicalCost(ShuttleReplaceCost) ?? ShuttleReplaceCost;
|
||||
if (purchasedHullRepairs != this.PurchasedHullRepairs)
|
||||
Wallet personalWallet = GetWallet(sender);
|
||||
|
||||
if (purchasedHullRepairs != PurchasedHullRepairs)
|
||||
{
|
||||
if (purchasedHullRepairs && Money >= hullRepairCost)
|
||||
switch (purchasedHullRepairs)
|
||||
{
|
||||
this.PurchasedHullRepairs = true;
|
||||
Money -= hullRepairCost;
|
||||
GameAnalyticsManager.AddMoneySpentEvent(hullRepairCost, GameAnalyticsManager.MoneySink.Service, "hullrepairs");
|
||||
}
|
||||
else if (!purchasedHullRepairs)
|
||||
{
|
||||
this.PurchasedHullRepairs = false;
|
||||
Money += hullRepairCost;
|
||||
case true when personalWallet.CanAfford(hullRepairCost):
|
||||
personalWallet.Deduct(hullRepairCost);
|
||||
PurchasedHullRepairs = true;
|
||||
GameAnalyticsManager.AddMoneySpentEvent(hullRepairCost, GameAnalyticsManager.MoneySink.Service, "hullrepairs");
|
||||
break;
|
||||
case false:
|
||||
PurchasedHullRepairs = false;
|
||||
personalWallet.Refund(hullRepairCost);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (purchasedItemRepairs != this.PurchasedItemRepairs)
|
||||
|
||||
if (purchasedItemRepairs != PurchasedItemRepairs)
|
||||
{
|
||||
if (purchasedItemRepairs && Money >= itemRepairCost)
|
||||
switch (purchasedItemRepairs)
|
||||
{
|
||||
this.PurchasedItemRepairs = true;
|
||||
Money -= itemRepairCost;
|
||||
GameAnalyticsManager.AddMoneySpentEvent(itemRepairCost, GameAnalyticsManager.MoneySink.Service, "devicerepairs");
|
||||
}
|
||||
else if (!purchasedItemRepairs)
|
||||
{
|
||||
this.PurchasedItemRepairs = false;
|
||||
Money += itemRepairCost;
|
||||
case true when personalWallet.CanAfford(itemRepairCost):
|
||||
personalWallet.Deduct(itemRepairCost);
|
||||
PurchasedItemRepairs = true;
|
||||
GameAnalyticsManager.AddMoneySpentEvent(itemRepairCost, GameAnalyticsManager.MoneySink.Service, "devicerepairs");
|
||||
break;
|
||||
case false:
|
||||
PurchasedItemRepairs = false;
|
||||
personalWallet.Refund(itemRepairCost);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (purchasedLostShuttles != this.PurchasedLostShuttles)
|
||||
|
||||
if (purchasedLostShuttles != PurchasedLostShuttles)
|
||||
{
|
||||
if (GameMain.GameSession?.SubmarineInfo != null &&
|
||||
GameMain.GameSession.SubmarineInfo.LeftBehindSubDockingPortOccupied)
|
||||
if (GameMain.GameSession?.SubmarineInfo != null && GameMain.GameSession.SubmarineInfo.LeftBehindSubDockingPortOccupied)
|
||||
{
|
||||
GameMain.Server.SendDirectChatMessage(TextManager.FormatServerMessage("ReplaceShuttleDockingPortOccupied"), sender, ChatMessageType.MessageBox);
|
||||
}
|
||||
else if (purchasedLostShuttles && Money >= shuttleRetrieveCost)
|
||||
else if (purchasedLostShuttles && personalWallet.TryDeduct(shuttleRetrieveCost))
|
||||
{
|
||||
this.PurchasedLostShuttles = true;
|
||||
Money -= shuttleRetrieveCost;
|
||||
PurchasedLostShuttles = true;
|
||||
GameAnalyticsManager.AddMoneySpentEvent(shuttleRetrieveCost, GameAnalyticsManager.MoneySink.Service, "retrieveshuttle");
|
||||
}
|
||||
else if (!purchasedItemRepairs)
|
||||
{
|
||||
this.PurchasedLostShuttles = false;
|
||||
Money += shuttleRetrieveCost;
|
||||
PurchasedLostShuttles = false;
|
||||
personalWallet.Refund(shuttleRetrieveCost);
|
||||
}
|
||||
}
|
||||
|
||||
if (currentLocIndex < Map.Locations.Count && Map.AllowDebugTeleport)
|
||||
{
|
||||
Map.SetLocation(currentLocIndex);
|
||||
}
|
||||
|
||||
Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex);
|
||||
if (Map.SelectedLocation == null) { Map.SelectRandomLocation(preferUndiscovered: true); }
|
||||
if (Map.SelectedConnection != null) { Map.SelectMission(selectedMissionIndices); }
|
||||
@@ -772,18 +840,18 @@ namespace Barotrauma
|
||||
if (allowedToManageCampaign || allowedToUseStore || AllowedToManageCampaign(sender, ClientPermissions.BuyItems))
|
||||
{
|
||||
var currentBuyCrateItems = new List<PurchasedItem>(CargoManager.ItemsInBuyCrate);
|
||||
currentBuyCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInBuyCrate(i.ItemPrefab, -i.Quantity));
|
||||
buyCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInBuyCrate(i.ItemPrefab, i.Quantity));
|
||||
currentBuyCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInBuyCrate(i.ItemPrefab, -i.Quantity, sender));
|
||||
buyCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInBuyCrate(i.ItemPrefab, i.Quantity, sender));
|
||||
CargoManager.SellBackPurchasedItems(new List<PurchasedItem>(CargoManager.PurchasedItems));
|
||||
CargoManager.PurchaseItems(purchasedItems, false);
|
||||
CargoManager.PurchaseItems(purchasedItems, false, sender);
|
||||
}
|
||||
|
||||
bool allowedToSellSubItems = AllowedToManageCampaign(sender, ClientPermissions.SellSubItems);
|
||||
if (allowedToManageCampaign || allowedToUseStore || allowedToSellSubItems)
|
||||
{
|
||||
var currentSubSellCrateItems = new List<PurchasedItem>(CargoManager.ItemsInSellFromSubCrate);
|
||||
currentSubSellCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInSubSellCrate(i.ItemPrefab, -i.Quantity));
|
||||
subSellCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInSubSellCrate(i.ItemPrefab, i.Quantity));
|
||||
currentSubSellCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInSubSellCrate(i.ItemPrefab, -i.Quantity, sender));
|
||||
subSellCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInSubSellCrate(i.ItemPrefab, i.Quantity, sender));
|
||||
}
|
||||
|
||||
bool allowedToSellInventoryItems = AllowedToManageCampaign(sender, ClientPermissions.SellInventoryItems);
|
||||
@@ -791,29 +859,29 @@ namespace Barotrauma
|
||||
{
|
||||
// for some reason CargoManager.SoldItem is never cleared by the server, I've added a check to SellItems that ignores all
|
||||
// sold items that are removed so they should be discarded on the next message
|
||||
CargoManager.BuyBackSoldItems(new List<SoldItem>(CargoManager.SoldItems));
|
||||
CargoManager.SellItems(soldItems);
|
||||
CargoManager.BuyBackSoldItems(new List<SoldItem>(CargoManager.SoldItems), sender);
|
||||
CargoManager.SellItems(soldItems, sender);
|
||||
}
|
||||
else if (allowedToSellInventoryItems || allowedToSellSubItems)
|
||||
{
|
||||
if (allowedToSellInventoryItems)
|
||||
{
|
||||
CargoManager.BuyBackSoldItems(new List<SoldItem>(CargoManager.SoldItems.Where(i => i.Origin == SoldItem.SellOrigin.Character)));
|
||||
CargoManager.BuyBackSoldItems(new List<SoldItem>(CargoManager.SoldItems.Where(i => i.Origin == SoldItem.SellOrigin.Character)), sender);
|
||||
soldItems.RemoveAll(i => i.Origin != SoldItem.SellOrigin.Character);
|
||||
}
|
||||
else
|
||||
{
|
||||
CargoManager.BuyBackSoldItems(new List<SoldItem>(CargoManager.SoldItems.Where(i => i.Origin == SoldItem.SellOrigin.Submarine)));
|
||||
CargoManager.BuyBackSoldItems(new List<SoldItem>(CargoManager.SoldItems.Where(i => i.Origin == SoldItem.SellOrigin.Submarine)), sender);
|
||||
soldItems.RemoveAll(i => i.Origin != SoldItem.SellOrigin.Submarine);
|
||||
}
|
||||
CargoManager.SellItems(soldItems);
|
||||
CargoManager.SellItems(soldItems, sender);
|
||||
}
|
||||
|
||||
if (allowedToManageCampaign)
|
||||
{
|
||||
foreach (var (prefab, category, _) in purchasedUpgrades)
|
||||
{
|
||||
UpgradeManager.PurchaseUpgrade(prefab, category);
|
||||
UpgradeManager.PurchaseUpgrade(prefab, category, client: sender);
|
||||
|
||||
// unstable logging
|
||||
int price = prefab.Price.GetBuyprice(UpgradeManager.GetUpgradeLevel(prefab, category), Map?.CurrentLocation);
|
||||
@@ -828,7 +896,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
UpgradeManager.PurchaseItemSwap(purchasedItemSwap.ItemToRemove, purchasedItemSwap.ItemToInstall);
|
||||
UpgradeManager.PurchaseItemSwap(purchasedItemSwap.ItemToRemove, purchasedItemSwap.ItemToInstall, client: sender);
|
||||
}
|
||||
}
|
||||
foreach (Item item in Item.ItemList)
|
||||
@@ -842,6 +910,64 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerReadMoney(IReadMessage msg, Client sender)
|
||||
{
|
||||
NetWalletTransfer transfer = INetSerializableStruct.Read<NetWalletTransfer>(msg);
|
||||
|
||||
switch (transfer.Sender)
|
||||
{
|
||||
case Some<ushort> { Value: var id }:
|
||||
|
||||
if (id != sender.CharacterID && !AllowedToManageCampaign(sender)) { return; }
|
||||
|
||||
Wallet wallet = GetWalletByID(id);
|
||||
if (wallet is InvalidWallet) { return; }
|
||||
|
||||
TransferMoney(wallet);
|
||||
break;
|
||||
|
||||
case None<ushort> _:
|
||||
if (!AllowedToManageCampaign(sender)) { return; }
|
||||
|
||||
TransferMoney(Bank);
|
||||
break;
|
||||
}
|
||||
|
||||
void TransferMoney(Wallet from)
|
||||
{
|
||||
if (!from.TryDeduct(transfer.Amount)) { return; }
|
||||
|
||||
switch (transfer.Receiver)
|
||||
{
|
||||
case Some<ushort> { Value: var id }:
|
||||
Wallet wallet = GetWalletByID(id);
|
||||
if (wallet is InvalidWallet) { return; }
|
||||
|
||||
wallet.Give(transfer.Amount);
|
||||
break;
|
||||
case None<ushort> _:
|
||||
Bank.Give(transfer.Amount);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Wallet GetWalletByID(ushort id)
|
||||
{
|
||||
Character targetCharacter = Character.CharacterList.FirstOrDefault(c => c.ID == id);
|
||||
return targetCharacter is null ? Wallet.Invalid : targetCharacter.Wallet;
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerReadRewardDistribution(IReadMessage msg, Client sender)
|
||||
{
|
||||
NetWalletSalaryUpdate update = INetSerializableStruct.Read<NetWalletSalaryUpdate>(msg);
|
||||
|
||||
if (!AllowedToManageCampaign(sender)) { return; }
|
||||
|
||||
Character targetCharacter = Character.CharacterList.FirstOrDefault(c => c.ID == update.Target);
|
||||
targetCharacter?.Wallet.SetRewardDistrubiton(update.NewRewardDistribution);
|
||||
}
|
||||
|
||||
public void ServerReadCrew(IReadMessage msg, Client sender)
|
||||
{
|
||||
int[] pendingHires = null;
|
||||
@@ -928,7 +1054,7 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (CharacterInfo hireInfo in location.HireManager.PendingHires)
|
||||
{
|
||||
if (TryHireCharacter(location, hireInfo))
|
||||
if (TryHireCharacter(location, hireInfo, sender))
|
||||
{
|
||||
hiredCharacters.Add(hireInfo);
|
||||
};
|
||||
@@ -1045,7 +1171,6 @@ namespace Barotrauma
|
||||
{
|
||||
element.Add(new XAttribute("campaignid", CampaignID));
|
||||
XElement modeElement = new XElement("MultiPlayerCampaign",
|
||||
new XAttribute("money", Money),
|
||||
new XAttribute("purchasedlostshuttles", PurchasedLostShuttles),
|
||||
new XAttribute("purchasedhullrepairs", PurchasedHullRepairs),
|
||||
new XAttribute("purchaseditemrepairs", PurchasedItemRepairs),
|
||||
@@ -1053,6 +1178,7 @@ namespace Barotrauma
|
||||
|
||||
modeElement.Add(Settings.Save());
|
||||
modeElement.Add(SaveStats());
|
||||
modeElement.Add(Bank.Save());
|
||||
CampaignMetadata?.Save(modeElement);
|
||||
Map.Save(modeElement);
|
||||
CargoManager?.SavePurchasedItems(modeElement);
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (CheckRateLimit(client) == RateLimitResult.LimitReached) { return; }
|
||||
|
||||
HealRequestResult result = HealAllPending();
|
||||
HealRequestResult result = HealAllPending(client: client);
|
||||
ServerSend(new NetHealRequest { Result = result }, NetworkHeader.HEAL_PENDING, DeliveryMethod.Reliable, reponseClient: client);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class DockingPort : ItemComponent, IDrawableComponent, IServerSerializable
|
||||
{
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
msg.Write(docked);
|
||||
|
||||
|
||||
@@ -6,6 +6,16 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Door
|
||||
{
|
||||
private readonly struct EventData : IEventData
|
||||
{
|
||||
public readonly bool ForcedOpen;
|
||||
|
||||
public EventData(bool forcedOpen)
|
||||
{
|
||||
ForcedOpen = forcedOpen;
|
||||
}
|
||||
}
|
||||
|
||||
partial void SetState(bool open, bool isNetworkMessage, bool sendNetworkMessage, bool forcedOpen)
|
||||
{
|
||||
if (IsStuck || isOpen == open)
|
||||
@@ -19,17 +29,18 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (sendNetworkMessage)
|
||||
{
|
||||
GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ComponentState, item.GetComponentIndex(this), forcedOpen });
|
||||
item.CreateServerEvent(this, new EventData(forcedOpen));
|
||||
}
|
||||
}
|
||||
|
||||
public override void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public override void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
base.ServerWrite(msg, c, extraData);
|
||||
bool forcedOpen = TryExtractEventData<EventData>(extraData, out var eventData) && eventData.ForcedOpen;
|
||||
base.ServerEventWrite(msg, c, extraData);
|
||||
|
||||
msg.Write(isOpen);
|
||||
msg.Write(isBroken);
|
||||
msg.Write(extraData.Length == 3 ? (bool)extraData[2] : false); //forced open
|
||||
msg.Write(forcedOpen); //forced open
|
||||
msg.Write(isStuck);
|
||||
msg.Write(isJammed);
|
||||
msg.WriteRangedSingle(stuck, 0.0f, 100.0f, 8);
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class GeneticMaterial : ItemComponent
|
||||
{
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
msg.Write(tainted);
|
||||
if (tainted)
|
||||
|
||||
@@ -6,6 +6,16 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
internal partial class Growable
|
||||
{
|
||||
private readonly struct EventData : IEventData
|
||||
{
|
||||
public readonly int Offset;
|
||||
|
||||
public EventData(int offset)
|
||||
{
|
||||
Offset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
private const int serverHealthUpdateDelay = 10;
|
||||
private int serverHealthUpdateTimer;
|
||||
|
||||
@@ -25,11 +35,12 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
msg.WriteRangedSingle(Health, 0f, (float) MaxHealth, 8);
|
||||
if (extraData != null && extraData.Length >= 3 && extraData[2] is int offset)
|
||||
if (TryExtractEventData(extraData, out EventData eventData))
|
||||
{
|
||||
int offset = eventData.Offset;
|
||||
int amountToSend = Math.Min(Vines.Count - offset, VineChunkSize);
|
||||
msg.WriteRangedInteger(offset, -1, MaximumVines);
|
||||
msg.WriteRangedInteger(amountToSend, 0, VineChunkSize);
|
||||
|
||||
@@ -5,9 +5,9 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Holdable : Pickable, IServerSerializable, IClientSerializable
|
||||
{
|
||||
public override void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public override void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
base.ServerWrite(msg, c, extraData);
|
||||
base.ServerEventWrite(msg, c, extraData);
|
||||
|
||||
bool writeAttachData = attachable && body != null;
|
||||
msg.Write(writeAttachData);
|
||||
@@ -19,7 +19,7 @@ namespace Barotrauma.Items.Components
|
||||
msg.Write(item.Submarine?.ID ?? Entity.NullEntityID);
|
||||
}
|
||||
|
||||
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
|
||||
public void ServerEventRead(IReadMessage msg, Client c)
|
||||
{
|
||||
Vector2 simPosition = new Vector2(msg.ReadSingle(), msg.ReadSingle());
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
private float lastSentDeattachTimer;
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
msg.Write(deattachTimer);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Xml.Linq;
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
@@ -18,7 +20,7 @@ namespace Barotrauma.Items.Components
|
||||
return true; //element processed
|
||||
}
|
||||
|
||||
public virtual void ServerAppendExtraData(ref object[] extraData) { }
|
||||
public virtual IEventData ServerGetEventData() => null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace Barotrauma.Items.Components
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
msg.Write(Text);
|
||||
lastSentText = Text;
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Barotrauma.Items.Components
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
msg.Write(IsActive);
|
||||
lastSentState = IsActive;
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Controller : ItemComponent, IServerSerializable
|
||||
{
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
msg.Write(State);
|
||||
msg.Write(user == null ? (ushort)0 : user.ID);
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Deconstructor : Powered, IServerSerializable, IClientSerializable
|
||||
{
|
||||
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
|
||||
public void ServerEventRead(IReadMessage msg, Client c)
|
||||
{
|
||||
bool active = msg.ReadBoolean();
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
msg.Write(user?.ID ?? 0);
|
||||
msg.Write(IsActive);
|
||||
|
||||
@@ -5,14 +5,14 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Engine : Powered, IServerSerializable, IClientSerializable
|
||||
{
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
//force can only be adjusted at 10% intervals -> no need for more accuracy than this
|
||||
msg.WriteRangedInteger((int)(targetForce / 10.0f), -10, 10);
|
||||
msg.Write(User == null ? Entity.NullEntityID : User.ID);
|
||||
}
|
||||
|
||||
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
|
||||
public void ServerEventRead(IReadMessage msg, Client c)
|
||||
{
|
||||
float newTargetForce = msg.ReadRangedInteger(-10, 10) * 10.0f;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Fabricator : Powered, IServerSerializable, IClientSerializable
|
||||
{
|
||||
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
|
||||
public void ServerEventRead(IReadMessage msg, Client c)
|
||||
{
|
||||
uint recipeHash = msg.ReadUInt32();
|
||||
|
||||
@@ -32,21 +32,33 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
private ulong serverEventId = 0;
|
||||
public override void ServerAppendExtraData(ref object[] extraData)
|
||||
{
|
||||
//ensuring the uniqueness of this event is
|
||||
//required for the fabricator to sync correctly;
|
||||
//otherwise, the event manager would incorrectly
|
||||
//assume that the client actually has the latest state
|
||||
Array.Resize(ref extraData, 4);
|
||||
extraData[2] = serverEventId;
|
||||
extraData[3] = State;
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
private readonly struct EventData : IEventData
|
||||
{
|
||||
FabricatorState stateAtEvent = (FabricatorState)extraData[3];
|
||||
msg.Write((byte)stateAtEvent);
|
||||
public readonly ulong ServerEventId;
|
||||
public readonly FabricatorState State;
|
||||
|
||||
public EventData(ulong serverEventId, FabricatorState state)
|
||||
{
|
||||
//ensuring the uniqueness of this event is
|
||||
//required for the fabricator to sync correctly;
|
||||
//otherwise, the event manager would incorrectly
|
||||
//assume that the client actually has the latest state
|
||||
ServerEventId = serverEventId;
|
||||
State = state;
|
||||
}
|
||||
}
|
||||
|
||||
public override IEventData ServerGetEventData()
|
||||
=> new EventData(serverEventId, State);
|
||||
|
||||
public override bool ValidateEventData(NetEntityEvent.IData data)
|
||||
=> TryExtractEventData<EventData>(data, out _);
|
||||
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
var componentData = ExtractEventData<EventData>(extraData);
|
||||
msg.Write((byte)componentData.State);
|
||||
msg.Write(timeUntilReady);
|
||||
uint recipeHash = fabricatedItem?.RecipeHash ?? 0;
|
||||
msg.Write(recipeHash);
|
||||
|
||||
+2
-2
@@ -4,12 +4,12 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class OutpostTerminal : ItemComponent, IClientSerializable, IServerSerializable
|
||||
{
|
||||
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
|
||||
public void ServerEventRead(IReadMessage msg, Client c)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Pump : Powered, IServerSerializable, IClientSerializable
|
||||
{
|
||||
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
|
||||
public void ServerEventRead(IReadMessage msg, Client c)
|
||||
{
|
||||
float newFlowPercentage = msg.ReadRangedInteger(-10, 10) * 10.0f;
|
||||
bool newIsActive = msg.ReadBoolean();
|
||||
@@ -36,7 +36,7 @@ namespace Barotrauma.Items.Components
|
||||
item.CreateServerEvent(this);
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
//flowpercentage can only be adjusted at 10% intervals -> no need for more accuracy than this
|
||||
msg.WriteRangedInteger((int)(flowPercentage / 10.0f), -10, 10);
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Barotrauma.Items.Components
|
||||
private float? nextServerLogWriteTime;
|
||||
private float lastServerLogWriteTime;
|
||||
|
||||
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
|
||||
public void ServerEventRead(IReadMessage msg, Client c)
|
||||
{
|
||||
bool autoTemp = msg.ReadBoolean();
|
||||
bool powerOn = msg.ReadBoolean();
|
||||
@@ -43,7 +43,7 @@ namespace Barotrauma.Items.Components
|
||||
unsentChanges = true;
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
msg.Write(autoTemp);
|
||||
msg.Write(_powerOn);
|
||||
|
||||
@@ -5,6 +5,16 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Steering : Powered, IServerSerializable, IClientSerializable
|
||||
{
|
||||
private readonly struct EventData : IEventData
|
||||
{
|
||||
public readonly bool DockingButtonClicked;
|
||||
|
||||
public EventData(bool dockingButtonClicked)
|
||||
{
|
||||
DockingButtonClicked = dockingButtonClicked;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: an enumeration would be much cleaner
|
||||
public bool MaintainPos;
|
||||
public bool LevelStartSelected;
|
||||
@@ -23,7 +33,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
|
||||
public void ServerRead(ClientNetObject type, IReadMessage msg, Barotrauma.Networking.Client c)
|
||||
public void ServerEventRead(IReadMessage msg, Client c)
|
||||
{
|
||||
bool autoPilot = msg.ReadBoolean();
|
||||
bool dockingButtonClicked = msg.ReadBoolean();
|
||||
@@ -58,7 +68,7 @@ namespace Barotrauma.Items.Components
|
||||
if (dockingButtonClicked)
|
||||
{
|
||||
item.SendSignal(new Signal("1", sender: c.Character), "toggle_docking");
|
||||
GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ComponentState, item.GetComponentIndex(this), true });
|
||||
item.CreateServerEvent(this, new EventData(dockingButtonClicked: true));
|
||||
}
|
||||
|
||||
if (!AutoPilot)
|
||||
@@ -88,10 +98,10 @@ namespace Barotrauma.Items.Components
|
||||
unsentChanges = true;
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Barotrauma.Networking.Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Barotrauma.Networking.Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
msg.Write(autoPilot);
|
||||
msg.Write(extraData.Length > 2 && extraData[2] is bool && (bool)extraData[2]);
|
||||
msg.Write(TryExtractEventData<EventData>(extraData, out var eventData) && eventData.DockingButtonClicked);
|
||||
|
||||
if (!autoPilot)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class PowerContainer : Powered, IDrawableComponent, IServerSerializable, IClientSerializable
|
||||
{
|
||||
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
|
||||
public void ServerEventRead(IReadMessage msg, Client c)
|
||||
{
|
||||
float newRechargeSpeed = msg.ReadRangedInteger(0, 10) / 10.0f * maxRechargeSpeed;
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Barotrauma.Items.Components
|
||||
item.CreateServerEvent(this);
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
msg.WriteRangedInteger((int)(rechargeSpeed / MaxRechargeSpeed * 10), 0, 10);
|
||||
|
||||
|
||||
@@ -5,11 +5,26 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Projectile : ItemComponent
|
||||
{
|
||||
private readonly struct EventData : IEventData
|
||||
{
|
||||
public readonly bool Launch;
|
||||
|
||||
public EventData(bool launch)
|
||||
{
|
||||
Launch = launch;
|
||||
}
|
||||
}
|
||||
|
||||
private float launchRot;
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public override bool ValidateEventData(NetEntityEvent.IData data)
|
||||
=> TryExtractEventData<EventData>(data, out _);
|
||||
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
bool launch = extraData.Length > 2 && (bool)extraData[2];
|
||||
var eventData = ExtractEventData<EventData>(extraData);
|
||||
bool launch = eventData.Launch;
|
||||
|
||||
msg.Write(launch);
|
||||
if (launch)
|
||||
{
|
||||
|
||||
@@ -7,13 +7,13 @@ namespace Barotrauma.Items.Components
|
||||
private Character prevLoggedFixer;
|
||||
private FixActions prevLoggedFixAction;
|
||||
|
||||
partial void InitProjSpecific(ContentXElement _)
|
||||
public override void OnMapLoaded()
|
||||
{
|
||||
//let the clients know the initial deterioration delay
|
||||
item.CreateServerEvent(this);
|
||||
}
|
||||
|
||||
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
|
||||
public void ServerEventRead(IReadMessage msg, Client c)
|
||||
{
|
||||
if (c.Character == null) { return; }
|
||||
var requestedFixAction = (FixActions)msg.ReadRangedInteger(0, 2);
|
||||
@@ -42,7 +42,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
msg.Write(deteriorationTimer);
|
||||
msg.Write(deteriorateAlwaysResetTimer);
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Rope : ItemComponent
|
||||
{
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
msg.Write(Snapped);
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
private float LastSentScanTimer { get; set; }
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
msg.Write(scanTimer);
|
||||
}
|
||||
|
||||
@@ -4,16 +4,16 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class ButtonTerminal : ItemComponent, IClientSerializable, IServerSerializable
|
||||
{
|
||||
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
|
||||
public void ServerEventRead(IReadMessage msg, Client c)
|
||||
{
|
||||
int signalIndex = msg.ReadRangedInteger(0, Signals.Length - 1);
|
||||
if (!item.CanClientAccess(c)) { return; }
|
||||
if (!SendSignal(signalIndex, c.Character)) { return; }
|
||||
GameServer.Log($"{GameServer.CharacterLogName(c.Character)} sent a signal \"{Signals[signalIndex]}\" from {item.Name}", ServerLog.MessageType.ItemInteraction);
|
||||
item.CreateServerEvent(this, new object[] { signalIndex });
|
||||
item.CreateServerEvent(this, new EventData(signalIndex));
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
Write(msg, extraData);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class ConnectionPanel : ItemComponent, IServerSerializable, IClientSerializable
|
||||
{
|
||||
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
|
||||
public void ServerEventRead(IReadMessage msg, Client c)
|
||||
{
|
||||
List<Wire>[] wires = new List<Wire>[Connections.Count];
|
||||
|
||||
@@ -84,7 +84,7 @@ namespace Barotrauma.Items.Components
|
||||
if (!selectedWire.Item.Removed) { selectedWire.CreateNetworkEvent(); }
|
||||
}, 1.0f);
|
||||
}
|
||||
GameMain.Server?.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnFailure, this, c.Character.ID });
|
||||
GameMain.Server?.CreateEntityEvent(item, new Item.ApplyStatusEffectEventData(ActionType.OnFailure, this, c.Character));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -210,10 +210,10 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
msg.Write(user == null ? (ushort)0 : user.ID);
|
||||
ClientWrite(msg, extraData);
|
||||
ClientEventWrite(msg, extraData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class CustomInterface : ItemComponent, IClientSerializable, IServerSerializable
|
||||
{
|
||||
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
|
||||
public void ServerEventRead(IReadMessage msg, Client c)
|
||||
{
|
||||
bool[] elementStates = new bool[customInterfaceElementList.Count];
|
||||
string[] elementValues = new string[customInterfaceElementList.Count];
|
||||
@@ -51,17 +51,12 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
//notify all clients of the new state
|
||||
GameMain.Server.CreateEntityEvent(item, new object[]
|
||||
{
|
||||
NetEntityEvent.Type.ComponentState,
|
||||
item.GetComponentIndex(this),
|
||||
clickedButton
|
||||
});
|
||||
item.CreateServerEvent(this, new EventData(clickedButton));
|
||||
|
||||
item.CreateServerEvent(this);
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
//extradata contains an array of buttons clicked by a client (or nothing if nothing was clicked)
|
||||
for (int i = 0; i < customInterfaceElementList.Count; i++)
|
||||
@@ -76,7 +71,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.Write(extraData != null && extraData.Any(d => d as CustomInterfaceElement == customInterfaceElementList[i]));
|
||||
msg.Write(extraData is Item.ComponentStateEventData { ComponentData: EventData eventData } && eventData.BtnElement == customInterfaceElementList[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Barotrauma.Items.Components
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
msg.Write(Value);
|
||||
lastSentValue = Value;
|
||||
|
||||
@@ -7,7 +7,19 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Terminal : ItemComponent, IClientSerializable, IServerSerializable
|
||||
{
|
||||
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
|
||||
private readonly struct ServerEventData : IEventData
|
||||
{
|
||||
public readonly int MsgIndex;
|
||||
public readonly string MsgToSend;
|
||||
|
||||
public ServerEventData(int msgIndex, string msgToSend)
|
||||
{
|
||||
MsgIndex = msgIndex;
|
||||
MsgToSend = msgToSend;
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerEventRead(IReadMessage msg, Client c)
|
||||
{
|
||||
string newOutputValue = msg.ReadString();
|
||||
|
||||
@@ -47,7 +59,7 @@ namespace Barotrauma.Items.Components
|
||||
string msgToSend = str;
|
||||
if (string.IsNullOrEmpty(msgToSend))
|
||||
{
|
||||
item.CreateServerEvent(this, new object[] { msgIndex, msgToSend });
|
||||
item.CreateServerEvent(this, new ServerEventData(msgIndex, msgToSend));
|
||||
msgIndex++;
|
||||
continue;
|
||||
}
|
||||
@@ -73,23 +85,23 @@ namespace Barotrauma.Items.Components
|
||||
if (!splitMessage.Any()) { break; }
|
||||
tempMsg += " ";
|
||||
} while (tempMsg.Length + splitMessage[0].Length < MaxMessageLength);
|
||||
item.CreateServerEvent(this, new object[] { msgIndex, tempMsg });
|
||||
item.CreateServerEvent(this, new ServerEventData(msgIndex, tempMsg));
|
||||
msgToSend = msgToSend.Remove(0, tempMsg.Length);
|
||||
}
|
||||
}
|
||||
if (!string.IsNullOrEmpty(msgToSend))
|
||||
{
|
||||
item.CreateServerEvent(this, new object[] { msgIndex, msgToSend });
|
||||
item.CreateServerEvent(this, new ServerEventData(msgIndex, msgToSend));
|
||||
}
|
||||
msgIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
if (extraData.Length > 3 && extraData[3] is string str)
|
||||
if (TryExtractEventData(extraData, out ServerEventData eventData))
|
||||
{
|
||||
msg.Write(str);
|
||||
msg.Write(eventData.MsgToSend);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class WifiComponent
|
||||
{
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
msg.WriteRangedInteger(Channel, MinChannel, MaxChannel);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,16 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class Wire : ItemComponent, IDrawableComponent, IServerSerializable
|
||||
{
|
||||
private readonly struct ServerEventData : IEventData
|
||||
{
|
||||
public readonly int EventIndex;
|
||||
|
||||
public ServerEventData(int eventIndex)
|
||||
{
|
||||
EventIndex = eventIndex;
|
||||
}
|
||||
}
|
||||
|
||||
public void CreateNetworkEvent()
|
||||
{
|
||||
if (GameMain.Server == null) return;
|
||||
@@ -13,13 +23,17 @@ namespace Barotrauma.Items.Components
|
||||
int eventCount = Math.Max((int)Math.Ceiling(nodes.Count / (float)MaxNodesPerNetworkEvent), 1);
|
||||
for (int i = 0; i < eventCount; i++)
|
||||
{
|
||||
GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ComponentState, item.GetComponentIndex(this), i });
|
||||
item.CreateServerEvent(this, new ServerEventData(i));
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public override bool ValidateEventData(NetEntityEvent.IData data)
|
||||
=> TryExtractEventData<ServerEventData>(data, out _);
|
||||
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
int eventIndex = (int)extraData[2];
|
||||
var eventData = ExtractEventData<ServerEventData>(extraData);
|
||||
int eventIndex = eventData.EventIndex;
|
||||
int nodeStartIndex = eventIndex * MaxNodesPerNetworkEvent;
|
||||
int nodeCount = MathHelper.Clamp(nodes.Count - nodeStartIndex, 0, MaxNodesPerNetworkEvent);
|
||||
|
||||
@@ -32,7 +46,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
|
||||
public void ServerEventRead(IReadMessage msg, Client c)
|
||||
{
|
||||
int nodeCount = msg.ReadByte();
|
||||
Vector2 lastNodePos = Vector2.Zero;
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class TriggerComponent : ItemComponent, IServerSerializable
|
||||
{
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
msg.WriteRangedSingle(CurrentForceFluctuation, 0.0f, 1.0f, 8);
|
||||
}
|
||||
|
||||
@@ -8,21 +8,11 @@ namespace Barotrauma
|
||||
{
|
||||
partial class Inventory : IServerSerializable, IClientSerializable
|
||||
{
|
||||
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
|
||||
public void ServerEventRead(IReadMessage msg, Client c)
|
||||
{
|
||||
List<Item> prevItems = new List<Item>(AllItems.Distinct());
|
||||
|
||||
byte slotCount = msg.ReadByte();
|
||||
List<ushort>[] newItemIDs = new List<ushort>[slotCount];
|
||||
for (int i = 0; i < slotCount; i++)
|
||||
{
|
||||
newItemIDs[i] = new List<ushort>();
|
||||
int itemCount = msg.ReadRangedInteger(0, MaxStackSize);
|
||||
for (int j = 0; j < itemCount; j++)
|
||||
{
|
||||
newItemIDs[i].Add(msg.ReadUInt16());
|
||||
}
|
||||
}
|
||||
SharedRead(msg, out var newItemIDs);
|
||||
|
||||
if (c == null || c.Character == null) { return; }
|
||||
|
||||
@@ -175,7 +165,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
SharedWrite(msg, extraData);
|
||||
}
|
||||
|
||||
@@ -20,103 +20,73 @@ namespace Barotrauma
|
||||
|
||||
partial void AssignCampaignInteractionTypeProjSpecific(CampaignMode.InteractionType interactionType)
|
||||
{
|
||||
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.AssignCampaignInteraction });
|
||||
GameMain.NetworkMember.CreateEntityEvent(this, new AssignCampaignInteractionEventData());
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
string errorMsg = "";
|
||||
if (extraData == null || extraData.Length == 0 || !(extraData[0] is NetEntityEvent.Type))
|
||||
Exception error(string reason)
|
||||
{
|
||||
if (extraData == null)
|
||||
{
|
||||
errorMsg = "Failed to write a network event for the item \"" + Name + "\" - event data was null.";
|
||||
}
|
||||
else if (extraData.Length == 0)
|
||||
{
|
||||
errorMsg = "Failed to write a network event for the item \"" + Name + "\" - event data was empty.";
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMsg = "Failed to write a network event for the item \"" + Name + "\" - event type not set.";
|
||||
}
|
||||
msg.WriteRangedInteger((int)NetEntityEvent.Type.Invalid, 0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1);
|
||||
DebugConsole.Log(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Item.ServerWrite:InvalidData" + Name, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
return;
|
||||
string errorMsg = $"Failed to write a network event for the item \"{Name}\" - {reason}";
|
||||
GameAnalyticsManager.AddErrorEventOnce($"Item.ServerWrite:{Name}", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
return new Exception(errorMsg);
|
||||
}
|
||||
|
||||
if (extraData is null) { throw error("event data was null"); }
|
||||
if (!(extraData is IEventData itemEventData)) { throw error($"event data was of the wrong type (\"{extraData.GetType().Name}\")"); }
|
||||
|
||||
int initialWritePos = msg.LengthBits;
|
||||
|
||||
NetEntityEvent.Type eventType = (NetEntityEvent.Type)extraData[0];
|
||||
msg.WriteRangedInteger((int)eventType, 0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1);
|
||||
switch (eventType)
|
||||
msg.WriteRangedInteger((int)itemEventData.EventType, (int)EventType.MinValue, (int)EventType.MaxValue);
|
||||
switch (itemEventData)
|
||||
{
|
||||
case NetEntityEvent.Type.ComponentState:
|
||||
if (extraData.Length < 2 || !(extraData[1] is int))
|
||||
case ComponentStateEventData componentStateEventData:
|
||||
int componentIndex = components.IndexOf(componentStateEventData.Component);
|
||||
if (componentIndex < 0)
|
||||
{
|
||||
errorMsg = "Failed to write a component state event for the item \"" + Name + "\" - component index not given.";
|
||||
break;
|
||||
throw error($"component index out of range ({componentIndex})");
|
||||
}
|
||||
int componentIndex = (int)extraData[1];
|
||||
if (componentIndex < 0 || componentIndex >= components.Count)
|
||||
if (!(components[componentIndex] is IServerSerializable serializableComponent))
|
||||
{
|
||||
errorMsg = "Failed to write a component state event for the item \"" + Name + "\" - component index out of range (" + componentIndex + ").";
|
||||
break;
|
||||
}
|
||||
else if (!(components[componentIndex] is IServerSerializable))
|
||||
{
|
||||
errorMsg = "Failed to write a component state event for the item \"" + Name + "\" - component \"" + components[componentIndex] + "\" is not server serializable.";
|
||||
break;
|
||||
throw error($"component \"{components[componentIndex]}\" is not server serializable");
|
||||
}
|
||||
msg.WriteRangedInteger(componentIndex, 0, components.Count - 1);
|
||||
(components[componentIndex] as IServerSerializable).ServerWrite(msg, c, extraData);
|
||||
serializableComponent.ServerEventWrite(msg, c, extraData);
|
||||
break;
|
||||
case NetEntityEvent.Type.InventoryState:
|
||||
if (extraData.Length < 2 || !(extraData[1] is int))
|
||||
case InventoryStateEventData inventoryStateEventData:
|
||||
int containerIndex = components.IndexOf(inventoryStateEventData.Component);
|
||||
if (containerIndex < 0)
|
||||
{
|
||||
errorMsg = "Failed to write an inventory state event for the item \"" + Name + "\" - component index not given.";
|
||||
throw error($"container index out of range ({containerIndex})");
|
||||
break;
|
||||
}
|
||||
int containerIndex = (int)extraData[1];
|
||||
if (containerIndex < 0 || containerIndex >= components.Count)
|
||||
if (!(components[containerIndex] is ItemContainer itemContainer))
|
||||
{
|
||||
errorMsg = "Failed to write an inventory state event for the item \"" + Name + "\" - container index out of range (" + containerIndex + ").";
|
||||
break;
|
||||
}
|
||||
else if (!(components[containerIndex] is ItemContainer))
|
||||
{
|
||||
errorMsg = "Failed to write an inventory state event for the item \"" + Name + "\" - component \"" + components[containerIndex] + "\" is not server serializable.";
|
||||
break;
|
||||
throw error("component \"" + components[containerIndex] + "\" is not server serializable");
|
||||
}
|
||||
msg.WriteRangedInteger(containerIndex, 0, components.Count - 1);
|
||||
msg.Write(GameMain.Server.EntityEventManager.Events.Last()?.ID ?? (ushort)0);
|
||||
(components[containerIndex] as ItemContainer).Inventory.ServerWrite(msg, c);
|
||||
itemContainer.Inventory.ServerEventWrite(msg, c);
|
||||
break;
|
||||
case NetEntityEvent.Type.Status:
|
||||
case StatusEventData _:
|
||||
msg.Write(condition);
|
||||
break;
|
||||
case NetEntityEvent.Type.AssignCampaignInteraction:
|
||||
case AssignCampaignInteractionEventData _:
|
||||
msg.Write((byte)CampaignInteractionType);
|
||||
break;
|
||||
case NetEntityEvent.Type.ApplyStatusEffect:
|
||||
case ApplyStatusEffectEventData applyStatusEffectEventData:
|
||||
{
|
||||
ActionType actionType = (ActionType)extraData[1];
|
||||
ItemComponent targetComponent = extraData.Length > 2 ? (ItemComponent)extraData[2] : null;
|
||||
ushort characterID = extraData.Length > 3 ? (ushort)extraData[3] : (ushort)0;
|
||||
Limb targetLimb = extraData.Length > 4 ? (Limb)extraData[4] : null;
|
||||
ushort useTargetID = extraData.Length > 5 ? (ushort)extraData[5] : (ushort)0;
|
||||
Vector2? worldPosition = null;
|
||||
if (extraData.Length > 6) { worldPosition = (Vector2)extraData[6]; }
|
||||
ActionType actionType = applyStatusEffectEventData.ActionType;
|
||||
ItemComponent targetComponent = applyStatusEffectEventData.TargetItemComponent;
|
||||
Limb targetLimb = applyStatusEffectEventData.TargetLimb;
|
||||
Vector2? worldPosition = applyStatusEffectEventData.WorldPosition;
|
||||
|
||||
Character targetCharacter = FindEntityByID(characterID) as Character;
|
||||
Character targetCharacter = applyStatusEffectEventData.TargetCharacter;
|
||||
byte targetLimbIndex = targetLimb != null && targetCharacter != null ? (byte)Array.IndexOf(targetCharacter.AnimController.Limbs, targetLimb) : (byte)255;
|
||||
|
||||
msg.WriteRangedInteger((int)actionType, 0, Enum.GetValues(typeof(ActionType)).Length - 1);
|
||||
msg.Write((byte)(targetComponent == null ? 255 : components.IndexOf(targetComponent)));
|
||||
msg.Write(characterID);
|
||||
msg.Write(applyStatusEffectEventData.TargetCharacter?.ID ?? (ushort)0);
|
||||
msg.Write(targetLimbIndex);
|
||||
msg.Write(useTargetID);
|
||||
msg.Write(applyStatusEffectEventData.UseTarget?.ID ?? (ushort)0);
|
||||
msg.Write(worldPosition.HasValue);
|
||||
if (worldPosition.HasValue)
|
||||
{
|
||||
@@ -125,74 +95,56 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NetEntityEvent.Type.ChangeProperty:
|
||||
case ChangePropertyEventData changePropertyEventData:
|
||||
try
|
||||
{
|
||||
WritePropertyChange(msg, extraData, inGameEditableOnly: !GameMain.NetworkMember.IsServer);
|
||||
WritePropertyChange(msg, changePropertyEventData, inGameEditableOnly: !GameMain.NetworkMember.IsServer);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
errorMsg = "Failed to write a ChangeProperty network event for the item \"" + Name + "\" (" + e.Message + ")";
|
||||
throw new Exception(
|
||||
$"Failed to write a ChangeProperty network event for the item \"{Name}\" ({e.Message})");
|
||||
}
|
||||
break;
|
||||
case NetEntityEvent.Type.Upgrade:
|
||||
if (extraData.Length > 0 && extraData[1] is Upgrade upgrade)
|
||||
case UpgradeEventData upgradeEventData:
|
||||
var upgrade = upgradeEventData.Upgrade;
|
||||
var upgradeTargets = upgrade.TargetComponents;
|
||||
msg.Write(upgrade.Identifier);
|
||||
msg.Write((byte)upgrade.Level);
|
||||
msg.Write((byte)upgradeTargets.Count);
|
||||
foreach (var (_, value) in upgrade.TargetComponents)
|
||||
{
|
||||
var upgradeTargets = upgrade.TargetComponents;
|
||||
msg.Write(upgrade.Identifier);
|
||||
msg.Write((byte)upgrade.Level);
|
||||
msg.Write((byte)upgradeTargets.Count);
|
||||
foreach (var (_, value) in upgrade.TargetComponents)
|
||||
msg.Write((byte)value.Length);
|
||||
foreach (var propertyReference in value)
|
||||
{
|
||||
msg.Write((byte)value.Length);
|
||||
foreach (var propertyReference in value)
|
||||
{
|
||||
object originalValue = propertyReference.OriginalValue;
|
||||
msg.Write((float)(originalValue ?? -1));
|
||||
}
|
||||
object originalValue = propertyReference.OriginalValue;
|
||||
msg.Write((float)(originalValue ?? -1));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMsg = extraData.Length > 0
|
||||
? $"Failed to write a network event for the item \"{Name}\" - \"{extraData[1].GetType()}\" is not a valid upgrade."
|
||||
: $"Failed to write a network event for the item \"{Name}\". No upgrade specified.";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
errorMsg = "Failed to write a network event for the item \"" + Name + "\" - \"" + eventType + "\" is not a valid entity event type for items.";
|
||||
break;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(errorMsg))
|
||||
{
|
||||
//something went wrong - rewind the write position and write invalid event type to prevent creating an unreadable event
|
||||
msg.BitPosition = initialWritePos;
|
||||
msg.LengthBits = initialWritePos;
|
||||
msg.WriteRangedInteger((int)NetEntityEvent.Type.Invalid, 0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1);
|
||||
DebugConsole.Log(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Item.ServerWrite:" + errorMsg, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
throw error($"Unsupported event type {itemEventData.GetType().Name}");
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
|
||||
public void ServerEventRead(IReadMessage msg, Client c)
|
||||
{
|
||||
NetEntityEvent.Type eventType =
|
||||
(NetEntityEvent.Type)msg.ReadRangedInteger(0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1);
|
||||
EventType eventType =
|
||||
(EventType)msg.ReadRangedInteger((int)EventType.MinValue, (int)EventType.MaxValue);
|
||||
|
||||
c.KickAFKTimer = 0.0f;
|
||||
|
||||
switch (eventType)
|
||||
{
|
||||
case NetEntityEvent.Type.ComponentState:
|
||||
case EventType.ComponentState:
|
||||
int componentIndex = msg.ReadRangedInteger(0, components.Count - 1);
|
||||
(components[componentIndex] as IClientSerializable).ServerRead(type, msg, c);
|
||||
(components[componentIndex] as IClientSerializable).ServerEventRead(msg, c);
|
||||
break;
|
||||
case NetEntityEvent.Type.InventoryState:
|
||||
case EventType.InventoryState:
|
||||
int containerIndex = msg.ReadRangedInteger(0, components.Count - 1);
|
||||
(components[containerIndex] as ItemContainer).Inventory.ServerRead(type, msg, c);
|
||||
(components[containerIndex] as ItemContainer).Inventory.ServerEventRead(msg, c);
|
||||
break;
|
||||
case NetEntityEvent.Type.Treatment:
|
||||
case EventType.Treatment:
|
||||
if (c.Character == null || !c.Character.CanInteractWith(this)) return;
|
||||
|
||||
UInt16 characterID = msg.ReadUInt16();
|
||||
@@ -218,10 +170,10 @@ namespace Barotrauma
|
||||
ApplyTreatment(c.Character, targetCharacter, targetLimb);
|
||||
|
||||
break;
|
||||
case NetEntityEvent.Type.ChangeProperty:
|
||||
case EventType.ChangeProperty:
|
||||
ReadPropertyChange(msg, inGameEditableOnly: GameMain.NetworkMember.IsServer, sender: c);
|
||||
break;
|
||||
case NetEntityEvent.Type.Combine:
|
||||
case EventType.Combine:
|
||||
UInt16 combineTargetID = msg.ReadUInt16();
|
||||
Item combineTarget = FindEntityByID(combineTargetID) as Item;
|
||||
if (combineTarget == null || !c.Character.CanInteractWith(this) || !c.Character.CanInteractWith(combineTarget))
|
||||
@@ -269,6 +221,7 @@ namespace Barotrauma
|
||||
msg.WriteRangedInteger(Quality, 0, Items.Components.Quality.MaxQuality);
|
||||
|
||||
byte teamID = 0;
|
||||
IdCard idCardComponent = null;
|
||||
foreach (WifiComponent wifiComponent in GetComponents<WifiComponent>())
|
||||
{
|
||||
teamID = (byte)wifiComponent.TeamID;
|
||||
@@ -279,11 +232,31 @@ namespace Barotrauma
|
||||
foreach (IdCard idCard in GetComponents<IdCard>())
|
||||
{
|
||||
teamID = (byte)idCard.TeamID;
|
||||
idCardComponent = idCard;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
msg.Write(teamID);
|
||||
|
||||
bool hasIdCard = idCardComponent != null;
|
||||
msg.Write(hasIdCard);
|
||||
if (hasIdCard)
|
||||
{
|
||||
msg.Write(idCardComponent.OwnerName);
|
||||
msg.Write(idCardComponent.OwnerTags);
|
||||
msg.Write((byte)Math.Max(0, idCardComponent.OwnerBeardIndex+1));
|
||||
msg.Write((byte)Math.Max(0, idCardComponent.OwnerHairIndex+1));
|
||||
msg.Write((byte)Math.Max(0, idCardComponent.OwnerMoustacheIndex+1));
|
||||
msg.Write((byte)Math.Max(0, idCardComponent.OwnerFaceAttachmentIndex+1));
|
||||
msg.WriteColorR8G8B8(idCardComponent.OwnerHairColor);
|
||||
msg.WriteColorR8G8B8(idCardComponent.OwnerFacialHairColor);
|
||||
msg.WriteColorR8G8B8(idCardComponent.OwnerSkinColor);
|
||||
msg.Write(idCardComponent.OwnerJobId);
|
||||
msg.Write((byte)idCardComponent.OwnerSheetIndex.X);
|
||||
msg.Write((byte)idCardComponent.OwnerSheetIndex.Y);
|
||||
}
|
||||
|
||||
bool tagsChanged = tags.Count != base.Prefab.Tags.Count || !tags.All(t => base.Prefab.Tags.Contains(t));
|
||||
msg.Write(tagsChanged);
|
||||
if (tagsChanged)
|
||||
@@ -367,39 +340,21 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerWritePosition(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerWritePosition(IWriteMessage msg, Client c)
|
||||
{
|
||||
msg.Write(ID);
|
||||
|
||||
IWriteMessage tempBuffer = new WriteOnlyMessage();
|
||||
body.ServerWrite(tempBuffer, c, extraData);
|
||||
body.ServerWrite(tempBuffer);
|
||||
msg.WriteVariableUInt32((uint)tempBuffer.LengthBytes);
|
||||
msg.Write(tempBuffer.Buffer, 0, tempBuffer.LengthBytes);
|
||||
msg.WritePadBits();
|
||||
}
|
||||
|
||||
public void CreateServerEvent<T>(T ic) where T : ItemComponent, IServerSerializable
|
||||
{
|
||||
if (GameMain.Server == null) { return; }
|
||||
=> CreateServerEvent(ic, ic.ServerGetEventData());
|
||||
|
||||
if (!ItemList.Contains(this))
|
||||
{
|
||||
string errorMsg = "Attempted to create a network event for an item (" + Name + ") that hasn't been fully initialized yet.\n" + Environment.StackTrace.CleanupStackTrace();
|
||||
DebugConsole.AddWarning(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Item.CreateServerEvent:EventForUninitializedItem" + Name + ID, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
int index = components.IndexOf(ic);
|
||||
if (index == -1) { return; }
|
||||
|
||||
object[] extraData = new object[] { NetEntityEvent.Type.ComponentState, index };
|
||||
ic.ServerAppendExtraData(ref extraData);
|
||||
|
||||
GameMain.Server.CreateEntityEvent(this, extraData);
|
||||
}
|
||||
|
||||
public void CreateServerEvent<T>(T ic, object[] extraData) where T : ItemComponent, IServerSerializable
|
||||
public void CreateServerEvent<T>(T ic, ItemComponent.IEventData extraData) where T : ItemComponent, IServerSerializable
|
||||
{
|
||||
if (GameMain.Server == null) { return; }
|
||||
|
||||
@@ -411,11 +366,12 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
int index = components.IndexOf(ic);
|
||||
if (index == -1) { return; }
|
||||
#warning TODO: this should throw an exception
|
||||
if (!components.Contains(ic)) { return; }
|
||||
|
||||
object[] data = new object[] { NetEntityEvent.Type.ComponentState, index }.Concat(extraData).ToArray();
|
||||
GameMain.Server.CreateEntityEvent(this, data);
|
||||
var eventData = new ComponentStateEventData(ic, extraData);
|
||||
if (!ic.ValidateEventData(eventData)) { throw new Exception($"Component event creation failed: {typeof(T).Name}.{nameof(ItemComponent.ValidateEventData)} returned false"); }
|
||||
GameMain.Server.CreateEntityEvent(this, eventData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using Barotrauma.Networking;
|
||||
using FarseerPhysics;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class Level : Entity, IServerSerializable
|
||||
{
|
||||
public interface IEventData : NetEntityEvent.IData
|
||||
{
|
||||
public EventType EventType { get; }
|
||||
}
|
||||
|
||||
public readonly struct SingleLevelWallEventData : IEventData
|
||||
{
|
||||
public EventType EventType => EventType.SingleDestructibleWall;
|
||||
public readonly DestructibleLevelWall Wall;
|
||||
|
||||
public SingleLevelWallEventData(DestructibleLevelWall wall)
|
||||
{
|
||||
Wall = wall;
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct GlobalLevelWallEventData : IEventData
|
||||
{
|
||||
public EventType EventType => EventType.GlobalDestructibleWall;
|
||||
}
|
||||
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
if (!(extraData is IEventData eventData)) { throw new Exception($"Malformed level event: expected {nameof(Level)}.{nameof(IEventData)}"); }
|
||||
|
||||
msg.Write((byte)eventData.EventType);
|
||||
switch (eventData)
|
||||
{
|
||||
case SingleLevelWallEventData { Wall: var destructibleWall }:
|
||||
int index = ExtraWalls.IndexOf(destructibleWall);
|
||||
msg.Write((ushort)(index == -1 ? ushort.MaxValue : index));
|
||||
//write health using one byte
|
||||
msg.Write((byte)MathHelper.Clamp((int)(MathUtils.InverseLerp(0.0f, destructibleWall.MaxHealth, destructibleWall.Damage) * 255.0f), 0, 255));
|
||||
break;
|
||||
case GlobalLevelWallEventData _:
|
||||
foreach (LevelWall levelWall in ExtraWalls)
|
||||
{
|
||||
if (levelWall.Body.BodyType == BodyType.Static) { continue; }
|
||||
msg.Write(levelWall.Body.Position.X);
|
||||
msg.Write(levelWall.Body.Position.Y);
|
||||
msg.WriteRangedSingle(levelWall.MoveState, 0.0f, MathHelper.TwoPi, 16);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Exception($"Malformed level event: did not expect {eventData.GetType().Name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,32 +31,43 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
partial void UpdateDamage(float deltaTime)
|
||||
public void ServerWrite(IWriteMessage msg, IEventData eventData)
|
||||
{
|
||||
if (damageUpdateTimer <= 0)
|
||||
msg.Write((byte)eventData.NetworkHeader);
|
||||
|
||||
switch (eventData)
|
||||
{
|
||||
foreach (BallastFloraBranch branch in Branches)
|
||||
{
|
||||
if (Math.Abs(branch.AccumulatedDamage) > 1.0f)
|
||||
{
|
||||
SendNetworkMessage(this, NetworkHeader.BranchDamage, branch);
|
||||
branch.AccumulatedDamage = 0f;
|
||||
}
|
||||
}
|
||||
damageUpdateTimer = 1f;
|
||||
case SpawnEventData spawnEventData:
|
||||
ServerWriteSpawn(msg);
|
||||
break;
|
||||
case KillEventData killEventData:
|
||||
//do nothing
|
||||
break;
|
||||
case BranchCreateEventData branchCreateEventData:
|
||||
ServerWriteBranchGrowth(msg, branchCreateEventData.NewBranch, branchCreateEventData.Parent.ID);
|
||||
break;
|
||||
case BranchDamageEventData branchDamageEventData:
|
||||
ServerWriteBranchDamage(msg, branchDamageEventData.Branch);
|
||||
break;
|
||||
case InfectEventData infectEventData:
|
||||
ServerWriteInfect(msg, infectEventData.Item.ID, infectEventData.Infect, infectEventData.Infector);
|
||||
break;
|
||||
case BranchRemoveEventData branchRemoveEventData:
|
||||
ServerWriteBranchRemove(msg, branchRemoveEventData.Branch);
|
||||
break;
|
||||
}
|
||||
damageUpdateTimer -= deltaTime;
|
||||
|
||||
msg.Write(PowerConsumptionTimer);
|
||||
}
|
||||
|
||||
public void ServerWriteSpawn(IWriteMessage msg)
|
||||
private void ServerWriteSpawn(IWriteMessage msg)
|
||||
{
|
||||
msg.Write(Prefab.Identifier);
|
||||
msg.Write(Offset.X);
|
||||
msg.Write(Offset.Y);
|
||||
}
|
||||
|
||||
public void ServerWriteBranchGrowth(IWriteMessage msg, BallastFloraBranch branch, int parentId = -1)
|
||||
private void ServerWriteBranchGrowth(IWriteMessage msg, BallastFloraBranch branch, int parentId = -1)
|
||||
{
|
||||
var (x, y) = branch.Position;
|
||||
msg.Write(parentId);
|
||||
@@ -71,30 +82,30 @@ namespace Barotrauma.MapCreatures.Behavior
|
||||
msg.Write(branch.ParentBranch == null ? -1 : Branches.IndexOf(branch.ParentBranch));
|
||||
}
|
||||
|
||||
public void ServerWriteBranchDamage(IWriteMessage msg, BallastFloraBranch branch)
|
||||
private void ServerWriteBranchDamage(IWriteMessage msg, BallastFloraBranch branch)
|
||||
{
|
||||
msg.Write((int)branch.ID);
|
||||
msg.Write(branch.Health);
|
||||
}
|
||||
|
||||
public void ServerWriteInfect(IWriteMessage msg, UInt16 itemID, bool infect, BallastFloraBranch infector = null)
|
||||
private void ServerWriteInfect(IWriteMessage msg, UInt16 itemID, InfectEventData.InfectState infect, BallastFloraBranch infector = null)
|
||||
{
|
||||
msg.Write(itemID);
|
||||
msg.Write(infect);
|
||||
if (infect)
|
||||
msg.Write(infect == InfectEventData.InfectState.Yes);
|
||||
if (infect == InfectEventData.InfectState.Yes)
|
||||
{
|
||||
msg.Write(infector?.ID ?? -1);
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerWriteBranchRemove(IWriteMessage msg, BallastFloraBranch branch)
|
||||
private void ServerWriteBranchRemove(IWriteMessage msg, BallastFloraBranch branch)
|
||||
{
|
||||
msg.Write(branch.ID);
|
||||
}
|
||||
|
||||
public void SendNetworkMessage(params object[] extraData)
|
||||
public void SendNetworkMessage(IEventData extraData)
|
||||
{
|
||||
GameMain.Server.CreateEntityEvent(Parent, extraData);
|
||||
GameMain.Server.CreateEntityEvent(Parent, new Hull.BallastFloraEventData(this, extraData));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,14 +4,20 @@ using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.MapCreatures.Behavior;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class Hull : MapEntity, ISerializableEntity, IServerSerializable, IClientSerializable
|
||||
{
|
||||
private float lastSentVolume, lastSentOxygen, lastSentFireCount;
|
||||
private float sendUpdateTimer;
|
||||
private float lastSentVolume;
|
||||
private float lastSentOxygen;
|
||||
private int lastSentFireCount;
|
||||
|
||||
private float statusUpdateTimer;
|
||||
private float decalUpdateTimer;
|
||||
private float backgroundSectionUpdateTimer;
|
||||
|
||||
private bool decalUpdatePending;
|
||||
|
||||
@@ -33,225 +39,163 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
|
||||
sendUpdateTimer -= deltaTime;
|
||||
statusUpdateTimer -= deltaTime;
|
||||
decalUpdateTimer -= deltaTime;
|
||||
backgroundSectionUpdateTimer -= deltaTime;
|
||||
|
||||
//update client hulls if the amount of water has changed by >10%
|
||||
//or if oxygen percentage has changed by 5%
|
||||
if (Math.Abs(lastSentVolume - waterVolume) > Volume * 0.1f || Math.Abs(lastSentOxygen - OxygenPercentage) > 5f ||
|
||||
lastSentFireCount != FireSources.Count || FireSources.Count > 0 ||
|
||||
pendingSectionUpdates.Count > 0 ||
|
||||
sendUpdateTimer < -NetConfig.SparseHullUpdateInterval ||
|
||||
decalUpdatePending)
|
||||
{
|
||||
if (sendUpdateTimer < 0.0f)
|
||||
{
|
||||
if (decalUpdatePending)
|
||||
{
|
||||
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { false });
|
||||
}
|
||||
if (pendingSectionUpdates.Count > 0)
|
||||
{
|
||||
foreach (int pendingSectionUpdate in pendingSectionUpdates)
|
||||
{
|
||||
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { true, pendingSectionUpdate } );
|
||||
}
|
||||
pendingSectionUpdates.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.NetworkMember.CreateEntityEvent(this);
|
||||
}
|
||||
bool shouldSendStatusUpdate =
|
||||
(Math.Abs(lastSentVolume - waterVolume) > Volume * 0.1f
|
||||
|| Math.Abs(lastSentOxygen - OxygenPercentage) > 5f
|
||||
|| lastSentFireCount != FireSources.Count)
|
||||
&& statusUpdateTimer <= 0.0f;
|
||||
|
||||
lastSentVolume = waterVolume;
|
||||
lastSentOxygen = OxygenPercentage;
|
||||
lastSentFireCount = FireSources.Count;
|
||||
sendUpdateTimer = NetConfig.HullUpdateInterval;
|
||||
if (shouldSendStatusUpdate)
|
||||
{
|
||||
GameMain.NetworkMember.CreateEntityEvent(this, new StatusEventData());
|
||||
|
||||
lastSentVolume = waterVolume;
|
||||
lastSentOxygen = OxygenPercentage;
|
||||
lastSentFireCount = FireSources.Count;
|
||||
|
||||
statusUpdateTimer = NetConfig.SparseHullUpdateInterval;
|
||||
}
|
||||
if (decalUpdatePending && decalUpdateTimer <= 0.0f)
|
||||
{
|
||||
GameMain.NetworkMember.CreateEntityEvent(this, new DecalEventData());
|
||||
|
||||
decalUpdateTimer = NetConfig.HullUpdateInterval;
|
||||
decalUpdatePending = false;
|
||||
}
|
||||
if (pendingSectionUpdates.Count > 0 && backgroundSectionUpdateTimer <= 0.0f)
|
||||
{
|
||||
foreach (int pendingSectionUpdate in pendingSectionUpdates)
|
||||
{
|
||||
GameMain.NetworkMember.CreateEntityEvent(this, new BackgroundSectionsEventData(pendingSectionUpdate));
|
||||
}
|
||||
|
||||
backgroundSectionUpdateTimer = NetConfig.HullUpdateInterval;
|
||||
pendingSectionUpdates.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage message, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
if (extraData != null && extraData.Length >= 2 && extraData[0] is BallastFloraBehavior behavior && extraData[1] is BallastFloraBehavior.NetworkHeader header)
|
||||
if (!(extraData is IEventData eventData)) { throw new Exception($"Malformed hull event: expected {nameof(Hull)}.{nameof(IEventData)}"); }
|
||||
msg.WriteRangedInteger((int)eventData.EventType, (int)EventType.MinValue, (int)EventType.MaxValue);
|
||||
|
||||
switch (eventData)
|
||||
{
|
||||
message.Write(true);
|
||||
message.Write((byte)header);
|
||||
|
||||
switch (header)
|
||||
{
|
||||
case BallastFloraBehavior.NetworkHeader.Spawn:
|
||||
behavior.ServerWriteSpawn(message);
|
||||
break;
|
||||
case BallastFloraBehavior.NetworkHeader.Kill:
|
||||
case BallastFloraBehavior.NetworkHeader.Remove:
|
||||
break;
|
||||
case BallastFloraBehavior.NetworkHeader.BranchCreate when extraData.Length >= 4 && extraData[2] is BallastFloraBranch branch && extraData[3] is int parentId:
|
||||
behavior.ServerWriteBranchGrowth(message, branch, parentId);
|
||||
break;
|
||||
case BallastFloraBehavior.NetworkHeader.BranchDamage when extraData.Length >= 4 && extraData[2] is BallastFloraBranch branch:
|
||||
behavior.ServerWriteBranchDamage(message, branch);
|
||||
break;
|
||||
case BallastFloraBehavior.NetworkHeader.BranchRemove when extraData.Length >= 3 && extraData[2] is BallastFloraBranch branch:
|
||||
behavior.ServerWriteBranchRemove(message, branch);
|
||||
break;
|
||||
case BallastFloraBehavior.NetworkHeader.Infect when extraData.Length >= 4 && extraData[2] is UInt16 itemID && extraData[3] is bool infect:
|
||||
BallastFloraBranch infector = null;
|
||||
if (extraData.Length >= 5 && extraData[4] is BallastFloraBranch b) { infector = b; }
|
||||
behavior.ServerWriteInfect(message, itemID, infect, infector);
|
||||
break;
|
||||
}
|
||||
|
||||
message.Write(behavior.PowerConsumptionTimer);
|
||||
return;
|
||||
}
|
||||
|
||||
message.Write(false); //not a ballast flora update
|
||||
message.WriteRangedSingle(MathHelper.Clamp(waterVolume / Volume, 0.0f, 1.5f), 0.0f, 1.5f, 8);
|
||||
message.WriteRangedSingle(MathHelper.Clamp(OxygenPercentage, 0.0f, 100.0f), 0.0f, 100.0f, 8);
|
||||
|
||||
message.Write(FireSources.Count > 0);
|
||||
if (FireSources.Count > 0)
|
||||
{
|
||||
message.WriteRangedInteger(Math.Min(FireSources.Count, 16), 0, 16);
|
||||
for (int i = 0; i < Math.Min(FireSources.Count, 16); i++)
|
||||
{
|
||||
var fireSource = FireSources[i];
|
||||
Vector2 normalizedPos = new Vector2(
|
||||
(fireSource.Position.X - rect.X) / rect.Width,
|
||||
(fireSource.Position.Y - (rect.Y - rect.Height)) / rect.Height);
|
||||
|
||||
message.WriteRangedSingle(MathHelper.Clamp(normalizedPos.X, 0.0f, 1.0f), 0.0f, 1.0f, 8);
|
||||
message.WriteRangedSingle(MathHelper.Clamp(normalizedPos.Y, 0.0f, 1.0f), 0.0f, 1.0f, 8);
|
||||
message.WriteRangedSingle(MathHelper.Clamp(fireSource.Size.X / rect.Width, 0.0f, 1.0f), 0, 1.0f, 8);
|
||||
}
|
||||
}
|
||||
|
||||
message.Write(extraData != null);
|
||||
if (extraData != null)
|
||||
{
|
||||
message.Write((bool)extraData[0]);
|
||||
|
||||
// Section update
|
||||
if ((bool)extraData[0])
|
||||
{
|
||||
int sectorToUpdate = (int)extraData[1];
|
||||
int start = sectorToUpdate * BackgroundSectionsPerNetworkEvent;
|
||||
int end = Math.Min((sectorToUpdate + 1) * BackgroundSectionsPerNetworkEvent, BackgroundSections.Count - 1);
|
||||
message.WriteRangedInteger(sectorToUpdate, 0, BackgroundSections.Count - 1);
|
||||
for (int i = start; i < end; i++)
|
||||
{
|
||||
message.WriteRangedSingle(BackgroundSections[i].ColorStrength, 0.0f, 1.0f, 8);
|
||||
message.Write(BackgroundSections[i].Color.PackedValue);
|
||||
}
|
||||
}
|
||||
else // Decal update
|
||||
{
|
||||
message.WriteRangedInteger(decals.Count, 0, MaxDecalsPerHull);
|
||||
case StatusEventData statusEventData:
|
||||
msg.WriteRangedSingle(MathHelper.Clamp(OxygenPercentage, 0.0f, 100.0f), 0.0f, 100.0f, 8);
|
||||
SharedStatusWrite(msg);
|
||||
break;
|
||||
case BackgroundSectionsEventData backgroundSectionsEventData:
|
||||
SharedBackgroundSectionsWrite(msg, backgroundSectionsEventData);
|
||||
break;
|
||||
case DecalEventData decalEventData:
|
||||
msg.WriteRangedInteger(decals.Count, 0, MaxDecalsPerHull);
|
||||
foreach (Decal decal in decals)
|
||||
{
|
||||
message.Write(decal.Prefab.UintIdentifier);
|
||||
message.Write((byte)decal.SpriteIndex);
|
||||
msg.Write(decal.Prefab.UintIdentifier);
|
||||
msg.Write((byte)decal.SpriteIndex);
|
||||
float normalizedXPos = MathHelper.Clamp(MathUtils.InverseLerp(0.0f, rect.Width, decal.CenterPosition.X), 0.0f, 1.0f);
|
||||
float normalizedYPos = MathHelper.Clamp(MathUtils.InverseLerp(-rect.Height, 0.0f, decal.CenterPosition.Y), 0.0f, 1.0f);
|
||||
message.WriteRangedSingle(normalizedXPos, 0.0f, 1.0f, 8);
|
||||
message.WriteRangedSingle(normalizedYPos, 0.0f, 1.0f, 8);
|
||||
message.WriteRangedSingle(decal.Scale, 0f, 2f, 12);
|
||||
msg.WriteRangedSingle(normalizedXPos, 0.0f, 1.0f, 8);
|
||||
msg.WriteRangedSingle(normalizedYPos, 0.0f, 1.0f, 8);
|
||||
msg.WriteRangedSingle(decal.Scale, 0f, 2f, 12);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BallastFloraEventData ballastFloraEventData:
|
||||
ballastFloraEventData.Behavior.ServerWrite(msg, ballastFloraEventData.SubEventData);
|
||||
break;
|
||||
default:
|
||||
throw new Exception($"Malformed hull event: did not expect {eventData.GetType().Name}");
|
||||
}
|
||||
}
|
||||
|
||||
//used when clients use the water/fire console commands or section / decal updates are received
|
||||
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
|
||||
public void ServerEventRead(IReadMessage msg, Client c)
|
||||
{
|
||||
int messageType = msg.ReadRangedInteger(0, 2);
|
||||
if (messageType == 0)
|
||||
EventType eventType = (EventType)msg.ReadRangedInteger((int)EventType.MinValue, (int)EventType.MaxValue);
|
||||
switch (eventType)
|
||||
{
|
||||
float newWaterVolume = msg.ReadRangedSingle(0.0f, 1.5f, 8) * Volume;
|
||||
case EventType.Status:
|
||||
SharedStatusRead(
|
||||
msg,
|
||||
out float newWaterVolume,
|
||||
out NetworkFireSource[] newFireSources);
|
||||
|
||||
bool hasFireSources = msg.ReadBoolean();
|
||||
int fireSourceCount = 0;
|
||||
List<Vector3> newFireSources = new List<Vector3>();
|
||||
if (hasFireSources)
|
||||
{
|
||||
fireSourceCount = msg.ReadRangedInteger(0, 16);
|
||||
for (int i = 0; i < fireSourceCount; i++)
|
||||
if (!c.HasPermission(ClientPermissions.ConsoleCommands) ||
|
||||
!c.PermittedConsoleCommands.Any(command => command.names.Contains("fire") || command.names.Contains("editfire")))
|
||||
{
|
||||
newFireSources.Add(new Vector3(
|
||||
MathHelper.Clamp(msg.ReadRangedSingle(0.0f, 1.0f, 8), 0.05f, 0.95f),
|
||||
MathHelper.Clamp(msg.ReadRangedSingle(0.0f, 1.0f, 8), 0.05f, 0.95f),
|
||||
msg.ReadRangedSingle(0.0f, 1.0f, 8)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!c.HasPermission(ClientPermissions.ConsoleCommands) ||
|
||||
!c.PermittedConsoleCommands.Any(command => command.names.Contains("fire") || command.names.Contains("editfire")))
|
||||
{
|
||||
return;
|
||||
}
|
||||
WaterVolume = newWaterVolume;
|
||||
|
||||
WaterVolume = newWaterVolume;
|
||||
|
||||
for (int i = 0; i < fireSourceCount; i++)
|
||||
{
|
||||
Vector2 pos = new Vector2(
|
||||
rect.X + rect.Width * newFireSources[i].X,
|
||||
rect.Y - rect.Height + (rect.Height * newFireSources[i].Y));
|
||||
float size = newFireSources[i].Z * rect.Width;
|
||||
|
||||
var newFire = i < FireSources.Count ?
|
||||
FireSources[i] :
|
||||
new FireSource(Submarine == null ? pos : pos + Submarine.Position, null, true);
|
||||
newFire.Position = pos;
|
||||
newFire.Size = new Vector2(size, newFire.Size.Y);
|
||||
|
||||
//ignore if the fire wasn't added to this room (invalid position)?
|
||||
if (!FireSources.Contains(newFire))
|
||||
for (int i = 0; i < newFireSources.Length; i++)
|
||||
{
|
||||
newFire.Remove();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Vector2 pos = newFireSources[i].Position;
|
||||
float size = newFireSources[i].Size;
|
||||
|
||||
for (int i = FireSources.Count - 1; i >= fireSourceCount; i--)
|
||||
{
|
||||
FireSources[i].Remove();
|
||||
if (i < FireSources.Count)
|
||||
var newFire = i < FireSources.Count ?
|
||||
FireSources[i] :
|
||||
new FireSource(Submarine == null ? pos : pos + Submarine.Position, null, true);
|
||||
newFire.Position = pos;
|
||||
newFire.Size = new Vector2(size, newFire.Size.Y);
|
||||
|
||||
//ignore if the fire wasn't added to this room (invalid position)?
|
||||
if (!FireSources.Contains(newFire))
|
||||
{
|
||||
newFire.Remove();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = FireSources.Count - 1; i >= newFireSources.Length; i--)
|
||||
{
|
||||
FireSources.RemoveAt(i);
|
||||
FireSources[i].Remove();
|
||||
if (i < FireSources.Count)
|
||||
{
|
||||
FireSources.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (messageType == 1)
|
||||
{
|
||||
byte decalIndex = msg.ReadByte();
|
||||
float decalAlpha = msg.ReadRangedSingle(0.0f, 1.0f, 255);
|
||||
if (decalIndex < 0 || decalIndex >= decals.Count) { return; }
|
||||
if (c.Character != null && c.Character.AllowInput && c.Character.HeldItems.Any(it => it.GetComponent<Sprayer>() != null))
|
||||
{
|
||||
decals[decalIndex].BaseAlpha = decalAlpha;
|
||||
}
|
||||
decalUpdatePending = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
int sectorToUpdate = msg.ReadRangedInteger(0, BackgroundSections.Count - 1);
|
||||
int start = sectorToUpdate * BackgroundSectionsPerNetworkEvent;
|
||||
int end = Math.Min((sectorToUpdate + 1) * BackgroundSectionsPerNetworkEvent, BackgroundSections.Count - 1);
|
||||
for (int i = start; i < end; i++)
|
||||
{
|
||||
float colorStrength = msg.ReadRangedSingle(0.0f, 1.0f, 8);
|
||||
Color color = new Color(msg.ReadUInt32());
|
||||
break;
|
||||
case EventType.BackgroundSections:
|
||||
SharedBackgroundSectionRead(
|
||||
msg,
|
||||
bsnu =>
|
||||
{
|
||||
int i = bsnu.SectionIndex;
|
||||
Color color = bsnu.Color;
|
||||
float colorStrength = bsnu.ColorStrength;
|
||||
|
||||
//TODO: verify the client is close enough to this hull to paint it, that the sprayer is functional and that the color matches
|
||||
#warning TODO: verify the client is close enough to this hull to paint it, that the sprayer is functional and that the color matches
|
||||
if (!(c.Character is { AllowInput: true })) { return; }
|
||||
if (c.Character.HeldItems.All(it => it.GetComponent<Sprayer>() == null)) { return; }
|
||||
|
||||
BackgroundSections[i].SetColorStrength(colorStrength);
|
||||
BackgroundSections[i].SetColor(color);
|
||||
},
|
||||
out int sectorToUpdate);
|
||||
//add to pending updates to notify other clients as well
|
||||
pendingSectionUpdates.Add(sectorToUpdate);
|
||||
break;
|
||||
case EventType.Decal:
|
||||
byte decalIndex = msg.ReadByte();
|
||||
float decalAlpha = msg.ReadRangedSingle(0.0f, 1.0f, 255);
|
||||
if (decalIndex < 0 || decalIndex >= decals.Count) { return; }
|
||||
if (c.Character != null && c.Character.AllowInput && c.Character.HeldItems.Any(it => it.GetComponent<Sprayer>() != null))
|
||||
{
|
||||
BackgroundSections[i].SetColorStrength(colorStrength);
|
||||
BackgroundSections[i].SetColor(color);
|
||||
decals[decalIndex].BaseAlpha = decalAlpha;
|
||||
}
|
||||
}
|
||||
//add to pending updates to notify other clients as well
|
||||
pendingSectionUpdates.Add(sectorToUpdate);
|
||||
}
|
||||
decalUpdatePending = true;
|
||||
break;
|
||||
default:
|
||||
throw new Exception($"Malformed incoming hull event: {eventType} is not a supported event type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Barotrauma
|
||||
GameMain.Server.KarmaManager.OnStructureHealthChanged(this, attacker, damageAmount);
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
msg.Write((byte)Sections.Length);
|
||||
for (int i = 0; i < Sections.Length; i++)
|
||||
|
||||
@@ -1,17 +1,23 @@
|
||||
using Barotrauma.Networking;
|
||||
using System;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class Submarine
|
||||
{
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerWritePosition(IWriteMessage msg, Client c)
|
||||
{
|
||||
msg.Write(ID);
|
||||
IWriteMessage tempBuffer = new WriteOnlyMessage();
|
||||
subBody.Body.ServerWrite(tempBuffer, c, extraData);
|
||||
subBody.Body.ServerWrite(tempBuffer);
|
||||
msg.Write((byte)tempBuffer.LengthBytes);
|
||||
msg.Write(tempBuffer.Buffer, 0, tempBuffer.LengthBytes);
|
||||
msg.WritePadBits();
|
||||
}
|
||||
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
throw new Exception($"Error while writing a network event for the submarine \"{Info.Name} ({ID})\". Submarines are not even supposed to send events!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
@@ -17,10 +16,10 @@ namespace Barotrauma.Networking
|
||||
Character orderTargetCharacter = null;
|
||||
Entity orderTargetEntity = null;
|
||||
OrderChatMessage orderMsg = null;
|
||||
OrderTarget orderTargetPosition = null;
|
||||
Order.OrderTargetType orderTargetType = Order.OrderTargetType.Entity;
|
||||
int? wallSectionIndex = null;
|
||||
Order order = null;
|
||||
bool isNewOrder = false;
|
||||
if (type == ChatMessageType.Order)
|
||||
{
|
||||
var orderMessageInfo = OrderChatMessage.ReadOrder(msg);
|
||||
@@ -30,9 +29,10 @@ namespace Barotrauma.Networking
|
||||
if (NetIdUtils.IdMoreRecent(ID, c.LastSentChatMsgID)) { c.LastSentChatMsgID = ID; }
|
||||
return;
|
||||
}
|
||||
isNewOrder = orderMessageInfo.IsNewOrder;
|
||||
orderTargetCharacter = orderMessageInfo.TargetCharacter;
|
||||
orderTargetEntity = orderMessageInfo.TargetEntity;
|
||||
orderTargetPosition = orderMessageInfo.TargetPosition;
|
||||
OrderTarget orderTargetPosition = orderMessageInfo.TargetPosition;
|
||||
orderTargetType = orderMessageInfo.TargetType;
|
||||
wallSectionIndex = orderMessageInfo.WallSectionIndex;
|
||||
var orderPrefab = orderMessageInfo.OrderPrefab ?? OrderPrefab.Prefabs[orderMessageInfo.OrderIdentifier];
|
||||
@@ -165,7 +165,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else if (orderTargetCharacter != null)
|
||||
{
|
||||
orderTargetCharacter.SetOrder(order);
|
||||
orderTargetCharacter.SetOrder(order, isNewOrder);
|
||||
}
|
||||
}
|
||||
GameMain.Server.SendOrderChatMessage(orderMsg);
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
using System.IO.Pipes;
|
||||
using System;
|
||||
using System.IO.Pipes;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
@@ -14,6 +17,12 @@ namespace Barotrauma.Networking
|
||||
PrivateStart();
|
||||
}
|
||||
|
||||
public static void NotifyCrash(string msg)
|
||||
{
|
||||
errorsToWrite.Enqueue(msg);
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
public static void ShutDown()
|
||||
{
|
||||
PrivateShutDown();
|
||||
|
||||
@@ -1,52 +1,55 @@
|
||||
using Barotrauma.Networking;
|
||||
using System;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class EntitySpawner : Entity, IServerSerializable
|
||||
{
|
||||
public void CreateNetworkEvent(Entity entity, bool remove)
|
||||
public void CreateNetworkEvent(SpawnOrRemove spawnOrRemove)
|
||||
{
|
||||
CreateNetworkEventProjSpecific(entity, remove);
|
||||
CreateNetworkEventProjSpecific(spawnOrRemove);
|
||||
}
|
||||
|
||||
partial void CreateNetworkEventProjSpecific(Entity entity, bool remove)
|
||||
partial void CreateNetworkEventProjSpecific(SpawnOrRemove spawnOrRemove)
|
||||
{
|
||||
if (GameMain.Server == null || entity == null) { return; }
|
||||
|
||||
GameMain.Server.CreateEntityEvent(this, new object[] { new SpawnOrRemove(entity, remove) });
|
||||
if (entity is Character character && character.Info != null)
|
||||
if (GameMain.Server == null || spawnOrRemove?.Entity == null) { return; }
|
||||
|
||||
GameMain.Server.CreateEntityEvent(this, spawnOrRemove);
|
||||
if (spawnOrRemove.Entity is Character { Info: { } } character)
|
||||
{
|
||||
foreach (var statKey in character.Info.SavedStatValues.Keys)
|
||||
{
|
||||
GameMain.NetworkMember.CreateEntityEvent(character, new object[] { NetEntityEvent.Type.UpdatePermanentStats, statKey });
|
||||
}
|
||||
}
|
||||
GameMain.NetworkMember.CreateEntityEvent(character, new Character.UpdatePermanentStatsEventData(statKey));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage message, Client client, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage message, Client client, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
if (GameMain.Server == null) { return; }
|
||||
if (GameMain.Server is null) { return; }
|
||||
if (!(extraData is SpawnOrRemove entities)) { throw new Exception($"Malformed {nameof(EntitySpawner)} event: expected {nameof(SpawnOrRemove)}"); }
|
||||
|
||||
SpawnOrRemove entities = (SpawnOrRemove)extraData[0];
|
||||
|
||||
message.Write(entities.Remove);
|
||||
if (entities.Remove)
|
||||
message.Write(entities is RemoveEntity);
|
||||
if (entities is RemoveEntity)
|
||||
{
|
||||
message.Write(entities.OriginalID);
|
||||
message.Write(entities.ID);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (entities.Entity is Item item)
|
||||
switch (entities.Entity)
|
||||
{
|
||||
message.Write((byte)SpawnableType.Item);
|
||||
DebugConsole.Log("Writing item spawn data " + entities.Entity.ToString() + " (original ID: " + entities.OriginalID + ", current ID: " + entities.Entity.ID + ")");
|
||||
item.WriteSpawnData(message, entities.OriginalID, entities.OriginalInventoryID, entities.OriginalItemContainerIndex, entities.OriginalSlotIndex);
|
||||
}
|
||||
else if (entities.Entity is Character character)
|
||||
{
|
||||
message.Write((byte)SpawnableType.Character);
|
||||
DebugConsole.Log("Writing character spawn data: " + entities.Entity.ToString() + " (original ID: " + entities.OriginalID + ", current ID: " + entities.Entity.ID + ")");
|
||||
character.WriteSpawnData(message, entities.OriginalID, restrictMessageSize: true);
|
||||
case Item item:
|
||||
message.Write((byte)SpawnableType.Item);
|
||||
DebugConsole.Log(
|
||||
$"Writing item spawn data {item} (ID: {entities.ID})");
|
||||
item.WriteSpawnData(message, entities.ID, entities.InventoryID, entities.ItemContainerIndex, entities.SlotIndex);
|
||||
break;
|
||||
case Character character:
|
||||
message.Write((byte)SpawnableType.Character);
|
||||
DebugConsole.Log(
|
||||
$"Writing character spawn data: {character} (ID: {entities.ID})");
|
||||
character.WriteSpawnData(message, entities.ID, restrictMessageSize: true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Barotrauma.Networking
|
||||
"ModSender",
|
||||
Task.WhenAll(
|
||||
ContentPackageManager.EnabledPackages.All
|
||||
.Where(p => p != ContentPackageManager.VanillaCorePackage && p.HasMultiplayerIncompatibleContent)
|
||||
.Where(p => p != ContentPackageManager.VanillaCorePackage && p.HasMultiplayerSyncedContent)
|
||||
.Select(CompressMod)),
|
||||
(t) => Ready = true);
|
||||
}
|
||||
|
||||
@@ -814,6 +814,12 @@ namespace Barotrauma.Networking
|
||||
case ClientPacketHeader.CREW:
|
||||
ReadCrewMessage(inc, connectedClient);
|
||||
break;
|
||||
case ClientPacketHeader.MONEY:
|
||||
ReadMoneyMessage(inc, connectedClient);
|
||||
break;
|
||||
case ClientPacketHeader.REWARD_DISTRIBUTION:
|
||||
ReadRewardDistributionMessage(inc, connectedClient);
|
||||
break;
|
||||
case ClientPacketHeader.MEDICAL:
|
||||
ReadMedicalMessage(inc, connectedClient);
|
||||
break;
|
||||
@@ -977,12 +983,12 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (entityEvent.Entity is EntitySpawner)
|
||||
{
|
||||
var spawnData = entityEvent.Data[0] as EntitySpawner.SpawnOrRemove;
|
||||
var spawnData = entityEvent.Data as EntitySpawner.SpawnOrRemove;
|
||||
errorLines.Add(
|
||||
entityEvent.ID + ": " +
|
||||
(spawnData.Remove ? "Remove " : "Create ") +
|
||||
(spawnData is EntitySpawner.RemoveEntity ? "Remove " : "Create ") +
|
||||
spawnData.Entity.ToString() +
|
||||
" (" + spawnData.OriginalID + ", " + spawnData.Entity.ID + ")");
|
||||
" (" + spawnData.ID + ", " + spawnData.Entity.ID + ")");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -996,7 +1002,7 @@ namespace Barotrauma.Networking
|
||||
File.WriteAllLines(filePath, errorLines);
|
||||
}
|
||||
|
||||
public override void CreateEntityEvent(INetSerializable entity, object[] extraData = null)
|
||||
public override void CreateEntityEvent(INetSerializable entity, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
if (!(entity is IServerSerializable serverSerializable))
|
||||
{
|
||||
@@ -1203,7 +1209,7 @@ namespace Barotrauma.Networking
|
||||
case ClientNetObject.CHARACTER_INPUT:
|
||||
if (c.Character != null)
|
||||
{
|
||||
c.Character.ServerRead(objHeader, inc, c);
|
||||
c.Character.ServerReadInput(inc, c);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1246,6 +1252,22 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadMoneyMessage(IReadMessage inc, Client sender)
|
||||
{
|
||||
if (GameMain.GameSession?.Campaign is MultiPlayerCampaign mpCampaign)
|
||||
{
|
||||
mpCampaign.ServerReadMoney(inc, sender);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadRewardDistributionMessage(IReadMessage inc, Client sender)
|
||||
{
|
||||
if (GameMain.GameSession?.Campaign is MultiPlayerCampaign mpCampaign)
|
||||
{
|
||||
mpCampaign.ServerReadRewardDistribution(inc, sender);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadMedicalMessage(IReadMessage inc, Client sender)
|
||||
{
|
||||
if (GameMain.GameSession?.Campaign is MultiPlayerCampaign mpCampaign)
|
||||
@@ -1714,7 +1736,8 @@ namespace Barotrauma.Networking
|
||||
while (!c.NeedsMidRoundSync && c.PendingPositionUpdates.Count > 0)
|
||||
{
|
||||
var entity = c.PendingPositionUpdates.Peek();
|
||||
if (entity == null || entity.Removed ||
|
||||
if (!(entity is IServerPositionSync entityPositionSync) ||
|
||||
entity.Removed ||
|
||||
(entity is Item item && float.IsInfinity(item.PositionUpdateInterval)))
|
||||
{
|
||||
c.PendingPositionUpdates.Dequeue();
|
||||
@@ -1724,14 +1747,7 @@ namespace Barotrauma.Networking
|
||||
IWriteMessage tempBuffer = new ReadWriteMessage();
|
||||
tempBuffer.Write(entity is Item); tempBuffer.WritePadBits();
|
||||
tempBuffer.Write(entity is MapEntity me ? me.Prefab.UintIdentifier : (UInt32)0);
|
||||
if (entity is Item)
|
||||
{
|
||||
((Item)entity).ServerWritePosition(tempBuffer, c);
|
||||
}
|
||||
else
|
||||
{
|
||||
((IServerSerializable)entity).ServerWrite(tempBuffer, c);
|
||||
}
|
||||
entityPositionSync.ServerWritePosition(tempBuffer, c);
|
||||
|
||||
//no more room in this packet
|
||||
if (outmsg.LengthBytes + tempBuffer.LengthBytes > MsgConstants.MTU - 100)
|
||||
@@ -1879,7 +1895,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
outmsg.Write(GameMain.NetLobbyScreen.SelectedSub.Name);
|
||||
outmsg.Write(GameMain.NetLobbyScreen.SelectedSub.MD5Hash.ToString());
|
||||
outmsg.Write(serverSettings.UseRespawnShuttle || (gameStarted && respawnManager.UsingShuttle));
|
||||
outmsg.Write(IsUsingRespawnShuttle());
|
||||
var selectedShuttle = gameStarted && respawnManager.UsingShuttle ? respawnManager.RespawnShuttle.Info : GameMain.NetLobbyScreen.SelectedShuttle;
|
||||
outmsg.Write(selectedShuttle.Name);
|
||||
outmsg.Write(selectedShuttle.MD5Hash.ToString());
|
||||
@@ -2061,7 +2077,7 @@ namespace Barotrauma.Networking
|
||||
msg.Write(selectedSub.Name);
|
||||
msg.Write(selectedSub.MD5Hash.StringRepresentation);
|
||||
|
||||
msg.Write(serverSettings.UseRespawnShuttle || (gameStarted && respawnManager.UsingShuttle));
|
||||
msg.Write(IsUsingRespawnShuttle());
|
||||
msg.Write(selectedShuttle.Name);
|
||||
msg.Write(selectedShuttle.MD5Hash.StringRepresentation);
|
||||
|
||||
@@ -2218,8 +2234,6 @@ namespace Barotrauma.Networking
|
||||
|
||||
CrewManager crewManager = campaign?.CrewManager;
|
||||
|
||||
entityEventManager.RefreshEntityIDs();
|
||||
|
||||
bool hadBots = true;
|
||||
|
||||
//assign jobs and spawnpoints separately for each team
|
||||
@@ -2366,6 +2380,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
characterData.ApplyHealthData(spawnedCharacter);
|
||||
characterData.ApplyOrderData(spawnedCharacter);
|
||||
characterData.ApplyWalletData(spawnedCharacter);
|
||||
spawnedCharacter.GiveIdCardTags(mainSubWaypoints[i]);
|
||||
spawnedCharacter.LoadTalents();
|
||||
|
||||
@@ -2419,7 +2434,7 @@ namespace Barotrauma.Networking
|
||||
List<PurchasedItem> spawnList = new List<PurchasedItem>();
|
||||
foreach (KeyValuePair<ItemPrefab, int> kvp in serverSettings.ExtraCargo)
|
||||
{
|
||||
spawnList.Add(new PurchasedItem(kvp.Key, kvp.Value));
|
||||
spawnList.Add(new PurchasedItem(kvp.Key, kvp.Value, buyer: null));
|
||||
}
|
||||
|
||||
CargoManager.CreateItems(spawnList, sub);
|
||||
@@ -2486,7 +2501,7 @@ namespace Barotrauma.Networking
|
||||
msg.Write(serverSettings.LockAllDefaultWires);
|
||||
msg.Write(serverSettings.AllowRagdollButton);
|
||||
msg.Write(serverSettings.AllowLinkingWifiToChat);
|
||||
msg.Write(serverSettings.UseRespawnShuttle || (gameStarted && respawnManager.UsingShuttle));
|
||||
msg.Write(IsUsingRespawnShuttle());
|
||||
msg.Write((byte)serverSettings.LosMode);
|
||||
msg.Write(includesFinalize); msg.WritePadBits();
|
||||
|
||||
@@ -2498,7 +2513,8 @@ namespace Barotrauma.Networking
|
||||
msg.Write(serverSettings.SelectedLevelDifficulty);
|
||||
msg.Write(gameSession.SubmarineInfo.Name);
|
||||
msg.Write(gameSession.SubmarineInfo.MD5Hash.StringRepresentation);
|
||||
var selectedShuttle = gameStarted && respawnManager.UsingShuttle ? respawnManager.RespawnShuttle.Info : GameMain.NetLobbyScreen.SelectedShuttle;
|
||||
var selectedShuttle = gameStarted && respawnManager != null && respawnManager.UsingShuttle ?
|
||||
respawnManager.RespawnShuttle.Info : GameMain.NetLobbyScreen.SelectedShuttle;
|
||||
msg.Write(selectedShuttle.Name);
|
||||
msg.Write(selectedShuttle.MD5Hash.StringRepresentation);
|
||||
msg.Write((byte)GameMain.GameSession.GameMode.Missions.Count());
|
||||
@@ -2527,6 +2543,11 @@ namespace Barotrauma.Networking
|
||||
serverPeer.Send(msg, client.Connection, DeliveryMethod.Reliable);
|
||||
}
|
||||
|
||||
private bool IsUsingRespawnShuttle()
|
||||
{
|
||||
return serverSettings.UseRespawnShuttle || (gameStarted && respawnManager != null && respawnManager.UsingShuttle);
|
||||
}
|
||||
|
||||
private void SendRoundStartFinalize(Client client)
|
||||
{
|
||||
IWriteMessage msg = new WriteOnlyMessage();
|
||||
@@ -3286,6 +3307,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
SubmarineInfo targetSubmarine = Voting.SubVote.Sub;
|
||||
VoteType voteType = Voting.SubVote.VoteType;
|
||||
Client starter = Voting.SubVote.VoteStarter;
|
||||
int deliveryFee = 0;
|
||||
|
||||
switch (voteType)
|
||||
@@ -3293,7 +3315,7 @@ namespace Barotrauma.Networking
|
||||
case VoteType.PurchaseAndSwitchSub:
|
||||
case VoteType.PurchaseSub:
|
||||
// Pay for submarine
|
||||
GameMain.GameSession.PurchaseSubmarine(targetSubmarine);
|
||||
GameMain.GameSession.PurchaseSubmarine(targetSubmarine, starter);
|
||||
break;
|
||||
case VoteType.SwitchSub:
|
||||
deliveryFee = Voting.SubVote.DeliveryFee;
|
||||
@@ -3304,7 +3326,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (voteType != VoteType.PurchaseSub)
|
||||
{
|
||||
SubmarineInfo newSub = GameMain.GameSession.SwitchSubmarine(targetSubmarine, deliveryFee);
|
||||
SubmarineInfo newSub = GameMain.GameSession.SwitchSubmarine(targetSubmarine, deliveryFee, starter);
|
||||
}
|
||||
|
||||
serverSettings.Voting.StopSubmarineVote(true);
|
||||
@@ -3461,7 +3483,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (client.Character != null) //removing control of the current character
|
||||
{
|
||||
CreateEntityEvent(client.Character, new object[] { NetEntityEvent.Type.Control, null });
|
||||
CreateEntityEvent(client.Character, new Character.ControlEventData(null));
|
||||
client.Character = null;
|
||||
}
|
||||
}
|
||||
@@ -3485,7 +3507,7 @@ namespace Barotrauma.Networking
|
||||
newCharacter.IsRemotePlayer = true;
|
||||
newCharacter.Enabled = true;
|
||||
client.Character = newCharacter;
|
||||
CreateEntityEvent(newCharacter, new object[] { NetEntityEvent.Type.Control, client });
|
||||
CreateEntityEvent(newCharacter, new Character.ControlEventData(client));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
-21
@@ -38,7 +38,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
public void Write(IWriteMessage msg, Client recipient)
|
||||
{
|
||||
serializable.ServerWrite(msg, recipient, Data);
|
||||
serializable.ServerEventWrite(msg, recipient, Data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ namespace Barotrauma.Networking
|
||||
lastWarningTime = -10.0;
|
||||
}
|
||||
|
||||
public void CreateEvent(IServerSerializable entity, object[] extraData = null)
|
||||
public void CreateEvent(IServerSerializable entity, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
if (!ValidateEntity(entity)) { return; }
|
||||
|
||||
@@ -291,12 +291,6 @@ namespace Barotrauma.Networking
|
||||
bufferedEvents.Add(bufferedEvent);
|
||||
}
|
||||
|
||||
public void RefreshEntityIDs()
|
||||
{
|
||||
events.ForEach(e => e.RefreshEntityID());
|
||||
uniqueEvents.ForEach(e => e.RefreshEntityID());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes all the events that the client hasn't received yet into the outgoing message
|
||||
/// </summary>
|
||||
@@ -310,15 +304,7 @@ namespace Barotrauma.Networking
|
||||
/// </summary>
|
||||
public void Write(Client client, IWriteMessage msg, out List<NetEntityEvent> sentEvents)
|
||||
{
|
||||
List<NetEntityEvent> eventsToSync = null;
|
||||
if (client.NeedsMidRoundSync)
|
||||
{
|
||||
eventsToSync = GetEventsToSync(client);
|
||||
}
|
||||
else
|
||||
{
|
||||
eventsToSync = GetEventsToSync(client);
|
||||
}
|
||||
List<NetEntityEvent> eventsToSync = GetEventsToSync(client);
|
||||
|
||||
if (eventsToSync.Count == 0)
|
||||
{
|
||||
@@ -460,6 +446,7 @@ namespace Barotrauma.Networking
|
||||
/// </summary>
|
||||
public void Read(IReadMessage msg, Client sender = null)
|
||||
{
|
||||
msg.ReadPadBits();
|
||||
UInt16 firstEventID = msg.ReadUInt16();
|
||||
int eventCount = msg.ReadByte();
|
||||
|
||||
@@ -470,7 +457,6 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (entityID == Entity.NullEntityID)
|
||||
{
|
||||
msg.ReadPadBits();
|
||||
if (thisEventID == (UInt16)(sender.LastSentEntityEventID + 1)) sender.LastSentEntityEventID++;
|
||||
continue;
|
||||
}
|
||||
@@ -490,7 +476,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else if (entity == null)
|
||||
{
|
||||
//entity not found -> consider the even read and skip over it
|
||||
//entity not found -> consider the event read and skip over it
|
||||
//(can happen, for example, when a client uses a medical item repeatedly
|
||||
//and creates an event for it before receiving the event about it being removed)
|
||||
if (GameSettings.CurrentConfig.VerboseLogging)
|
||||
@@ -519,7 +505,6 @@ namespace Barotrauma.Networking
|
||||
|
||||
sender.LastSentEntityEventID++;
|
||||
}
|
||||
msg.ReadPadBits();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -536,7 +521,7 @@ namespace Barotrauma.Networking
|
||||
var clientEntity = entity as IClientSerializable;
|
||||
if (clientEntity == null) return;
|
||||
|
||||
clientEntity.ServerRead(ClientNetObject.ENTITY_STATE, buffer, sender);
|
||||
clientEntity.ServerEventRead(buffer, sender);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
|
||||
+1
-1
@@ -246,7 +246,7 @@ namespace Barotrauma.Networking
|
||||
case ConnectionInitialization.ContentPackageOrder:
|
||||
outMsg.Write(GameMain.Server.ServerName);
|
||||
|
||||
var mpContentPackages = ContentPackageManager.EnabledPackages.All.Where(cp => cp.HasMultiplayerIncompatibleContent).ToList();
|
||||
var mpContentPackages = ContentPackageManager.EnabledPackages.All.Where(cp => cp.HasMultiplayerSyncedContent).ToList();
|
||||
outMsg.WriteVariableUInt32((UInt32)mpContentPackages.Count);
|
||||
for (int i = 0; i < mpContentPackages.Count; i++)
|
||||
{
|
||||
|
||||
@@ -447,11 +447,11 @@ namespace Barotrauma.Networking
|
||||
if (divingSuitPrefab != null && oxyPrefab != null)
|
||||
{
|
||||
var divingSuit = new Item(divingSuitPrefab, pos, respawnSub);
|
||||
Spawner.CreateNetworkEvent(divingSuit, false);
|
||||
Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(divingSuit));
|
||||
respawnItems.Add(divingSuit);
|
||||
|
||||
var oxyTank = new Item(oxyPrefab, pos, respawnSub);
|
||||
Spawner.CreateNetworkEvent(oxyTank, false);
|
||||
Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(oxyTank));
|
||||
divingSuit.Combine(oxyTank, user: null);
|
||||
respawnItems.Add(oxyTank);
|
||||
}
|
||||
@@ -459,10 +459,10 @@ namespace Barotrauma.Networking
|
||||
if (scooterPrefab != null && batteryPrefab != null)
|
||||
{
|
||||
var scooter = new Item(scooterPrefab, pos, respawnSub);
|
||||
Spawner.CreateNetworkEvent(scooter, false);
|
||||
Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(scooter));
|
||||
|
||||
var battery = new Item(batteryPrefab, pos, respawnSub);
|
||||
Spawner.CreateNetworkEvent(battery, false);
|
||||
Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(battery));
|
||||
|
||||
scooter.Combine(battery, user: null);
|
||||
respawnItems.Add(scooter);
|
||||
@@ -528,7 +528,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
msg.WriteRangedInteger((int)CurrentState, 0, Enum.GetNames(typeof(State)).Length);
|
||||
|
||||
|
||||
@@ -131,7 +131,7 @@ namespace Barotrauma
|
||||
{
|
||||
string subName = inc.ReadString();
|
||||
SubmarineInfo subInfo = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == subName);
|
||||
if (GameMain.GameSession?.Campaign is MultiPlayerCampaign campaign && (campaign.CanPurchaseSub(subInfo) || GameMain.GameSession.IsSubmarineOwned(subInfo)))
|
||||
if (GameMain.GameSession?.Campaign is MultiPlayerCampaign campaign && (campaign.CanPurchaseSub(subInfo, sender) || GameMain.GameSession.IsSubmarineOwned(subInfo)))
|
||||
{
|
||||
StartSubmarineVote(subInfo, voteType, sender);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Barotrauma
|
||||
{
|
||||
partial class PhysicsBody
|
||||
{
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerWrite(IWriteMessage msg)
|
||||
{
|
||||
float MaxVel = NetConfig.MaxPhysicsBodyVelocity;
|
||||
float MaxAngularVel = NetConfig.MaxPhysicsBodyAngularVelocity;
|
||||
|
||||
@@ -5,6 +5,7 @@ using System;
|
||||
using Barotrauma.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Barotrauma.Networking;
|
||||
#if LINUX
|
||||
using System.Runtime.InteropServices;
|
||||
#endif
|
||||
@@ -26,6 +27,20 @@ namespace Barotrauma
|
||||
private static extern void setLinuxEnv();
|
||||
#endif
|
||||
|
||||
public static bool TryStartChildServerRelay(string[] commandLineArgs)
|
||||
{
|
||||
for (int i = 0; i < commandLineArgs.Length; i++)
|
||||
{
|
||||
switch (commandLineArgs[i].Trim())
|
||||
{
|
||||
case "-pipes":
|
||||
ChildServerRelay.Start(commandLineArgs[i + 2], commandLineArgs[i + 1]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
@@ -36,6 +51,7 @@ namespace Barotrauma
|
||||
AppDomain currentDomain = AppDomain.CurrentDomain;
|
||||
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(CrashHandler);
|
||||
#endif
|
||||
TryStartChildServerRelay(args);
|
||||
|
||||
#if LINUX
|
||||
setLinuxEnv();
|
||||
@@ -62,22 +78,49 @@ namespace Barotrauma
|
||||
|
||||
static GameMain Game;
|
||||
|
||||
private static void NotifyCrash(string reportFilePath, Exception e)
|
||||
{
|
||||
string errorMsg = $"{reportFilePath}||\n{e.Message} ({e.GetType().Name}) {e.StackTrace}";
|
||||
if (e.InnerException != null)
|
||||
{
|
||||
var innerMost = e.GetInnermost();
|
||||
errorMsg += $"\nInner exception: {innerMost.Message} ({innerMost.GetType().Name}) {e.StackTrace}";
|
||||
}
|
||||
if (errorMsg.Length > ushort.MaxValue) { errorMsg = errorMsg[..ushort.MaxValue]; }
|
||||
ChildServerRelay.NotifyCrash(errorMsg);
|
||||
GameMain.Server?.NotifyCrash();
|
||||
}
|
||||
|
||||
private static void CrashHandler(object sender, UnhandledExceptionEventArgs args)
|
||||
{
|
||||
void swallowExceptions(Action action)
|
||||
{
|
||||
try
|
||||
{
|
||||
action();
|
||||
}
|
||||
catch
|
||||
{
|
||||
//discard exceptions and keep going
|
||||
}
|
||||
}
|
||||
|
||||
string reportFilePath = "";
|
||||
try
|
||||
{
|
||||
Game?.Exit();
|
||||
CrashDump("servercrashreport.log", (Exception)args.ExceptionObject);
|
||||
GameMain.Server?.NotifyCrash();
|
||||
reportFilePath = "servercrashreport.log";
|
||||
CrashDump(ref reportFilePath, (Exception)args.ExceptionObject);
|
||||
}
|
||||
catch
|
||||
{
|
||||
//exception handler is broken, we have a serious problem here!!
|
||||
return;
|
||||
//fuck
|
||||
reportFilePath = "";
|
||||
}
|
||||
swallowExceptions(() => NotifyCrash(reportFilePath, (Exception)args.ExceptionObject));
|
||||
swallowExceptions(() => Game?.Exit());
|
||||
}
|
||||
|
||||
static void CrashDump(string filePath, Exception exception)
|
||||
static void CrashDump(ref string filePath, Exception exception)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace Barotrauma.Steam
|
||||
return false;
|
||||
}
|
||||
|
||||
var contentPackages = ContentPackageManager.EnabledPackages.All.Where(cp => cp.HasMultiplayerIncompatibleContent);
|
||||
var contentPackages = ContentPackageManager.EnabledPackages.All.Where(cp => cp.HasMultiplayerSyncedContent);
|
||||
|
||||
// These server state variables may be changed at any time. Note that there is no longer a mechanism
|
||||
// to send the player count. The player count is maintained by Steam and you should use the player
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Barotrauma
|
||||
Role = role;
|
||||
Character = character;
|
||||
Character.IsTraitor = true;
|
||||
GameMain.NetworkMember.CreateEntityEvent(Character, new object[] { NetEntityEvent.Type.Status });
|
||||
GameMain.NetworkMember.CreateEntityEvent(Character, new Character.StatusEventData());
|
||||
}
|
||||
|
||||
public delegate void MessageSender(string message);
|
||||
|
||||
Reference in New Issue
Block a user