diff --git a/Subsurface/Content/Characters/Human/human.xml b/Subsurface/Content/Characters/Human/human.xml index c4d03a9ca..28e4be637 100644 --- a/Subsurface/Content/Characters/Human/human.xml +++ b/Subsurface/Content/Characters/Human/human.xml @@ -75,20 +75,17 @@ - - - - + - + - + diff --git a/Subsurface/Content/Items/Clothes/clothes.xml b/Subsurface/Content/Items/Clothes/clothes.xml index 84d4c66d4..59237a2c2 100644 --- a/Subsurface/Content/Items/Clothes/clothes.xml +++ b/Subsurface/Content/Items/Clothes/clothes.xml @@ -95,6 +95,24 @@ + + + + + + + + + + + + + + 0) { @@ -134,10 +164,10 @@ namespace Barotrauma return; } - if (Anim != Animation.UsingConstruction) ResetPullJoints(); - if (TargetDir != dir) Flip(); + if (Anim != Animation.UsingConstruction) ResetPullJoints(); + if (SimplePhysicsEnabled) { UpdateStandingSimple(); @@ -815,7 +845,17 @@ namespace Barotrauma target.AnimController.IgnorePlatforms = IgnorePlatforms; - target.AnimController.TargetMovement = TargetMovement; + + if (target.Stun > 0.0f || target.IsDead) + { + target.AnimController.TargetMovement = TargetMovement; + } + else if (target is AICharacter) + { + target.AnimController.TargetMovement = Vector2.Lerp(target.AnimController.TargetMovement, (character.SimPosition + Vector2.UnitX*Dir) - target.SimPosition, 0.5f); + } + + } public override void HoldItem(float deltaTime, Item item, Vector2[] handlePos, Vector2 holdPos, Vector2 aimPos, bool aim, float holdAngle) @@ -994,12 +1034,14 @@ namespace Barotrauma case LimbType.LeftArm: case LimbType.RightHand: case LimbType.RightArm: - difference = limb.body.SimPosition - torso.SimPosition; - difference = Vector2.Transform(difference, torsoTransform); - difference.Y = -difference.Y; - - TrySetLimbPosition(limb, limb.SimPosition, torso.SimPosition + Vector2.Transform(difference, -torsoTransform)); + if (!limb.pullJoint.Enabled) + { + difference = limb.body.SimPosition - torso.SimPosition; + difference = Vector2.Transform(difference, torsoTransform); + difference.Y = -difference.Y; + TrySetLimbPosition(limb, limb.SimPosition, torso.SimPosition + Vector2.Transform(difference, -torsoTransform)); + } limb.body.SetTransform(limb.body.SimPosition, -limb.body.Rotation); break; default: diff --git a/Subsurface/Source/Characters/Character.cs b/Subsurface/Source/Characters/Character.cs index 80628d056..19204dfcd 100644 --- a/Subsurface/Source/Characters/Character.cs +++ b/Subsurface/Source/Characters/Character.cs @@ -149,6 +149,19 @@ namespace Barotrauma get { return inventory; } } + private float lockHandsTimer; + public bool LockHands + { + get + { + return lockHandsTimer > 0.0f; + } + set + { + lockHandsTimer = MathHelper.Clamp(lockHandsTimer + (value ? 1.0f : -0.5f), 0.0f, 10.0f); + } + } + public Vector2 CursorPosition { get { return cursorPosition; } @@ -244,7 +257,7 @@ namespace Barotrauma if (!MathUtils.IsValid(value)) return; health = MathHelper.Clamp(value, 0.0f, maxHealth); } - } + } public float MaxHealth { @@ -304,14 +317,6 @@ namespace Barotrauma public bool IsDead { get { return isDead; } - //set - //{ - // if (isDead == value) return; - // if (isDead) - // { - // Revive(false); - // } - //} } public CauseOfDeath CauseOfDeath @@ -319,6 +324,14 @@ namespace Barotrauma get { return causeOfDeath; } } + public bool CanBeSelected + { + get + { + return isDead || Stun > 0.0f || LockHands; + } + } + public override Vector2 SimPosition { get { return AnimController.RefLimb.SimPosition; } @@ -658,8 +671,7 @@ namespace Barotrauma if (selectedCharacter!=null) { - if (Vector2.Distance(selectedCharacter.SimPosition, SimPosition) > 3.0f || - (!selectedCharacter.isDead && selectedCharacter.Stun <= 0.0f)) + if (Vector2.Distance(selectedCharacter.SimPosition, SimPosition) > 2.0f || !selectedCharacter.CanBeSelected) { DeselectCharacter(); } @@ -765,9 +777,7 @@ namespace Barotrauma selectedCharacter = character; - if (createNetworkEvent) - new NetworkEvent(NetworkEventType.SelectCharacter, ID, true, selectedCharacter.ID); - + if (createNetworkEvent) new NetworkEvent(NetworkEventType.SelectCharacter, ID, true, selectedCharacter.ID); } private void DeselectCharacter(bool createNetworkEvent = true) @@ -820,8 +830,6 @@ namespace Barotrauma (AnimController.CurrentHull.LethalPressure - 50.0f) / 50.0f); } cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, (Submarine == null ? 400.0f : 250.0f)+pressureEffect, 0.05f); - - } cursorPosition = cam.ScreenToWorld(PlayerInput.MousePosition); @@ -844,69 +852,68 @@ namespace Barotrauma } - //find the closest item if selectkey has been hit, or if the Character is being - //controlled by the player (in order to highlight it) - - if (findClosestTimer <= 0.0f || Screen.Selected == GameMain.EditMapScreen) + if (!LockHands) { - closestCharacter = FindClosestCharacter(mouseSimPos); - if (closestCharacter != null && closestCharacter.info==null) - { - closestCharacter = null; - } + //find the closest item if selectkey has been hit, or if the Character is being + //controlled by the player (in order to highlight it) - closestItem = FindClosestItem(mouseSimPos); - - if (closestCharacter != null && closestItem != null) + if (findClosestTimer <= 0.0f || Screen.Selected == GameMain.EditMapScreen) { - if (Vector2.Distance(closestCharacter.SimPosition, mouseSimPos) < Vector2.Distance(closestItem.SimPosition, mouseSimPos)) - { - if (selectedConstruction != closestItem) closestItem = null; - } - else + closestCharacter = FindClosestCharacter(mouseSimPos); + if (closestCharacter != null && closestCharacter.info==null) { closestCharacter = null; } + + closestItem = FindClosestItem(mouseSimPos); + + if (closestCharacter != null && closestItem != null) + { + if (Vector2.Distance(closestCharacter.SimPosition, mouseSimPos) < Vector2.Distance(closestItem.SimPosition, mouseSimPos)) + { + if (selectedConstruction != closestItem) closestItem = null; + } + else + { + closestCharacter = null; + } + } + + findClosestTimer = 0.1f; + } + else + { + findClosestTimer -= deltaTime; } - findClosestTimer = 0.1f; - } - else - { - findClosestTimer -= deltaTime; - } - - if (selectedCharacter == null) - { - if (closestItem != null) + if (selectedCharacter == null && closestItem != null) { closestItem.IsHighlighted = true; - if (closestItem.Pick(this)) + if (!LockHands && closestItem.Pick(this)) { new NetworkEvent(NetworkEventType.PickItem, ID, true, new int[] - { - closestItem.ID, - IsKeyHit(InputType.Select) ? 1 : 0, - IsKeyHit(InputType.Use) ? 1 : 0 - }); + { + closestItem.ID, + IsKeyHit(InputType.Select) ? 1 : 0, + IsKeyHit(InputType.Use) ? 1 : 0 + }); + } + } + + if (IsKeyHit(InputType.Select)) + { + if (selectedCharacter != null) + { + DeselectCharacter(); + } + else if (closestCharacter != null && closestCharacter.IsHumanoid && closestCharacter.CanBeSelected) + { + SelectCharacter(closestCharacter); } } } - if (IsKeyHit(InputType.Select)) - { - if (selectedCharacter != null) - { - DeselectCharacter(); - } - else if (closestCharacter != null && closestCharacter.IsHumanoid && - (closestCharacter.isDead || closestCharacter.AnimController.StunTimer > 0.0f)) - { - SelectCharacter(closestCharacter); - } - } - DisableControls = false; } @@ -1003,6 +1010,8 @@ namespace Barotrauma Health -= bleeding*deltaTime; if (health <= 0.0f) Kill(CauseOfDeath.Bloodloss, false); + + if (!IsDead) LockHands = false; } diff --git a/Subsurface/Source/Characters/CharacterHUD.cs b/Subsurface/Source/Characters/CharacterHUD.cs index f35fb466a..c917b6eaf 100644 --- a/Subsurface/Source/Characters/CharacterHUD.cs +++ b/Subsurface/Source/Characters/CharacterHUD.cs @@ -56,16 +56,16 @@ namespace Barotrauma DrawStatusIcons(spriteBatch, character); - if (character.Inventory != null) character.Inventory.DrawOwn(spriteBatch); + if (character.Inventory != null && !character.LockHands) character.Inventory.DrawOwn(spriteBatch, Vector2.Zero); if (character.SelectedCharacter != null && character.SelectedCharacter.Inventory!=null) { - character.SelectedCharacter.Inventory.Draw(spriteBatch); + character.SelectedCharacter.Inventory.DrawOwn(spriteBatch, new Vector2(GameMain.GraphicsWidth - 310, 0.0f)); //if (Vector2.Distance(selectedCharacter.SimPosition, SimPosition) > 2.0f) selectedCharacter = null; } - if (character.ClosestCharacter != null && (character.ClosestCharacter.IsDead || character.ClosestCharacter.Stun > 0.0f)) + if (character.ClosestCharacter != null && character.ClosestCharacter.CanBeSelected) { Vector2 startPos = character.DrawPosition + (character.ClosestCharacter.DrawPosition - character.DrawPosition) * 0.7f; startPos = cam.WorldToScreen(startPos); diff --git a/Subsurface/Source/Characters/Limb.cs b/Subsurface/Source/Characters/Limb.cs index 4463aa0b7..37ec28622 100644 --- a/Subsurface/Source/Characters/Limb.cs +++ b/Subsurface/Source/Characters/Limb.cs @@ -6,6 +6,7 @@ using FarseerPhysics.Dynamics.Joints; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Barotrauma.Items.Components; +using System.Collections.Generic; namespace Barotrauma { @@ -64,8 +65,7 @@ namespace Barotrauma private Direction dir; - private Wearable wearingItem; - private WearableSprite wearingItemSprite; + private List wearingItems; private Vector2 animTargetPos; @@ -172,21 +172,23 @@ namespace Barotrauma // set { bleeding = MathHelper.Clamp(value, 0.0f, 100.0f); } //} - public Wearable WearingItem + public List WearingItems { - get { return wearingItem; } - set { wearingItem = value; } + get { return wearingItems; } + set { wearingItems = value; } } - public WearableSprite WearingItemSprite - { - get { return wearingItemSprite; } - set { wearingItemSprite = value; } - } + //public WearableSprite WearingItemSprite + //{ + // get { return wearingItemSprite; } + // set { wearingItemSprite = value; } + //} public Limb (Character character, XElement element, float scale = 1.0f) { this.character = character; + + WearingItems = new List(); dir = Direction.Right; @@ -327,13 +329,16 @@ namespace Barotrauma totalArmorValue += armorValue; } - if (wearingItem!=null && - wearingItem.ArmorValue>0.0f && - SectorHit(wearingItem.ArmorSectorLimits, position)) + foreach (WearableSprite wearable in wearingItems) { - hitArmor = true; - totalArmorValue += wearingItem.ArmorValue; - } + if (wearable.WearableComponent.ArmorValue > 0.0f && + SectorHit(wearable.WearableComponent.ArmorSectorLimits, position)) + { + hitArmor = true; + totalArmorValue += wearable.WearableComponent.ArmorValue; + } + } + if (hitArmor) { @@ -456,7 +461,7 @@ namespace Barotrauma body.Dir = Dir; - if (wearingItem == null || !wearingItemSprite.HideLimb) + if (wearingItems.Find(w => w != null && w.HideLimb) == null) { body.Draw(spriteBatch, sprite, color, null, scale); } @@ -464,32 +469,32 @@ namespace Barotrauma { body.UpdateDrawPosition(); } - - if (wearingItem != null) + + foreach (WearableSprite wearable in wearingItems) { SpriteEffects spriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipHorizontally; - Vector2 origin = wearingItemSprite.Sprite.Origin; - if (body.Dir == -1.0f) origin.X = wearingItemSprite.Sprite.SourceRect.Width - origin.X; + Vector2 origin = wearable.Sprite.Origin; + if (body.Dir == -1.0f) origin.X = wearable.Sprite.SourceRect.Width - origin.X; float depth = sprite.Depth - 0.000001f; - if (wearingItemSprite.DepthLimb!=LimbType.None) + if (wearable.DepthLimb != LimbType.None) { - Limb depthLimb = character.AnimController.GetLimb(wearingItemSprite.DepthLimb); - if (depthLimb!=null) + Limb depthLimb = character.AnimController.GetLimb(wearable.DepthLimb); + if (depthLimb != null) { depth = depthLimb.sprite.Depth - 0.000001f; } } - wearingItemSprite.Sprite.Draw(spriteBatch, + wearable.Sprite.Draw(spriteBatch, new Vector2(body.DrawPosition.X, -body.DrawPosition.Y), color, origin, -body.DrawRotation, scale, spriteEffect, depth); } - + if (damage>0.0f && damagedSprite!=null) { SpriteEffects spriteEffect = (dir == Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipHorizontally; diff --git a/Subsurface/Source/GameSession/CrewManager.cs b/Subsurface/Source/GameSession/CrewManager.cs index 225faeb1e..d1b0ba614 100644 --- a/Subsurface/Source/GameSession/CrewManager.cs +++ b/Subsurface/Source/GameSession/CrewManager.cs @@ -71,7 +71,7 @@ namespace Barotrauma //listBox.Select(selection); Character character = selection as Character; - if (character == null) return false; + if (character == null || character.IsDead) return false; if (characters.Contains(character)) { diff --git a/Subsurface/Source/Items/CharacterInventory.cs b/Subsurface/Source/Items/CharacterInventory.cs index 207ca6863..b7c9697d9 100644 --- a/Subsurface/Source/Items/CharacterInventory.cs +++ b/Subsurface/Source/Items/CharacterInventory.cs @@ -210,7 +210,7 @@ namespace Barotrauma return TryPutItem(item, new List() {placeToSlots}, createNetworkEvent); } - public void DrawOwn(SpriteBatch spriteBatch) + public void DrawOwn(SpriteBatch spriteBatch, Vector2 offset) { string toolTip = ""; Rectangle highlightedSlot = Rectangle.Empty; @@ -227,8 +227,8 @@ namespace Barotrauma for (int i = 0; i < capacity; i++) { - slotRect.X = (int)SlotPositions[i].X; - slotRect.Y = (int)SlotPositions[i].Y; + slotRect.X = (int)(SlotPositions[i].X + offset.X); + slotRect.Y = (int)(SlotPositions[i].Y + offset.Y); if (i==1) //head { @@ -248,8 +248,8 @@ namespace Barotrauma for (int i = 0; i < capacity; i++) { - slotRect.X = (int)SlotPositions[i].X; - slotRect.Y = (int)SlotPositions[i].Y; + slotRect.X = (int)(SlotPositions[i].X + offset.X); + slotRect.Y = (int)(SlotPositions[i].Y + offset.Y); bool multiSlot = false; //skip if the item is in multiple slots @@ -295,8 +295,8 @@ namespace Barotrauma //check if the item is in multiple slots if (Items[i] != null) { - slotRect.X = (int)SlotPositions[i].X; - slotRect.Y = (int)SlotPositions[i].Y; + slotRect.X = (int)(SlotPositions[i].X + offset.X); + slotRect.Y = (int)(SlotPositions[i].Y + offset.Y); slotRect.Width = 40; slotRect.Height = 40; @@ -310,7 +310,7 @@ namespace Barotrauma { multiSlot = true; slotRect = Rectangle.Union( - new Rectangle((int)SlotPositions[n].X, (int)SlotPositions[n].Y, rectWidth, rectHeight), slotRect); + new Rectangle((int)(SlotPositions[n].X+offset.X), (int)(SlotPositions[n].Y+offset.Y), rectWidth, rectHeight), slotRect); } } } diff --git a/Subsurface/Source/Items/Components/Holdable/Propulsion.cs b/Subsurface/Source/Items/Components/Holdable/Propulsion.cs index bd3f523ad..5b29339db 100644 --- a/Subsurface/Source/Items/Components/Holdable/Propulsion.cs +++ b/Subsurface/Source/Items/Components/Holdable/Propulsion.cs @@ -76,7 +76,7 @@ namespace Barotrauma.Items.Components { foreach (Limb limb in character.AnimController.Limbs) { - if (limb.WearingItem==null || limb.WearingItem.Item != item) continue; + if (limb.WearingItems.Find(w => w.WearableComponent.Item != this.item)==null) continue; limb.body.ApplyForce(propulsion); } diff --git a/Subsurface/Source/Items/Components/Wearable.cs b/Subsurface/Source/Items/Components/Wearable.cs index 6f267bc20..36539d95e 100644 --- a/Subsurface/Source/Items/Components/Wearable.cs +++ b/Subsurface/Source/Items/Components/Wearable.cs @@ -12,8 +12,11 @@ namespace Barotrauma.Items.Components public bool HideLimb; public LimbType DepthLimb; - public WearableSprite(Sprite sprite, bool hideLimb, LimbType depthLimb = LimbType.None) + public Wearable WearableComponent; + + public WearableSprite(Wearable item, Sprite sprite, bool hideLimb, LimbType depthLimb = LimbType.None) { + WearableComponent = item; Sprite = sprite; HideLimb = hideLimb; @@ -85,7 +88,7 @@ namespace Barotrauma.Items.Components spritePath = Path.GetDirectoryName( item.Prefab.ConfigFile)+"/"+spritePath; var sprite = new Sprite(subElement, "", spritePath); - wearableSprites[i] = new WearableSprite(sprite, ToolBox.GetAttributeBool(subElement, "hidelimb", false), + wearableSprites[i] = new WearableSprite(this, sprite, ToolBox.GetAttributeBool(subElement, "hidelimb", false), (LimbType)Enum.Parse(typeof(LimbType), ToolBox.GetAttributeString(subElement, "depthlimb", "None"), true)); @@ -105,10 +108,10 @@ namespace Barotrauma.Items.Components if (equipLimb == null) continue; //something is already on the limb -> unequip it - if (equipLimb.WearingItem != null && equipLimb.WearingItem != this) - { - equipLimb.WearingItem.Unequip(character); - } + //if (equipLimb.WearingItem != null && equipLimb.WearingItem != this) + //{ + // equipLimb.WearingItem.Unequip(character); + //} //sprite[i].Depth = equipLimb.sprite.Depth - 0.001f; @@ -117,8 +120,7 @@ namespace Barotrauma.Items.Components IsActive = true; limb[i] = equipLimb; - equipLimb.WearingItem = this; - equipLimb.WearingItemSprite = wearableSprites[i]; + equipLimb.WearingItems.Add(wearableSprites[i]); } } @@ -140,11 +142,20 @@ namespace Barotrauma.Items.Components Limb equipLimb = character.AnimController.GetLimb(limbType[i]); if (equipLimb == null) continue; - if (equipLimb.WearingItem != this) continue; + //foreach (WearableSprite wearable in equipLimb.WearingItems) + //{ + // if (wearable != wearableSprites[i]) continue; + + // equipLimb.WearingItems.Remove(wearableSprites[i]); + //} + + equipLimb.WearingItems.RemoveAll(w=> w!=null && w==wearableSprites[i]); + + //if (equipLimb.WearingItem != this) continue; limb[i] = null; - equipLimb.WearingItem = null; - equipLimb.WearingItemSprite = null; + //equipLimb.WearingItem = null; + //equipLimb.WearingItemSprite = null; } IsActive = false; diff --git a/Subsurface/Source/Map/FireSource.cs b/Subsurface/Source/Map/FireSource.cs index 4800ab0d5..24898c8bf 100644 --- a/Subsurface/Source/Map/FireSource.cs +++ b/Subsurface/Source/Map/FireSource.cs @@ -236,7 +236,7 @@ namespace Barotrauma float dmg = (float)Math.Sqrt(size.X) * deltaTime / c.AnimController.Limbs.Count(); foreach (Limb limb in c.AnimController.Limbs) { - if (limb.WearingItem != null && limb.WearingItem.Item.FireProof) continue; + if (limb.WearingItems.Find(w => w!=null && w.WearableComponent.Item.FireProof)!=null) continue; limb.Burnt += dmg * 10.0f; c.AddDamage(limb.SimPosition, DamageType.None, dmg, 0,0,false); } diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index 3719f4b10..ce544257f 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -35,6 +35,8 @@ namespace Barotrauma.Networking private ServerLog log; private GUIButton showLogButton; + private GUIScrollBar clientListScrollBar; + public TraitorManager TraitorManager; public GameServer(string name, int port, bool isPublic = false, string password = "", bool attemptUPnP = false, int maxPlayers = 10) @@ -1177,33 +1179,57 @@ namespace Barotrauma.Networking if (!ShowNetStats) return; int width = 200, height = 300; - int x = GameMain.GraphicsWidth - width, y = (int)(GameMain.GraphicsHeight*0.3f); + int x = GameMain.GraphicsWidth - width, y = (int)(GameMain.GraphicsHeight * 0.3f); - GUI.DrawRectangle(spriteBatch, new Rectangle(x,y,width,height), Color.Black*0.7f, true); - spriteBatch.DrawString(GUI.Font, "Network statistics:", new Vector2(x+10, y+10), Color.White); + + if (clientListScrollBar == null) + { + clientListScrollBar = new GUIScrollBar(new Rectangle(x + width - 10, y, 10, height), GUI.Style, 1.0f); + } + + + GUI.DrawRectangle(spriteBatch, new Rectangle(x, y, width, height), Color.Black * 0.7f, true); + spriteBatch.DrawString(GUI.Font, "Network statistics:", new Vector2(x + 10, y + 10), Color.White); spriteBatch.DrawString(GUI.SmallFont, "Connections: "+server.ConnectionsCount, new Vector2(x + 10, y + 30), Color.White); - spriteBatch.DrawString(GUI.SmallFont, "Received bytes: " + server.Statistics.ReceivedBytes, new Vector2(x + 10, y + 45), Color.White); + spriteBatch.DrawString(GUI.SmallFont, "Received bytes: " + MathUtils.GetBytesReadable(server.Statistics.ReceivedBytes), new Vector2(x + 10, y + 45), Color.White); spriteBatch.DrawString(GUI.SmallFont, "Received packets: " + server.Statistics.ReceivedPackets, new Vector2(x + 10, y + 60), Color.White); - spriteBatch.DrawString(GUI.SmallFont, "Sent bytes: " + server.Statistics.SentBytes, new Vector2(x + 10, y + 75), Color.White); + spriteBatch.DrawString(GUI.SmallFont, "Sent bytes: " + MathUtils.GetBytesReadable(server.Statistics.SentBytes), new Vector2(x + 10, y + 75), Color.White); spriteBatch.DrawString(GUI.SmallFont, "Sent packets: " + server.Statistics.SentPackets, new Vector2(x + 10, y + 90), Color.White); int resentMessages = 0; - y += 110; - foreach (Client c in ConnectedClients) - { - spriteBatch.DrawString(GUI.SmallFont, c.name + ":", new Vector2(x + 10, y), Color.White); - spriteBatch.DrawString(GUI.SmallFont, "- avg roundtrip " + c.Connection.AverageRoundtripTime+" s", new Vector2(x + 20, y + 15), Color.White); - spriteBatch.DrawString(GUI.SmallFont, "- resent messages " + c.Connection.Statistics.ResentMessages, new Vector2(x + 20, y + 30), Color.White); + int clientListHeight = ConnectedClients.Count() * 40; + float scrollBarHeight = (height - 110) / (float)Math.Max(clientListHeight, 110); - resentMessages += (int)c.Connection.Statistics.ResentMessages; - - y += 50; + if (clientListScrollBar.BarSize != scrollBarHeight) + { + clientListScrollBar.BarSize = scrollBarHeight; } - netStats.AddValue(NetStats.NetStatType.ResentMessages, resentMessages); + int startY = y + 110; + y = (startY - (int)(clientListScrollBar.BarScroll * (clientListHeight-(height - 110)))); + foreach (Client c in ConnectedClients) + { + Color clientColor = c.Connection.AverageRoundtripTime > 0.3f ? Color.Red : Color.White; + + if (y >= startY && y < startY + height - 120) + { + spriteBatch.DrawString(GUI.SmallFont, c.name + ":", new Vector2(x + 10, y), clientColor); + spriteBatch.DrawString(GUI.SmallFont, "Ping: " + (int)(c.Connection.AverageRoundtripTime * 1000.0f) + " ms", new Vector2(x + width - 100, y), clientColor); + } + if (y + 10 >= startY && y < startY + height - 130) spriteBatch.DrawString(GUI.SmallFont, "Resent messages: " + c.Connection.Statistics.ResentMessages, new Vector2(x + 10, y + 10), clientColor); + + resentMessages += (int)c.Connection.Statistics.ResentMessages; + + y += 40; + } + + clientListScrollBar.Update(1.0f / 60.0f); + clientListScrollBar.Draw(spriteBatch); + + netStats.AddValue(NetStats.NetStatType.ResentMessages, Math.Max(resentMessages, 0)); netStats.AddValue(NetStats.NetStatType.SentBytes, server.Statistics.SentBytes); netStats.AddValue(NetStats.NetStatType.ReceivedBytes, server.Statistics.ReceivedBytes); diff --git a/Subsurface/Source/Networking/NetStats.cs b/Subsurface/Source/Networking/NetStats.cs index 650012ae5..8fc3c3ddc 100644 --- a/Subsurface/Source/Networking/NetStats.cs +++ b/Subsurface/Source/Networking/NetStats.cs @@ -71,14 +71,14 @@ namespace Barotrauma.Networking graphs[(int)NetStatType.ResentMessages].Draw(spriteBatch, rect, null, 0.0f, Color.Red); - spriteBatch.DrawString(GUI.SmallFont, - "Peak received: "+graphs[(int)NetStatType.ReceivedBytes].LargestValue()+" bytes/s " + - "Avg received: " + graphs[(int)NetStatType.ReceivedBytes].Average() + " bytes/s", - new Vector2(rect.X + 10, rect.Y+10), Color.Cyan); + spriteBatch.DrawString(GUI.SmallFont, + "Peak received: " + MathUtils.GetBytesReadable((int)graphs[(int)NetStatType.ReceivedBytes].LargestValue()) + "/s " + + "Avg received: " + MathUtils.GetBytesReadable((int)graphs[(int)NetStatType.ReceivedBytes].Average()) + "/s", + new Vector2(rect.X + 10, rect.Y + 10), Color.Cyan); - spriteBatch.DrawString(GUI.SmallFont, "Peak sent: " + graphs[(int)NetStatType.SentBytes].LargestValue() + " bytes/s " + - "Avg sent: " + graphs[(int)NetStatType.SentBytes].Average() + " bytes/s", + spriteBatch.DrawString(GUI.SmallFont, "Peak sent: " + MathUtils.GetBytesReadable((int)graphs[(int)NetStatType.SentBytes].LargestValue()) + "/s " + + "Avg sent: " + MathUtils.GetBytesReadable((int)graphs[(int)NetStatType.SentBytes].Average()) + " bytes/s", new Vector2(rect.X + 10, rect.Y + 30), Color.Orange); spriteBatch.DrawString(GUI.SmallFont, "Peak resent: " + graphs[(int)NetStatType.ResentMessages].LargestValue() + " messages/s", diff --git a/Subsurface/Source/Utils/MathUtils.cs b/Subsurface/Source/Utils/MathUtils.cs index ddba37391..6f8c5788b 100644 --- a/Subsurface/Source/Utils/MathUtils.cs +++ b/Subsurface/Source/Utils/MathUtils.cs @@ -273,6 +273,55 @@ namespace Barotrauma return segments; } + + // Returns the human-readable file size for an arbitrary, 64-bit file size + // The default format is "0.### XB", e.g. "4.2 KB" or "1.434 GB" + public static string GetBytesReadable(long i) + { + // Get absolute value + long absolute_i = (i < 0 ? -i : i); + // Determine the suffix and readable value + string suffix; + double readable; + if (absolute_i >= 0x1000000000000000) // Exabyte + { + suffix = "EB"; + readable = (i >> 50); + } + else if (absolute_i >= 0x4000000000000) // Petabyte + { + suffix = "PB"; + readable = (i >> 40); + } + else if (absolute_i >= 0x10000000000) // Terabyte + { + suffix = "TB"; + readable = (i >> 30); + } + else if (absolute_i >= 0x40000000) // Gigabyte + { + suffix = "GB"; + readable = (i >> 20); + } + else if (absolute_i >= 0x100000) // Megabyte + { + suffix = "MB"; + readable = (i >> 10); + } + else if (absolute_i >= 0x400) // Kilobyte + { + suffix = "KB"; + readable = i; + } + else + { + return i.ToString("0 B"); // Byte + } + // Divide by 1024 to get fractional value + readable = (readable / 1024); + // Return formatted number with suffix + return readable.ToString("0.# ") + suffix; + } } class CompareCCW : IComparer diff --git a/Subsurface_Solution.v12.suo b/Subsurface_Solution.v12.suo index 3427d79bf..64698d302 100644 Binary files a/Subsurface_Solution.v12.suo and b/Subsurface_Solution.v12.suo differ