Unstable 0.17.1.0
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user