diff --git a/Subsurface/Properties/AssemblyInfo.cs b/Subsurface/Properties/AssemblyInfo.cs index caaef8883..744e0f391 100644 --- a/Subsurface/Properties/AssemblyInfo.cs +++ b/Subsurface/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.2.3.0")] -[assembly: AssemblyFileVersion("0.2.3.0")] +[assembly: AssemblyVersion("0.2.3.1")] +[assembly: AssemblyFileVersion("0.2.3.1")] diff --git a/Subsurface/Source/Characters/AICharacter.cs b/Subsurface/Source/Characters/AICharacter.cs index 6ea38dab6..30f24bc05 100644 --- a/Subsurface/Source/Characters/AICharacter.cs +++ b/Subsurface/Source/Characters/AICharacter.cs @@ -85,50 +85,43 @@ namespace Barotrauma public override bool FillNetworkData(NetworkEventType type, NetOutgoingMessage message, object data) { - if (type == NetworkEventType.KillCharacter) + switch (type) { - return true; - } + case NetworkEventType.KillCharacter: + return true; + case NetworkEventType.ImportantEntityUpdate: + int i = 0; + foreach (Limb limb in AnimController.Limbs) + { + if (limb.ignoreCollisions) continue; - message.Write((float)NetTime.Now); + message.Write(limb.body.SimPosition.X); + message.Write(limb.body.SimPosition.Y); - message.Write(LargeUpdateTimer <= 0); + message.Write(limb.body.Rotation); + i++; + } + + message.WriteRangedSingle(MathHelper.Clamp(AnimController.StunTimer, 0.0f, 60.0f), 0.0f, 60.0f, 8); + message.Write((byte)((health / maxHealth) * 255.0f)); + + aiController.FillNetworkData(message); + return true; + case NetworkEventType.EntityUpdate: + message.Write((float)NetTime.Now); + + message.Write(AnimController.TargetDir == Direction.Right); + message.WriteRangedSingle(MathHelper.Clamp(AnimController.TargetMovement.X, -10.0f, 10.0f), -10.0f, 10.0f, 16); + message.WriteRangedSingle(MathHelper.Clamp(AnimController.TargetMovement.Y, -10.0f, 10.0f), -10.0f, 10.0f, 16); - message.Write(AnimController.TargetDir == Direction.Right); - message.WriteRangedSingle(MathHelper.Clamp(AnimController.TargetMovement.X, -10.0f, 10.0f), -10.0f, 10.0f, 16); - message.WriteRangedSingle(MathHelper.Clamp(AnimController.TargetMovement.Y, -10.0f, 10.0f), -10.0f, 10.0f, 16); + message.Write(AnimController.RefLimb.SimPosition.X); + message.Write(AnimController.RefLimb.SimPosition.Y); + + message.Write(AnimController.RefLimb.LinearVelocity.X); + message.Write(AnimController.RefLimb.LinearVelocity.Y); + return true; + } - if (LargeUpdateTimer <= 0) - { - int i = 0; - foreach (Limb limb in AnimController.Limbs) - { - message.Write(limb.body.SimPosition.X); - message.Write(limb.body.SimPosition.Y); - - message.Write(limb.body.Rotation); - i++; - } - - message.WriteRangedSingle(MathHelper.Clamp(AnimController.StunTimer, 0.0f, 60.0f), 0.0f, 60.0f, 8); - message.Write((byte)((health / maxHealth) * 255.0f)); - - aiController.FillNetworkData(message); - - LargeUpdateTimer = 50; - } - else - { - message.Write(AnimController.RefLimb.SimPosition.X); - message.Write(AnimController.RefLimb.SimPosition.Y); - - message.Write(AnimController.RefLimb.LinearVelocity.X); - message.Write(AnimController.RefLimb.LinearVelocity.Y); - - LargeUpdateTimer = Math.Max(0, LargeUpdateTimer - 1); - } - - return true; } @@ -136,115 +129,91 @@ namespace Barotrauma { Enabled = true; - if (type == NetworkEventType.KillCharacter) + switch (type) { - Kill(true); - return; - } + case NetworkEventType.KillCharacter: + Kill(CauseOfDeath.Damage, true); + return; + case NetworkEventType.ImportantEntityUpdate: + foreach (Limb limb in AnimController.Limbs) + { + if (limb.ignoreCollisions) continue; - float sendingTime = 0.0f; - Vector2 targetMovement = Vector2.Zero; - bool targetDir = false; + Vector2 limbPos = limb.SimPosition; + float rotation = limb.Rotation; - bool isLargeUpdate; + try + { + limbPos.X = message.ReadFloat(); + limbPos.Y = message.ReadFloat(); - - try - { - sendingTime = message.ReadFloat(); - isLargeUpdate = message.ReadBoolean(); - } + rotation = message.ReadFloat(); + } + catch + { + return; + } - catch - { - return; - } + if (limb.body != null) + { + limb.body.TargetVelocity = limb.body.LinearVelocity; + limb.body.TargetPosition = limbPos;// +vel * (float)(deltaTime / 60.0); + limb.body.TargetRotation = rotation;// +angularVel * (float)(deltaTime / 60.0); + limb.body.TargetAngularVelocity = limb.body.AngularVelocity; + } + } - if (sendingTime <= LastNetworkUpdate) return; - - try - { - targetDir = message.ReadBoolean(); - targetMovement.X = message.ReadRangedSingle(-10.0f, 10.0f, 16); - targetMovement.Y = message.ReadRangedSingle(-10.0f, 10.0f, 16); - - } - catch - { - return; - } - - AnimController.TargetDir = (targetDir) ? Direction.Right : Direction.Left; - AnimController.TargetMovement = targetMovement; - - - if (isLargeUpdate) - { - foreach (Limb limb in AnimController.Limbs) - { - Vector2 pos = Vector2.Zero, vel = Vector2.Zero; - float rotation = 0.0f; + float newStunTimer = 0.0f, newHealth = 0.0f; try { + newStunTimer = message.ReadRangedSingle(0.0f, 60.0f, 8); + newHealth = (message.ReadByte() / 255.0f) * maxHealth; + } + catch { return; } + + AnimController.StunTimer = newStunTimer; + health = newHealth; + + aiController.ReadNetworkData(message); + return; + case NetworkEventType.EntityUpdate: + float sendingTime = 0.0f; + Vector2 targetMovement = Vector2.Zero; + bool targetDir = false; + + sendingTime = message.ReadFloat(); + if (sendingTime <= LastNetworkUpdate) return; + + Vector2 pos = Vector2.Zero, vel = Vector2.Zero; + + try + { + targetDir = message.ReadBoolean(); + targetMovement.X = message.ReadRangedSingle(-10.0f, 10.0f, 16); + targetMovement.Y = message.ReadRangedSingle(-10.0f, 10.0f, 16); + pos.X = message.ReadFloat(); pos.Y = message.ReadFloat(); - rotation = message.ReadFloat(); + vel.X = message.ReadFloat(); + vel.Y = message.ReadFloat(); + } - catch + catch (Exception e) { return; } - if (limb.body != null) - { - limb.body.TargetVelocity = limb.body.LinearVelocity; - limb.body.TargetPosition = pos;// +vel * (float)(deltaTime / 60.0); - limb.body.TargetRotation = rotation;// +angularVel * (float)(deltaTime / 60.0); - limb.body.TargetAngularVelocity = limb.body.AngularVelocity; - } - } - - float newStunTimer = 0.0f, newHealth = 0.0f; - - try - { - newStunTimer = message.ReadRangedSingle(0.0f, 60.0f, 8); - newHealth = (message.ReadByte() / 255.0f) * maxHealth; - } - catch { return; } - - AnimController.StunTimer = newStunTimer; - Health = newHealth; - - LargeUpdateTimer = 1; - - aiController.ReadNetworkData(message); + AnimController.TargetDir = (targetDir) ? Direction.Right : Direction.Left; + AnimController.TargetMovement = targetMovement; + + AnimController.RefLimb.body.TargetPosition = pos; + AnimController.RefLimb.body.TargetVelocity = vel; + + LastNetworkUpdate = sendingTime; + return; } - else - { - Vector2 pos = Vector2.Zero, vel = Vector2.Zero; - try - { - pos.X = message.ReadFloat(); - pos.Y = message.ReadFloat(); - - vel.X = message.ReadFloat(); - vel.Y = message.ReadFloat(); - } - - catch { return; } - - //error - AnimController.RefLimb.body.TargetPosition = pos; - AnimController.RefLimb.body.TargetVelocity = vel; - - LargeUpdateTimer = 0; - } - - LastNetworkUpdate = sendingTime; - } diff --git a/Subsurface/Source/Characters/Attack.cs b/Subsurface/Source/Characters/Attack.cs index 68e217394..26a19cc89 100644 --- a/Subsurface/Source/Characters/Attack.cs +++ b/Subsurface/Source/Characters/Attack.cs @@ -6,6 +6,10 @@ using System.Xml.Linq; namespace Barotrauma { + enum CauseOfDeath + { + Damage, Bloodloss, Pressure, Suffocation, Drowning + } public enum DamageType { None, Blunt, Slash } diff --git a/Subsurface/Source/Characters/Character.cs b/Subsurface/Source/Characters/Character.cs index d8e9835a5..961b6d05b 100644 --- a/Subsurface/Source/Characters/Character.cs +++ b/Subsurface/Source/Characters/Character.cs @@ -15,9 +15,11 @@ using System.Xml.Linq; namespace Barotrauma { - + class Character : Entity, IDamageable, IPropertyObject { + public static string[] DeathMsg = new string[Enum.GetNames(typeof(CauseOfDeath)).Length]; + public static List CharacterList = new List(); public static Queue NewCharacterQueue = new Queue(); @@ -40,12 +42,13 @@ namespace Barotrauma } public readonly bool IsNetworkPlayer; + private int importantUpdateTimer; private CharacterInventory inventory; public float LastNetworkUpdate; - public int LargeUpdateTimer; + //public int LargeUpdateTimer; public readonly Dictionary Properties; public Dictionary ObjectProperties @@ -173,7 +176,7 @@ namespace Barotrauma set { oxygen = MathHelper.Clamp(value, 0.0f, 100.0f); - if (oxygen == 0.0f) Kill(); + if (oxygen == 0.0f) Kill(CauseOfDeath.Suffocation); } } @@ -185,17 +188,14 @@ namespace Barotrauma public float Health { - get - { - return health; - } - set - { + get { return health; } + set + { health = MathHelper.Clamp(value, 0.0f, maxHealth); - if (health == 0.0f) Kill(); + if (health <= 0.0f) Kill(CauseOfDeath.Damage); } - } - + } + public float MaxHealth { get { return maxHealth; } @@ -221,47 +221,6 @@ namespace Barotrauma { get { return selectedItems; } } - - public bool HasSelectedItem(Item item) - { - return selectedItems.Contains(item); - } - - public bool TrySelectItem(Item item) - { - bool rightHand = ((CharacterInventory)inventory).IsInLimbSlot(item, LimbSlot.RightHand); - bool leftHand = ((CharacterInventory)inventory).IsInLimbSlot(item, LimbSlot.LeftHand); - - bool selected = false; - if (rightHand && SelectedItems[0] == null) - { - selectedItems[0] = item; - selected = true; - } - if (leftHand && SelectedItems[1] == null) - { - selectedItems[1] = item; - selected = true; - } - - return selected; - } - - public bool TrySelectItem(Item item, int index) - { - if (selectedItems[index] != null) return false; - - selectedItems[index] = item; - return true; - } - - public void DeselectItem(Item item) - { - for (int i = 0; i < selectedItems.Length; i++) - { - if (selectedItems[i] == item) selectedItems[i] = null; - } - } public Item SelectedConstruction { @@ -294,6 +253,15 @@ namespace Barotrauma get { return ConvertUnits.ToDisplayUnits(AnimController.Limbs[0].SimPosition); } } + static Character() + { + DeathMsg[(int)CauseOfDeath.Damage] = "died"; + DeathMsg[(int)CauseOfDeath.Bloodloss] = "bled out"; + DeathMsg[(int)CauseOfDeath.Drowning] = "drowned"; + DeathMsg[(int)CauseOfDeath.Suffocation] = "suffocated"; + DeathMsg[(int)CauseOfDeath.Pressure] = "been crushed by water pressure"; + } + public Character(string file) : this(file, Vector2.Zero, null) { } @@ -559,7 +527,7 @@ namespace Barotrauma if (selectedConstruction != null) { if (GetInputState(InputType.ActionHeld)) selectedConstruction.Use(deltaTime, this); - if (GetInputState(InputType.SecondaryHeld)) selectedConstruction.SecondaryUse(deltaTime, this); + if (selectedConstruction != null && GetInputState(InputType.SecondaryHeld)) selectedConstruction.SecondaryUse(deltaTime, this); } if (IsNetworkPlayer) @@ -571,6 +539,56 @@ namespace Barotrauma } } + public void CreateUpdateNetworkEvent(bool isClient) + { + new NetworkEvent(importantUpdateTimer <= 0 ? NetworkEventType.ImportantEntityUpdate : NetworkEventType.EntityUpdate, ID, isClient); + + importantUpdateTimer -= 1; + if (importantUpdateTimer < 0) importantUpdateTimer = (this is AICharacter) ? 40 : 25; + } + + + public bool HasSelectedItem(Item item) + { + return selectedItems.Contains(item); + } + + public bool TrySelectItem(Item item) + { + bool rightHand = ((CharacterInventory)inventory).IsInLimbSlot(item, LimbSlot.RightHand); + bool leftHand = ((CharacterInventory)inventory).IsInLimbSlot(item, LimbSlot.LeftHand); + + bool selected = false; + if (rightHand && SelectedItems[0] == null) + { + selectedItems[0] = item; + selected = true; + } + if (leftHand && SelectedItems[1] == null) + { + selectedItems[1] = item; + selected = true; + } + + return selected; + } + + public bool TrySelectItem(Item item, int index) + { + if (selectedItems[index] != null) return false; + + selectedItems[index] = item; + return true; + } + + public void DeselectItem(Item item) + { + for (int i = 0; i < selectedItems.Length; i++) + { + if (selectedItems[i] == item) selectedItems[i] = null; + } + } + private Item FindClosestItem(Vector2 mouseSimPos) { Limb torso = AnimController.GetLimb(LimbType.Torso); @@ -824,6 +842,7 @@ namespace Barotrauma } Health = health - bleeding * deltaTime; + if (health <= 0.0f) Kill(CauseOfDeath.Bloodloss, false); } @@ -960,8 +979,14 @@ namespace Barotrauma selectedConstruction = null; } - private void Implode() + private void Implode(bool isNetworkMessage = false) { + if (!isNetworkMessage) + { + //if the game is run by a client, characters are only killed when the server says so + if (GameMain.Client != null && GameMain.Server == null) return; + } + Vector2 centerOfMass = AnimController.GetCenterOfMass(); health = 0.0f; @@ -992,7 +1017,7 @@ namespace Barotrauma { joint.LimitEnabled = false; } - Kill(); + Kill(CauseOfDeath.Pressure, isNetworkMessage); } private IEnumerable DeathAnim(Camera cam) @@ -1040,7 +1065,7 @@ namespace Barotrauma yield return CoroutineStatus.Success; } - public void Kill(bool networkMessage = false) + public void Kill(CauseOfDeath causeOfDeath, bool networkMessage = false) { if (isDead) return; @@ -1077,7 +1102,7 @@ namespace Barotrauma if (GameMain.Server != null) { - new NetworkEvent(NetworkEventType.KillCharacter, ID, false, true); + new NetworkEvent(NetworkEventType.KillCharacter, ID, false, causeOfDeath); } if (GameMain.GameSession != null) @@ -1088,313 +1113,311 @@ namespace Barotrauma public override bool FillNetworkData(NetworkEventType type, NetOutgoingMessage message, object data) { - if (type == NetworkEventType.PickItem) + switch (type) { - int[] pickData = (int[])data; - if (pickData.Length != 3) return false; + case NetworkEventType.PickItem: + int[] pickData = (int[])data; + if (pickData.Length != 3) return false; - message.Write((ushort)pickData[0]); - message.Write((int)pickData[1] == 1); - message.Write((int)pickData[2] == 1); - message.WritePadBits(); + message.Write((ushort)pickData[0]); + message.Write((int)pickData[1] == 1); + message.Write((int)pickData[2] == 1); + message.WritePadBits(); - return true; - } - else if (type == NetworkEventType.SelectCharacter) - { - message.Write((ushort)data); - return true; - } - else if (type == NetworkEventType.KillCharacter) - { - return true; - } - else if (type == NetworkEventType.InventoryUpdate) - { - if (inventory == null) return false; - return inventory.FillNetworkData(NetworkEventType.InventoryUpdate, message, data); - } + return true; + case NetworkEventType.SelectCharacter: + message.Write((ushort)data); + return true; + case NetworkEventType.KillCharacter: + CauseOfDeath causeOfDeath = CauseOfDeath.Damage; + try + { + causeOfDeath = (CauseOfDeath)data; + } + catch + { + causeOfDeath = CauseOfDeath.Damage; + } - var hasInputs = - (GetInputState(InputType.Left) || - GetInputState(InputType.Right) || - GetInputState(InputType.Up) || - GetInputState(InputType.Down) || - GetInputState(InputType.ActionHeld) || - GetInputState(InputType.SecondaryHeld)) || LargeUpdateTimer <= 0; - - message.Write(hasInputs); - message.Write((float)NetTime.Now); + message.Write((byte)causeOfDeath); - if (!hasInputs) return true; + return true; + case NetworkEventType.InventoryUpdate: + if (inventory == null) return false; + return inventory.FillNetworkData(NetworkEventType.InventoryUpdate, message, data); + case NetworkEventType.ImportantEntityUpdate: + int i = 0; + foreach (Limb limb in AnimController.Limbs) + { + message.Write(limb.body.SimPosition.X); + message.Write(limb.body.SimPosition.Y); - - // Write byte = move direction - //message.WriteRangedSingle(MathHelper.Clamp(AnimController.TargetMovement.X, -10.0f, 10.0f), -10.0f, 10.0f, 8); - //message.WriteRangedSingle(MathHelper.Clamp(AnimController.TargetMovement.Y, -10.0f, 10.0f), -10.0f, 10.0f, 8); - - message.Write(keys[(int)InputType.ActionHeld].Dequeue); + //message.Write(limb.body.LinearVelocity.X); + //message.Write(limb.body.LinearVelocity.Y); - bool secondaryHeld = keys[(int)InputType.SecondaryHeld].Dequeue; - message.Write(secondaryHeld); + message.Write(limb.body.Rotation); + //message.WriteRangedSingle(MathHelper.Clamp(limb.body.AngularVelocity, -10.0f, 10.0f), -10.0f, 10.0f, 8); + i++; + } + + message.WriteRangedSingle(MathHelper.Clamp(AnimController.StunTimer,0.0f,60.0f), 0.0f, 60.0f, 8); + message.Write((byte)((health/maxHealth)*255.0f)); + message.Write((byte)(MathHelper.Clamp(oxygen * 2.55f, 0.0f, 255.0f))); + + + return true; + case NetworkEventType.EntityUpdate: + var hasInputs = + GetInputState(InputType.Left) || + GetInputState(InputType.Right) || + GetInputState(InputType.Up) || + GetInputState(InputType.Down) || + GetInputState(InputType.ActionHeld) || + GetInputState(InputType.SecondaryHeld); + + message.Write(hasInputs); + message.Write((float)NetTime.Now); + + if (!hasInputs) return true; + + message.Write(keys[(int)InputType.ActionHeld].Dequeue); + + bool secondaryHeld = keys[(int)InputType.SecondaryHeld].Dequeue; + message.Write(secondaryHeld); - message.Write(keys[(int)InputType.Left].Dequeue); - message.Write(keys[(int)InputType.Right].Dequeue); + message.Write(keys[(int)InputType.Left].Dequeue); + message.Write(keys[(int)InputType.Right].Dequeue); - message.Write(keys[(int)InputType.Up].Dequeue); - message.Write(keys[(int)InputType.Down].Dequeue); + message.Write(keys[(int)InputType.Up].Dequeue); + message.Write(keys[(int)InputType.Down].Dequeue); - message.Write(keys[(int)InputType.Run].Dequeue); + message.Write(keys[(int)InputType.Run].Dequeue); - if (secondaryHeld) - { - message.Write(cursorPosition.X); - message.Write(cursorPosition.Y); + if (secondaryHeld) + { + message.Write(cursorPosition.X); + message.Write(cursorPosition.Y); + } + else + { + message.Write(AnimController.Dir > 0.0f); + } + + message.Write(AnimController.RefLimb.SimPosition.X); + message.Write(AnimController.RefLimb.SimPosition.Y); + + return true; + default: +#if DEBUG + DebugConsole.ThrowError("Character "+this+" tried to fill a networkevent of the wrong type: "+type); +#endif + return false; } - else - { - message.Write(AnimController.Dir > 0.0f); - } - - message.Write(LargeUpdateTimer <= 0); - - if (LargeUpdateTimer<=0) - { - int i = 0; - foreach (Limb limb in AnimController.Limbs) - { - message.Write(limb.body.SimPosition.X); - message.Write(limb.body.SimPosition.Y); - - //message.Write(limb.body.LinearVelocity.X); - //message.Write(limb.body.LinearVelocity.Y); - - message.Write(limb.body.Rotation); - //message.WriteRangedSingle(MathHelper.Clamp(limb.body.AngularVelocity, -10.0f, 10.0f), -10.0f, 10.0f, 8); - i++; - } - - message.WriteRangedSingle(MathHelper.Clamp(AnimController.StunTimer,0.0f,60.0f), 0.0f, 60.0f, 8); - message.Write((byte)((health/maxHealth)*255.0f)); - - LargeUpdateTimer = 30; - } - else - { - message.Write(AnimController.RefLimb.SimPosition.X); - message.Write(AnimController.RefLimb.SimPosition.Y); - - LargeUpdateTimer = Math.Max(0, LargeUpdateTimer-1); - } - - return true; } public override void ReadNetworkData(NetworkEventType type, NetIncomingMessage message) { Enabled = true; - if (type == NetworkEventType.PickItem) + switch (type) { - System.Diagnostics.Debug.WriteLine("**************** PickItem networkevent received"); + case NetworkEventType.PickItem: + System.Diagnostics.Debug.WriteLine("**************** PickItem networkevent received"); - ushort itemId = 0; + ushort itemId = message.ReadUInt16(); - itemId = message.ReadUInt16(); + bool pickHit = message.ReadBoolean(); + bool actionHit = message.ReadBoolean(); - bool pickHit = message.ReadBoolean(); - bool actionHit = message.ReadBoolean(); + System.Diagnostics.Debug.WriteLine("item id: "+itemId); - System.Diagnostics.Debug.WriteLine("item id: "+itemId); + Item item = FindEntityByID(itemId) as Item; + if (item != null) item.Pick(this, false, pickHit, actionHit); - Item item = FindEntityByID(itemId) as Item; - if (item != null) - { - item.Pick(this, false, pickHit, actionHit); - } - - return; - } - else if (type == NetworkEventType.SelectCharacter) - { - ushort characterId = message.ReadUInt16(); - if (characterId==0) - { - DeselectCharacter(false); - } - else - { - Character character = FindEntityByID(characterId) as Character; - if (character != null) SelectCharacter(character, false); - } - return; - } - else if (type == NetworkEventType.KillCharacter) - { - Kill(true); - if (GameMain.NetworkMember != null && controlled == this) - { - GameMain.NetworkMember.AddChatMessage("YOU HAVE DIED. Your chat messages will only be visible to other dead players.", ChatMessageType.Dead); - GameMain.LightManager.LosEnabled = false; - } - return; - } - else if (type == NetworkEventType.InventoryUpdate) - { - if (inventory == null) return; - inventory.ReadNetworkData(NetworkEventType.InventoryUpdate, message); - return; - } - - bool actionKeyState = false; - bool secondaryKeyState = false; - float sendingTime = 0.0f; - Vector2 cursorPos = Vector2.Zero; - - bool leftKeyState = false, rightKeyState = false; - bool upKeyState = false, downKeyState = false; - - bool runState = false; - - try - { - bool hasInputs = message.ReadBoolean(); - sendingTime = message.ReadFloat(); - - if (!hasInputs) - { - if (sendingTime > LastNetworkUpdate) ClearInputs(); return; - } + case NetworkEventType.SelectCharacter: + ushort characterId = message.ReadUInt16(); + if (characterId==0) + { + DeselectCharacter(false); + } + else + { + Character character = FindEntityByID(characterId) as Character; + if (character != null) SelectCharacter(character, false); + } + return; + case NetworkEventType.KillCharacter: + CauseOfDeath causeOfDeath = CauseOfDeath.Damage; + try + { + byte causeOfDeathByte = message.ReadByte(); + causeOfDeath = (CauseOfDeath)causeOfDeathByte; + } + catch + { + causeOfDeath = CauseOfDeath.Damage; + } - actionKeyState = message.ReadBoolean(); - secondaryKeyState = message.ReadBoolean(); - - leftKeyState = message.ReadBoolean(); - rightKeyState = message.ReadBoolean(); - upKeyState = message.ReadBoolean(); - downKeyState = message.ReadBoolean(); + if (causeOfDeath==CauseOfDeath.Pressure) + { + Implode(true); + } + else + { + Kill(causeOfDeath, true); + } - runState = message.ReadBoolean(); - } + if (GameMain.NetworkMember != null && controlled == this) + { + GameMain.NetworkMember.AddChatMessage("You have "+DeathMsg[(int)causeOfDeath]+". Your chat messages will only be visible to other dead players.", ChatMessageType.Dead); + GameMain.LightManager.LosEnabled = false; + } + return; + case NetworkEventType.InventoryUpdate: + if (inventory == null) return; + inventory.ReadNetworkData(NetworkEventType.InventoryUpdate, message); + return; + case NetworkEventType.ImportantEntityUpdate: + foreach (Limb limb in AnimController.Limbs) + { + Vector2 limbPos = limb.SimPosition, vel = Vector2.Zero; + float rotation = limb.Rotation; - catch (Exception e) - { - return; - } + try + { + limbPos.X = message.ReadFloat(); + limbPos.Y = message.ReadFloat(); + + rotation = message.ReadFloat(); + } + catch + { + return; + } - AnimController.IsStanding = true; + if (limb.body != null) + { + limb.body.TargetVelocity = limb.body.LinearVelocity; + limb.body.TargetPosition = limbPos;// +vel * (float)(deltaTime / 60.0); + limb.body.TargetRotation = rotation;// +angularVel * (float)(deltaTime / 60.0); + limb.body.TargetAngularVelocity = limb.body.AngularVelocity; + } - keys[(int)InputType.ActionHeld].State = actionKeyState; - keys[(int)InputType.SecondaryHeld].State = secondaryKeyState; + } - if (sendingTime <= LastNetworkUpdate) return; - - keys[(int)InputType.Left].State = leftKeyState; - keys[(int)InputType.Right].State = rightKeyState; - - keys[(int)InputType.Up].State = upKeyState; - keys[(int)InputType.Down].State = downKeyState; - - keys[(int)InputType.Run].State = runState; - - float dir = 1.0f; - bool isLargeUpdate; - - try - { - if (secondaryKeyState) - { - cursorPos = new Vector2( - message.ReadFloat(), - message.ReadFloat()); - } - else - { - dir = message.ReadBoolean() ? 1.0f : -1.0f; - } - - isLargeUpdate = message.ReadBoolean(); - } - catch - { - return; - } - if (secondaryKeyState) - { - cursorPosition = MathUtils.IsValid(cursorPos) ? cursorPos : Vector2.Zero; - } - else - { - cursorPosition = Position + new Vector2(1000.0f, 0.0f) * dir; - } - - if (isLargeUpdate) - { - foreach (Limb limb in AnimController.Limbs) - { - Vector2 pos = Vector2.Zero, vel = Vector2.Zero; - float rotation = 0.0f; + float newStunTimer = 0.0f, newHealth = 0.0f, newOxygen = 0.0f; try { - pos.X = message.ReadFloat(); - pos.Y = message.ReadFloat(); - - //vel.X = message.ReadFloat(); - //vel.Y = message.ReadFloat(); - - rotation = message.ReadFloat(); - //angularVel = message.ReadFloat(); + newStunTimer = message.ReadRangedSingle(0.0f, 60.0f, 8); + newHealth = (message.ReadByte() / 255.0f) * maxHealth; + newOxygen = (message.ReadByte() / 2.55f); } - catch + catch { return; } + + StartStun(newStunTimer); + Health = newHealth; + oxygen = newOxygen; + + return; + case NetworkEventType.EntityUpdate: + float sendingTime = 0.0f; + Vector2 cursorPos = Vector2.Zero; + + bool actionKeyState, secondaryKeyState; + bool leftKeyState, rightKeyState, upKeyState, downKeyState; + bool runState; + + try + { + bool hasInputs = message.ReadBoolean(); + sendingTime = message.ReadFloat(); + + if (!hasInputs) + { + if (sendingTime > LastNetworkUpdate) ClearInputs(); + return; + } + + actionKeyState = message.ReadBoolean(); + secondaryKeyState = message.ReadBoolean(); + + leftKeyState = message.ReadBoolean(); + rightKeyState = message.ReadBoolean(); + upKeyState = message.ReadBoolean(); + downKeyState = message.ReadBoolean(); + + runState = message.ReadBoolean(); + } + + catch (Exception e) { return; } - if (limb.body != null) + AnimController.IsStanding = true; + + keys[(int)InputType.ActionHeld].State = actionKeyState; + keys[(int)InputType.SecondaryHeld].State = secondaryKeyState; + + if (sendingTime <= LastNetworkUpdate) return; + + keys[(int)InputType.Left].State = leftKeyState; + keys[(int)InputType.Right].State = rightKeyState; + + keys[(int)InputType.Up].State = upKeyState; + keys[(int)InputType.Down].State = downKeyState; + + keys[(int)InputType.Run].State = runState; + + float dir = 1.0f; + Vector2 pos = Vector2.Zero; + + try { - limb.body.TargetVelocity = limb.body.LinearVelocity; - limb.body.TargetPosition = pos;// +vel * (float)(deltaTime / 60.0); - limb.body.TargetRotation = rotation;// +angularVel * (float)(deltaTime / 60.0); - limb.body.TargetAngularVelocity = limb.body.AngularVelocity; + if (secondaryKeyState) + { + cursorPos = new Vector2( + message.ReadFloat(), + message.ReadFloat()); + } + else + { + dir = message.ReadBoolean() ? 1.0f : -1.0f; + } + + pos.X = message.ReadFloat(); + pos.Y = message.ReadFloat(); + } + catch + { +#if DEBUG + DebugConsole.ThrowError("Failed to read netowkrevent for "+this.ToString()); +#endif + return; + } + if (secondaryKeyState) + { + cursorPosition = MathUtils.IsValid(cursorPos) ? cursorPos : Vector2.Zero; + } + else + { + cursorPosition = Position + new Vector2(1000.0f, 0.0f) * dir; + } - } + AnimController.RefLimb.body.TargetPosition = pos; - float newStunTimer = 0.0f, newHealth = 0.0f; + LastNetworkUpdate = sendingTime; - try - { - newStunTimer = message.ReadRangedSingle(0.0f, 60.0f, 8); - newHealth = (message.ReadByte() / 255.0f) * maxHealth; - } - catch { return; } - - StartStun(newStunTimer); - Health = newHealth; - - LargeUpdateTimer = 1; + return; + default: +#if DEBUG + DebugConsole.ThrowError("Character " + this + " tried to read a networkevent of the wrong type: " + type); +#endif + return; } - else - { - Vector2 pos = Vector2.Zero; - try - { - pos.X = message.ReadFloat(); - pos.Y = message.ReadFloat(); - } - - catch { return; } - - - AnimController.RefLimb.body.TargetPosition = pos; - - LargeUpdateTimer = 0; - } - - LastNetworkUpdate = sendingTime; - } public override void Remove() diff --git a/Subsurface/Source/Characters/Ragdoll.cs b/Subsurface/Source/Characters/Ragdoll.cs index b2cd94834..fe01e2bd4 100644 --- a/Subsurface/Source/Characters/Ragdoll.cs +++ b/Subsurface/Source/Characters/Ragdoll.cs @@ -667,11 +667,15 @@ namespace Barotrauma float allowedDistance = NetConfig.AllowedRagdollDistance * ((inWater) ? 2.0f : 1.0f); float dist = Vector2.Distance(refLimb.body.SimPosition, refLimb.body.TargetPosition); - bool resetAll = (dist > resetDistance && character.LargeUpdateTimer == 1); + bool resetAll = dist > resetDistance; + if (resetAll) + { + if (Limbs.FirstOrDefault(limb => !limb.ignoreCollisions && limb.body.TargetPosition == Vector2.Zero) != null) resetAll = false; + } - Vector2 newMovement = (refLimb.body.TargetPosition - refLimb.body.SimPosition); + Vector2 diff = (refLimb.body.TargetPosition - refLimb.body.SimPosition); - if (newMovement == Vector2.Zero || newMovement.Length() < allowedDistance) + if (diff == Vector2.Zero || diff.Length() < allowedDistance) { refLimb.body.TargetPosition = Vector2.Zero; foreach (Limb limb in Limbs) @@ -694,12 +698,12 @@ namespace Barotrauma } correctionMovement = - Vector2.Lerp(targetMovement, Vector2.Normalize(newMovement) * MathHelper.Clamp(dist * 5.0f, 0.1f, 5.0f), 0.2f); + Vector2.Lerp(targetMovement, Vector2.Normalize(diff) * MathHelper.Clamp(dist * 5.0f, 0.1f, 5.0f), 0.2f); } else { correctionMovement = - Vector2.Lerp(targetMovement, Vector2.Normalize(newMovement) * MathHelper.Clamp(dist * 5.0f, 0.1f, 5.0f), 0.2f); + Vector2.Lerp(targetMovement, Vector2.Normalize(diff) * MathHelper.Clamp(dist * 5.0f, 0.1f, 5.0f), 0.2f); if (Math.Abs(correctionMovement.Y) < 0.1f) correctionMovement.Y = 0.0f; } @@ -711,7 +715,11 @@ namespace Barotrauma foreach (Limb limb in Limbs) { - if (limb.body.TargetPosition == Vector2.Zero) continue; + if (limb.body.TargetPosition == Vector2.Zero) + { + limb.body.SetTransform(limb.body.SimPosition + diff, limb.body.Rotation); + continue; + } limb.body.LinearVelocity = limb.body.TargetVelocity; limb.body.AngularVelocity = limb.body.TargetAngularVelocity; diff --git a/Subsurface/Source/DebugConsole.cs b/Subsurface/Source/DebugConsole.cs index d132e6a6c..69945e1c4 100644 --- a/Subsurface/Source/DebugConsole.cs +++ b/Subsurface/Source/DebugConsole.cs @@ -43,7 +43,7 @@ namespace Barotrauma public static void Init(GameWindow window) { textBox = new GUITextBox(new Rectangle(30, 480,780, 30), Color.Black, Color.White, Alignment.Left, Alignment.Left); - NewMessage("Press F3 to open/close the debug console", Color.Green); + NewMessage("Press F3 to open/close the debug console", Color.Cyan); } public static void Update(GameMain game, float deltaTime) @@ -212,8 +212,14 @@ namespace Barotrauma case "editchar": GameMain.EditCharacterScreen.Select(); break; + case "controlcharacter": + case "control": + if (commands.Length < 2) break; + commands[1] = commands[1].ToLower(); + Character.Controlled = Character.CharacterList.Find(c => c.Name.ToLower() == commands[1]); + break; case "heal": - if (Character.Controlled!=null) + if (Character.Controlled != null) { Character.Controlled.Health = Character.Controlled.MaxHealth; Character.Controlled.Bleeding = 0.0f; diff --git a/Subsurface/Source/Items/Components/ItemContainer.cs b/Subsurface/Source/Items/Components/ItemContainer.cs index e8ccd3022..3cb9cfad4 100644 --- a/Subsurface/Source/Items/Components/ItemContainer.cs +++ b/Subsurface/Source/Items/Components/ItemContainer.cs @@ -239,6 +239,17 @@ namespace Barotrauma.Items.Components itemIds = null; } + public override void Remove() + { + base.Remove(); + + foreach (Item item in inventory.items) + { + if (item == null) continue; + item.Remove(); + } + } + public override void Load(XElement componentElement) { base.Load(componentElement); diff --git a/Subsurface/Source/Map/Hull.cs b/Subsurface/Source/Map/Hull.cs index 97244e295..b3a3e42f0 100644 --- a/Subsurface/Source/Map/Hull.cs +++ b/Subsurface/Source/Map/Hull.cs @@ -308,7 +308,6 @@ namespace Barotrauma Color.Red*((100.0f-OxygenPercentage)/400.0f), true); spriteBatch.DrawString(GUI.Font, "Pressure: " + ((int)pressure - rect.Y).ToString() + - " - Lethality: " + lethalPressure + " - Oxygen: "+((int)OxygenPercentage), new Vector2(rect.X+10, -rect.Y+10), Color.Black); spriteBatch.DrawString(GUI.Font, volume +" / "+ FullVolume, new Vector2(rect.X+10, -rect.Y+30), Color.Black); diff --git a/Subsurface/Source/Map/MapEntity.cs b/Subsurface/Source/Map/MapEntity.cs index 4722963ba..9660beee3 100644 --- a/Subsurface/Source/Map/MapEntity.cs +++ b/Subsurface/Source/Map/MapEntity.cs @@ -506,7 +506,7 @@ namespace Barotrauma /// Has to be done after all the entities have been loaded (an entity can't /// be linked to some other entity that hasn't been loaded yet) /// - public static void OnMapLoaded() + public static void MapLoaded() { foreach (MapEntity e in mapEntityList) { @@ -524,13 +524,19 @@ namespace Barotrauma } } + foreach (MapEntity e in mapEntityList) + { + e.OnMapLoaded(); + } + //mapEntityList.Sort((x, y) => //{ // return x.Name.CompareTo(y.Name); //}); - } - + + + public virtual void OnMapLoaded() { } public void RemoveLinked(MapEntity e) diff --git a/Subsurface/Source/Map/Submarine.cs b/Subsurface/Source/Map/Submarine.cs index 1ef28c468..3018e175c 100644 --- a/Subsurface/Source/Map/Submarine.cs +++ b/Subsurface/Source/Map/Submarine.cs @@ -623,7 +623,7 @@ namespace Barotrauma subBody = new SubmarineBody(this); - MapEntity.OnMapLoaded(); + MapEntity.MapLoaded(); foreach (Item item in Item.itemList) { diff --git a/Subsurface/Source/Networking/GameClient.cs b/Subsurface/Source/Networking/GameClient.cs index 350da59ed..29d693b85 100644 --- a/Subsurface/Source/Networking/GameClient.cs +++ b/Subsurface/Source/Networking/GameClient.cs @@ -266,8 +266,9 @@ namespace Barotrauma.Networking } } - catch - { + catch (Exception e) + { + DebugConsole.ThrowError("Error while connecting to server", e); break; } } @@ -354,7 +355,7 @@ namespace Barotrauma.Networking } else if (gameStarted) { - new NetworkEvent(myCharacter.ID, true); + myCharacter.CreateUpdateNetworkEvent(true); } } diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index 9b38cfab3..b8c5da921 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -302,16 +302,15 @@ namespace Barotrauma.Networking { if (gameStarted) { - if (myCharacter != null) new NetworkEvent(myCharacter.ID, true); + if (myCharacter != null) myCharacter.CreateUpdateNetworkEvent(false); foreach (Character c in Character.CharacterList) { if (c as AICharacter == null) continue; - if (c.SimPosition == Vector2.Zero || c.SimPosition.Length() < 100.0f) - { - new NetworkEvent(c.ID, false); - } + if (c.SimPosition.Length() > 100.0f) continue; + + c.CreateUpdateNetworkEvent(false); } } diff --git a/Subsurface/Source/Networking/NetConfig.cs b/Subsurface/Source/Networking/NetConfig.cs index d957dda9b..5777d8107 100644 --- a/Subsurface/Source/Networking/NetConfig.cs +++ b/Subsurface/Source/Networking/NetConfig.cs @@ -21,6 +21,8 @@ namespace Barotrauma.Networking //if the ragdoll is closer than this, don't try to correct its position public const float AllowedRagdollDistance = 0.1f; + public const float LargeCharacterUpdateInterval = 5.0f; + public const float DeleteDisconnectedTime = 10.0f; public const float AckInterval = 0.2f; diff --git a/Subsurface/Source/Networking/NetworkEvent.cs b/Subsurface/Source/Networking/NetworkEvent.cs index 8195c75b6..11edf668c 100644 --- a/Subsurface/Source/Networking/NetworkEvent.cs +++ b/Subsurface/Source/Networking/NetworkEvent.cs @@ -18,8 +18,7 @@ namespace Barotrauma.Networking PickItem = 6, DropItem = 7, InventoryUpdate = 8, - - + UpdateProperty = 9, WallDamage = 10, diff --git a/Subsurface/Source/Screens/EditMapScreen.cs b/Subsurface/Source/Screens/EditMapScreen.cs index 57611e69e..5a4c68f78 100644 --- a/Subsurface/Source/Screens/EditMapScreen.cs +++ b/Subsurface/Source/Screens/EditMapScreen.cs @@ -176,6 +176,13 @@ namespace Barotrauma } else if (dummyCharacter != null) { + foreach (Item item in dummyCharacter.Inventory.items) + { + if (item == null) continue; + + item.Remove(); + } + dummyCharacter.Remove(); dummyCharacter = null; } diff --git a/Subsurface/changelog.txt b/Subsurface/changelog.txt index c6d7790bc..d1bf2b2e4 100644 --- a/Subsurface/changelog.txt +++ b/Subsurface/changelog.txt @@ -1,3 +1,39 @@ +--------------------------------------------------------------------------------------------------------- +v0.2.3.1 +--------------------------------------------------------------------------------------------------------- + +- fixed some broken items in Aegir Mark II which caused inventories to get messed up +- fixed the gap at observation deck which vents water out from the lower level of the room + +--------------------------------------------------------------------------------------------------------- +v0.2.3 +--------------------------------------------------------------------------------------------------------- + +Multiplayer: + - major changes to the way the game handles sending reliable messages through UDP, should get rid of + the occasional massive lag spikes + - fixed multiple issues in inventory syncing + - fixed attachable items occasionally crashing the game + - players can be banned from servers + - fixed not being able to kick players while a round is running + - misc optimization + +Items: + - screwdrivers and wrenches are used by left clicking now, so it's possible to start rewiring a + button without activating it for example + - the inventory slots are "combined" when equipping an item that takes up more than one slot + - door shadows aren't visible if the door is open when loading a map + - fixed projectiles crashing the game if they're stuck to a wall while a hole appears on it + - wrenches can be used as an ineffective melee weapon + +Submarine: + - another minimap and a sonar monitor at the "observation deck" on Aegir + - changed one of the cabins to a holding cell on Aegir + +Misc: + - fixed a bug in UI listboxes that may have caused crashes in the server list screen + + --------------------------------------------------------------------------------------------------------- v0.2.2 --------------------------------------------------------------------------------------------------------- diff --git a/Subsurface_Solution.v12.suo b/Subsurface_Solution.v12.suo index 162aad873..4715cb1df 100644 Binary files a/Subsurface_Solution.v12.suo and b/Subsurface_Solution.v12.suo differ