diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Character.cs b/Barotrauma/BarotraumaClient/Source/Characters/Character.cs index 633916804..b281ff3bb 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/Character.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/Character.cs @@ -442,7 +442,8 @@ namespace Barotrauma if (draggingItemToWorld) { if (item.OwnInventory == null || - !item.OwnInventory.CanBePut(CharacterInventory.draggingItem)) + !item.OwnInventory.CanBePut(CharacterInventory.draggingItem) || + !CanAccessInventory(item.OwnInventory)) { continue; } diff --git a/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs b/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs index aaf8d1e3b..91ea2bcf8 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/CharacterHUD.cs @@ -139,7 +139,7 @@ namespace Barotrauma foreach (Item item in Item.ItemList) { if (!item.Repairables.Any(r => item.Condition < r.ShowRepairUIThreshold)) { continue; } - if (!Submarine.VisibleEntities.Contains(item)) { continue; } + if (Submarine.VisibleEntities != null && !Submarine.VisibleEntities.Contains(item)) { continue; } Vector2 diff = item.WorldPosition - character.WorldPosition; if (Submarine.CheckVisibility(character.SimPosition, character.SimPosition + ConvertUnits.ToSimUnits(diff)) == null) @@ -216,7 +216,7 @@ namespace Barotrauma Color.LightGreen, Color.Black, 2, GUI.SmallFont); textPos.Y += offset.Y; } - if (character.FocusedCharacter.CharacterHealth.UseHealthWindow) + if (character.FocusedCharacter.CharacterHealth.UseHealthWindow && character.CanInteractWith(character.FocusedCharacter, 160f, false)) { GUI.DrawString(spriteBatch, textPos, GetCachedHudText("HealHint", GameMain.Config.KeyBind(InputType.Health).ToString()), Color.LightGreen, Color.Black, 2, GUI.SmallFont); diff --git a/Barotrauma/BarotraumaClient/Source/Characters/Limb.cs b/Barotrauma/BarotraumaClient/Source/Characters/Limb.cs index a3d57f795..846e82d39 100644 --- a/Barotrauma/BarotraumaClient/Source/Characters/Limb.cs +++ b/Barotrauma/BarotraumaClient/Source/Characters/Limb.cs @@ -449,12 +449,11 @@ namespace Barotrauma { float depth = ActiveSprite.Depth - 0.0000015f; - // TODO: enable when the damage overlay textures have been remade. - //DamagedSprite.Draw(spriteBatch, - // new Vector2(body.DrawPosition.X, -body.DrawPosition.Y), - // color * Math.Min(damageOverlayStrength, 1.0f), ActiveSprite.Origin, - // -body.DrawRotation, - // 1.0f, spriteEffect, depth); + DamagedSprite.Draw(spriteBatch, + new Vector2(body.DrawPosition.X, -body.DrawPosition.Y), + color * Math.Min(damageOverlayStrength, 1.0f), ActiveSprite.Origin, + -body.DrawRotation, + 1.0f, spriteEffect, depth); } if (GameMain.DebugDraw) diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUIDropDown.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUIDropDown.cs index 6cdba8652..c2f8351bc 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUIDropDown.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUIDropDown.cs @@ -148,7 +148,14 @@ namespace Barotrauma //find the parent GUIListBox highest in the hierarchy for (int i = parentHierarchy.Count - 1; i >= 0; i--) { - if (parentHierarchy[i].GUIComponent is GUIListBox) return parentHierarchy[i]; + if (parentHierarchy[i].GUIComponent is GUIListBox) + { + if (parentHierarchy[i].Parent != null && parentHierarchy[i].Parent.GUIComponent != null) + { + return parentHierarchy[i].Parent; + } + return parentHierarchy[i]; + } } //or just go with the direct parent if there are no listboxes in the hierarchy parentHierarchy.Clear(); diff --git a/Barotrauma/BarotraumaClient/Source/GUI/GUIStyle.cs b/Barotrauma/BarotraumaClient/Source/GUI/GUIStyle.cs index 780264181..26fe1031b 100644 --- a/Barotrauma/BarotraumaClient/Source/GUI/GUIStyle.cs +++ b/Barotrauma/BarotraumaClient/Source/GUI/GUIStyle.cs @@ -40,6 +40,9 @@ namespace Barotrauma { ToolBox.IsProperFilenameCase(file); doc = XDocument.Load(file, LoadOptions.SetBaseUri); + if (doc == null) { throw new Exception("doc is null"); } + if (doc.Root == null) { throw new Exception("doc.Root is null"); } + if (doc.Root.Elements() == null) { throw new Exception("doc.Root.Elements() is null"); } } catch (Exception e) { @@ -113,26 +116,34 @@ namespace Barotrauma private void RescaleFonts() { + if (configElement == null) { return; } + if (configElement.Elements() == null) { return; } foreach (XElement subElement in configElement.Elements()) { switch (subElement.Name.ToString().ToLowerInvariant()) { case "font": + if (Font == null) { continue; } Font.Size = GetFontSize(subElement); break; case "smallfont": + if (SmallFont == null) { continue; } SmallFont.Size = GetFontSize(subElement); break; case "largefont": + if (LargeFont == null) { continue; } LargeFont.Size = GetFontSize(subElement); break; case "objectivetitle": + if (ObjectiveTitleFont == null) { continue; } ObjectiveTitleFont.Size = GetFontSize(subElement); break; case "objectivename": + if (ObjectiveNameFont == null) { continue; } ObjectiveNameFont.Size = GetFontSize(subElement); break; case "videotitle": + if (VideoTitleFont == null) { continue; } VideoTitleFont.Size = GetFontSize(subElement); break; } diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs b/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs index 69b2aa985..a95140454 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs @@ -20,8 +20,8 @@ namespace Barotrauma /// const float CharacterWaitOnSwitch = 10.0f; - private List characterInfos = new List(); - private List characters = new List(); + private readonly List characterInfos = new List(); + private readonly List characters = new List(); private Point screenResolution; diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/SinglePlayerCampaign.cs b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/SinglePlayerCampaign.cs index 0bb370465..ad998bd39 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/SinglePlayerCampaign.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSession/GameModes/SinglePlayerCampaign.cs @@ -256,6 +256,18 @@ namespace Barotrauma { if (c.Info == null || c.Inventory == null) { continue; } var inventoryElement = new XElement("inventory"); + + // Recharge headset batteries + var headset = c.Inventory.FindItemByIdentifier("headset"); + if (headset != null) + { + var battery = headset.OwnInventory.FindItemByTag("loadable"); + if (battery != null) + { + battery.Condition = battery.MaxCondition; + } + } + c.SaveInventory(c.Inventory, inventoryElement); c.Info.InventoryData = inventoryElement; c.Inventory?.DeleteAllItems(); diff --git a/Barotrauma/BarotraumaClient/Source/Items/Inventory.cs b/Barotrauma/BarotraumaClient/Source/Items/Inventory.cs index 8c3597b8d..2ebb44dc4 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/Inventory.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/Inventory.cs @@ -620,6 +620,7 @@ namespace Barotrauma { if (DraggingItemToWorld && Character.Controlled.FocusedItem?.OwnInventory != null && + Character.Controlled.FocusedItem.OwnInventory.CanBePut(draggingItem) && Character.Controlled.FocusedItem.OwnInventory.TryPutItem(draggingItem, Character.Controlled)) { GUI.PlayUISound(GUISoundType.PickItem); diff --git a/Barotrauma/BarotraumaClient/Source/Map/ItemAssemblyPrefab.cs b/Barotrauma/BarotraumaClient/Source/Map/ItemAssemblyPrefab.cs index 00eb633c9..0fcff3a6d 100644 --- a/Barotrauma/BarotraumaClient/Source/Map/ItemAssemblyPrefab.cs +++ b/Barotrauma/BarotraumaClient/Source/Map/ItemAssemblyPrefab.cs @@ -82,7 +82,7 @@ namespace Barotrauma center.Y -= center.Y % Submarine.GridSize.Y; MapEntity.SelectedList.Clear(); - MapEntity.SelectedList.AddRange(assemblyEntities); + assemblyEntities.ForEach(e => MapEntity.AddSelection(e)); foreach (MapEntity mapEntity in assemblyEntities) { diff --git a/Barotrauma/BarotraumaClient/Source/Map/Levels/LevelRenderer.cs b/Barotrauma/BarotraumaClient/Source/Map/Levels/LevelRenderer.cs index 28a1f7b89..fe1140184 100644 --- a/Barotrauma/BarotraumaClient/Source/Map/Levels/LevelRenderer.cs +++ b/Barotrauma/BarotraumaClient/Source/Map/Levels/LevelRenderer.cs @@ -142,24 +142,27 @@ namespace Barotrauma backgroundPos.Y = -backgroundPos.Y; backgroundPos *= 0.05f; - - if (backgroundPos.Y < 1024) + if (level.GenerationParams.BackgroundTopSprite != null) { - if (backgroundPos.Y < 0 && level.GenerationParams.BackgroundTopSprite != null) + int backgroundSize = (int)level.GenerationParams.BackgroundTopSprite.size.Y; + if (backgroundPos.Y < backgroundSize) { - var backgroundTop = level.GenerationParams.BackgroundTopSprite; - backgroundTop.SourceRect = new Rectangle((int)backgroundPos.X, (int)backgroundPos.Y, 1024, (int)Math.Min(-backgroundPos.Y, 1024)); - backgroundTop.DrawTiled(spriteBatch, Vector2.Zero, new Vector2(GameMain.GraphicsWidth, Math.Min(-backgroundPos.Y, GameMain.GraphicsHeight)), - color: level.BackgroundTextureColor); - } - if (backgroundPos.Y > -1024 && level.GenerationParams.BackgroundSprite != null) - { - var background = level.GenerationParams.BackgroundSprite; - background.SourceRect = new Rectangle((int)backgroundPos.X, (int)Math.Max(backgroundPos.Y, 0), 1024, 1024); - background.DrawTiled(spriteBatch, - (backgroundPos.Y < 0) ? new Vector2(0.0f, (int)-backgroundPos.Y) : Vector2.Zero, - new Vector2(GameMain.GraphicsWidth, (int)Math.Ceiling(1024 - backgroundPos.Y)), - color: level.BackgroundTextureColor); + if (backgroundPos.Y < 0) + { + var backgroundTop = level.GenerationParams.BackgroundTopSprite; + backgroundTop.SourceRect = new Rectangle((int)backgroundPos.X, (int)backgroundPos.Y, backgroundSize, (int)Math.Min(-backgroundPos.Y, backgroundSize)); + backgroundTop.DrawTiled(spriteBatch, Vector2.Zero, new Vector2(GameMain.GraphicsWidth, Math.Min(-backgroundPos.Y, GameMain.GraphicsHeight)), + color: level.BackgroundTextureColor); + } + if (-backgroundPos.Y < GameMain.GraphicsHeight && level.GenerationParams.BackgroundSprite != null) + { + var background = level.GenerationParams.BackgroundSprite; + background.SourceRect = new Rectangle((int)backgroundPos.X, (int)Math.Max(backgroundPos.Y, 0), backgroundSize, backgroundSize); + background.DrawTiled(spriteBatch, + (backgroundPos.Y < 0) ? new Vector2(0.0f, (int)-backgroundPos.Y) : Vector2.Zero, + new Vector2(GameMain.GraphicsWidth, (int)Math.Min(Math.Ceiling(backgroundSize - backgroundPos.Y), backgroundSize)), + color: level.BackgroundTextureColor); + } } } diff --git a/Barotrauma/BarotraumaClient/Source/Map/MapEntity.cs b/Barotrauma/BarotraumaClient/Source/Map/MapEntity.cs index a428bdd93..9831b7cf3 100644 --- a/Barotrauma/BarotraumaClient/Source/Map/MapEntity.cs +++ b/Barotrauma/BarotraumaClient/Source/Map/MapEntity.cs @@ -482,6 +482,60 @@ namespace Barotrauma return true; }; } + + public static void AddSelection(MapEntity entity) + { + if (selectedList.Contains(entity)) { return; } + selectedList.Add(entity); + HandleDoorGapLinks(entity, + onGapFound: (door, gap) => + { + door.RefreshLinkedGap(); + if (!selectedList.Contains(gap)) + { + selectedList.Add(gap); + } + }, + onDoorFound: (door, gap) => + { + if (!selectedList.Contains(door.Item)) + { + selectedList.Add(door.Item); + } + }); + } + + private static void HandleDoorGapLinks(MapEntity entity, Action onGapFound, Action onDoorFound) + { + if (entity is Item i) + { + var door = i.GetComponent(); + if (door != null) + { + var gap = door.LinkedGap; + if (gap != null) + { + onGapFound(door, gap); + } + } + } + else if (entity is Gap gap) + { + var door = gap.ConnectedDoor; + if (door != null) + { + onDoorFound(door, gap); + } + } + } + + public static void RemoveSelection(MapEntity entity) + { + selectedList.Remove(entity); + HandleDoorGapLinks(entity, + onGapFound: (door, gap) => selectedList.Remove(gap), + onDoorFound: (door, gap) => selectedList.Remove(door.Item)); + } static partial void UpdateAllProjSpecific(float deltaTime) { @@ -554,7 +608,7 @@ namespace Barotrauma if (editingHUD != null) { - if (selectedList.Count == 0 || editingHUD.UserData != selectedList[0]) + if (FilteredSelectedList.Count == 0 || editingHUD.UserData != FilteredSelectedList[0]) { foreach (GUIComponent component in editingHUD.Children) { @@ -565,59 +619,6 @@ namespace Barotrauma editingHUD = null; } } - - if (selectedList.Count == 0) return; - - if (editingHUD != null) - { - selectedList[0].UpdateEditing(cam); - if (selectedList[0].ResizeHorizontal || selectedList[0].ResizeVertical) - { - foreach (GUIComponent component in editingHUD.Children) - { - var textBox = component as GUITextBox; - if (textBox == null) continue; - textBox.Deselect(); - } - editingHUD = null; - } - } - - if ((PlayerInput.KeyDown(Keys.LeftControl) || PlayerInput.KeyDown(Keys.RightControl))) - { - if (PlayerInput.KeyHit(Keys.N)) - { - float minX = selectedList[0].WorldRect.X, maxX = selectedList[0].WorldRect.Right; - for (int i = 0; i < selectedList.Count; i++) - { - minX = Math.Min(minX, selectedList[i].WorldRect.X); - maxX = Math.Max(maxX, selectedList[i].WorldRect.Right); - } - - float centerX = (minX + maxX) / 2.0f; - foreach (MapEntity me in selectedList) - { - me.FlipX(false); - me.Move(new Vector2((centerX - me.WorldPosition.X) * 2.0f, 0.0f)); - } - } - else if (PlayerInput.KeyHit(Keys.M)) - { - float minY = selectedList[0].WorldRect.Y - selectedList[0].WorldRect.Height, maxY = selectedList[0].WorldRect.Y; - for (int i = 0; i < selectedList.Count; i++) - { - minY = Math.Min(minY, selectedList[i].WorldRect.Y - selectedList[i].WorldRect.Height); - maxY = Math.Max(maxY, selectedList[i].WorldRect.Y); - } - - float centerY = (minY + maxY) / 2.0f; - foreach (MapEntity me in selectedList) - { - me.FlipY(false); - me.Move(new Vector2(0.0f, (centerY - me.WorldPosition.Y) * 2.0f)); - } - } - } FilteredSelectedList.Clear(); if (selectedList.Count == 0) return; foreach (var e in selectedList) diff --git a/Barotrauma/BarotraumaClient/Source/Map/WayPoint.cs b/Barotrauma/BarotraumaClient/Source/Map/WayPoint.cs index d1f937d7f..27c059ccf 100644 --- a/Barotrauma/BarotraumaClient/Source/Map/WayPoint.cs +++ b/Barotrauma/BarotraumaClient/Source/Map/WayPoint.cs @@ -51,6 +51,10 @@ namespace Barotrauma { iconSize = (int)(iconSize * 1.5f); } + if (Stairs != null) + { + iconSize = (int)(iconSize * 1.5f); + } spriteBatch.Draw(iconTexture, new Rectangle((int)(drawPos.X - iconSize / 2), (int)(drawPos.Y - iconSize / 2), iconSize, iconSize), @@ -93,7 +97,7 @@ namespace Barotrauma editingHUD = CreateEditingHUD(); } - if (PlayerInput.LeftButtonClicked()) + if (IsSelected && PlayerInput.LeftButtonClicked()) { Vector2 position = cam.ScreenToWorld(PlayerInput.MousePosition); @@ -149,6 +153,23 @@ namespace Barotrauma } } + private void UpdateLinkedEntity(Vector2 worldPos, IEnumerable list, Action match, Action noMatch, int inflate = 0) where T : MapEntity + { + foreach (var entity in list) + { + var rect = entity.WorldRect; + rect.Inflate(inflate, inflate); + if (Submarine.RectContains(rect, worldPos)) + { + match(entity); + } + else + { + noMatch(entity); + } + } + } + private bool ChangeSpawnType(GUIButton button, object obj) { GUITextBlock spawnTypeText = button.Parent.GetChildByUserData("spawntypetext") as GUITextBlock; diff --git a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs index 4b910e119..bcf031886 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs @@ -2047,13 +2047,15 @@ namespace Barotrauma.Networking client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered); } - public void SetupNewCampaign(Submarine sub, string savePath, string mapSeed) + public void SetupNewCampaign(Submarine sub, string saveName, string mapSeed) { + saveName = Path.GetFileNameWithoutExtension(saveName); + NetOutgoingMessage msg = client.CreateMessage(); msg.Write((byte)ClientPacketHeader.CAMPAIGN_SETUP_INFO); msg.Write(true); msg.WritePadBits(); - msg.Write(savePath); + msg.Write(saveName); msg.Write(mapSeed); msg.Write(sub.Name); msg.Write(sub.MD5Hash.Hash); diff --git a/Barotrauma/BarotraumaClient/Source/Networking/SteamManager.cs b/Barotrauma/BarotraumaClient/Source/Networking/SteamManager.cs index 4b27e024c..224623330 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/SteamManager.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/SteamManager.cs @@ -590,12 +590,19 @@ namespace Barotrauma.Steam } else { - DebugConsole.ThrowError("Publishing workshop item " + item.Title + " failed. " + item.Error); + DebugConsole.NewMessage("Publishing workshop item " + item.Title + " failed. " + item.Error, Microsoft.Xna.Framework.Color.Red); } SaveUtil.ClearFolder(WorkshopItemStagingFolder); - Directory.Delete(WorkshopItemStagingFolder); File.Delete(PreviewImageName); + try + { + Directory.Delete(WorkshopItemStagingFolder); + } + catch (Exception e) + { + DebugConsole.ThrowError("Failed to delete Workshop item staging folder.", e); + } yield return CoroutineStatus.Success; } @@ -927,28 +934,50 @@ namespace Barotrauma.Steam { if (instance == null || !instance.isInitialized) { return false; } - bool itemsUpdated = false; - foreach (ulong subscribedItemId in instance.client.Workshop.GetSubscribedItemIds()) + bool? itemsUpdated = null; + bool timedOut = false; + var query = instance.client.Workshop.CreateQuery(); + query.FileId = new List(instance.client.Workshop.GetSubscribedItemIds()); + query.UploaderAppId = AppID; + query.Run(); + query.OnResult = (Workshop.Query q) => { - //TODO: fix this, GetItem doesn't query item.Modified - var item = instance.client.Workshop.GetItem(subscribedItemId); - if (item.Installed && CheckWorkshopItemEnabled(item) && !CheckWorkshopItemUpToDate(item)) + if (timedOut) { return; } + itemsUpdated = false; + foreach (var item in q.Items) { - if (!UpdateWorkshopItem(item, out string errorMsg)) + if (item.Installed && CheckWorkshopItemEnabled(item) && !CheckWorkshopItemUpToDate(item)) { - DebugConsole.ThrowError(errorMsg); - new GUIMessageBox( - TextManager.Get("Error"), - TextManager.GetWithVariables("WorkshopItemUpdateFailed", new string[2] { "[itemname]", "[errormessage]" }, new string[2] { item.Title, errorMsg })); - } - else - { - new GUIMessageBox("", TextManager.GetWithVariable("WorkshopItemUpdated", "[itemname]", item.Title)); - itemsUpdated = true; + if (!UpdateWorkshopItem(item, out string errorMsg)) + { + DebugConsole.ThrowError(errorMsg); + new GUIMessageBox( + TextManager.Get("Error"), + TextManager.GetWithVariables("WorkshopItemUpdateFailed", new string[2] { "[itemname]", "[errormessage]" }, new string[2] { item.Title, errorMsg })); + } + else + { + new GUIMessageBox("", TextManager.GetWithVariable("WorkshopItemUpdated", "[itemname]", item.Title)); + itemsUpdated = true; + } } } + }; + + DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, 10); + while (!itemsUpdated.HasValue) + { + if (DateTime.Now > timeOut) + { + itemsUpdated = false; + timedOut = true; + break; + } + instance.client.Update(); + System.Threading.Thread.Sleep(10); } - return itemsUpdated; + + return itemsUpdated.Value; } public static bool UpdateWorkshopItem(Workshop.Item item, out string errorMsg) diff --git a/Barotrauma/BarotraumaClient/Source/Networking/WhiteList.cs b/Barotrauma/BarotraumaClient/Source/Networking/WhiteList.cs index 120fdf0bd..58427e1e1 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/WhiteList.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/WhiteList.cs @@ -61,6 +61,7 @@ namespace Barotrauma.Networking localEnabled = box.Selected; + return true; } }; @@ -145,16 +146,12 @@ namespace Barotrauma.Networking { if (obj is WhiteListedPlayer) { - WhiteListedPlayer wlp = obj as WhiteListedPlayer; - if (wlp == null) return false; - + if (!(obj is WhiteListedPlayer wlp)) return false; if (!localRemoved.Contains(wlp.UniqueIdentifier)) localRemoved.Add(wlp.UniqueIdentifier); } else if (obj is LocalAdded) { - LocalAdded lad = obj as LocalAdded; - if (lad == null) return false; - + if (!(obj is LocalAdded lad)) return false; if (localAdded.Contains(lad)) localAdded.Remove(lad); } @@ -210,7 +207,6 @@ namespace Barotrauma.Networking { ip = "IP concealed by host"; } - DebugConsole.NewMessage("nerd: " + name, Color.Lime); whitelistedPlayers.Add(new WhiteListedPlayer(name, uniqueIdentifier, ip)); } diff --git a/Barotrauma/BarotraumaClient/Source/Screens/CampaignUI.cs b/Barotrauma/BarotraumaClient/Source/Screens/CampaignUI.cs index 4f96e0cdc..7f02549df 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/CampaignUI.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/CampaignUI.cs @@ -441,38 +441,44 @@ namespace Barotrauma characterPreviewFrame = null; } - if (Campaign is SinglePlayerCampaign) + if (characterList != null) { - var hireableCharacters = location.GetHireableCharacters(); - foreach (GUIComponent child in characterList.Content.Children.ToList()) + if (Campaign is SinglePlayerCampaign) { - if (child.UserData is CharacterInfo character) + var hireableCharacters = location.GetHireableCharacters(); + foreach (GUIComponent child in characterList.Content.Children.ToList()) { - if (GameMain.GameSession.CrewManager.GetCharacterInfos().Contains(character)) { continue; } + if (child.UserData is CharacterInfo character) + { + if (GameMain.GameSession.CrewManager != null) + { + if (GameMain.GameSession.CrewManager.GetCharacterInfos().Contains(character)) { continue; } + } + } + else if (child.UserData as string == "mycrew" || child.UserData as string == "hire") + { + continue; + } + characterList.RemoveChild(child); } - else if (child.UserData as string == "mycrew" || child.UserData as string == "hire") + if (!hireableCharacters.Any()) { - continue; + new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), characterList.Content.RectTransform), TextManager.Get("HireUnavailable"), textAlignment: Alignment.Center) + { + CanBeFocused = false + }; } - characterList.RemoveChild(child); - } - if (!hireableCharacters.Any()) - { - new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), characterList.Content.RectTransform), TextManager.Get("HireUnavailable"), textAlignment: Alignment.Center) + else { - CanBeFocused = false - }; - } - else - { - foreach (CharacterInfo c in hireableCharacters) - { - var frame = c.CreateCharacterFrame(characterList.Content, c.Name + " (" + c.Job.Name + ")", c); - new GUITextBlock(new RectTransform(Vector2.One, frame.RectTransform, Anchor.TopRight), c.Salary.ToString(), textAlignment: Alignment.CenterRight); + foreach (CharacterInfo c in hireableCharacters) + { + var frame = c.CreateCharacterFrame(characterList.Content, c.Name + " (" + c.Job.Name + ")", c); + new GUITextBlock(new RectTransform(Vector2.One, frame.RectTransform, Anchor.TopRight), c.Salary.ToString(), textAlignment: Alignment.CenterRight); + } } } + characterList.UpdateScrollBarSize(); } - characterList.UpdateScrollBarSize(); RefreshMyItems(); diff --git a/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs index d8ab767b4..7736660f8 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/MainMenuScreen.cs @@ -14,7 +14,7 @@ namespace Barotrauma { class MainMenuScreen : Screen { - public enum Tab { NewGame = 1, LoadGame = 2, HostServer = 3, Settings = 4, Tutorials = 5, JoinServer = 6, CharacterEditor = 7, SubmarineEditor = 8, QuickStartDev = 9, SteamWorkshop = 10, Credits = 11 } + public enum Tab { NewGame = 1, LoadGame = 2, HostServer = 3, Settings = 4, Tutorials = 5, JoinServer = 6, CharacterEditor = 7, SubmarineEditor = 8, QuickStartDev = 9, SteamWorkshop = 10, Credits = 11, Empty = 12 } private GUIComponent buttonsParent; @@ -37,7 +37,11 @@ namespace Barotrauma private GUIComponent titleText; private CreditsPlayer creditsPlayer; - + + #if OSX + private bool firstLoadOnMac = true; + #endif + #region Creation public MainMenuScreen(GameMain game) { @@ -360,9 +364,9 @@ namespace Barotrauma OnClicked = SelectTab }; } -#endregion + #endregion -#region Selection + #region Selection public override void Select() { base.Select(); @@ -378,6 +382,25 @@ namespace Barotrauma ResetButtonStates(null); GameAnalyticsManager.SetCustomDimension01(""); + + #if OSX + // Hack for adjusting the viewport properly after splash screens on older Macs + if (firstLoadOnMac) + { + firstLoadOnMac = false; + + menuTabs[(int)Tab.Empty] = new GUIFrame(new RectTransform(new Vector2(1f, 1f), GUI.Canvas), "", Color.Transparent) + { + CanBeFocused = false + }; + var emptyList = new GUIListBox(new RectTransform(new Vector2(0.0f, 0.0f), menuTabs[(int)Tab.Empty].RectTransform)) + { + CanBeFocused = false + }; + + SelectTab(null, Tab.Empty); + } + #endif } public override void Deselect() @@ -701,7 +724,14 @@ namespace Barotrauma GameMain.NetLobbyScreen = new NetLobbyScreen(); try { - int ownerKey = Math.Max(CryptoRandom.Instance.Next(),1); + string exeName = ContentPackage.GetFilesOfType(GameMain.Config.SelectedContentPackages, ContentType.ServerExecutable)?.FirstOrDefault(); + if (string.IsNullOrEmpty(exeName)) + { + DebugConsole.ThrowError("No server executable defined in the selected content packages. Attempting to use the default executable..."); + exeName = "DedicatedServer.exe"; + } + + int ownerKey = Math.Max(CryptoRandom.Instance.Next(), 1); string arguments = "-name \"" + name.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\"" + " -port " + port.ToString() + @@ -711,16 +741,15 @@ namespace Barotrauma " -maxplayers " + maxPlayersBox.Text + " -ownerkey " + ownerKey.ToString(); - string filename = "DedicatedServer.exe"; + string filename = exeName; #if LINUX || OSX - filename = "./DedicatedServer"; + filename = "./" + Path.GetFileNameWithoutExtension(exeName); #endif var processInfo = new ProcessStartInfo { FileName = filename, - Arguments = arguments + Arguments = arguments, #if !DEBUG - , WindowStyle = ProcessWindowStyle.Hidden #endif }; @@ -925,7 +954,11 @@ namespace Barotrauma new GUITextBlock(new RectTransform(textLabelSize, parent.RectTransform), TextManager.Get("HostServerButton"), textAlignment: Alignment.Center, font: GUI.LargeFont) { ForceUpperCase = true }; var label = new GUITextBlock(new RectTransform(textLabelSize, parent.RectTransform), TextManager.Get("ServerName"), textAlignment: textAlignment); - serverNameBox = new GUITextBox(new RectTransform(textFieldSize, label.RectTransform, Anchor.CenterRight), textAlignment: textAlignment); + serverNameBox = new GUITextBox(new RectTransform(textFieldSize, label.RectTransform, Anchor.CenterRight), textAlignment: textAlignment) + { + MaxTextLength = NetConfig.ServerNameMaxLength, + OverflowClip = true + }; label = new GUITextBlock(new RectTransform(textLabelSize, parent.RectTransform), TextManager.Get("ServerPort"), textAlignment: textAlignment); portBox = new GUITextBox(new RectTransform(textFieldSize, label.RectTransform, Anchor.CenterRight), textAlignment: textAlignment) diff --git a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs index d050187db..d392f2bfa 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/NetLobbyScreen.cs @@ -335,8 +335,12 @@ namespace Barotrauma new GUIFrame(new RectTransform(new Vector2(1.0f, 0.03f), rightInfoColumn.RectTransform), style: null); //server info ------------------------------------------------------------------ - - ServerName = new GUITextBox(new RectTransform(new Vector2(0.3f, 0.05f), infoFrameContent.RectTransform)); + + ServerName = new GUITextBox(new RectTransform(new Vector2(infoColumnContainer.RectTransform.RelativeSize.X, 0.05f), infoFrameContent.RectTransform)) + { + MaxTextLength = NetConfig.ServerNameMaxLength, + OverflowClip = true + }; ServerName.OnDeselected += (textBox, key) => { GameMain.Client.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Name); diff --git a/Barotrauma/BarotraumaClient/Source/Screens/SteamWorkshopScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/SteamWorkshopScreen.cs index ce5b54c2d..1a62ec6db 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/SteamWorkshopScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/SteamWorkshopScreen.cs @@ -49,7 +49,7 @@ namespace Barotrauma { tabs = new GUIFrame[Enum.GetValues(typeof(Tab)).Length]; - menu = new GUIFrame(new RectTransform(new Vector2(0.6f, 0.8f), GUI.Canvas, Anchor.Center) { MinSize = new Point(GameMain.GraphicsHeight, 0) }); + menu = new GUIFrame(new RectTransform(new Vector2(0.85f, 0.8f), GUI.Canvas, Anchor.Center) { MinSize = new Point(GameMain.GraphicsHeight, 0) }); var container = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.85f), menu.RectTransform, Anchor.Center) { RelativeOffset = new Vector2(0.0f, 0.05f) }) { Stretch = true }; @@ -394,6 +394,7 @@ namespace Barotrauma { IsHorizontal = true, Stretch = true, + RelativeSpacing = 0.05f, CanBeFocused = false }; @@ -405,32 +406,6 @@ namespace Barotrauma if (item.Installed) { - if (listBox != publishedItemList && SteamManager.CheckWorkshopItemEnabled(item) && !SteamManager.CheckWorkshopItemUpToDate(item)) - { - new GUIButton(new RectTransform(new Vector2(0.4f, 0.5f), rightColumn.RectTransform, Anchor.BottomLeft), text: "Update") - { - UserData = "updatebutton", - IgnoreLayoutGroups = true, - OnClicked = (btn, userdata) => - { - if (SteamManager.UpdateWorkshopItem(item, out string errorMsg)) - { - new GUIMessageBox("", TextManager.GetWithVariable("WorkshopItemUpdated", "[itemname]", TextManager.EnsureUTF8(item.Title))); - } - else - { - DebugConsole.ThrowError(errorMsg); - new GUIMessageBox( - TextManager.Get("Error"), - TextManager.GetWithVariables("WorkshopItemUpdateFailed", new string[2] { "[itemname]", "[errormessage]" }, new string[2] { TextManager.EnsureUTF8(item.Title), errorMsg })); - } - btn.Enabled = false; - btn.Visible = false; - return true; - } - }; - } - GUITickBox enabledTickBox = null; try { @@ -476,6 +451,33 @@ namespace Barotrauma }; } } + + if (listBox != publishedItemList && SteamManager.CheckWorkshopItemEnabled(item) && !SteamManager.CheckWorkshopItemUpToDate(item)) + { + new GUIButton(new RectTransform(new Vector2(0.4f, 0.5f), rightColumn.RectTransform, Anchor.BottomLeft), text: TextManager.Get("WorkshopItemUpdate")) + { + UserData = "updatebutton", + Font = GUI.SmallFont, + OnClicked = (btn, userdata) => + { + if (SteamManager.UpdateWorkshopItem(item, out string errorMsg)) + { + new GUIMessageBox("", TextManager.GetWithVariable("WorkshopItemUpdated", "[itemname]", TextManager.EnsureUTF8(item.Title))); + } + else + { + DebugConsole.ThrowError(errorMsg); + new GUIMessageBox( + TextManager.Get("Error"), + TextManager.GetWithVariables("WorkshopItemUpdateFailed", new string[2] { "[itemname]", "[errormessage]" }, new string[2] { TextManager.EnsureUTF8(item.Title), errorMsg })); + } + btn.Enabled = false; + btn.Visible = false; + return true; + } + }; + } + } else if (item.Downloading) { @@ -746,7 +748,7 @@ namespace Barotrauma for (int i = 0; i < item.Tags.Length && i < 5; i++) { if (string.IsNullOrEmpty(item.Tags[i])) { continue; } - string tag = TextManager.Get("Workshop.ContentTag." + item.Tags[i], true); + string tag = TextManager.Get("Workshop.ContentTag." + item.Tags[i].Replace(" ", ""), true); if (string.IsNullOrEmpty(tag)) { tag = item.Tags[i].CapitaliseFirstInvariant(); } tags.Add(tag); } @@ -900,7 +902,7 @@ namespace Barotrauma new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), topRightColumn.RectTransform), TextManager.Get("WorkshopItemDescription")); var descriptionContainer = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.4f), topRightColumn.RectTransform)); - var descriptionBox = new GUITextBox(new RectTransform(Vector2.One, descriptionContainer.Content.RectTransform), itemEditor.Description, textAlignment: Alignment.TopLeft, wrap: true); + var descriptionBox = new GUITextBox(new RectTransform(Vector2.One, descriptionContainer.Content.RectTransform), itemEditor.Description, textAlignment: Alignment.TopLeft, font: GUI.SmallFont, wrap: true); descriptionBox.OnTextChanged += (textBox, text) => { Vector2 textSize = textBox.Font.MeasureString(descriptionBox.WrappedText); @@ -1081,6 +1083,7 @@ namespace Barotrauma { InitialDirectory = Path.GetFullPath(SteamManager.WorkshopItemStagingFolder), Title = TextManager.Get("workshopitemaddfiles"), + Multiselect = true }; if (ofd.ShowDialog() == DialogResult.OK) { @@ -1228,7 +1231,7 @@ namespace Barotrauma private void OnAddFilesSelected(string[] fileNames) { if (fileNames == null) { return; } - for(int i = 0; i < fileNames.Length; i++) + for (int i = 0; i < fileNames.Length; i++) { string file = fileNames[i]; if (string.IsNullOrEmpty(file)) { continue; } @@ -1258,6 +1261,7 @@ namespace Barotrauma itemContentPackage.AddFile(filePathRelativeToStagingFolder, ContentType.None); } } + itemContentPackage.Save(itemContentPackage.Path); RefreshCreateItemFileList(); } @@ -1331,6 +1335,7 @@ namespace Barotrauma OnClicked = (btn, userdata) => { itemContentPackage.RemoveFile(contentFile); + itemContentPackage.Save(itemContentPackage.Path); RefreshCreateItemFileList(); return true; } @@ -1346,7 +1351,7 @@ namespace Barotrauma { if (itemContentPackage == null || itemEditor == null) return; - SteamManager.StartPublishItem(itemContentPackage, itemEditor); + SteamManager.StartPublishItem(itemContentPackage, itemEditor); CoroutineManager.StartCoroutine(WaitForPublish(itemEditor), "WaitForPublish"); } @@ -1381,9 +1386,20 @@ namespace Barotrauma } else { - new GUIMessageBox( - TextManager.Get("Error"), - TextManager.GetWithVariable("WorkshopItemPublishFailed", "[itemname]", TextManager.EnsureUTF8(item.Title)) + item.Error); + string errorMsg = item.ErrorCode.HasValue ? + TextManager.Get("WorkshopPublishError." + item.ErrorCode.Value.ToString(), returnNull: true) : + null; + + if (errorMsg == null) + { + new GUIMessageBox( + TextManager.Get("Error"), + TextManager.GetWithVariable("WorkshopItemPublishFailed", "[itemname]", TextManager.EnsureUTF8(item.Title)) + item.Error); + } + else + { + new GUIMessageBox(TextManager.Get("Error"), errorMsg); + } } createItemFrame.ClearChildren(); diff --git a/Barotrauma/BarotraumaClient/Source/Screens/SubEditorScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/SubEditorScreen.cs index a45f872e6..e69d4a663 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/SubEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/SubEditorScreen.cs @@ -2109,10 +2109,7 @@ namespace Barotrauma public override void AddToGUIUpdateList() { - if (MapEntity.SelectedList.Count == 1) - { - MapEntity.SelectedList[0].AddToGUIUpdateList(); - } + MapEntity.FilteredSelectedList.FirstOrDefault()?.AddToGUIUpdateList(); if (MapEntity.HighlightedListBox != null) { MapEntity.HighlightedListBox.AddToGUIUpdateList(); @@ -2293,9 +2290,9 @@ namespace Barotrauma dummyCharacter.SelectedConstruction = null; }*/ } - else if (MapEntity.SelectedList.Count == 1) + else if (MapEntity.FilteredSelectedList.Count == 1) { - (MapEntity.SelectedList[0] as Item)?.UpdateHUD(cam, dummyCharacter, (float)deltaTime); + (MapEntity.FilteredSelectedList[0] as Item)?.UpdateHUD(cam, dummyCharacter, (float)deltaTime); } CharacterHUD.Update((float)deltaTime, dummyCharacter, cam); diff --git a/Barotrauma/BarotraumaClient/Source/Utils/OpenFileDialog.cs b/Barotrauma/BarotraumaClient/Source/Utils/OpenFileDialog.cs index b7e5dba5c..54257c19a 100644 --- a/Barotrauma/BarotraumaClient/Source/Utils/OpenFileDialog.cs +++ b/Barotrauma/BarotraumaClient/Source/Utils/OpenFileDialog.cs @@ -18,34 +18,33 @@ namespace Barotrauma public string FileName { get; private set; } public string[] FileNames { get; private set; } - public OpenFileDialog() - { - ofd = new System.Windows.Forms.OpenFileDialog(); - } + public OpenFileDialog() { } public System.Windows.Forms.DialogResult ShowDialog() { + ofd = new System.Windows.Forms.OpenFileDialog(); ofd.Multiselect = Multiselect; ofd.InitialDirectory = InitialDirectory; ofd.Filter = Filter; ofd.Title = Title; -#if LINUX + System.Windows.Forms.DialogResult result; +#if LINUX || OSX var wrapperForm = new WrapperForm(ofd); System.Windows.Forms.Application.Run(wrapperForm); - System.Windows.Forms.Application.Exit(); FileName = wrapperForm.FileName; FileNames = wrapperForm.FileNames; - return wrapperForm.Result; + result = wrapperForm.Result; #else - var result = ofd.ShowDialog(); + result = ofd.ShowDialog(); FileName = ofd.FileName; FileNames = ofd.FileNames; - return result; #endif + ofd = null; + return result; } -#if LINUX +#if LINUX || OSX private class WrapperForm : System.Windows.Forms.Form { private System.Windows.Forms.OpenFileDialog ofd; @@ -66,7 +65,7 @@ namespace Barotrauma FileName = ofd.FileName; FileNames = ofd.FileNames; System.Threading.Thread.Sleep(100); - this.Close(); + System.Windows.Forms.Application.Exit(); } } #endif diff --git a/Barotrauma/BarotraumaServer/Source/DebugConsole.cs b/Barotrauma/BarotraumaServer/Source/DebugConsole.cs index c06a6807b..f097ff73b 100644 --- a/Barotrauma/BarotraumaServer/Source/DebugConsole.cs +++ b/Barotrauma/BarotraumaServer/Source/DebugConsole.cs @@ -90,7 +90,16 @@ namespace Barotrauma while (queuedMessages.Count > 0) { ColoredText msg = queuedMessages.Dequeue(); - + if (GameSettings.SaveDebugConsoleLogs) + { + unsavedMessages.Add(msg); + if (unsavedMessages.Count >= messagesPerFile) + { + SaveLogs(); + unsavedMessages.Clear(); + } + } + string msgTxt = msg.Text; if (msg.IsCommand) commandMemory.Add(msgTxt); @@ -167,7 +176,8 @@ namespace Barotrauma RewriteInputToCommandLine(input); } - Thread.Yield(); + //TODO: be more clever about it + Thread.Sleep(10); //sleep for 10ms to not pin the CPU super hard } } catch (ThreadAbortException) diff --git a/Barotrauma/BarotraumaServer/Source/Networking/BanList.cs b/Barotrauma/BarotraumaServer/Source/Networking/BanList.cs index f8b1c148d..58a1aa5b5 100644 --- a/Barotrauma/BarotraumaServer/Source/Networking/BanList.cs +++ b/Barotrauma/BarotraumaServer/Source/Networking/BanList.cs @@ -184,7 +184,8 @@ namespace Barotrauma.Networking public void UnbanPlayer(string name) { - var player = bannedPlayers.Find(bp => bp.Name == name); + name = name.ToLower(); + var player = bannedPlayers.Find(bp => bp.Name.ToLower() == name); if (player == null) { DebugConsole.Log("Could not unban player \"" + name + "\". Matching player not found."); diff --git a/Barotrauma/BarotraumaServer/Source/Networking/GameServer.cs b/Barotrauma/BarotraumaServer/Source/Networking/GameServer.cs index 291ca50dc..c48bb85f6 100644 --- a/Barotrauma/BarotraumaServer/Source/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaServer/Source/Networking/GameServer.cs @@ -93,6 +93,10 @@ namespace Barotrauma.Networking { name = name.Replace(":", ""); name = name.Replace(";", ""); + if (name.Length > NetConfig.ServerNameMaxLength) + { + name = name.Substring(0, NetConfig.ServerNameMaxLength); + } this.name = name; @@ -724,7 +728,7 @@ namespace Barotrauma.Networking bool isNew = inc.ReadBoolean(); inc.ReadPadBits(); if (isNew) { - string savePath = inc.ReadString(); + string saveName = inc.ReadString(); string seed = inc.ReadString(); string subName = inc.ReadString(); string subHash = inc.ReadString(); @@ -739,7 +743,11 @@ namespace Barotrauma.Networking } else { - if (connectedClient.HasPermission(ClientPermissions.SelectMode)) MultiPlayerCampaign.StartNewCampaign(savePath, matchingSub.FilePath, seed); + string localSavePath = SaveUtil.CreateSavePath(SaveUtil.SaveType.Multiplayer, saveName); + if (connectedClient.HasPermission(ClientPermissions.SelectMode)) + { + MultiPlayerCampaign.StartNewCampaign(localSavePath, matchingSub.FilePath, seed); + } } } else @@ -2182,7 +2190,6 @@ namespace Barotrauma.Networking public override void UnbanPlayer(string playerName, string playerIP) { - playerName = playerName.ToLowerInvariant(); if (!string.IsNullOrEmpty(playerIP)) { serverSettings.BanList.UnbanIP(playerIP); diff --git a/Barotrauma/BarotraumaServer/Source/Networking/SteamManager.cs b/Barotrauma/BarotraumaServer/Source/Networking/SteamManager.cs index 1bc7105a6..912a50eb2 100644 --- a/Barotrauma/BarotraumaServer/Source/Networking/SteamManager.cs +++ b/Barotrauma/BarotraumaServer/Source/Networking/SteamManager.cs @@ -42,6 +42,8 @@ namespace Barotrauma.Steam return false; } + var contentPackages = GameMain.Config.SelectedContentPackages.Where(cp => cp.HasMultiplayerIncompatibleContent); + // These server state variables may be changed at any time. Note that there is no longer a mechanism // to send the player count. The player count is maintained by steam and you should use the player // creation/authentication functions to maintain your player count. @@ -51,9 +53,9 @@ namespace Barotrauma.Steam instance.server.MapName = GameMain.NetLobbyScreen?.SelectedSub?.DisplayName ?? ""; Instance.server.SetKey("message", GameMain.Server.ServerSettings.ServerMessageText); Instance.server.SetKey("version", GameMain.Version.ToString()); - Instance.server.SetKey("contentpackage", string.Join(",", GameMain.Config.SelectedContentPackages.Select(cp => cp.Name))); - Instance.server.SetKey("contentpackagehash", string.Join(",", GameMain.Config.SelectedContentPackages.Select(cp => cp.MD5hash.Hash))); - Instance.server.SetKey("contentpackageurl", string.Join(",", GameMain.Config.SelectedContentPackages.Select(cp => cp.SteamWorkshopUrl ?? ""))); + Instance.server.SetKey("contentpackage", string.Join(",", contentPackages.Select(cp => cp.Name))); + Instance.server.SetKey("contentpackagehash", string.Join(",", contentPackages.Select(cp => cp.MD5hash.Hash))); + Instance.server.SetKey("contentpackageurl", string.Join(",", contentPackages.Select(cp => cp.SteamWorkshopUrl ?? ""))); Instance.server.SetKey("usingwhitelist", (server.ServerSettings.Whitelist != null && server.ServerSettings.Whitelist.Enabled).ToString()); Instance.server.SetKey("modeselectionmode", server.ServerSettings.ModeSelectionMode.ToString()); Instance.server.SetKey("subselectionmode", server.ServerSettings.SubSelectionMode.ToString()); diff --git a/Barotrauma/BarotraumaServer/Source/Networking/WhiteList.cs b/Barotrauma/BarotraumaServer/Source/Networking/WhiteList.cs index 2efdb46fa..c5e27a867 100644 --- a/Barotrauma/BarotraumaServer/Source/Networking/WhiteList.cs +++ b/Barotrauma/BarotraumaServer/Source/Networking/WhiteList.cs @@ -25,47 +25,45 @@ namespace Barotrauma.Networking { partial void InitProjSpecific() { - if (File.Exists(SavePath)) + if (!File.Exists(SavePath)) { return; } + + string[] lines; + try { - string[] lines; - try - { - lines = File.ReadAllLines(SavePath); - } - catch (Exception e) - { - DebugConsole.ThrowError("Failed to open whitelist in " + SavePath, e); - return; - } + lines = File.ReadAllLines(SavePath); + } + catch (Exception e) + { + DebugConsole.ThrowError("Failed to open whitelist in " + SavePath, e); + return; + } - foreach (string line in lines) + foreach (string line in lines) + { + if (line[0] == '#') { - if (line[0] == '#') + string lineval = line.Substring(1, line.Length - 1); + Int32.TryParse(lineval, out int intVal); + if (lineval.ToLower() == "true" || intVal != 0) { - string lineval = line.Substring(1, line.Length - 1); - int intVal = 0; - Int32.TryParse(lineval, out intVal); - if (lineval.ToLower() == "true" || intVal != 0) - { - Enabled = true; - } - else - { - Enabled = false; - } + Enabled = true; } else { - string[] separatedLine = line.Split(','); - if (separatedLine.Length < 2) continue; - - string name = String.Join(",", separatedLine.Take(separatedLine.Length - 1)); - string ip = separatedLine.Last(); - - whitelistedPlayers.Add(new WhiteListedPlayer(name, ip)); + Enabled = false; } } - } + else + { + string[] separatedLine = line.Split(','); + if (separatedLine.Length < 2) continue; + + string name = string.Join(",", separatedLine.Take(separatedLine.Length - 1)); + string ip = separatedLine.Last(); + + whitelistedPlayers.Add(new WhiteListedPlayer(name, ip)); + } + } } public void Save() @@ -119,9 +117,7 @@ namespace Barotrauma.Networking private void RemoveFromWhiteList(WhiteListedPlayer wlp) { GameServer.Log("Removing " + wlp.Name + " from whitelist", ServerLog.MessageType.ServerMessage); - whitelistedPlayers.Remove(wlp); - Save(); } private void AddToWhiteList(string name, string ip) @@ -129,7 +125,6 @@ namespace Barotrauma.Networking if (string.IsNullOrWhiteSpace(name)) return; if (whitelistedPlayers.Any(x => x.Name.ToLower() == name.ToLower() && x.IP == ip)) return; whitelistedPlayers.Add(new WhiteListedPlayer(name, ip)); - Save(); } public void ServerAdminWrite(NetBuffer outMsg, Client c) @@ -201,8 +196,10 @@ namespace Barotrauma.Networking GameServer.Log(c.Name + " added " + name + " to whitelist (" + ip + ")", ServerLog.MessageType.ConsoleUsage); AddToWhiteList(name, ip); } - - return removeCount > 0 || addCount > 0 || prevEnabled!=enabled; + + bool changed = removeCount > 0 || addCount > 0 || prevEnabled != enabled; + if (changed) { Save(); } + return changed; } } } diff --git a/Barotrauma/BarotraumaShared/SharedContent.projitems b/Barotrauma/BarotraumaShared/SharedContent.projitems index 8987fe9ea..f46f763d8 100644 --- a/Barotrauma/BarotraumaShared/SharedContent.projitems +++ b/Barotrauma/BarotraumaShared/SharedContent.projitems @@ -1295,15 +1295,6 @@ PreserveNewest - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - PreserveNewest diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs index e79606874..6fff0ba9f 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs @@ -840,7 +840,15 @@ namespace Barotrauma { if (string.IsNullOrEmpty(humanConfigFile)) { - humanConfigFile = GetConfigFile("Human"); + humanConfigFile = GameMain.Instance.GetFilesOfType(ContentType.Character)? + .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == "human.xml"); + + if (humanConfigFile == null) + { + DebugConsole.ThrowError($"Couldn't find a human config file from the selected content packages!"); + DebugConsole.ThrowError($"(The config file must end with \"human.xml\")"); + return string.Empty; + } } return humanConfigFile; } @@ -859,12 +867,16 @@ namespace Barotrauma } } + /// + /// Searches for a character config file from all currently selected content packages, + /// or from a specific package if the contentPackage parameter is given. + /// public static string GetConfigFile(string speciesName, ContentPackage contentPackage = null) { string configFile = null; if (contentPackage == null) { - configFile = GameMain.Instance.GetFilesOfType(ContentType.Character, searchAllContentPackages: true) + configFile = GameMain.Instance.GetFilesOfType(ContentType.Character) .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); } else @@ -887,7 +899,7 @@ namespace Barotrauma #if SERVER if (GameMain.Server != null && IsRemotePlayer) { - if (characterConfigFiles == null) + switch (inputType) { case InputType.Left: return !(dequeuedInput.HasFlag(InputNetFlags.Left)) && (prevDequeuedInput.HasFlag(InputNetFlags.Left)); @@ -918,672 +930,13 @@ namespace Barotrauma default: return false; } - return characterConfigFiles; } #endif return keys[(int)inputType].Hit; } - /// - /// Searches for a character config file from all currently selected content packages, - /// or from a specific package if the contentPackage parameter is given. - /// - public static string GetConfigFile(string speciesName, ContentPackage contentPackage = null) - { -#if SERVER - if (GameMain.Server != null && IsRemotePlayer) - { - configFile = GameMain.Instance.GetFilesOfType(ContentType.Character) - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } - else - { - configFile = contentPackage.GetFilesOfType(ContentType.Character)? - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } - - if (configFile == null) - { - DebugConsole.ThrowError($"Couldn't find a config file for {speciesName} from the selected content packages!"); - DebugConsole.ThrowError($"(The config file must end with \"{speciesName}.xml\")"); - return string.Empty; - } - return configFile; - } - - private static IEnumerable characterConfigFiles; - private static IEnumerable CharacterConfigFiles - { - get - { - if (characterConfigFiles == null) - { - characterConfigFiles = GameMain.Instance.GetFilesOfType(ContentType.Character); - } - return characterConfigFiles; - } - } - - public static string GetConfigFile(string speciesName, ContentPackage contentPackage = null) - { - string configFile = null; - if (contentPackage == null) - { - configFile = GameMain.Instance.GetFilesOfType(ContentType.Character, searchAllContentPackages: true) - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } - else - { - configFile = contentPackage.GetFilesOfType(ContentType.Character)? - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } - - if (configFile == null) - { - DebugConsole.ThrowError($"Couldn't find a config file for {speciesName} from the selected content packages!"); - DebugConsole.ThrowError($"(The config file must end with \"{speciesName}.xml\")"); - return string.Empty; - } - return configFile; - } - - public bool IsKeyHit(InputType inputType) - { -#if SERVER - if (GameMain.Server != null && IsRemotePlayer) - { - if (characterConfigFiles == null) - { - case InputType.Left: - return !(dequeuedInput.HasFlag(InputNetFlags.Left)) && (prevDequeuedInput.HasFlag(InputNetFlags.Left)); - case InputType.Right: - return !(dequeuedInput.HasFlag(InputNetFlags.Right)) && (prevDequeuedInput.HasFlag(InputNetFlags.Right)); - case InputType.Up: - return !(dequeuedInput.HasFlag(InputNetFlags.Up)) && (prevDequeuedInput.HasFlag(InputNetFlags.Up)); - case InputType.Down: - return !(dequeuedInput.HasFlag(InputNetFlags.Down)) && (prevDequeuedInput.HasFlag(InputNetFlags.Down)); - case InputType.Run: - return !(dequeuedInput.HasFlag(InputNetFlags.Run)) && (prevDequeuedInput.HasFlag(InputNetFlags.Run)); - case InputType.Crouch: - return !(dequeuedInput.HasFlag(InputNetFlags.Crouch)) && (prevDequeuedInput.HasFlag(InputNetFlags.Crouch)); - case InputType.Select: - return dequeuedInput.HasFlag(InputNetFlags.Select); //TODO: clean up the way this input is registered - case InputType.Deselect: - return dequeuedInput.HasFlag(InputNetFlags.Deselect); - case InputType.Health: - return dequeuedInput.HasFlag(InputNetFlags.Health); - case InputType.Grab: - return dequeuedInput.HasFlag(InputNetFlags.Grab); - case InputType.Use: - return !(dequeuedInput.HasFlag(InputNetFlags.Use)) && (prevDequeuedInput.HasFlag(InputNetFlags.Use)); - case InputType.Shoot: - return !(dequeuedInput.HasFlag(InputNetFlags.Shoot)) && (prevDequeuedInput.HasFlag(InputNetFlags.Shoot)); - case InputType.Ragdoll: - return !(dequeuedInput.HasFlag(InputNetFlags.Ragdoll)) && (prevDequeuedInput.HasFlag(InputNetFlags.Ragdoll)); - default: - return false; - } - return characterConfigFiles; - } -#endif - - if (configFile == null) - { - DebugConsole.ThrowError($"Couldn't find a config file for {speciesName} from the selected content packages!"); - DebugConsole.ThrowError($"(The config file must end with \"{speciesName}.xml\")"); - return string.Empty; - } - return configFile; - } - - private static IEnumerable characterConfigFiles; - private static IEnumerable CharacterConfigFiles - { -#if SERVER - if (GameMain.Server != null && IsRemotePlayer) - { - if (characterConfigFiles == null) - { - characterConfigFiles = GameMain.Instance.GetFilesOfType(ContentType.Character); - } - return characterConfigFiles; - } - } - - /// - /// Searches for a character config file from all currently selected content packages, - /// or from a specific package if the contentPackage parameter is given. - /// - public static string GetConfigFile(string speciesName, ContentPackage contentPackage = null) - { - string configFile = null; - if (contentPackage == null) - { - configFile = GameMain.Instance.GetFilesOfType(ContentType.Character) - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } - else - { - configFile = contentPackage.GetFilesOfType(ContentType.Character)? - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } - - if (configFile == null) - { - DebugConsole.ThrowError($"Couldn't find a config file for {speciesName} from the selected content packages!"); - DebugConsole.ThrowError($"(The config file must end with \"{speciesName}.xml\")"); - return string.Empty; - } - return configFile; - } - - private static IEnumerable characterConfigFiles; - private static IEnumerable CharacterConfigFiles - { -#if SERVER - if (GameMain.Server != null && IsRemotePlayer) - { - if (characterConfigFiles == null) - { - case InputType.Left: - return !(dequeuedInput.HasFlag(InputNetFlags.Left)) && (prevDequeuedInput.HasFlag(InputNetFlags.Left)); - case InputType.Right: - return !(dequeuedInput.HasFlag(InputNetFlags.Right)) && (prevDequeuedInput.HasFlag(InputNetFlags.Right)); - case InputType.Up: - return !(dequeuedInput.HasFlag(InputNetFlags.Up)) && (prevDequeuedInput.HasFlag(InputNetFlags.Up)); - case InputType.Down: - return !(dequeuedInput.HasFlag(InputNetFlags.Down)) && (prevDequeuedInput.HasFlag(InputNetFlags.Down)); - case InputType.Run: - return !(dequeuedInput.HasFlag(InputNetFlags.Run)) && (prevDequeuedInput.HasFlag(InputNetFlags.Run)); - case InputType.Crouch: - return !(dequeuedInput.HasFlag(InputNetFlags.Crouch)) && (prevDequeuedInput.HasFlag(InputNetFlags.Crouch)); - case InputType.Select: - return dequeuedInput.HasFlag(InputNetFlags.Select); //TODO: clean up the way this input is registered - case InputType.Deselect: - return dequeuedInput.HasFlag(InputNetFlags.Deselect); - case InputType.Health: - return dequeuedInput.HasFlag(InputNetFlags.Health); - case InputType.Grab: - return dequeuedInput.HasFlag(InputNetFlags.Grab); - case InputType.Use: - return !(dequeuedInput.HasFlag(InputNetFlags.Use)) && (prevDequeuedInput.HasFlag(InputNetFlags.Use)); - case InputType.Shoot: - return !(dequeuedInput.HasFlag(InputNetFlags.Shoot)) && (prevDequeuedInput.HasFlag(InputNetFlags.Shoot)); - case InputType.Ragdoll: - return !(dequeuedInput.HasFlag(InputNetFlags.Ragdoll)) && (prevDequeuedInput.HasFlag(InputNetFlags.Ragdoll)); - default: - return false; - } - return characterConfigFiles; - } - } - - /// - /// Searches for a character config file from all currently selected content packages, - /// or from a specific package if the contentPackage parameter is given. - /// - public static string GetConfigFile(string speciesName, ContentPackage contentPackage = null) - { - string configFile = null; - if (contentPackage == null) - { - configFile = GameMain.Instance.GetFilesOfType(ContentType.Character) - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } - else - { - configFile = contentPackage.GetFilesOfType(ContentType.Character)? - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } -#endif - - if (configFile == null) - { - DebugConsole.ThrowError($"Couldn't find a config file for {speciesName} from the selected content packages!"); - DebugConsole.ThrowError($"(The config file must end with \"{speciesName}.xml\")"); - return string.Empty; - } - return configFile; - } - - private static IEnumerable characterConfigFiles; - private static IEnumerable CharacterConfigFiles - { -#if SERVER - if (GameMain.Server != null && IsRemotePlayer) - { - if (characterConfigFiles == null) - { - characterConfigFiles = GameMain.Instance.GetFilesOfType(ContentType.Character); - } - return characterConfigFiles; - } - } - - /// - /// Searches for a character config file from all currently selected content packages, - /// or from a specific package if the contentPackage parameter is given. - /// - public static string GetConfigFile(string speciesName, ContentPackage contentPackage = null) - { - string configFile = null; - if (contentPackage == null) - { - configFile = GameMain.Instance.GetFilesOfType(ContentType.Character) - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } - else - { - configFile = contentPackage.GetFilesOfType(ContentType.Character)? - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } - - if (configFile == null) - { - DebugConsole.ThrowError($"Couldn't find a config file for {speciesName} from the selected content packages!"); - DebugConsole.ThrowError($"(The config file must end with \"{speciesName}.xml\")"); - return string.Empty; - } - return configFile; - } - - private static IEnumerable characterConfigFiles; - private static IEnumerable CharacterConfigFiles - { -#if SERVER - if (GameMain.Server != null && IsRemotePlayer) - { - if (characterConfigFiles == null) - { - case InputType.Left: - return !(dequeuedInput.HasFlag(InputNetFlags.Left)) && (prevDequeuedInput.HasFlag(InputNetFlags.Left)); - case InputType.Right: - return !(dequeuedInput.HasFlag(InputNetFlags.Right)) && (prevDequeuedInput.HasFlag(InputNetFlags.Right)); - case InputType.Up: - return !(dequeuedInput.HasFlag(InputNetFlags.Up)) && (prevDequeuedInput.HasFlag(InputNetFlags.Up)); - case InputType.Down: - return !(dequeuedInput.HasFlag(InputNetFlags.Down)) && (prevDequeuedInput.HasFlag(InputNetFlags.Down)); - case InputType.Run: - return !(dequeuedInput.HasFlag(InputNetFlags.Run)) && (prevDequeuedInput.HasFlag(InputNetFlags.Run)); - case InputType.Crouch: - return !(dequeuedInput.HasFlag(InputNetFlags.Crouch)) && (prevDequeuedInput.HasFlag(InputNetFlags.Crouch)); - case InputType.Select: - return dequeuedInput.HasFlag(InputNetFlags.Select); //TODO: clean up the way this input is registered - case InputType.Deselect: - return dequeuedInput.HasFlag(InputNetFlags.Deselect); - case InputType.Health: - return dequeuedInput.HasFlag(InputNetFlags.Health); - case InputType.Grab: - return dequeuedInput.HasFlag(InputNetFlags.Grab); - case InputType.Use: - return !(dequeuedInput.HasFlag(InputNetFlags.Use)) && (prevDequeuedInput.HasFlag(InputNetFlags.Use)); - case InputType.Shoot: - return !(dequeuedInput.HasFlag(InputNetFlags.Shoot)) && (prevDequeuedInput.HasFlag(InputNetFlags.Shoot)); - case InputType.Ragdoll: - return !(dequeuedInput.HasFlag(InputNetFlags.Ragdoll)) && (prevDequeuedInput.HasFlag(InputNetFlags.Ragdoll)); - default: - return false; - } - return characterConfigFiles; - } - } - - /// - /// Searches for a character config file from all currently selected content packages, - /// or from a specific package if the contentPackage parameter is given. - /// - public static string GetConfigFile(string speciesName, ContentPackage contentPackage = null) - { - string configFile = null; - if (contentPackage == null) - { - configFile = GameMain.Instance.GetFilesOfType(ContentType.Character) - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } - else - { - configFile = contentPackage.GetFilesOfType(ContentType.Character)? - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } -#endif - - if (configFile == null) - { - DebugConsole.ThrowError($"Couldn't find a config file for {speciesName} from the selected content packages!"); - DebugConsole.ThrowError($"(The config file must end with \"{speciesName}.xml\")"); - return string.Empty; - } - return configFile; - } - - private static IEnumerable characterConfigFiles; - private static IEnumerable CharacterConfigFiles - { -#if SERVER - if (GameMain.Server != null && IsRemotePlayer) - { - if (characterConfigFiles == null) - { - characterConfigFiles = GameMain.Instance.GetFilesOfType(ContentType.Character); - } - return characterConfigFiles; - } - } - - /// - /// Searches for a character config file from all currently selected content packages, - /// or from a specific package if the contentPackage parameter is given. - /// - public static string GetConfigFile(string speciesName, ContentPackage contentPackage = null) - { - string configFile = null; - if (contentPackage == null) - { - configFile = GameMain.Instance.GetFilesOfType(ContentType.Character) - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } - else - { - configFile = contentPackage.GetFilesOfType(ContentType.Character)? - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } - - if (configFile == null) - { - DebugConsole.ThrowError($"Couldn't find a config file for {speciesName} from the selected content packages!"); - DebugConsole.ThrowError($"(The config file must end with \"{speciesName}.xml\")"); - return string.Empty; - } - return configFile; - } - - private static IEnumerable characterConfigFiles; - private static IEnumerable CharacterConfigFiles - { -#if SERVER - if (GameMain.Server != null && IsRemotePlayer) - { - if (characterConfigFiles == null) - { - case InputType.Left: - return !(dequeuedInput.HasFlag(InputNetFlags.Left)) && (prevDequeuedInput.HasFlag(InputNetFlags.Left)); - case InputType.Right: - return !(dequeuedInput.HasFlag(InputNetFlags.Right)) && (prevDequeuedInput.HasFlag(InputNetFlags.Right)); - case InputType.Up: - return !(dequeuedInput.HasFlag(InputNetFlags.Up)) && (prevDequeuedInput.HasFlag(InputNetFlags.Up)); - case InputType.Down: - return !(dequeuedInput.HasFlag(InputNetFlags.Down)) && (prevDequeuedInput.HasFlag(InputNetFlags.Down)); - case InputType.Run: - return !(dequeuedInput.HasFlag(InputNetFlags.Run)) && (prevDequeuedInput.HasFlag(InputNetFlags.Run)); - case InputType.Crouch: - return !(dequeuedInput.HasFlag(InputNetFlags.Crouch)) && (prevDequeuedInput.HasFlag(InputNetFlags.Crouch)); - case InputType.Select: - return dequeuedInput.HasFlag(InputNetFlags.Select); //TODO: clean up the way this input is registered - case InputType.Deselect: - return dequeuedInput.HasFlag(InputNetFlags.Deselect); - case InputType.Health: - return dequeuedInput.HasFlag(InputNetFlags.Health); - case InputType.Grab: - return dequeuedInput.HasFlag(InputNetFlags.Grab); - case InputType.Use: - return !(dequeuedInput.HasFlag(InputNetFlags.Use)) && (prevDequeuedInput.HasFlag(InputNetFlags.Use)); - case InputType.Shoot: - return !(dequeuedInput.HasFlag(InputNetFlags.Shoot)) && (prevDequeuedInput.HasFlag(InputNetFlags.Shoot)); - case InputType.Ragdoll: - return !(dequeuedInput.HasFlag(InputNetFlags.Ragdoll)) && (prevDequeuedInput.HasFlag(InputNetFlags.Ragdoll)); - default: - return false; - } - return characterConfigFiles; - } - } - - /// - /// Searches for a character config file from all currently selected content packages, - /// or from a specific package if the contentPackage parameter is given. - /// - public static string GetConfigFile(string speciesName, ContentPackage contentPackage = null) - { - string configFile = null; - if (contentPackage == null) - { - configFile = GameMain.Instance.GetFilesOfType(ContentType.Character) - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } - else - { - configFile = contentPackage.GetFilesOfType(ContentType.Character)? - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } -#endif - - if (configFile == null) - { - DebugConsole.ThrowError($"Couldn't find a config file for {speciesName} from the selected content packages!"); - DebugConsole.ThrowError($"(The config file must end with \"{speciesName}.xml\")"); - return string.Empty; - } - return configFile; - } - - private static IEnumerable characterConfigFiles; - private static IEnumerable CharacterConfigFiles - { -#if SERVER - if (GameMain.Server != null && IsRemotePlayer) - { - if (characterConfigFiles == null) - { - characterConfigFiles = GameMain.Instance.GetFilesOfType(ContentType.Character); - } - return characterConfigFiles; - } - } - - /// - /// Searches for a character config file from all currently selected content packages, - /// or from a specific package if the contentPackage parameter is given. - /// - public static string GetConfigFile(string speciesName, ContentPackage contentPackage = null) - { - string configFile = null; - if (contentPackage == null) - { - configFile = GameMain.Instance.GetFilesOfType(ContentType.Character) - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } - else - { - configFile = contentPackage.GetFilesOfType(ContentType.Character)? - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } - - if (configFile == null) - { - DebugConsole.ThrowError($"Couldn't find a config file for {speciesName} from the selected content packages!"); - DebugConsole.ThrowError($"(The config file must end with \"{speciesName}.xml\")"); - return string.Empty; - } - return configFile; - } - - private static IEnumerable characterConfigFiles; - private static IEnumerable CharacterConfigFiles - { -#if SERVER - if (GameMain.Server != null && IsRemotePlayer) - { - if (characterConfigFiles == null) - { - case InputType.Left: - return !(dequeuedInput.HasFlag(InputNetFlags.Left)) && (prevDequeuedInput.HasFlag(InputNetFlags.Left)); - case InputType.Right: - return !(dequeuedInput.HasFlag(InputNetFlags.Right)) && (prevDequeuedInput.HasFlag(InputNetFlags.Right)); - case InputType.Up: - return !(dequeuedInput.HasFlag(InputNetFlags.Up)) && (prevDequeuedInput.HasFlag(InputNetFlags.Up)); - case InputType.Down: - return !(dequeuedInput.HasFlag(InputNetFlags.Down)) && (prevDequeuedInput.HasFlag(InputNetFlags.Down)); - case InputType.Run: - return !(dequeuedInput.HasFlag(InputNetFlags.Run)) && (prevDequeuedInput.HasFlag(InputNetFlags.Run)); - case InputType.Crouch: - return !(dequeuedInput.HasFlag(InputNetFlags.Crouch)) && (prevDequeuedInput.HasFlag(InputNetFlags.Crouch)); - case InputType.Select: - return dequeuedInput.HasFlag(InputNetFlags.Select); //TODO: clean up the way this input is registered - case InputType.Deselect: - return dequeuedInput.HasFlag(InputNetFlags.Deselect); - case InputType.Health: - return dequeuedInput.HasFlag(InputNetFlags.Health); - case InputType.Grab: - return dequeuedInput.HasFlag(InputNetFlags.Grab); - case InputType.Use: - return !(dequeuedInput.HasFlag(InputNetFlags.Use)) && (prevDequeuedInput.HasFlag(InputNetFlags.Use)); - case InputType.Shoot: - return !(dequeuedInput.HasFlag(InputNetFlags.Shoot)) && (prevDequeuedInput.HasFlag(InputNetFlags.Shoot)); - case InputType.Ragdoll: - return !(dequeuedInput.HasFlag(InputNetFlags.Ragdoll)) && (prevDequeuedInput.HasFlag(InputNetFlags.Ragdoll)); - default: - return false; - } - return characterConfigFiles; - } - } - - public static string GetConfigFile(string speciesName, ContentPackage contentPackage = null) - { - string configFile = null; - if (contentPackage == null) - { - configFile = GameMain.Instance.GetFilesOfType(ContentType.Character, searchAllContentPackages: true) - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } - else - { - configFile = contentPackage.GetFilesOfType(ContentType.Character)? - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } -#endif - - if (configFile == null) - { - DebugConsole.ThrowError($"Couldn't find a config file for {speciesName} from the selected content packages!"); - DebugConsole.ThrowError($"(The config file must end with \"{speciesName}.xml\")"); - return string.Empty; - } - return configFile; - } - - public bool IsKeyHit(InputType inputType) - { -#if SERVER - if (GameMain.Server != null && IsRemotePlayer) - { - if (characterConfigFiles == null) - { - characterConfigFiles = GameMain.Instance.GetFilesOfType(ContentType.Character); - } - return characterConfigFiles; - } - } - - /// - /// Searches for a character config file from all currently selected content packages, - /// or from a specific package if the contentPackage parameter is given. - /// - public static string GetConfigFile(string speciesName, ContentPackage contentPackage = null) - { - string configFile = null; - if (contentPackage == null) - { - configFile = GameMain.Instance.GetFilesOfType(ContentType.Character) - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } - else - { - configFile = contentPackage.GetFilesOfType(ContentType.Character)? - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } - - if (configFile == null) - { - DebugConsole.ThrowError($"Couldn't find a config file for {speciesName} from the selected content packages!"); - DebugConsole.ThrowError($"(The config file must end with \"{speciesName}.xml\")"); - return string.Empty; - } - return configFile; - } - - private static IEnumerable characterConfigFiles; - private static IEnumerable CharacterConfigFiles - { -#if SERVER - if (GameMain.Server != null && IsRemotePlayer) - { - if (characterConfigFiles == null) - { - case InputType.Left: - return !(dequeuedInput.HasFlag(InputNetFlags.Left)) && (prevDequeuedInput.HasFlag(InputNetFlags.Left)); - case InputType.Right: - return !(dequeuedInput.HasFlag(InputNetFlags.Right)) && (prevDequeuedInput.HasFlag(InputNetFlags.Right)); - case InputType.Up: - return !(dequeuedInput.HasFlag(InputNetFlags.Up)) && (prevDequeuedInput.HasFlag(InputNetFlags.Up)); - case InputType.Down: - return !(dequeuedInput.HasFlag(InputNetFlags.Down)) && (prevDequeuedInput.HasFlag(InputNetFlags.Down)); - case InputType.Run: - return !(dequeuedInput.HasFlag(InputNetFlags.Run)) && (prevDequeuedInput.HasFlag(InputNetFlags.Run)); - case InputType.Crouch: - return !(dequeuedInput.HasFlag(InputNetFlags.Crouch)) && (prevDequeuedInput.HasFlag(InputNetFlags.Crouch)); - case InputType.Select: - return dequeuedInput.HasFlag(InputNetFlags.Select); //TODO: clean up the way this input is registered - case InputType.Deselect: - return dequeuedInput.HasFlag(InputNetFlags.Deselect); - case InputType.Health: - return dequeuedInput.HasFlag(InputNetFlags.Health); - case InputType.Grab: - return dequeuedInput.HasFlag(InputNetFlags.Grab); - case InputType.Use: - return !(dequeuedInput.HasFlag(InputNetFlags.Use)) && (prevDequeuedInput.HasFlag(InputNetFlags.Use)); - case InputType.Shoot: - return !(dequeuedInput.HasFlag(InputNetFlags.Shoot)) && (prevDequeuedInput.HasFlag(InputNetFlags.Shoot)); - case InputType.Ragdoll: - return !(dequeuedInput.HasFlag(InputNetFlags.Ragdoll)) && (prevDequeuedInput.HasFlag(InputNetFlags.Ragdoll)); - default: - return false; - } - return characterConfigFiles; - } -#endif - - /// - /// Searches for a character config file from all currently selected content packages, - /// or from a specific package if the contentPackage parameter is given. - /// - public static string GetConfigFile(string speciesName, ContentPackage contentPackage = null) - { - string configFile = null; - if (contentPackage == null) - { - configFile = GameMain.Instance.GetFilesOfType(ContentType.Character) - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } - else - { - configFile = contentPackage.GetFilesOfType(ContentType.Character)? - .FirstOrDefault(c => Path.GetFileName(c).ToLowerInvariant() == $"{speciesName.ToLowerInvariant()}.xml"); - } -#endif - - if (configFile == null) - { - DebugConsole.ThrowError($"Couldn't find a config file for {speciesName} from the selected content packages!"); - DebugConsole.ThrowError($"(The config file must end with \"{speciesName}.xml\")"); - return string.Empty; - } - return configFile; - } - - private static IEnumerable characterConfigFiles; - private static IEnumerable CharacterConfigFiles + public bool IsKeyDown(InputType inputType) { #if SERVER if (GameMain.Server != null && IsRemotePlayer) @@ -1719,7 +1072,7 @@ namespace Barotrauma ResetSpeedMultiplier(); // Reset, items will set the value before the next update - return speed; + return targetMovement; } /// @@ -2449,7 +1802,7 @@ namespace Barotrauma { SelectCharacter(focusedCharacter); } - else if (focusedCharacter != null && IsKeyHit(InputType.Health) && focusedCharacter.CharacterHealth.UseHealthWindow) + else if (focusedCharacter != null && IsKeyHit(InputType.Health) && focusedCharacter.CharacterHealth.UseHealthWindow && CanInteractWith(focusedCharacter, 160f, false)) { if (focusedCharacter == SelectedCharacter) { diff --git a/Barotrauma/BarotraumaShared/Source/DebugConsole.cs b/Barotrauma/BarotraumaShared/Source/DebugConsole.cs index 572c7ae1d..9b84bcb61 100644 --- a/Barotrauma/BarotraumaShared/Source/DebugConsole.cs +++ b/Barotrauma/BarotraumaShared/Source/DebugConsole.cs @@ -380,7 +380,7 @@ namespace Barotrauma }; })); - commands.Add(new Command("banid", "banid [id]: Kick and ban the player with the specified client ID from the server.", (string[] args) => + commands.Add(new Command("banid", "banid [id]: Kick and ban the player with the specified client ID from the server. You can see the IDs of the clients using the command \"clientlist\".", (string[] args) => { if (GameMain.NetworkMember == null || args.Length == 0) return; @@ -648,6 +648,20 @@ namespace Barotrauma },null)); #if DEBUG + commands.Add(new Command("teleportsub", "teleportsub [start/end]: Teleport the submarine to the start or end of the level. WARNING: does not take outposts into account, so often leads to physics glitches. Only use for debugging.", (string[] args) => + { + if (Submarine.MainSub == null || Level.Loaded == null) return; + + if (args.Length > 0 && args[0].ToLowerInvariant() == "start") + { + Submarine.MainSub.SetPosition(Level.Loaded.StartPosition); + } + else + { + Submarine.MainSub.SetPosition(Level.Loaded.EndPosition); + } + }, isCheat: true)); + commands.Add(new Command("waterphysicsparams", "waterphysicsparams [stiffness] [spread] [damping]: defaults 0.02, 0.05, 0.05", (string[] args) => { Vector2 explosionPos = GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition); diff --git a/Barotrauma/BarotraumaShared/Source/GameSettings.cs b/Barotrauma/BarotraumaShared/Source/GameSettings.cs index 2ef903590..c74164dd4 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSettings.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSettings.cs @@ -278,7 +278,6 @@ namespace Barotrauma public GameSettings() { - SelectedContentPackages = new HashSet(); ContentPackage.LoadAll(ContentPackage.Folder); CompletedTutorialNames = new List(); diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Door.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Door.cs index 43dc9e2b5..cf5b12bd3 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Door.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Door.cs @@ -22,7 +22,6 @@ namespace Barotrauma.Items.Components private float openState; private Sprite doorSprite, weldedSprite, brokenSprite; private bool scaleBrokenSprite, fadeBrokenSprite; - private bool createdNewGap; private bool autoOrientGap; private bool isStuck; @@ -89,12 +88,7 @@ namespace Barotrauma.Items.Components { if (linkedGap == null) { - linkedGap = e as Gap; - if (linkedGap != null) - { - linkedGap.PassAmbientLight = Window != Rectangle.Empty; - return linkedGap; - } + GetLinkedGap(); } return linkedGap; } @@ -116,16 +110,11 @@ namespace Barotrauma.Items.Components rect.X -= 5; rect.Width += 10; } - linkedGap = new Gap(rect, !IsHorizontal, Item.Submarine) { - Submarine = item.Submarine, - PassAmbientLight = Window != Rectangle.Empty, - Open = openState + Submarine = item.Submarine }; item.linkedTo.Add(linkedGap); - createdNewGap = true; - return linkedGap; } RefreshLinkedGap(); } @@ -386,7 +375,8 @@ namespace Barotrauma.Items.Components LinkedGap.AutoOrient(); } LinkedGap.Open = openState; - if (createdNewGap && autoOrientGap) linkedGap.AutoOrient(); + LinkedGap.PassAmbientLight = Window != Rectangle.Empty; + } public override void OnMapLoaded() { diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/MeleeWeapon.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/MeleeWeapon.cs index a76d1dc86..c9210a753 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/MeleeWeapon.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/MeleeWeapon.cs @@ -53,12 +53,6 @@ namespace Barotrauma.Items.Components set; } - /// - /// How useful the weapon is in combat? Used by AI to sort the used weapon. For the sake of clarity, use a value between 0 and 100 (not enforced). - /// - [Serialize(0f, false)] - public float CombatPriority { get; private set; } - public MeleeWeapon(Item item, XElement element) : base(item, element) { diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/RangedWeapon.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/RangedWeapon.cs index de0f31eb8..1a58bbbe4 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/RangedWeapon.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/Holdable/RangedWeapon.cs @@ -43,12 +43,6 @@ namespace Barotrauma.Items.Components set; } - /// - /// How useful the weapon is in combat? Used by AI to sort the used weapon. For the sake of clarity, use a value between 0 and 100 (not enforced). - /// - [Serialize(0f, false)] - public float CombatPriority { get; private set; } - public Vector2 TransformedBarrelPos { get @@ -170,6 +164,7 @@ namespace Barotrauma.Items.Components projectile.Item.SetTransform(projectilePos, rotation); projectile.Use(deltaTime); + if (projectile.Item.Removed) { return true; } projectile.User = character; projectile.Item.body.ApplyTorque(projectile.Item.body.Mass * degreeOfFailure * Rand.Range(-10.0f, 10.0f)); diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/ItemComponent.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/ItemComponent.cs index 39df86e4c..f24471693 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/ItemComponent.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/ItemComponent.cs @@ -545,7 +545,6 @@ namespace Barotrauma.Items.Components GameAnalyticsManager.AddErrorEventOnce("ItemComponent.DegreeOfSuccess:CharacterNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); return 0.0f; } - float average = skillSuccessSum / requiredSkills.Count; float skillSuccessSum = 0.0f; for (int i = 0; i < requiredSkills.Count; i++) diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/ItemContainer.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/ItemContainer.cs index d9abe0511..6266d4111 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/ItemContainer.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/ItemContainer.cs @@ -97,6 +97,7 @@ namespace Barotrauma.Items.Components RelatedItem ri = containableItems.Find(x => x.MatchesItem(containedItem)); if (ri != null) { + itemsWithStatusEffects.RemoveAll(i => i.First == containedItem); foreach (StatusEffect effect in ri.statusEffects) { itemsWithStatusEffects.Add(new Pair(containedItem, effect)); @@ -107,12 +108,12 @@ namespace Barotrauma.Items.Components IsActive = itemsWithStatusEffects.Count > 0 || containedItem.body != null; } - public void OnItemRemoved(Item item) + public void OnItemRemoved(Item containedItem) { - itemsWithStatusEffects.RemoveAll(i => i.First == item); + itemsWithStatusEffects.RemoveAll(i => i.First == containedItem); //deactivate if the inventory is empty - IsActive = itemsWithStatusEffects.Count > 0 || item.body != null; + IsActive = itemsWithStatusEffects.Count > 0 || containedItem.body != null; } public bool CanBeContained(Item item) diff --git a/Barotrauma/BarotraumaShared/Source/Items/Item.cs b/Barotrauma/BarotraumaShared/Source/Items/Item.cs index b2da749cd..a4e132a32 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Item.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Item.cs @@ -315,7 +315,7 @@ namespace Barotrauma get { return spriteColor; } } - public bool IsFullCondition => Condition >= MaxCondition; + public bool IsFullCondition => MathUtils.NearlyEqual(Condition, MaxCondition); public float MaxCondition => Prefab.Health; public float ConditionPercentage => MathUtils.Percentage(Condition, MaxCondition); @@ -334,6 +334,7 @@ namespace Barotrauma if (Indestructible) return; float prev = condition; + condition = MathHelper.Clamp(value, 0.0f, Prefab.Health); if (condition == 0.0f && prev > 0.0f) { @@ -1588,7 +1589,7 @@ namespace Barotrauma public void Use(float deltaTime, Character character = null, Limb targetLimb = null) { - if (RequireAimToUse && !character.IsKeyDown(InputType.Aim)) + if (RequireAimToUse && (character == null || !character.IsKeyDown(InputType.Aim))) { return; } diff --git a/Barotrauma/BarotraumaShared/Source/Items/RelatedItem.cs b/Barotrauma/BarotraumaShared/Source/Items/RelatedItem.cs index 5317f2df1..7c907cd87 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/RelatedItem.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/RelatedItem.cs @@ -17,7 +17,8 @@ namespace Barotrauma } public bool IsOptional { get; set; } - + public bool MatchOnEmpty { get; set; } + public bool IgnoreInEditor { get; set; } private string[] excludedIdentifiers; @@ -227,6 +228,7 @@ namespace Barotrauma ri.IsOptional = element.GetAttributeBool("optional", false); ri.IgnoreInEditor = element.GetAttributeBool("ignoreineditor", false); + ri.MatchOnEmpty = element.GetAttributeBool("matchonempty", false); return ri; } } diff --git a/Barotrauma/BarotraumaShared/Source/Map/Entity.cs b/Barotrauma/BarotraumaShared/Source/Map/Entity.cs index 54d21b2ee..60ff02152 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Entity.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Entity.cs @@ -9,6 +9,7 @@ namespace Barotrauma class Entity : ISpatialEntity { public const ushort NullEntityID = 0; + public const ushort EntitySpawnerID = ushort.MaxValue; private static Dictionary dictionary = new Dictionary(); public static List GetEntityList() @@ -43,12 +44,19 @@ namespace Barotrauma } set { + if (this is EntitySpawner) { return; } if (value == NullEntityID) { DebugConsole.ThrowError("Cannot set the ID of an entity to " + NullEntityID + "! The value is reserved for entity events referring to a non-existent (e.g. removed) entity.\n" + Environment.StackTrace); return; } + if (value == EntitySpawnerID) + { + DebugConsole.ThrowError("Cannot set the ID of an entity to " + EntitySpawnerID + + "! The value is reserved for EntitySpawner.\n" + Environment.StackTrace); + return; + } if (dictionary.TryGetValue(id, out Entity thisEntity) && thisEntity == this) { @@ -107,15 +115,17 @@ namespace Barotrauma this.Submarine = submarine; //give a unique ID - id = FindFreeID(submarine == null ? (ushort)1 : submarine.IdOffset); - + id = this is EntitySpawner ? + EntitySpawnerID : + FindFreeID(submarine == null ? (ushort)1 : submarine.IdOffset); + dictionary.Add(id, this); } public static ushort FindFreeID(ushort idOffset = 0) { - //ushort.MaxValue - 1 because 0 is a reserved value - if (dictionary.Count >= ushort.MaxValue - 1) + //ushort.MaxValue - 2 because 0 and ushort.MaxValue are reserved values + if (dictionary.Count >= ushort.MaxValue - 2) { throw new Exception("Maximum amount of entities (" + (ushort.MaxValue - 1) + ") reached!"); } diff --git a/Barotrauma/BarotraumaShared/Source/Map/ItemAssemblyPrefab.cs b/Barotrauma/BarotraumaShared/Source/Map/ItemAssemblyPrefab.cs index 736acb775..3e1024dfa 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/ItemAssemblyPrefab.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/ItemAssemblyPrefab.cs @@ -107,7 +107,7 @@ namespace Barotrauma if (Screen.Selected == GameMain.SubEditorScreen) { MapEntity.SelectedList.Clear(); - MapEntity.SelectedList.AddRange(entities); + entities.ForEach(e => MapEntity.AddSelection(e)); } #endif return entities; diff --git a/Barotrauma/BarotraumaShared/Source/Map/Levels/Level.cs b/Barotrauma/BarotraumaShared/Source/Map/Levels/Level.cs index 41b29c95a..6b469c300 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Levels/Level.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Levels/Level.cs @@ -1274,6 +1274,8 @@ namespace Barotrauma } } + DebugConsole.Log("Generating level resources..."); + for (int i = 0; i < generationParams.ItemCount; i++) { var selectedPrefab = ToolBox.SelectWeightedRandom( @@ -1286,6 +1288,7 @@ namespace Barotrauma var selectedEdge = selectedCell.Edges.GetRandom(e => e.IsSolid && !e.OutsideLevel, Rand.RandSync.Server); if (selectedEdge == null) continue; + float edgePos = Rand.Range(0.0f, 1.0f, Rand.RandSync.Server); Vector2 selectedPos = Vector2.Lerp(selectedEdge.Point1, selectedEdge.Point2, edgePos); Vector2 edgeNormal = selectedEdge.GetNormal(selectedCell); @@ -1306,6 +1309,8 @@ namespace Barotrauma #endif } } + + DebugConsole.Log("Level resources generated"); } public Vector2 GetRandomItemPos(PositionType spawnPosType, float randomSpread, float minDistFromSubs, float offsetFromWall = 10.0f) diff --git a/Barotrauma/BarotraumaShared/Source/Map/Levels/Ruins/RuinGenerator.cs b/Barotrauma/BarotraumaShared/Source/Map/Levels/Ruins/RuinGenerator.cs index 86a73d3c2..70813cd69 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Levels/Ruins/RuinGenerator.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Levels/Ruins/RuinGenerator.cs @@ -1022,12 +1022,12 @@ namespace Barotrauma.RuinGeneration { targetEntity = ruinEntities.GetRandom(e => e.Room == targetRoom && - e.Entity.prefab?.Identifier == connection.TargetEntityIdentifier)?.Entity; + e.Entity.prefab?.Identifier == connection.TargetEntityIdentifier, Rand.RandSync.Server)?.Entity; } } else { - targetEntity = ruinEntities.GetRandom(e => e.Entity.prefab?.Identifier == connection.TargetEntityIdentifier)?.Entity; + targetEntity = ruinEntities.GetRandom(e => e.Entity.prefab?.Identifier == connection.TargetEntityIdentifier, Rand.RandSync.Server)?.Entity; } if (targetEntity == null) continue; diff --git a/Barotrauma/BarotraumaShared/Source/Map/Structure.cs b/Barotrauma/BarotraumaShared/Source/Map/Structure.cs index 099bf9813..217e60041 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Structure.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Structure.cs @@ -388,20 +388,6 @@ namespace Barotrauma return Name; } - partial void InitProjSpecific(); - - public override string ToString() - { - return Name; - } - - partial void InitProjSpecific(); - - public override string ToString() - { - return Name; - } - public override MapEntity Clone() { var clone = new Structure(rect, Prefab, Submarine) diff --git a/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs b/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs index 1a31b77c7..eb3714650 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs @@ -1404,7 +1404,6 @@ namespace Barotrauma } - ID = (ushort)(ushort.MaxValue - 1 - Submarine.loaded.IndexOf(this)); } diff --git a/Barotrauma/BarotraumaShared/Source/Networking/SteamManager.cs b/Barotrauma/BarotraumaShared/Source/Networking/SteamManager.cs index f72c8354b..937048f9c 100644 --- a/Barotrauma/BarotraumaShared/Source/Networking/SteamManager.cs +++ b/Barotrauma/BarotraumaShared/Source/Networking/SteamManager.cs @@ -21,7 +21,11 @@ namespace Barotrauma.Steam { "monster", 8 }, { "art", 8 }, { "mission", 8 }, - { "environment", 5 } + { "event set", 8 }, + { "total conversion", 5 }, + { "environment", 5 }, + { "item assembly", 5 }, + { "language", 5 } }; private List popularTags = new List(); diff --git a/Barotrauma/BarotraumaShared/Source/Physics/PhysicsBody.cs b/Barotrauma/BarotraumaShared/Source/Physics/PhysicsBody.cs index 17d762f18..5484e3ffe 100644 --- a/Barotrauma/BarotraumaShared/Source/Physics/PhysicsBody.cs +++ b/Barotrauma/BarotraumaShared/Source/Physics/PhysicsBody.cs @@ -375,7 +375,7 @@ namespace Barotrauma //Enum.TryParse(element.GetAttributeString("bodytype", "Dynamic"), out BodyType bodyType); body.BodyType = BodyType.Dynamic; body.CollisionCategories = Physics.CollisionItem; - body.CollidesWith = Physics.CollisionWall | Physics.CollisionLevel; + body.CollidesWith = Physics.CollisionWall | Physics.CollisionLevel | Physics.CollisionPlatform; body.Friction = element.GetAttributeFloat("friction", 0.3f); body.Restitution = element.GetAttributeFloat("restitution", 0.05f); body.UserData = this; diff --git a/Barotrauma/BarotraumaShared/Source/StatusEffects/StatusEffect.cs b/Barotrauma/BarotraumaShared/Source/StatusEffects/StatusEffect.cs index dfe562c88..550d7c11f 100644 --- a/Barotrauma/BarotraumaShared/Source/StatusEffects/StatusEffect.cs +++ b/Barotrauma/BarotraumaShared/Source/StatusEffects/StatusEffect.cs @@ -424,6 +424,7 @@ namespace Barotrauma public virtual bool HasRequiredConditions(List targets) { if (!propertyConditionals.Any()) return true; + if (requiredItems.All(ri => ri.MatchOnEmpty) && targets.Count == 0) return true; switch (conditionalComparison) { case PropertyConditional.Comparison.Or: @@ -640,14 +641,14 @@ namespace Barotrauma character.LastDamageSource = entity; foreach (Limb limb in character.AnimController.Limbs) { - limb.character.DamageLimb(entity.WorldPosition, limb, new List() { multipliedAffliction }, stun: 0.0f, playSound: false, attackImpulse: 0.0f); + limb.character.DamageLimb(entity.WorldPosition, limb, new List() { multipliedAffliction }, stun: 0.0f, playSound: false, attackImpulse: 0.0f, attacker: affliction.Source); //only apply non-limb-specific afflictions to the first limb if (!affliction.Prefab.LimbSpecific) { break; } } } else if (target is Limb limb) { - limb.character.DamageLimb(entity.WorldPosition, limb, new List() { multipliedAffliction }, stun: 0.0f, playSound: false, attackImpulse: 0.0f); + limb.character.DamageLimb(entity.WorldPosition, limb, new List() { multipliedAffliction }, stun: 0.0f, playSound: false, attackImpulse: 0.0f, attacker: affliction.Source); } } diff --git a/Barotrauma/BarotraumaShared/Source/SteamAchievementManager.cs b/Barotrauma/BarotraumaShared/Source/SteamAchievementManager.cs index cd5989c75..bdc2a394c 100644 --- a/Barotrauma/BarotraumaShared/Source/SteamAchievementManager.cs +++ b/Barotrauma/BarotraumaShared/Source/SteamAchievementManager.cs @@ -311,11 +311,9 @@ namespace Barotrauma { if (gameSession.Mission is CombatMission combatMission) { -#if CLIENT //all characters that are alive and in the winning team get an achievement UnlockAchievement(gameSession.Mission.Prefab.AchievementIdentifier + (int)GameMain.GameSession.WinningTeam, true, c => c != null && !c.IsDead && !c.IsUnconscious && combatMission.IsInWinningTeam(c)); -#endif } else if (gameSession.Mission.Completed) { diff --git a/Barotrauma/BarotraumaShared/Source/Utils/SaveUtil.cs b/Barotrauma/BarotraumaShared/Source/Utils/SaveUtil.cs index acbe640cb..23c9465fa 100644 --- a/Barotrauma/BarotraumaShared/Source/Utils/SaveUtil.cs +++ b/Barotrauma/BarotraumaShared/Source/Utils/SaveUtil.cs @@ -378,8 +378,6 @@ namespace Barotrauma Thread.Sleep(250); } } - - return true; } @@ -470,7 +468,20 @@ namespace Barotrauma foreach (DirectoryInfo di in dir.GetDirectories()) { ClearFolder(di.FullName, ignoredFileNames); - di.Delete(); + int maxRetries = 4; + for (int i = 0; i <= maxRetries; i++) + { + try + { + di.Delete(); + break; + } + catch (IOException) + { + if (i >= maxRetries) { throw; } + Thread.Sleep(250); + } + } } } } diff --git a/Barotrauma/BarotraumaShared/Submarines/Berilia.sub b/Barotrauma/BarotraumaShared/Submarines/Berilia.sub index b8903bf84..7d10e0914 100644 Binary files a/Barotrauma/BarotraumaShared/Submarines/Berilia.sub and b/Barotrauma/BarotraumaShared/Submarines/Berilia.sub differ diff --git a/Barotrauma_Solution.sln b/Barotrauma_Solution.sln index 88ed780fe..bea6b8805 100644 --- a/Barotrauma_Solution.sln +++ b/Barotrauma_Solution.sln @@ -338,6 +338,7 @@ Global {85232B20-074D-4723-B0C6-91495391E448}.ReleaseWindows|x86.ActiveCfg = ReleaseWindows|x86 {85232B20-074D-4723-B0C6-91495391E448}.ReleaseWindows|x86.Build.0 = ReleaseWindows|x86 {85232B20-074D-4723-B0C6-91495391E448}.ReleaseMac|Any CPU.Build.0 = ReleaseMac|x64 + {85232B20-074D-4723-B0C6-91495391E448}.DebugMac|Any CPU.Build.0 = DebugMac|x64 {A4610E4C-DD34-428B-BABB-779CA0B5993A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A4610E4C-DD34-428B-BABB-779CA0B5993A}.Debug|Any CPU.Build.0 = Debug|Any CPU {A4610E4C-DD34-428B-BABB-779CA0B5993A}.Debug|x64.ActiveCfg = Debug|Any CPU diff --git a/Libraries/Facepunch.Steamworks/Interfaces/Workshop.Editor.cs b/Libraries/Facepunch.Steamworks/Interfaces/Workshop.Editor.cs index 36bcb330d..771768dbd 100644 --- a/Libraries/Facepunch.Steamworks/Interfaces/Workshop.Editor.cs +++ b/Libraries/Facepunch.Steamworks/Interfaces/Workshop.Editor.cs @@ -24,6 +24,7 @@ namespace Facepunch.Steamworks public bool Publishing { get; internal set; } public ItemType? Type { get; set; } public string Error { get; internal set; } = null; + public SteamNative.Result? ErrorCode { get; internal set; } = null; public string ChangeNote { get; set; } = ""; public uint WorkshopUploadAppId { get; set; } public string MetaData { get; set; } = null; @@ -99,6 +100,7 @@ namespace Facepunch.Steamworks Publishing = true; Error = null; + ErrorCode = null; if ( Id == 0 ) { @@ -129,12 +131,14 @@ namespace Facepunch.Steamworks if ( obj.Result == SteamNative.Result.OK && !Failed ) { Error = null; + ErrorCode = null; Id = obj.PublishedFileId; PublishChanges(); return; } Error = $"Error creating new file: {obj.Result} ({obj.PublishedFileId})"; + ErrorCode = obj.Result; Publishing = false; OnChangesSubmitted?.Invoke( (Result) obj.Result ); @@ -221,6 +225,7 @@ namespace Facepunch.Steamworks NeedToAgreeToWorkshopLegal = obj.UserNeedsToAcceptWorkshopLegalAgreement; Publishing = false; + ErrorCode = obj.Result; Error = obj.Result != SteamNative.Result.OK ? $"Error publishing changes: {obj.Result} ({NeedToAgreeToWorkshopLegal})" : null; diff --git a/Libraries/Facepunch.Steamworks/SteamNative/SteamNative.Enums.cs b/Libraries/Facepunch.Steamworks/SteamNative/SteamNative.Enums.cs index f57eb4066..5729eca44 100644 --- a/Libraries/Facepunch.Steamworks/SteamNative/SteamNative.Enums.cs +++ b/Libraries/Facepunch.Steamworks/SteamNative/SteamNative.Enums.cs @@ -20,7 +20,7 @@ namespace SteamNative // // EResult // - internal enum Result : int + public enum Result : int { OK = 1, Fail = 2,