diff --git a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Fabricator.cs b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Fabricator.cs index a9973fce8..5cbdb527a 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Fabricator.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/Components/Machines/Fabricator.cs @@ -36,7 +36,12 @@ namespace Barotrauma.Items.Components itemList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.5f), paddedFrame.RectTransform)) { - OnSelected = SelectItem + OnSelected = (GUIComponent component, object userdata) => + { + selectedItem = userdata as FabricableItem; + if (selectedItem != null) { SelectItem(Character.Controlled, selectedItem); } + return true; + } }; inputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(0.7f, 0.15f), paddedFrame.RectTransform), style: null); @@ -252,11 +257,8 @@ namespace Barotrauma.Items.Components } } - private bool SelectItem(GUIComponent component, object obj) + private bool SelectItem(Character user, FabricableItem selectedItem) { - selectedItem = obj as FabricableItem; - if (selectedItem == null) return false; - selectedItemFrame.ClearChildren(); var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), selectedItemFrame.RectTransform, Anchor.Center)) { RelativeSpacing = 0.03f, Stretch = true }; @@ -288,9 +290,9 @@ namespace Barotrauma.Items.Components } List inadequateSkills = new List(); - if (Character.Controlled != null) + if (user != null) { - inadequateSkills = selectedItem.RequiredSkills.FindAll(skill => Character.Controlled.GetSkillLevel(skill.Identifier) < skill.Level); + inadequateSkills = selectedItem.RequiredSkills.FindAll(skill => user.GetSkillLevel(skill.Identifier) < skill.Level); } if (selectedItem.RequiredSkills.Any()) @@ -305,10 +307,10 @@ namespace Barotrauma.Items.Components textColor: inadequateSkills.Any() ? Color.Red : Color.LightGreen, font: GUI.SmallFont); } - float degreeOfSuccess = DegreeOfSuccess(Character.Controlled, selectedItem.RequiredSkills); + float degreeOfSuccess = user == null ? 0.0f : DegreeOfSuccess(user, selectedItem.RequiredSkills); if (degreeOfSuccess > 0.5f) { degreeOfSuccess = 1.0f; } - float requiredTime = GetRequiredTime(selectedItem, Character.Controlled); + float requiredTime = user == null ? selectedItem.RequiredTime : GetRequiredTime(selectedItem, user); string requiredTimeText = TextManager.Get("FabricatorRequiredTime") + ": " + ToolBox.SecondsToReadableTime(requiredTime); new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform), requiredTimeText, textColor: ToolBox.GradientLerp(degreeOfSuccess, Color.Red, Color.Yellow, Color.LightGreen), font: GUI.SmallFont); @@ -387,7 +389,7 @@ namespace Barotrauma.Items.Components if (fabricatedItem != null && fabricableItems.IndexOf(fabricatedItem) == itemIndex) return; if (itemIndex < 0 || itemIndex >= fabricableItems.Count) return; - SelectItem(null, fabricableItems[itemIndex]); + SelectItem(user, fabricableItems[itemIndex]); StartFabricating(fabricableItems[itemIndex], user); } } diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFixLeak.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFixLeak.cs index 194b873ce..de61743b5 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFixLeak.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFixLeak.cs @@ -8,6 +8,8 @@ namespace Barotrauma class AIObjectiveFixLeak : AIObjective { private readonly Gap leak; + + private bool pathUnreachable; public Gap Leak { @@ -22,12 +24,13 @@ namespace Barotrauma public override bool IsCompleted() { - return leak.Open <= 0.0f || leak.Removed; + return leak.Open <= 0.0f || leak.Removed || pathUnreachable; } public override float GetPriority(AIObjectiveManager objectiveManager) { - if (leak.Open == 0.0f) return 0.0f; + if (leak.Open == 0.0f) { return 0.0f; } + if (pathUnreachable) { return 0.0f; } float leakSize = (leak.IsHorizontal ? leak.Rect.Height : leak.Rect.Width) * Math.Max(leak.Open, 0.1f); @@ -66,7 +69,7 @@ namespace Barotrauma } var repairTool = weldingTool.GetComponent(); - if (repairTool == null) return; + if (repairTool == null) { return; } Vector2 standPosition = GetStandPosition(); @@ -83,7 +86,11 @@ namespace Barotrauma var gotoObjective = new AIObjectiveGoTo(ConvertUnits.ToSimUnits(standPosition), character); if (!gotoObjective.IsCompleted()) { - AddSubObjective(gotoObjective); + pathUnreachable = !gotoObjective.CanBeCompleted; + if (!pathUnreachable) + { + AddSubObjective(gotoObjective); + } return; } } diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFixLeaks.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFixLeaks.cs index 02a561f10..688adc661 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFixLeaks.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveFixLeaks.cs @@ -98,13 +98,15 @@ namespace Barotrauma private void UpdateGapList() { - if (objectiveList == null) objectiveList = new List(); - objectiveList.Clear(); - + if (objectiveList == null) { objectiveList = new List(); } + objectiveList.Clear(); + foreach (Gap gap in Gap.GapList) { - if (gap.ConnectedWall == null) continue; - if (gap.ConnectedDoor != null || gap.Open <= 0.0f) continue; + if (gap.ConnectedWall == null) { continue; } + if (gap.ConnectedDoor != null || gap.Open <= 0.0f) { continue; } + //not linked to a hull -> ignore + if (gap.linkedTo.All(l => l == null)) { continue; } if (character.TeamID == 0) { diff --git a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveGoTo.cs b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveGoTo.cs index 31d114e31..9660bf489 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveGoTo.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/AI/Objectives/AIObjectiveGoTo.cs @@ -61,7 +61,7 @@ namespace Barotrauma this.Target = target; this.repeat = repeat; - waitUntilPathUnreachable = 5.0f; + waitUntilPathUnreachable = 1.0f; this.getDivingGearIfNeeded = getDivingGearIfNeeded; } @@ -91,7 +91,7 @@ namespace Barotrauma character.SelectedConstruction = null; } - if (Target != null) character.AIController.SelectTarget(Target.AiTarget); + if (Target != null) { character.AIController.SelectTarget(Target.AiTarget); } Vector2 currTargetPos = Vector2.Zero; @@ -117,11 +117,35 @@ namespace Barotrauma } else { + if (!AllowGoingOutside) + { + //if path is up-to-date and contains outdoors nodes, this path is unreachable + var pathSteering = character.AIController.SteeringManager as IndoorsSteeringManager; + if (pathSteering.CurrentPath != null && + Vector2.Distance(pathSteering.CurrentTarget, currTargetPos) < 1.0f && + pathSteering.CurrentPath.HasOutdoorsNodes) + { + waitUntilPathUnreachable = 0.0f; + character.AIController.SteeringManager.Reset(); + return; + } + } + float normalSpeed = character.AnimController.GetCurrentSpeed(false); character.AIController.SteeringManager.SteeringSeek(currTargetPos, normalSpeed); if (getDivingGearIfNeeded && Target?.Submarine == null && AllowGoingOutside) { - AddSubObjective(new AIObjectiveFindDivingGear(character, true)); + if (indoorsSteering.CurrentPath == null || indoorsSteering.CurrentPath.Unreachable) + { + indoorsSteering.SteeringWander(normalSpeed); + } + else if (AllowGoingOutside && + getDivingGearIfNeeded && + indoorsSteering.CurrentPath != null && + indoorsSteering.CurrentPath.HasOutdoorsNodes) + { + AddSubObjective(new AIObjectiveFindDivingGear(character, true)); + } } else if (character.AIController.SteeringManager is IndoorsSteeringManager indoorsSteering) { diff --git a/Barotrauma/BarotraumaShared/Source/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaShared/Source/Characters/CharacterNetworking.cs index 0306aa6ac..29fd0e697 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/CharacterNetworking.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/CharacterNetworking.cs @@ -575,20 +575,27 @@ namespace Barotrauma public void WriteSpawnData(NetBuffer msg) { - if (GameMain.Server == null) return; + if (GameMain.Server == null) { return; } msg.Write(Info == null); msg.Write(ID); msg.Write(ConfigPath); msg.Write(seed); - msg.Write(WorldPosition.X); - msg.Write(WorldPosition.Y); - + if (Removed) + { + msg.Write(0.0f); + msg.Write(0.0f); + } + else + { + msg.Write(WorldPosition.X); + msg.Write(WorldPosition.Y); + } msg.Write(Enabled); //character with no characterinfo (e.g. some monster) - if (Info == null) return; + if (Info == null) { return; } Client ownerClient = GameMain.Server.ConnectedClients.Find(c => c.Character == this); if (ownerClient != null) diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Health/AfflictionHusk.cs b/Barotrauma/BarotraumaShared/Source/Characters/Health/AfflictionHusk.cs index ccf753825..6472e6d04 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Health/AfflictionHusk.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Health/AfflictionHusk.cs @@ -211,7 +211,7 @@ namespace Barotrauma Entity.Spawner.AddToRemoveQueue(character); var characterFiles = GameMain.Instance.GetFilesOfType(ContentType.Character); - var configFile = characterFiles.FirstOrDefault(f => Path.GetFileNameWithoutExtension(f) == "humanhusk"); + var configFile = characterFiles.FirstOrDefault(f => Path.GetFileNameWithoutExtension(f)?.ToLowerInvariant() == "humanhusk"); if (string.IsNullOrEmpty(configFile)) { diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Fabricator.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Fabricator.cs index 928f1021f..7f52abd52 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Fabricator.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Machines/Fabricator.cs @@ -443,9 +443,8 @@ namespace Barotrauma.Items.Components //if already fabricating the selected item, return if (fabricatedItem != null && fabricableItems.IndexOf(fabricatedItem) == itemIndex) return; if (itemIndex < 0 || itemIndex >= fabricableItems.Count) return; - #if CLIENT - SelectItem(null, fabricableItems[itemIndex]); + SelectItem(c.Character, fabricableItems[itemIndex]); #endif StartFabricating(fabricableItems[itemIndex], c.Character); } diff --git a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs index 518d4bc8d..04600dd21 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/GameServer.cs @@ -357,7 +357,8 @@ namespace Barotrauma.Networking unauthClient.AuthTimer -= deltaTime; if (unauthClient.AuthTimer <= 0.0f) { - unauthClient.Connection.Disconnect("Connection timed out"); + unauthClient.Connection.Disconnect("Authentication timed out."); + Log("Disconnected unauthenticated client (authentication timed out).", ServerLog.MessageType.ServerMessage); } } diff --git a/Barotrauma/BarotraumaShared/Source/Networking/GameServerLogin.cs b/Barotrauma/BarotraumaShared/Source/Networking/GameServerLogin.cs index 1e6ecec18..e2c43da0f 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/GameServerLogin.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/GameServerLogin.cs @@ -92,6 +92,7 @@ namespace Barotrauma.Networking if (GameMain.Config.RequireSteamAuthentication) { unauthClient.Connection.Disconnect(DisconnectReason.SteamAuthenticationFailed.ToString()); + Log("Disconnected unauthenticated client (Steam ID: " + steamID + "). Steam authentication failed.", ServerLog.MessageType.ServerMessage); } else { @@ -119,12 +120,14 @@ namespace Barotrauma.Networking { case Facepunch.Steamworks.ServerAuth.Status.OK: ////steam authentication done, check password next + Log("Successfully authenticated client via Steam (Steam ID: " + steamID + ").", ServerLog.MessageType.ServerMessage); HandleClientAuthRequest(unauthClient.Connection, unauthClient.SteamID); break; default: unauthenticatedClients.Remove(unauthClient); if (GameMain.Config.RequireSteamAuthentication) { + Log("Disconnected unauthenticated client (Steam ID: " + steamID + "). Steam authentication failed, (" + status + ").", ServerLog.MessageType.ServerMessage); unauthClient.Connection.Disconnect(DisconnectReason.SteamAuthenticationFailed.ToString() + "; (" + status.ToString() + ")"); } else @@ -148,6 +151,7 @@ namespace Barotrauma.Networking var connectedClient = connectedClients.Find(c => c.SteamID == ownerID); if (connectedClient != null) { + Log("Disconnecting client " + connectedClient.Name + " (Steam ID: " + steamID + "). Steam authentication no longer valid (" + status + ").", ServerLog.MessageType.ServerMessage); KickClient(connectedClient, TextManager.Get("DisconnectMessage.SteamAuthNoLongerValid").Replace("[status]", status.ToString())); } } diff --git a/Barotrauma/BarotraumaShared/Source/Networking/NetEntityEvent/ServerEntityEventManager.cs b/Barotrauma/BarotraumaShared/Source/Networking/NetEntityEvent/ServerEntityEventManager.cs index b0d760c47..1c6f678ea 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/NetEntityEvent/ServerEntityEventManager.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/NetEntityEvent/ServerEntityEventManager.cs @@ -174,6 +174,7 @@ namespace Barotrauma.Networking toKick.ForEach(c => { DebugConsole.NewMessage(c.Name + " was kicked due to excessive desync (expected old event " + c.LastRecvEntityEventID.ToString() + ")", Microsoft.Xna.Framework.Color.Red); + GameServer.Log("Disconnecting client " + c.Name + " due to excessive desync (expected old event " + c.LastRecvEntityEventID.ToString() + ").", ServerLog.MessageType.ServerMessage); server.DisconnectClient(c, "", "You have been disconnected because of excessive desync"); } ); @@ -187,14 +188,18 @@ namespace Barotrauma.Networking toKick.ForEach(c => { DebugConsole.NewMessage(c.Name + " was kicked due to excessive desync (expected " + c.LastRecvEntityEventID.ToString() + ", last available is " + events[0].ID.ToString() + ")", Microsoft.Xna.Framework.Color.Red); + GameServer.Log("Disconnecting client " + c.Name + " due to excessive desync (expected " + c.LastRecvEntityEventID.ToString() + ", last available is " + events[0].ID.ToString() + ")", ServerLog.MessageType.ServerMessage); server.DisconnectClient(c, "", "You have been disconnected because of excessive desync"); - } - ); + }); } } var timedOutClients = clients.FindAll(c => c.InGame && c.NeedsMidRoundSync && Timing.TotalTime > c.MidRoundSyncTimeOut); - timedOutClients.ForEach(c => GameMain.Server.DisconnectClient(c, "", "You have been disconnected because syncing your client with the server took too long.")); + foreach (Client timedOutClient in timedOutClients) + { + GameServer.Log("Disconnecting client " + timedOutClient.Name + ". Syncing the client with the server took too long.", ServerLog.MessageType.ServerMessage); + GameMain.Server.DisconnectClient(timedOutClient, "", "You have been disconnected because syncing your client with the server took too long."); + } bufferedEvents.RemoveAll(b => b.IsProcessed); }