Unstable 0.17.6.0

This commit is contained in:
Markus Isberg
2022-04-04 16:46:08 +09:00
parent 44ded0225a
commit 95764d1fa8
78 changed files with 1265 additions and 703 deletions
@@ -5,6 +5,7 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using Barotrauma.Extensions;
using Barotrauma.Steam;
using Microsoft.Xna.Framework;
@@ -26,9 +27,9 @@ namespace Barotrauma.Transition
{
TaskPool.Add("UgcTransition.Prepare", DetermineItemsToTransition(), t =>
{
if (!t.TryGetResult(out (OldSubs, OldMods) pair)) { return; }
var (subs, mods) = pair;
if (!subs.FilePaths.Any() && !mods.Mods.Any()) { return; }
if (!t.TryGetResult(out (OldSubs, OldItemAssemblies, OldMods) result)) { return; }
var (subs, itemAssemblies, mods) = result;
if (!subs.FilePaths.Any() && !itemAssemblies.FilePaths.Any() && !mods.Mods.Any()) { return; }
var msgBox = new GUIMessageBox(TextManager.Get("Ugc.TransferTitle"), "", relativeSize: (0.5f, 0.8f),
buttons: new LocalizedString[] { TextManager.Get("Ugc.TransferButton") });
@@ -63,19 +64,45 @@ namespace Barotrauma.Transition
};
pathTickboxMap.Add(dir, tickbox);
}
addHeader(TextManager.Get("WorkshopLabelSubmarines"));
foreach (var sub in subs.FilePaths)
bool firstHeader = true;
void addSpacer()
{
var subName = Path.GetFileNameWithoutExtension(sub);
addTickbox(sub, subName, ticked: !ContentPackageManager.LocalPackages.Any(p => p.NameMatches(subName)));
if (firstHeader) { firstHeader = false; return; }
addHeader("");
}
addHeader("");
addHeader(TextManager.Get("SubscribedMods"));
foreach (var mod in mods.Mods)
if (subs.FilePaths.Any())
{
addTickbox(mod.Dir, mod.Name, ticked: !ContentPackageManager.LocalPackages.Any(p => p.SteamWorkshopId != 0 && p.SteamWorkshopId == mod.Item?.Id));
addSpacer();
addHeader(TextManager.Get("WorkshopLabelSubmarines"));
foreach (var sub in subs.FilePaths)
{
var subName = Path.GetFileNameWithoutExtension(sub);
addTickbox(sub, subName, ticked: !ContentPackageManager.LocalPackages.Any(p => p.NameMatches(subName)));
}
}
if (itemAssemblies.FilePaths.Any())
{
addSpacer();
addHeader(TextManager.Get("ItemAssemblies"));
foreach (var itemAssembly in itemAssemblies.FilePaths)
{
var assemblyName = Path.GetFileNameWithoutExtension(itemAssembly);
addTickbox(itemAssembly, assemblyName, ticked: !ContentPackageManager.LocalPackages.Any(p => p.NameMatches(assemblyName)));
}
}
if (mods.Mods.Any())
{
addSpacer();
addHeader(TextManager.Get("SubscribedMods"));
foreach (var mod in mods.Mods)
{
addTickbox(mod.Dir, mod.Name, ticked: !ContentPackageManager.LocalPackages.Any(p => p.SteamWorkshopId != 0 && p.SteamWorkshopId == mod.Item?.Id));
}
}
GUIMessageBox? subMsgBox = null;
@@ -119,6 +146,16 @@ namespace Barotrauma.Transition
}
}
private struct OldItemAssemblies
{
public readonly IReadOnlyList<string> FilePaths;
public OldItemAssemblies(IReadOnlyList<string> filePaths)
{
FilePaths = filePaths;
}
}
private struct OldMods
{
public readonly IReadOnlyList<(string Dir, string Name, Steamworks.Ugc.Item? Item, DateTime InstallTime)> Mods;
@@ -131,15 +168,24 @@ namespace Barotrauma.Transition
private const string oldSubsPath = "Submarines";
private const string oldModsPath = "Mods";
private const string oldItemAssembliesPath = "ItemAssemblies";
private static async Task<(OldSubs Subs, OldMods Mods)> DetermineItemsToTransition()
private static async Task<(OldSubs Subs, OldItemAssemblies ItemAssemblies, OldMods Mods)> DetermineItemsToTransition()
{
string[] subs = Array.Empty<string>();
string[] itemAssemblies = Array.Empty<string>();
List<(string Dir, string Name, Steamworks.Ugc.Item? Item, DateTime InstallTime)> mods
= new List<(string Dir, string Name, Steamworks.Ugc.Item? Item, DateTime InstallTime)>();
if (FolderShouldBeTransitioned(oldModsPath))
{
subs = Directory.GetFiles(oldSubsPath, "*.sub", SearchOption.TopDirectoryOnly);
string[] getFiles(string path, string pattern)
=> Directory.Exists(path)
? Directory.GetFiles(path, pattern, SearchOption.TopDirectoryOnly)
: Array.Empty<string>();
subs = getFiles(oldSubsPath, "*.sub");
itemAssemblies = getFiles(oldItemAssembliesPath, "*.xml");
string[] allOldMods = Directory.GetDirectories(oldModsPath, "*", SearchOption.TopDirectoryOnly);
var publishedItems = await SteamManager.Workshop.GetPublishedItems();
@@ -160,9 +206,9 @@ namespace Barotrauma.Transition
}
}
while (!(Screen.Selected is MainMenuScreen)) { await Task.Delay(500); }
while (!(Screen.Selected is MainMenuScreen)) { await Task.Delay(50); }
return (new OldSubs(subs), new OldMods(mods));
return (new OldSubs(subs), new OldItemAssemblies(itemAssemblies), new OldMods(mods));
}
private static bool FolderShouldBeTransitioned(string folderName)
@@ -173,45 +219,71 @@ namespace Barotrauma.Transition
private static async Task TransferMods(Dictionary<string, GUITickBox> pathTickboxMap)
{
//WriteReadme(oldSubsPath); //can't do this because the submarine discovery code is borked
//WriteReadme(oldSubsPath); //can't do this because the old submarine discovery code is borked
WriteReadme(oldModsPath);
foreach (var (path, tickbox) in pathTickboxMap)
{
if (!tickbox.Selected) { continue; }
string dirName = Path.GetFileNameWithoutExtension(path);
string destPath = Path.Combine(ContentPackage.LocalModsDir, dirName);
//find unique path to save in
for (int i = 0;;i++)
{
if (!Directory.Exists(destPath)) { break; }
destPath = Path.Combine(ContentPackage.LocalModsDir, $"{dirName}.{i}");
}
if (path.StartsWith(oldSubsPath, StringComparison.OrdinalIgnoreCase))
{
//copying a sub: manually create filelist.xml
ModProject modProject = new ModProject
{
Name = dirName,
ModVersion = ContentPackage.DefaultModVersion
};
modProject.AddFile(ModProject.File.FromPath<SubmarineFile>(Path.Combine(ContentPath.ModDirStr, $"{dirName}.sub")));
await Task.WhenAll(pathTickboxMap.Select(TransferMod));
}
Directory.CreateDirectory(destPath);
File.Copy(path, Path.Combine(destPath, $"{dirName}.sub"));
modProject.Save(Path.Combine(destPath, ContentPackage.FileListFileName));
await Task.Yield();
private static Task TransferMod(KeyValuePair<string, GUITickBox> kvp)
=> TransferMod(kvp.Key, kvp.Value);
private static async Task TransferMod(string path, GUITickBox tickbox)
{
if (!tickbox.Selected) { return; }
string dirName = Path.GetFileNameWithoutExtension(path);
string destPath = Path.Combine(ContentPackage.LocalModsDir, dirName);
//find unique path to save in
for (int i = 0;;i++)
{
if (!Directory.Exists(destPath)) { break; }
destPath = Path.Combine(ContentPackage.LocalModsDir, $"{dirName}.{i}");
}
bool isSub = path.StartsWith(oldSubsPath, StringComparison.OrdinalIgnoreCase);
bool isItemAssembly = path.StartsWith(oldItemAssembliesPath, StringComparison.OrdinalIgnoreCase);
if (isSub || isItemAssembly)
{
//copying a sub or item assembly: manually create filelist.xml
ModProject modProject = new ModProject
{
Name = dirName,
ModVersion = ContentPackage.DefaultModVersion
};
Type fileType;
if (isSub)
{
fileType = typeof(SubmarineFile);
XDocument? doc = SubmarineInfo.OpenFile(path, out _);
if (doc?.Root != null)
{
SubmarineType subType = doc.Root.GetAttributeEnum("type", SubmarineType.Player);
fileType = SubEditorScreen.DetermineSubFileType(subType);
}
}
else
{
//copying a mod: we have a neat method for that!
await SteamManager.Workshop.CopyDirectory(path, Path.GetFileName(path), path, destPath);
fileType = typeof(ItemAssemblyFile);
}
modProject.AddFile(ModProject.File.FromPath(
Path.Combine(ContentPath.ModDirStr, $"{dirName}.{(isSub ? "sub" : "xml")}"),
fileType));
Directory.CreateDirectory(destPath);
File.Copy(path, Path.Combine(destPath, $"{dirName}.{(isSub ? "sub" : "xml")}"));
modProject.Save(Path.Combine(destPath, ContentPackage.FileListFileName));
await Task.Yield();
}
else
{
//copying a mod: we have a neat method for that!
await SteamManager.Workshop.CopyDirectory(path, Path.GetFileName(path), path, destPath);
}
}
private static void WriteReadme(string folderName)
{
if (!Directory.Exists(folderName)) { return; }
@@ -3310,11 +3310,7 @@ namespace Barotrauma
}
depth += " ";
if (newPrice > 0)
{
newPrices.TryAdd(materialPrefab, newPrice);
}
newPrices.TryAdd(materialPrefab, newPrice);
int componentCost = 0;
int newComponentCost = 0;
@@ -25,12 +25,14 @@ namespace Barotrauma
get { return _toggleOpen; }
set
{
_toggleOpen = value;
if (value) hideableElements.Visible = true;
_toggleOpen = PreferChatBoxOpen = value;
if (value) { hideableElements.Visible = true; }
}
}
private float openState;
public static bool PreferChatBoxOpen = true;
public bool CloseAfterMessageSent;
private float prevUIScale;
@@ -99,6 +101,7 @@ namespace Barotrauma
var channelSettingsContent = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.9f), channelSettingsFrame.RectTransform, Anchor.Center), isHorizontal: true, childAnchor: Anchor.CenterLeft)
{
Stretch = true,
CanBeFocused = true,
RelativeSpacing = 0.01f
};
@@ -119,7 +122,7 @@ namespace Barotrauma
Color = new Color(51, 59, 46),
SpriteEffects = Microsoft.Xna.Framework.Graphics.SpriteEffects.FlipHorizontally
};
arrowIcon.HoverColor = arrowIcon.PressedColor = arrowIcon.PressedColor = arrowIcon.Color;
arrowIcon.HoverColor = arrowIcon.PressedColor = arrowIcon.SelectedColor = arrowIcon.Color;
channelText = new GUITextBox(new RectTransform(new Vector2(0.25f, 0.8f), channelSettingsContent.RectTransform), style: "DigitalFrameLight", textAlignment: Alignment.Center, font: GUIStyle.DigitalFont)
{
@@ -265,7 +268,7 @@ namespace Barotrauma
};
showNewMessagesButton.Visible = false;
ToggleOpen = GameSettings.CurrentConfig.ChatOpen;
ToggleOpen = PreferChatBoxOpen = GameSettings.CurrentConfig.ChatOpen;
}
public bool TypingChatMessage(GUITextBox textBox, string text)
@@ -415,9 +415,9 @@ namespace Barotrauma
if (dir.EndsWith("/")) { dir = dir.Substring(0, dir.Length - 1); }
int index = dir.LastIndexOf("/");
if (index < 0) { return false; }
CurrentDirectory = CurrentDirectory.Substring(0, index+1);
CurrentDirectory = CurrentDirectory.Substring(0, index + 1);
return false;
return true;
}
public static void AddToGUIUpdateList()
@@ -343,7 +343,7 @@ namespace Barotrauma
foreach (string childKey in GameMain.PerformanceCounter.GetSavedPartialIdentifiers(key))
{
elapsedMillisecs = GameMain.PerformanceCounter.GetPartialAverageElapsedMillisecs(key, childKey);
DrawString(spriteBatch, new Vector2(315, y),
DrawString(spriteBatch, new Vector2(x + 15, y),
childKey + ": " + elapsedMillisecs.ToString("0.00"),
Color.Lerp(Color.LightGreen, GUIStyle.Red, elapsedMillisecs / 10.0f), Color.Black * 0.5f, 0, GUIStyle.SmallFont);
y += 15;
@@ -1422,8 +1422,9 @@ namespace Barotrauma
public static void DrawString(SpriteBatch sb, Vector2 pos, string text, Color color, Color? backgroundColor = null, int backgroundPadding = 0, GUIFont font = null, ForceUpperCase forceUpperCase = ForceUpperCase.Inherit)
{
if (font == null) font = GUIStyle.Font;
if (backgroundColor != null)
if (color.A == 0) { return; }
if (font == null) { font = GUIStyle.Font; }
if (backgroundColor != null && backgroundColor.Value.A > 0)
{
Vector2 textSize = font.MeasureString(text);
DrawRectangle(sb, pos - Vector2.One * backgroundPadding, textSize + Vector2.One * 2.0f * backgroundPadding, (Color)backgroundColor, true);
@@ -95,14 +95,21 @@ namespace Barotrauma
// Construct the GUI elements
//----------------------------------------------------------------------------------
GUILayoutGroup background = new GUILayoutGroup(new RectTransform(Vector2.One, RectTransform, Anchor.Center));
GUILayoutGroup background = new GUILayoutGroup(new RectTransform(Vector2.One, RectTransform, Anchor.Center))
{
Stretch = true
};
Point listSize = estimatedSize;
if (hasHeader)
{
HeaderLabel = new GUITextBlock(new RectTransform(new Vector2(1f, 0.2f), background.RectTransform), header, font: headerFont) { Padding = headerPadding };
Point sz = Point.Zero;
InflateSize(ref sz, header, headerFont);
listSize.Y -= sz.Y;
HeaderLabel = new GUITextBlock(new RectTransform(sz, background.RectTransform), header, font: headerFont) { Padding = headerPadding };
}
GUIListBox optionList = new GUIListBox(new RectTransform(new Vector2(1f, hasHeader ? 0.8f : 1f), background.RectTransform), style: null)
GUIListBox optionList = new GUIListBox(new RectTransform(listSize, background.RectTransform), style: null)
{
AutoHideScrollBar = false,
ScrollBarVisible = false,
@@ -316,6 +316,7 @@ namespace Barotrauma
}
if (Text == text) { return false; }
textBlock.Text = text;
ClearSelection();
if (Text == null) textBlock.Text = "";
if (Text != "" && !Wrap)
{
@@ -808,10 +809,10 @@ namespace Barotrauma
{
if (selectedText.Length == 0) { return; }
selectionStartIndex = Math.Max(0, Math.Min(selectionEndIndex, Math.Min(selectionStartIndex, Text.Length - 1)));
int selectionLength = Math.Min(Text.Length - selectionStartIndex, selectedText.Length);
SetText(Text.Remove(selectionStartIndex, selectionLength));
CaretIndex = Math.Min(Text.Length, selectionStartIndex);
int targetCaretIndex = Math.Max(0, Math.Min(selectionEndIndex, Math.Min(selectionStartIndex, Text.Length - 1)));
int selectionLength = Math.Min(Text.Length - targetCaretIndex, selectedText.Length);
SetText(Text.Remove(targetCaretIndex, selectionLength));
CaretIndex = targetCaretIndex;
ClearSelection();
OnTextChanged?.Invoke(this, Text);
@@ -570,7 +570,7 @@ namespace Barotrauma
AutoHideScrollBar = false,
Visible = false
};
storeDailySpecialsGroup = CreateDealsGroup(storeBuyList);
storeDailySpecialsGroup = CreateDealsGroup(storeBuyList, CurrentLocation?.DailySpecialsCount ?? 1);
tabLists.Add(StoreTab.Buy, storeBuyList);
storeSellList = new GUIListBox(new RectTransform(Vector2.One, storeItemListContainer.RectTransform))
@@ -578,7 +578,7 @@ namespace Barotrauma
AutoHideScrollBar = false,
Visible = false
};
storeRequestedGoodGroup = CreateDealsGroup(storeSellList);
storeRequestedGoodGroup = CreateDealsGroup(storeSellList, CurrentLocation?.RequestedGoodsCount ?? 1);
tabLists.Add(StoreTab.Sell, storeSellList);
storeSellFromSubList = new GUIListBox(new RectTransform(Vector2.One, storeItemListContainer.RectTransform))
@@ -586,7 +586,7 @@ namespace Barotrauma
AutoHideScrollBar = false,
Visible = false
};
storeRequestedSubGoodGroup = CreateDealsGroup(storeSellFromSubList);
storeRequestedSubGoodGroup = CreateDealsGroup(storeSellFromSubList, CurrentLocation?.RequestedGoodsCount ?? 1);
tabLists.Add(StoreTab.SellSub, storeSellFromSubList);
// Shopping Crate ------------------------------------------------------------------------------------------------------------------------------------------
@@ -713,8 +713,10 @@ namespace Barotrauma
private LocalizedString GetPlayerBalanceText() => TextManager.FormatCurrency(PlayerWallet.Balance);
private GUILayoutGroup CreateDealsGroup(GUIListBox parentList, int elementCount = 4)
private GUILayoutGroup CreateDealsGroup(GUIListBox parentList, int elementCount)
{
// Add 1 for the header
elementCount++;
var elementHeight = (int)(GUI.yScale * 80);
var frame = new GUIFrame(new RectTransform(new Point(parentList.Content.Rect.Width, elementCount * elementHeight + 3), parent: parentList.Content.RectTransform), style: null)
{
@@ -852,24 +854,20 @@ namespace Barotrauma
FilterStoreItems(category, searchBox.Text);
}
int prevDailySpecialCount;
int prevDailySpecialCount, prevRequestedGoodsCount, prevSubRequestedGoodsCount;
private void RefreshStoreBuyList()
{
float prevBuyListScroll = storeBuyList.BarScroll;
float prevShoppingCrateScroll = shoppingCrateBuyList.BarScroll;
bool hasPermissions = HasBuyPermissions;
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
int dailySpecialCount = ActiveStore.DailySpecials.Count;
if ((storeDailySpecialsGroup != null) != ActiveStore.DailySpecials.Any() || dailySpecialCount != prevDailySpecialCount)
{
if (storeDailySpecialsGroup == null || dailySpecialCount != prevDailySpecialCount)
{
storeBuyList.RemoveChild(storeDailySpecialsGroup?.Parent);
storeDailySpecialsGroup = CreateDealsGroup(storeBuyList, 1 + dailySpecialCount);
storeDailySpecialsGroup = CreateDealsGroup(storeBuyList, dailySpecialCount);
storeDailySpecialsGroup.Parent.SetAsFirstChild();
}
else
@@ -881,6 +879,8 @@ namespace Barotrauma
prevDailySpecialCount = dailySpecialCount;
}
bool hasPermissions = HasTabPermissions(StoreTab.Sell);
var existingItemFrames = new HashSet<GUIComponent>();
foreach (PurchasedItem item in ActiveStore.Stock)
{
CreateOrUpdateItemFrame(item.ItemPrefab, item.Quantity);
@@ -942,29 +942,30 @@ namespace Barotrauma
{
float prevSellListScroll = storeSellList.BarScroll;
float prevShoppingCrateScroll = shoppingCrateSellList.BarScroll;
bool hasPermissions = HasTabPermissions(StoreTab.Sell);
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
if ((storeRequestedGoodGroup != null) != ActiveStore.RequestedGoods.Any())
int requestedGoodsCount = ActiveStore.RequestedGoods.Count;
if ((storeRequestedGoodGroup != null) != ActiveStore.RequestedGoods.Any() || requestedGoodsCount != prevRequestedGoodsCount)
{
if (storeRequestedGoodGroup == null)
storeSellList.RemoveChild(storeRequestedGoodGroup?.Parent);
if (storeRequestedGoodGroup == null || requestedGoodsCount != prevRequestedGoodsCount)
{
storeRequestedGoodGroup = CreateDealsGroup(storeSellList);
storeRequestedGoodGroup = CreateDealsGroup(storeSellList, requestedGoodsCount);
storeRequestedGoodGroup.Parent.SetAsFirstChild();
}
else
{
storeSellList.RemoveChild(storeRequestedGoodGroup.Parent);
storeRequestedGoodGroup = null;
}
storeSellList.RecalculateChildren();
prevRequestedGoodsCount = requestedGoodsCount;
}
bool hasPermissions = HasTabPermissions(StoreTab.Sell);
var existingItemFrames = new HashSet<GUIComponent>();
foreach (PurchasedItem item in itemsToSell)
{
CreateOrUpdateItemFrame(item.ItemPrefab, item.Quantity);
}
foreach (var requestedGood in ActiveStore.RequestedGoods)
{
if (itemsToSell.Any(pi => pi.ItemPrefab == requestedGood)) { continue; }
@@ -1009,6 +1010,7 @@ namespace Barotrauma
removedItemFrames.AddRange(storeRequestedGoodGroup.Children.Where(c => c.UserData is PurchasedItem).Except(existingItemFrames).ToList());
}
removedItemFrames.ForEach(f => f.RectTransform.Parent = null);
if (activeTab == StoreTab.Sell) { FilterStoreItems(); }
SortItems(StoreTab.Sell);
@@ -1020,29 +1022,30 @@ namespace Barotrauma
{
float prevSellListScroll = storeSellFromSubList.BarScroll;
float prevShoppingCrateScroll = shoppingCrateSellFromSubList.BarScroll;
bool hasPermissions = HasSellSubPermissions;
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
if ((storeRequestedSubGoodGroup != null) != ActiveStore.RequestedGoods.Any())
int requestedGoodsCount = ActiveStore.RequestedGoods.Count;
if ((storeRequestedSubGoodGroup != null) != ActiveStore.RequestedGoods.Any() || requestedGoodsCount != prevSubRequestedGoodsCount)
{
if (storeRequestedSubGoodGroup == null)
storeSellFromSubList.RemoveChild(storeRequestedSubGoodGroup?.Parent);
if (storeRequestedSubGoodGroup == null || requestedGoodsCount != prevSubRequestedGoodsCount)
{
storeRequestedSubGoodGroup = CreateDealsGroup(storeSellList);
storeRequestedSubGoodGroup = CreateDealsGroup(storeSellFromSubList, requestedGoodsCount);
storeRequestedSubGoodGroup.Parent.SetAsFirstChild();
}
else
{
storeSellFromSubList.RemoveChild(storeRequestedSubGoodGroup.Parent);
storeRequestedSubGoodGroup = null;
}
storeSellFromSubList.RecalculateChildren();
prevSubRequestedGoodsCount = requestedGoodsCount;
}
bool hasPermissions = HasSellSubPermissions;
var existingItemFrames = new HashSet<GUIComponent>();
foreach (PurchasedItem item in itemsToSellFromSub)
{
CreateOrUpdateItemFrame(item.ItemPrefab, item.Quantity);
}
foreach (var requestedGood in ActiveStore.RequestedGoods)
{
if (itemsToSellFromSub.Any(pi => pi.ItemPrefab == requestedGood)) { continue; }
@@ -1087,6 +1090,7 @@ namespace Barotrauma
removedItemFrames.AddRange(storeRequestedSubGoodGroup.Children.Where(c => c.UserData is PurchasedItem).Except(existingItemFrames).ToList());
}
removedItemFrames.ForEach(f => f.RectTransform.Parent = null);
if (activeTab == StoreTab.SellSub) { FilterStoreItems(); }
SortItems(StoreTab.SellSub);
@@ -2164,6 +2168,10 @@ namespace Barotrauma
{
RefreshItemsToSellFromSub();
}
if (needsRefresh)
{
Refresh(updateOwned: ownedItemsUpdateTimer > 0.0f);
}
if (needsBuyingRefresh || HavePermissionsChanged(StoreTab.Buy))
{
RefreshBuying(updateOwned: ownedItemsUpdateTimer > 0.0f);
@@ -84,19 +84,16 @@ namespace Barotrauma
private void Initialize()
{
initialized = true;
currentSubText = TextManager.Get("currentsub");
deliveryFeeText = TextManager.Get("deliveryfee");
deliveryText = TextManager.Get("requestdeliverybutton");
switchText = TextManager.Get("switchtosubmarinebutton");
purchaseAndSwitchText = TextManager.Get("purchaseandswitch");
purchaseOnlyText = TextManager.Get("purchase");
priceText = TextManager.Get("price");
if (transferService)
{
deliveryFee = CalculateDeliveryFee();
currentSubText = TextManager.Get("currentsub");
deliveryFeeText = TextManager.Get("deliveryfee");
deliveryText = TextManager.Get("requestdeliverybutton");
switchText = TextManager.Get("switchtosubmarinebutton");
}
else
{
purchaseAndSwitchText = TextManager.Get("purchaseandswitch");
purchaseOnlyText = TextManager.Get("purchase");
priceText = TextManager.Get("price");
}
currencyName = TextManager.Get("credit").Value.ToLowerInvariant();
@@ -305,10 +305,10 @@ namespace Barotrauma
public static LocalizedString GetMoneyTransferVoteResultMessage(Client from, Client to, int transferAmount, int yesVoteCount, int noVoteCount, bool votePassed)
{
LocalizedString result = string.Empty;
if (from != null)
if (from == null && to != null)
{
result = TextManager.GetWithVariables(votePassed ? "crewwallet.banktoplayer.votepassed" : "crewwallet.banktoplayer.votefailed",
("[playername]", from.Name),
("[playername]", to.Name),
("[amount]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", transferAmount)),
("[yesvotecount]", yesVoteCount.ToString()),
("[novotecount]", noVoteCount.ToString()));
@@ -472,7 +472,9 @@ namespace Barotrauma
TitleScreen.LoadState = MathHelper.Lerp(min, max, progress.Value);
yield return CoroutineStatus.Running;
}
TextManager.VerifyLanguageAvailable();
DebugConsole.Init();
#if !DEBUG && !OSX
@@ -55,15 +55,17 @@ namespace Barotrauma
{
if (_isCrewMenuOpen == value) { return; }
_isCrewMenuOpen = value;
#warning TODO: update GameSettings.CurrentConfig.CrewMenuOpen when round ends
PreferCrewMenuOpen = value;
}
}
public static bool PreferCrewMenuOpen = true;
public bool AutoShowCrewList() => _isCrewMenuOpen = true;
public void AutoHideCrewList() => _isCrewMenuOpen = false;
public void ResetCrewList() => _isCrewMenuOpen = GameSettings.CurrentConfig.CrewMenuOpen;
public void ResetCrewList() => _isCrewMenuOpen = PreferCrewMenuOpen;
const float CommandNodeAnimDuration = 0.2f;
@@ -217,7 +219,7 @@ namespace Barotrauma
screenResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
prevUIScale = GUI.Scale;
_isCrewMenuOpen = GameSettings.CurrentConfig.CrewMenuOpen;
_isCrewMenuOpen = PreferCrewMenuOpen = GameSettings.CurrentConfig.CrewMenuOpen;
}
public static void CreateReportButtons(CrewManager crewManager, GUIComponent parent, IReadOnlyList<OrderPrefab> reports, bool isHorizontal)
@@ -592,6 +592,13 @@ namespace Barotrauma
selectedMissionIndices.Add(msg.ReadByte());
}
ushort ownedSubCount = msg.ReadUInt16();
List<ushort> ownedSubIndices = new List<ushort>();
for (int i = 0; i < ownedSubCount; i++)
{
ownedSubIndices.Add(msg.ReadUInt16());
}
bool allowDebugTeleport = msg.ReadBoolean();
float? reputation = null;
if (msg.ReadBoolean()) { reputation = msg.ReadSingle(); }
@@ -697,6 +704,17 @@ namespace Barotrauma
campaign.Map.SetLocation(currentLocIndex == UInt16.MaxValue ? -1 : currentLocIndex);
campaign.Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex);
campaign.Map.SelectMission(selectedMissionIndices);
GameMain.GameSession.OwnedSubmarines.Clear();
foreach (int ownedSubIndex in ownedSubIndices)
{
SubmarineInfo sub = GameMain.Client.ServerSubmarines[ownedSubIndex];
if (GameMain.NetLobbyScreen.CheckIfCampaignSubMatches(sub, NetLobbyScreen.SubmarineDeliveryData.Owned))
{
GameMain.GameSession.OwnedSubmarines.Add(sub);
}
}
campaign.Map.AllowDebugTeleport = allowDebugTeleport;
campaign.CargoManager.SetItemsInBuyCrate(buyCrateItems);
campaign.CargoManager.SetItemsInSubSellCrate(subSellCrateItems);
@@ -4,9 +4,7 @@ using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection.Metadata;
namespace Barotrauma.Items.Components
{
@@ -53,15 +51,12 @@ namespace Barotrauma.Items.Components
[Serialize("vendingmachine.outofstock", IsPropertySaveable.Yes)]
public string FabricationLimitReachedText { get; set; }
partial void InitProjSpecific()
{
//CreateGUI();
}
protected override void OnResolutionChanged()
{
base.OnResolutionChanged();
OnItemLoadedProjSpecific();
if (GuiFrame != null)
{
OnItemLoadedProjSpecific();
}
}
protected override void CreateGUI()
@@ -162,7 +157,7 @@ namespace Barotrauma.Items.Components
// === ACTIVATE BUTTON === //
var buttonFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.3f, 0.8f), inputArea.RectTransform), childAnchor: Anchor.CenterRight);
activateButton = new GUIButton(new RectTransform(new Vector2(1f, 0.6f), buttonFrame.RectTransform),
TextManager.Get(CreateButtonText), style: "DeviceButton")
TextManager.Get(CreateButtonText), style: "DeviceButtonFixedSize")
{
OnClicked = StartButtonClicked,
UserData = selectedItem,
@@ -173,7 +168,7 @@ namespace Barotrauma.Items.Components
{
bottomFrame.RectTransform.RelativeSize = new Vector2(1.0f, 0.1f);
activateButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), bottomFrame.RectTransform, Anchor.CenterRight),
TextManager.Get(CreateButtonText), style: "DeviceButton")
TextManager.Get(CreateButtonText), style: "DeviceButtonFixedSize")
{
OnClicked = StartButtonClicked,
UserData = selectedItem,
@@ -566,7 +561,7 @@ namespace Barotrauma.Items.Components
LocalizedString itemName = GetRecipeNameAndAmount(selectedItem);
LocalizedString name = itemName;
float quality = GetFabricatedItemQuality(selectedItem, user);
float quality = selectedItem.Quality ?? GetFabricatedItemQuality(selectedItem, user);
if (quality > 0)
{
name = TextManager.GetWithVariable("itemname.quality" + (int)quality, "[itemname]", itemName + '\n')
@@ -636,7 +631,7 @@ namespace Barotrauma.Items.Components
float requiredTime = overrideRequiredTime ??
(user == null ? selectedItem.RequiredTime : GetRequiredTime(selectedItem, user));
if (requiredTime > 0.0f)
if ((int)requiredTime > 0)
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedReqFrame.RectTransform),
TextManager.Get("FabricatorRequiredTime") , textColor: ToolBox.GradientLerp(degreeOfSuccess, GUIStyle.Red, Color.Yellow, GUIStyle.Green), font: GUIStyle.SubHeadingFont)
@@ -778,6 +773,12 @@ namespace Barotrauma.Items.Components
UInt16 userID = msg.ReadUInt16();
Character user = Entity.FindEntityByID(userID) as Character;
ushort reachedLimitCount = msg.ReadUInt16();
for (int i = 0; i < reachedLimitCount; i++)
{
fabricationLimits[msg.ReadUInt32()] = 0;
}
State = newState;
if (newState == FabricatorState.Stopped || recipeHash == 0)
{
@@ -320,7 +320,7 @@ namespace Barotrauma.Items.Components
}
}
GUI.DrawString(spriteBatch, hudPos, texts[0], textColors[0] * alpha, Color.Black * 0.7f * alpha, 2, GUIStyle.SubHeadingFont);
GUI.DrawString(spriteBatch, hudPos, texts[0].Value, textColors[0] * alpha, Color.Black * 0.7f * alpha, 2, GUIStyle.SubHeadingFont, ForceUpperCase.No);
hudPos.X += 5.0f;
hudPos.Y += 24.0f * GameSettings.CurrentConfig.Graphics.TextScale;
@@ -77,7 +77,7 @@ namespace Barotrauma
get { return base.Rect; }
set
{
cachedVisibleSize = null;
cachedVisibleExtents = null;
base.Rect = value;
}
}
@@ -213,11 +213,11 @@ namespace Barotrauma
UpdateSpriteStates(0.0f);
}
private Vector2? cachedVisibleSize;
private Rectangle? cachedVisibleExtents;
public void ResetCachedVisibleSize()
{
cachedVisibleSize = null;
cachedVisibleExtents = null;
}
public override bool IsVisible(Rectangle worldView)
@@ -234,28 +234,39 @@ namespace Barotrauma
return false;
}
Vector2 size;
if (cachedVisibleSize.HasValue)
Rectangle extents;
if (cachedVisibleExtents.HasValue)
{
size = cachedVisibleSize.Value;
extents = cachedVisibleExtents.Value;
}
else
{
float padding = 100.0f;
size = new Vector2(rect.Width + padding, rect.Height + padding);
int padding = 100;
Vector2 min = new Vector2(-rect.Width / 2 - padding, -rect.Height / 2 - padding);
Vector2 max = -min;
foreach (IDrawableComponent drawable in drawableComponents)
{
size.X = Math.Max(drawable.DrawSize.X, size.X);
size.Y = Math.Max(drawable.DrawSize.Y, size.Y);
min.X = Math.Min(min.X, -drawable.DrawSize.X / 2);
min.Y = Math.Min(min.Y, -drawable.DrawSize.Y / 2);
max.X = Math.Max(max.X, drawable.DrawSize.X / 2);
max.Y = Math.Max(max.Y, drawable.DrawSize.Y / 2);
}
size *= 0.5f;
cachedVisibleSize = size;
foreach (DecorativeSprite decorativeSprite in Prefab.DecorativeSprites)
{
float scale = decorativeSprite.GetScale(spriteAnimState[decorativeSprite].RandomScaleFactor) * Scale;
min.X = Math.Min(-decorativeSprite.Sprite.size.X * decorativeSprite.Sprite.RelativeOrigin.X * scale, min.X);
min.Y = Math.Min(-decorativeSprite.Sprite.size.Y * (1.0f - decorativeSprite.Sprite.RelativeOrigin.Y) * scale, min.Y);
max.X = Math.Max(decorativeSprite.Sprite.size.X * (1.0f - decorativeSprite.Sprite.RelativeOrigin.X) * scale, max.X);
max.Y = Math.Max(decorativeSprite.Sprite.size.Y * decorativeSprite.Sprite.RelativeOrigin.Y * scale, max.Y);
}
cachedVisibleExtents = extents = new Rectangle(min.ToPoint(), max.ToPoint());
}
//cache world position so we don't need to calculate it 4 times
Vector2 worldPosition = WorldPosition;
if (worldPosition.X - size.X > worldView.Right || worldPosition.X + size.X < worldView.X) return false;
if (worldPosition.Y + size.Y < worldView.Y - worldView.Height || worldPosition.Y - size.Y > worldView.Y) return false;
if (worldPosition.X + extents.X > worldView.Right || worldPosition.X + extents.Width < worldView.X) { return false; }
if (worldPosition.Y + extents.Height < worldView.Y - worldView.Height || worldPosition.Y + extents.Y > worldView.Y) { return false; }
return true;
}
@@ -934,8 +945,8 @@ namespace Barotrauma
{
OnSelected = (component, userData) =>
{
string text = userData as string ?? "";
AddTag(text);
if (!(userData is Identifier)) { return true; }
AddTag((Identifier)userData);
textBox.Text = Tags;
msgBox.Close();
return true;
@@ -239,7 +239,7 @@ namespace Barotrauma
}
if (min.X > worldView.Right || max.X < worldView.X) { return false; }
if ( min.Y > worldView.Y || max.Y < worldView.Y - worldView.Height) { return false; }
if (min.Y > worldView.Y || max.Y < worldView.Y - worldView.Height) { return false; }
return true;
}
@@ -6,23 +6,6 @@ using System.Linq;
namespace Barotrauma.Networking
{
struct TempClient
{
public string Name;
public Identifier PreferredJob;
public CharacterTeamType PreferredTeam;
public UInt16 NameID;
public UInt64 SteamID;
public byte ID;
public UInt16 CharacterID;
public float Karma;
public bool Muted;
public bool InGame;
public bool HasPermissions;
public bool IsOwner;
public bool AllowKicking;
}
partial class Client : IDisposable
{
public VoipSound VoipSound
@@ -50,6 +33,8 @@ namespace Barotrauma.Networking
public bool AllowKicking;
public bool IsDownloading;
public float Karma;
public void UpdateSoundPosition()
@@ -1899,44 +1899,6 @@ namespace Barotrauma.Networking
if (gameStarted)
{
string ownedSubmarineIndexes = inc.ReadString();
if (ownedSubmarineIndexes != string.Empty)
{
string[] ownedIndexes = ownedSubmarineIndexes.Split(';');
if (GameMain.GameSession != null)
{
GameMain.GameSession.OwnedSubmarines = new List<SubmarineInfo>();
for (int i = 0; i < ownedIndexes.Length; i++)
{
if (int.TryParse(ownedIndexes[i], out int index))
{
SubmarineInfo sub = GameMain.Client.ServerSubmarines[index];
if (GameMain.NetLobbyScreen.CheckIfCampaignSubMatches(sub, NetLobbyScreen.SubmarineDeliveryData.Owned))
{
GameMain.GameSession.OwnedSubmarines.Add(sub);
}
}
}
}
else
{
GameMain.NetLobbyScreen.ServerOwnedSubmarines = new List<SubmarineInfo>();
for (int i = 0; i < ownedIndexes.Length; i++)
{
int index;
if (int.TryParse(ownedIndexes[i], out index))
{
SubmarineInfo sub = GameMain.Client.ServerSubmarines[index];
if (GameMain.NetLobbyScreen.CheckIfCampaignSubMatches(sub, NetLobbyScreen.SubmarineDeliveryData.Owned))
{
GameMain.NetLobbyScreen.ServerOwnedSubmarines.Add(sub);
}
}
}
}
}
if (Screen.Selected != GameMain.GameScreen)
{
new GUIMessageBox(TextManager.Get("PleaseWait"), TextManager.Get(allowSpectating ? "RoundRunningSpectateEnabled" : "RoundRunningSpectateDisabled"));
@@ -1953,37 +1915,8 @@ namespace Barotrauma.Networking
int clientCount = inc.ReadByte();
for (int i = 0; i < clientCount; i++)
{
byte id = inc.ReadByte();
UInt64 steamId = inc.ReadUInt64();
UInt16 nameId = inc.ReadUInt16();
string name = inc.ReadString();
Identifier preferredJob = inc.ReadIdentifier();
byte preferredTeam = inc.ReadByte();
UInt16 characterID = inc.ReadUInt16();
float karma = inc.ReadSingle();
bool muted = inc.ReadBoolean();
bool inGame = inc.ReadBoolean();
bool hasPermissions = inc.ReadBoolean();
bool isOwner = inc.ReadBoolean();
bool allowKicking = inc.ReadBoolean() || IsServerOwner;
tempClients.Add(INetSerializableStruct.Read<TempClient>(inc));
inc.ReadPadBits();
tempClients.Add(new TempClient
{
ID = id,
NameID = nameId,
SteamID = steamId,
Name = name,
PreferredJob = preferredJob,
PreferredTeam = (CharacterTeamType)preferredTeam,
CharacterID = characterID,
Karma = karma,
Muted = muted,
InGame = inGame,
HasPermissions = hasPermissions,
IsOwner = isOwner,
AllowKicking = allowKicking
});
}
if (NetIdUtils.IdMoreRecent(listId, LastClientListUpdateID))
@@ -2018,6 +1951,7 @@ namespace Barotrauma.Networking
existingClient.InGame = tc.InGame;
existingClient.IsOwner = tc.IsOwner;
existingClient.AllowKicking = tc.AllowKicking;
existingClient.IsDownloading = tc.IsDownloading;
GameMain.NetLobbyScreen.SetPlayerNameAndJobPreference(existingClient);
if (Screen.Selected != GameMain.NetLobbyScreen && tc.CharacterID > 0)
{
@@ -2584,7 +2518,7 @@ namespace Barotrauma.Networking
switch (transfer.FileType)
{
case FileTransferType.Submarine:
new GUIMessageBox(TextManager.Get("ServerDownloadFinished"), TextManager.GetWithVariable("FileDownloadedNotification", "[filename]", transfer.FileName));
//new GUIMessageBox(TextManager.Get("ServerDownloadFinished"), TextManager.GetWithVariable("FileDownloadedNotification", "[filename]", transfer.FileName));
var newSub = new SubmarineInfo(transfer.FilePath);
if (newSub.IsFileCorrupted) { return; }
@@ -2644,7 +2578,6 @@ namespace Barotrauma.Networking
NetLobbyScreen.FailedSubInfo failedOwnedSub = GameMain.NetLobbyScreen.FailedOwnedSubs.Find(s => s.Name == newSub.Name && s.Hash == newSub.MD5Hash.StringRepresentation);
if (failedOwnedSub != default)
{
GameMain.NetLobbyScreen.ServerOwnedSubmarines.Add(newSub);
GameMain.NetLobbyScreen.FailedOwnedSubs.Remove(failedOwnedSub);
}
@@ -166,9 +166,12 @@ namespace Barotrauma
int votes = inc.ReadByte();
string subName = inc.ReadString();
List<SubmarineInfo> serversubs = new List<SubmarineInfo>();
foreach (GUIComponent item in GameMain.NetLobbyScreen?.SubList?.Content?.Children)
if (GameMain.NetLobbyScreen?.SubList?.Content != null)
{
if (item.UserData != null && item.UserData is SubmarineInfo) { serversubs.Add(item.UserData as SubmarineInfo); }
foreach (GUIComponent item in GameMain.NetLobbyScreen.SubList.Content.Children)
{
if (item.UserData != null && item.UserData is SubmarineInfo) { serversubs.Add(item.UserData as SubmarineInfo); }
}
}
SubmarineInfo sub = serversubs.FirstOrDefault(s => s.Name == subName);
SetVoteText(GameMain.NetLobbyScreen.SubList, sub, votes);
@@ -271,7 +271,10 @@ namespace Barotrauma.Particles
StartRotationMax = StartRotationMin;
}
if (CollisionRadius <= 0.0f) CollisionRadius = Sprites.Count > 0 ? 1 : Sprites[0].SourceRect.Width / 2.0f;
if (CollisionRadius <= 0.0f && UseCollision)
{
CollisionRadius = Sprites.Count > 0 ? Sprites[0].SourceRect.Width / 2.0f : 1;
}
}
public Vector2 CalculateEndPosition(Vector2 startPosition, Vector2 velocity)
@@ -1048,7 +1048,7 @@ namespace Barotrauma
box.Content.ChildAnchor = Anchor.TopCenter;
box.Content.AbsoluteSpacing = 20;
int elementSize = 30;
var listBox = new GUIListBox(new RectTransform(new Vector2(1, 0.9f), box.Content.RectTransform));
var listBox = new GUIListBox(new RectTransform(new Vector2(1, 0.75f), box.Content.RectTransform));
new GUITextBlock(new RectTransform(new Point(listBox.Content.Rect.Width, elementSize), listBox.Content.RectTransform),
TextManager.Get("leveleditor.levelobjname")) { CanBeFocused = false };
@@ -1059,13 +1059,13 @@ namespace Barotrauma
var texturePathBox = new GUITextBox(new RectTransform(new Point(listBox.Content.Rect.Width, elementSize), listBox.Content.RectTransform));
foreach (LevelObjectPrefab prefab in LevelObjectPrefab.Prefabs)
{
if (prefab.Sprites.FirstOrDefault() == null) continue;
if (prefab.Sprites.FirstOrDefault() == null) { continue; }
texturePathBox.Text = Path.GetDirectoryName(prefab.Sprites.FirstOrDefault().FilePath.Value);
break;
}
//this is nasty :(
newPrefab = new LevelObjectPrefab(null, null, Identifier.Empty);
newPrefab = new LevelObjectPrefab(null, null, new Identifier("No identifier"));
new SerializableEntityEditor(listBox.Content.RectTransform, newPrefab, false, false);
@@ -828,7 +828,6 @@ namespace Barotrauma
" -playstyle " + ((PlayStyle)playstyleBanner.UserData).ToString() +
" -banafterwrongpassword " + wrongPasswordBanBox.Selected.ToString() +
" -karmaenabled " + (!karmaBox.Selected).ToString() +
" -karmapreset default" +
" -maxplayers " + maxPlayersBox.Text;
if (!string.IsNullOrWhiteSpace(passwordBox.Text))
@@ -5,6 +5,7 @@ using System.Linq;
using Barotrauma.Extensions;
using Barotrauma.IO;
using Barotrauma.Networking;
using Barotrauma.Steam;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Steamworks.Data;
@@ -94,7 +95,7 @@ namespace Barotrauma
}
GUIMessageBox msgBox = new GUIMessageBox(
TextManager.Get("WorkshopItemDownloadTitle"),
TextManager.Get("ModDownloadTitle"),
"",
Array.Empty<LocalizedString>(),
relativeSize: (0.5f, 0.75f));
@@ -122,8 +123,6 @@ namespace Barotrauma
return tb;
}
var title = textBlock(TextManager.Get("ModDownloadTitle"), GUIStyle.SubHeadingFont, Alignment.Center);
innerLayoutSpacing(0.05f);
var header = textBlock(TextManager.Get("ModDownloadHeader"), GUIStyle.Font);
innerLayoutSpacing(0.05f);
@@ -138,8 +137,8 @@ namespace Barotrauma
void buttonContainerSpacing(float width)
=> new GUIFrame(new RectTransform((width, 1.0f), buttonContainer.RectTransform), style: null);
void button(LocalizedString text, Action action)
=> new GUIButton(new RectTransform((0.3f, 1.0f), buttonContainer.RectTransform), text)
void button(LocalizedString text, Action action, float width = 0.3f)
=> new GUIButton(new RectTransform((width, 1.0f), buttonContainer.RectTransform), text)
{
OnClicked = (_, __) =>
{
@@ -159,6 +158,28 @@ namespace Barotrauma
});
buttonContainerSpacing(0.1f);
var missingIds = missingPackages.Where(
mp => mp.WorkshopId != 0
&& ContentPackageManager.WorkshopPackages.All(wp
=> wp.SteamWorkshopId != mp.WorkshopId))
.Select(mp => mp.WorkshopId)
.ToArray();
if (missingIds.Any())
{
buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), innerLayout.RectTransform), isHorizontal: true);
buttonContainerSpacing(0.15f);
button(TextManager.Get("SubscribeToAllOnWorkshop"), () =>
{
BulkDownloader.SubscribeToServerMods(missingIds,
rejoinEndpoint: GameMain.Client.ClientPeer.ServerConnection.EndPointString,
rejoinLobby: SteamManager.CurrentLobbyID,
rejoinServerName: GameMain.NetLobbyScreen.ServerName.Text);
GameMain.Client.Disconnect();
GameMain.MainMenuScreen.Select();
}, width: 0.7f);
buttonContainerSpacing(0.15f);
}
foreach (var p in missingPackages)
{
pendingDownloads.Enqueue(p);
@@ -218,9 +218,6 @@ namespace Barotrauma
public MultiPlayerCampaignSetupUI CampaignSetupUI;
// Passed onto the gamesession when created
public List<SubmarineInfo> ServerOwnedSubmarines = new List<SubmarineInfo>();
public bool UsingShuttle
{
get { return shuttleTickBox.Selected; }
@@ -2007,7 +2004,7 @@ namespace Barotrauma
SelectedTextColor = Color.Black,
UserData = client
};
var soundIcon = new GUIImage(new RectTransform(new Point((int)(textBlock.Rect.Height * 0.8f)), textBlock.RectTransform, Anchor.CenterRight) { AbsoluteOffset = new Point(5, 0) },
var soundIcon = new GUIImage(new RectTransform(Vector2.One * 0.8f, textBlock.RectTransform, Anchor.CenterRight, scaleBasis: ScaleBasis.BothHeight) { AbsoluteOffset = new Point(5, 0) },
sprite: GUIStyle.GetComponentStyle("GUISoundIcon").GetDefaultSprite(), scaleToFit: true)
{
UserData = new Pair<string, float>("soundicon", 0.0f),
@@ -2017,7 +2014,7 @@ namespace Barotrauma
HoverColor = Color.White
};
new GUIImage(new RectTransform(new Point((int)(textBlock.Rect.Height * 0.8f)), textBlock.RectTransform, Anchor.CenterRight) { AbsoluteOffset = new Point(5, 0) },
var soundIconDisabled = new GUIImage(new RectTransform(Vector2.One * 0.8f, textBlock.RectTransform, Anchor.CenterRight, scaleBasis: ScaleBasis.BothHeight) { AbsoluteOffset = new Point(5, 0) },
"GUISoundIconDisabled")
{
UserData = "soundicondisabled",
@@ -2026,15 +2023,55 @@ namespace Barotrauma
OverrideState = GUIComponent.ComponentState.None,
HoverColor = Color.White
};
new GUIFrame(new RectTransform(new Vector2(0.6f, 0.6f), textBlock.RectTransform, Anchor.CenterRight, scaleBasis: ScaleBasis.BothHeight) { AbsoluteOffset = new Point(10 + soundIcon.Rect.Width, 0) }, style: "GUIReadyToStart")
var readyTick = new GUIFrame(new RectTransform(new Vector2(0.6f, 0.6f), textBlock.RectTransform, Anchor.CenterRight, scaleBasis: ScaleBasis.BothHeight) { AbsoluteOffset = new Point(10 + soundIcon.Rect.Width, 0) }, style: "GUIReadyToStart")
{
Visible = false,
CanBeFocused = false,
ToolTip = TextManager.Get("ReadyToStartTickBox"),
UserData = "clientready"
};
var downloadingThrobber = new GUICustomComponent(
new RectTransform(Vector2.One, textBlock.RectTransform, scaleBasis: ScaleBasis.BothHeight),
onUpdate: null,
onDraw: DrawDownloadThrobber(client, soundIcon, soundIconDisabled, readyTick));
}
private Action<SpriteBatch, GUICustomComponent> DrawDownloadThrobber(Client client, params GUIComponent[] otherComponents)
=> (sb, c) => DrawDownloadThrobber(client, otherComponents, sb, c); //poor man's currying
private void DrawDownloadThrobber(Client client, GUIComponent[] otherComponents, SpriteBatch spriteBatch, GUICustomComponent component)
{
if (!client.IsDownloading)
{
component.ToolTip = "";
return;
}
component.HideElementsOutsideFrame = false;
int drawRectX = otherComponents.Where(c => c.Visible)
.Select(c => c.Rect)
.Concat(new Rectangle(component.Parent.Rect.Right, component.Parent.Rect.Y, 0, component.Parent.Rect.Height).ToEnumerable())
.Min(r => r.X) - component.Parent.Rect.Height - 10;
Rectangle drawRect
= new Rectangle(drawRectX, component.Rect.Y, component.Parent.Rect.Height, component.Parent.Rect.Height);
component.RectTransform.AbsoluteOffset = drawRect.Location - component.Parent.Rect.Location;
component.RectTransform.NonScaledSize = drawRect.Size;
var sheet = GUIStyle.GenericThrobber;
sheet.Draw(
spriteBatch,
pos: drawRect.Location.ToVector2(),
spriteIndex: (int)Math.Floor(Timing.TotalTime * 24.0f) % sheet.FrameCount,
color: Color.White,
origin: Vector2.Zero, rotate: 0.0f,
scale: Vector2.One * component.Parent.Rect.Height / sheet.FrameSize.ToVector2());
if (component.ToolTip.IsNullOrEmpty())
{
component.ToolTip = TextManager.Get("PlayerIsDownloadingFiles");
}
}
public void SetPlayerNameAndJobPreference(Client client)
{
var playerFrame = (GUITextBlock)PlayerList.Content.FindChild(client);
@@ -2160,17 +2197,16 @@ namespace Barotrauma
Steamworks.SteamFriends.OpenWebOverlay($"https://steamcommunity.com/profiles/{client.SteamID}");
}));
options.Add(new ContextMenuOption("ModerationMenu.UserDetails", isEnabled: true, onSelected: delegate
options.Add(new ContextMenuOption("ModerationMenu.ManagePlayer", isEnabled: true, onSelected: delegate
{
GameMain.NetLobbyScreen?.SelectPlayer(client);
}));
// Creates sub context menu options for all the ranks
List<ContextMenuOption> permissionOptions = new List<ContextMenuOption>();
List<ContextMenuOption> rankOptions = new List<ContextMenuOption>();
foreach (PermissionPreset rank in PermissionPreset.List)
{
permissionOptions.Add(new ContextMenuOption(rank.Name, isEnabled: true, onSelected: () =>
rankOptions.Add(new ContextMenuOption(rank.Name, isEnabled: true, onSelected: () =>
{
LocalizedString label = TextManager.GetWithVariables(rank.Permissions == ClientPermissions.None ? "clearrankprompt" : "giverankprompt", ("[user]", client.Name), ("[rank]", rank.Name));
GUIMessageBox msgBox = new GUIMessageBox(string.Empty, label, new[] { TextManager.Get("Yes"), TextManager.Get("Cancel") });
@@ -2190,7 +2226,7 @@ namespace Barotrauma
}) { Tooltip = rank.Description });
}
options.Add(new ContextMenuOption("Permissions", isEnabled: canPromo, options: permissionOptions.ToArray()));
options.Add(new ContextMenuOption("Rank", isEnabled: canPromo, options: rankOptions.ToArray()));
Color clientColor = client.Character?.Info?.Job.Prefab.UIColor ?? Color.White;
@@ -3554,12 +3590,6 @@ namespace Barotrauma
("[serverhash]", Md5Hash.GetShortHash(md5Hash))) + " ";
}
//already showing a message about the same sub
if (GUIMessageBox.MessageBoxes.Any(mb => mb.UserData as string == "request" + subName))
{
return false;
}
if (GameMain.Client.ServerSettings.AllowFileTransfers)
{
GameMain.Client?.RequestFile(FileTransferType.Submarine, subName, md5Hash);
@@ -793,7 +793,7 @@ namespace Barotrauma
showEntitiesPanel.RectTransform.NonScaledSize =
new Point(
(int)(paddedShowEntitiesPanel.RectTransform.Children.Max(c => (int)((c.GUIComponent as GUITickBox)?.TextBlock.TextSize.X ?? 0)) / paddedShowEntitiesPanel.RectTransform.RelativeSize.X),
(int)Math.Max(showEntitiesPanel.RectTransform.NonScaledSize.X, paddedShowEntitiesPanel.RectTransform.Children.Max(c => (int)((c.GUIComponent as GUITickBox)?.TextBlock.TextSize.X ?? 0)) / paddedShowEntitiesPanel.RectTransform.RelativeSize.X),
(int)(paddedShowEntitiesPanel.RectTransform.Children.Sum(c => c.MinSize.Y) / paddedShowEntitiesPanel.RectTransform.RelativeSize.Y));
GUITextBlock.AutoScaleAndNormalize(paddedShowEntitiesPanel.Children.Where(c => c is GUITickBox).Select(c => ((GUITickBox)c).TextBlock));
@@ -1700,44 +1700,13 @@ namespace Barotrauma
return false;
}
string specialSavePath = "";
if (MainSub.Info.Type != SubmarineType.Player)
{
Identifier typeIdentifier = MainSub.Info.Type.ToString().ToIdentifier();
Type contentType = ContentFile.Types.FirstOrDefault(t
=> !t.Type.IsAbstract
&& t.Type.IsSubclassOf(typeof(BaseSubFile))
&& t.Names.Contains(typeIdentifier))
?.Type ??
typeof(SubmarineFile);
if (MainSub.Info.Type == SubmarineType.OutpostModule &&
MainSub.Info.OutpostModuleInfo != null)
{
contentType = typeof(OutpostModuleFile);
MainSub.Info.PreviewImage = null;
}
if (contentType != typeof(SubmarineFile))
{
#if DEBUG
var existingFiles = GameMain.VanillaContent.GetFiles(contentType);
if (contentType == typeof(OutpostModuleFile))
{
existingFiles = existingFiles.Where(f => f.Path.Value.Contains("Ruin") == MainSub.Info.OutpostModuleInfo.ModuleFlags.Contains("ruin".ToIdentifier()));
}
#else
var existingFiles = ContentPackageManager.EnabledPackages.All
.Where(c => c != GameMain.VanillaContent)
.SelectMany(c => c.GetFiles(contentType));
#endif
specialSavePath = existingFiles.FirstOrDefault(f =>
ContentPackage.PathAllowedAsLocalModFile(f.Path.Value))?.Path.Value;
if (!string.IsNullOrEmpty(specialSavePath))
{
specialSavePath = Path.GetDirectoryName(specialSavePath);
}
}
}
else if (MainSub.Info.SubmarineClass == SubmarineClass.Undefined && !MainSub.Info.HasTag(SubmarineTag.Shuttle))
{
@@ -1758,35 +1727,7 @@ namespace Barotrauma
return true;
}
if (!string.IsNullOrEmpty(specialSavePath) &&
(string.IsNullOrEmpty(MainSub?.Info.FilePath) || Path.GetFileNameWithoutExtension(MainSub.Info.Name) != nameBox.Text || Path.GetDirectoryName(MainSub?.Info.FilePath) != specialSavePath))
{
string submarineTypeTag = $"SubmarineType.{MainSub.Info.Type}";
if (MainSub.Info.Type == SubmarineType.EnemySubmarine && !TextManager.ContainsTag(submarineTypeTag))
{
submarineTypeTag = "MissionType.Pirate";
}
var msgBox = new GUIMessageBox("", TextManager.GetWithVariables("savesubtospecialfolderprompt",
("[type]", TextManager.Get(submarineTypeTag)), ("[outpostpath]", specialSavePath)),
new LocalizedString[] { TextManager.Get("yes"), TextManager.Get("no") });
msgBox.Buttons[0].OnClicked = (bt, userdata) =>
{
SaveSubToFile(nameBox.Text, specialSavePath);
saveFrame = null;
msgBox.Close();
return true;
};
msgBox.Buttons[1].OnClicked = (bt, userdata) =>
{
SaveSubToFile(nameBox.Text);
saveFrame = null;
msgBox.Close();
return true;
};
return true;
}
var result = SaveSubToFile(nameBox.Text, specialSavePath);
var result = SaveSubToFile(nameBox.Text);
saveFrame = null;
return result;
}
@@ -1798,13 +1739,9 @@ namespace Barotrauma
if (p is null) { return; }
if (!packageReloadQueue.Contains(p)) { packageReloadQueue.Enqueue(p); }
}
private bool SaveSubToFile(string name, string specialSavePath = null)
{
bool canModifyPackage(ContentPackage p)
=> p != null && ContentPackageManager.LocalPackages.Contains(p) && p != ContentPackageManager.VanillaCorePackage;
Type subFileType = MainSub?.Info.Type switch
public static Type DetermineSubFileType(SubmarineType type)
=> type switch
{
SubmarineType.Outpost => typeof(OutpostFile),
SubmarineType.OutpostModule => typeof(OutpostModuleFile),
@@ -1812,8 +1749,16 @@ namespace Barotrauma
SubmarineType.Wreck => typeof(WreckFile),
SubmarineType.BeaconStation => typeof(BeaconStationFile),
SubmarineType.EnemySubmarine => typeof(EnemySubmarineFile),
SubmarineType.Player => typeof(SubmarineFile)
SubmarineType.Player => typeof(SubmarineFile),
_ => null
};
private bool SaveSubToFile(string name)
{
bool canModifyPackage(ContentPackage p)
=> p != null && ContentPackageManager.LocalPackages.Contains(p) && p != ContentPackageManager.VanillaCorePackage;
Type subFileType = DetermineSubFileType(MainSub?.Info.Type ?? SubmarineType.Player);
void addSubAndSaveModProject(ModProject modProject, string filePath, string packagePath)
{
@@ -1858,11 +1803,13 @@ namespace Barotrauma
foreach (var illegalChar in Path.GetInvalidFileNameChars())
{
if (!name.Contains(illegalChar)) continue;
if (!name.Contains(illegalChar)) { continue; }
GUI.AddMessage(TextManager.GetWithVariable("SubNameIllegalCharsWarning", "[illegalchar]", illegalChar.ToString()), GUIStyle.Red);
return false;
}
name = name.Trim();
string newLocalModDir = $"{ContentPackage.LocalModsDir}/{name}";
var vanilla = GameMain.VanillaContent;
@@ -1871,33 +1818,7 @@ namespace Barotrauma
string savePath = name + ".sub";
string prevSavePath = null;
if (!string.IsNullOrEmpty(specialSavePath))
{
string directoryName = specialSavePath;
savePath = Path.Combine(directoryName, savePath);
ContentPackage contentPackage = ContentPackageManager.EnabledPackages.All.FirstOrDefault(cp => cp.Files.Any(f => Path.GetDirectoryName(f.Path.Value) == directoryName));
if (!contentPackage.Files.Any(f => f.Path == savePath) && canModifyPackage(contentPackage))
{
var msgBox = new GUIMessageBox("", TextManager.GetWithVariable("addtocontentpackageprompt", "[packagename]", contentPackage.Name),
new LocalizedString[] { TextManager.Get("yes"), TextManager.Get("no") });
msgBox.Buttons[0].OnClicked = (bt, userdata) =>
{
ModProject modProject = new ModProject(contentPackage);
addSubAndSaveModProject(modProject, savePath, contentPackage.Path);
EnqueueForReload(contentPackage);
msgBox.Close();
return true;
};
msgBox.Buttons[1].OnClicked = (bt, userdata) =>
{
msgBox.Close();
return true;
};
}
}
else if (!string.IsNullOrEmpty(MainSub?.Info.FilePath) &&
if (!string.IsNullOrEmpty(MainSub?.Info.FilePath) &&
MainSub.Info.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
{
prevSavePath = MainSub.Info.FilePath.CleanUpPath();
@@ -2515,7 +2436,7 @@ namespace Barotrauma
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), rightColumn.RectTransform), TextManager.Get("SubPreviewImage"), font: GUIStyle.SubHeadingFont);
var previewImageHolder = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.5f), rightColumn.RectTransform), style: null) { Color = Color.Black, CanBeFocused = false };
var previewImageHolder = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.4f), rightColumn.RectTransform), style: null) { Color = Color.Black, CanBeFocused = false };
previewImage = new GUIImage(new RectTransform(Vector2.One, previewImageHolder.RectTransform), MainSub?.Info.PreviewImage, scaleToFit: true);
previewImageButtonHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), rightColumn.RectTransform), isHorizontal: true) { Stretch = true, RelativeSpacing = 0.05f };
@@ -2567,7 +2488,7 @@ namespace Barotrauma
previewImageButtonHolder.RectTransform.MinSize = new Point(0, previewImageButtonHolder.RectTransform.Children.Max(c => c.MinSize.Y));
var horizontalArea = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.35f), rightColumn.RectTransform), style: null);
var horizontalArea = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.45f), rightColumn.RectTransform), style: null);
var settingsLabel = new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.0f), horizontalArea.RectTransform),
TextManager.Get("SaveSubDialogSettings"), wrap: true, font: GUIStyle.SmallFont);
@@ -2613,11 +2534,30 @@ namespace Barotrauma
};
}
var contentPackagesLabel = new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.0f), horizontalArea.RectTransform, Anchor.TopRight),
var contentPackagesLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f),
horizontalArea.RectTransform, Anchor.BottomRight))
{
Stretch = true
};
var contentPackagesLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), contentPackagesLayout.RectTransform),
TextManager.Get("RequiredContentPackages"), wrap: true, font: GUIStyle.SmallFont);
contentPackagesLabel.RectTransform.MinSize
= GUIStyle.SmallFont.MeasureString(contentPackagesLabel.WrappedText).ToPoint();
var contentPackList = new GUIListBox(new RectTransform(new Vector2(0.5f, 1.0f - contentPackagesLabel.RectTransform.RelativeSize.Y),
horizontalArea.RectTransform, Anchor.BottomRight));
var contentPackList = new GUIListBox(new RectTransform(new Vector2(1.0f, 1.0f),
contentPackagesLayout.RectTransform));
var contentPackFilter
= new GUITextBox(new RectTransform(new Vector2(1.0f, 0.0f), contentPackagesLayout.RectTransform),
createClearButton: true);
contentPackFilter.OnTextChanged += (box, text) =>
{
contentPackList.Content.Children.ForEach(c
=> c.Visible = !(c is GUITickBox tb &&
!tb.Text.Contains(text, StringComparison.OrdinalIgnoreCase)));
return true;
};
if (MainSub != null)
{
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using Barotrauma.IO;
using System.Linq;
using System.Threading;
using System.Xml.Linq;
namespace Barotrauma
@@ -479,6 +480,36 @@ namespace Barotrauma
return sound.Play(volume ?? sound.BaseGain, far, freqMult ?? 1.0f, position, muffle: muffle);
}
public static void DisposeDisabledMusic()
{
bool musicDisposed = false;
for (int i = 0; i < currentMusic.Length; i++)
{
var music = currentMusic[i];
if (music is null) { continue; }
if (!SoundPrefab.Prefabs.Contains(music))
{
musicChannel[i].Dispose();
musicDisposed = true;
currentMusic[i] = null;
}
}
for (int i = 0; i < targetMusic.Length; i++)
{
var music = targetMusic[i];
if (music is null) { continue; }
if (!SoundPrefab.Prefabs.Contains(music))
{
targetMusic[i] = null;
}
}
if (musicDisposed) { Thread.Sleep(60); }
}
private static void UpdateMusic(float deltaTime)
{
if (musicClips == null || (GameMain.SoundManager?.Disabled ?? true)) { return; }
@@ -121,6 +121,7 @@ namespace Barotrauma
}
if (prefabSelectors.ContainsKey(p.ElementName)) { prefabSelectors[p.ElementName].RemoveIfContains(p); }
UpdateSoundsWithTag();
SoundPlayer.DisposeDisabledMusic();
},
onSort: () =>
{
@@ -0,0 +1,125 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Barotrauma.Extensions;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
namespace Barotrauma.Steam
{
public static class BulkDownloader
{
public static void PrepareUpdates()
{
GUIMessageBox msgBox = new GUIMessageBox(headerText: "", text: TextManager.Get("DeterminingRequiredModUpdates"),
buttons: Array.Empty<LocalizedString>());
TaskPool.Add(
"BulkDownloader.PrepareUpdates > GetItemsThatNeedUpdating",
GetItemsThatNeedUpdating(),
t =>
{
msgBox.Close();
if (!t.TryGetResult(out IReadOnlyList<Steamworks.Ugc.Item> items)) { return; }
InitiateDownloads(items);
});
}
internal static void SubscribeToServerMods(IEnumerable<UInt64> missingIds, string rejoinEndpoint, ulong rejoinLobby, string rejoinServerName)
{
GUIMessageBox msgBox = new GUIMessageBox(headerText: "", text: TextManager.Get("PreparingWorkshopDownloads"),
buttons: Array.Empty<LocalizedString>());
TaskPool.Add(
"BulkDownloader.SubscribeToServerMods > GetItems",
Task.WhenAll(missingIds.Select(SteamManager.Workshop.GetItem)),
t =>
{
msgBox.Close();
if (!t.TryGetResult(out Steamworks.Ugc.Item?[] itemsNullable)) { return; }
var items = itemsNullable
.Where(it => it.HasValue)
.Select(it => it ?? default)
.ToArray();
items.ForEach(it => it.Subscribe());
InitiateDownloads(items, onComplete: () =>
{
ContentPackageManager.UpdateContentPackageList();
GameMain.Instance.ConnectEndpoint = rejoinEndpoint;
GameMain.Instance.ConnectLobby = rejoinLobby;
GameMain.Instance.ConnectName = rejoinServerName;
});
});
}
private static async Task<IReadOnlyList<Steamworks.Ugc.Item>> GetItemsThatNeedUpdating()
{
var determiningTasks = ContentPackageManager.WorkshopPackages.Select(async p => (p, await p.IsUpToDate()));
(ContentPackage Package, bool IsUpToDate)[] outOfDatePackages = await Task.WhenAll(determiningTasks);
return (await Task.WhenAll(outOfDatePackages.Where(p => !p.IsUpToDate)
.Select(async p => await SteamManager.Workshop.GetItem(p.Package.SteamWorkshopId))))
.Where(p => p.HasValue).Select(p => p ?? default).ToArray();
}
public static void InitiateDownloads(IReadOnlyList<Steamworks.Ugc.Item> itemsToDownload, Action? onComplete = null)
{
var msgBox = new GUIMessageBox(TextManager.Get("WorkshopItemDownloading"), "", relativeSize: (0.5f, 0.6f),
buttons: new LocalizedString[] { TextManager.Get("Cancel") });
msgBox.Buttons[0].OnClicked = msgBox.Close;
var modsList = new GUIListBox(new RectTransform((1.0f, 0.8f), msgBox.Content.RectTransform))
{
HoverCursor = CursorState.Default
};
foreach (var item in itemsToDownload)
{
var itemFrame = new GUIFrame(new RectTransform((1.0f, 0.08f), modsList.Content.RectTransform),
style: null)
{
CanBeFocused = false
};
var itemTitle = new GUITextBlock(new RectTransform(Vector2.One, itemFrame.RectTransform),
text: item.Title);
var itemDownloadProgress
= new GUIProgressBar(new RectTransform((0.5f, 0.75f),
itemFrame.RectTransform, Anchor.CenterRight), 0.0f)
{
Color = GUIStyle.Green
};
itemDownloadProgress.ProgressGetter = () =>
{
float progress = 0.0f;
if (item.IsDownloading) { progress = item.DownloadAmount; }
else if (itemDownloadProgress.BarSize > 0.0f) { progress = 1.0f; }
return Math.Max(itemDownloadProgress.BarSize,
MathHelper.Lerp(itemDownloadProgress.BarSize, progress, 0.05f));
};
}
TaskPool.Add("DownloadItems", DownloadItems(itemsToDownload, msgBox), _ =>
{
if (GUIMessageBox.MessageBoxes.Contains(msgBox))
{
onComplete?.Invoke();
}
msgBox.Close();
if (SettingsMenu.Instance?.WorkshopMenu is MutableWorkshopMenu mutableWorkshopMenu)
{
mutableWorkshopMenu.PopulateInstalledModLists();
}
});
}
private static async Task DownloadItems(IReadOnlyList<Steamworks.Ugc.Item> itemsToDownload, GUIMessageBox msgBox)
{
foreach (var item in itemsToDownload)
{
await SteamManager.Workshop.Reinstall(item);
if (!GUIMessageBox.MessageBoxes.Contains(msgBox)) { break; }
}
}
}
}
@@ -1,10 +1,15 @@
#nullable enable
using System;
using Barotrauma.Extensions;
using Microsoft.Xna.Framework;
namespace Barotrauma.Steam
{
sealed class ImmutableWorkshopMenu : WorkshopMenu
{
private readonly GUIListBox regularList;
private readonly GUITextBox filterBox;
public ImmutableWorkshopMenu(GUIFrame parent) : base(parent)
{
var mainLayout
@@ -20,8 +25,8 @@ namespace Barotrauma.Steam
coreBox.TextBlock.Padding = new Vector4(10.0f, 0.0f, 10.0f, 0.0f);
Label(mainLayout, TextManager.Get("enabledregular"), GUIStyle.SubHeadingFont);
var regularList = new GUIListBox(
NewItemRectT(mainLayout, heightScale: 12f))
regularList = new GUIListBox(
NewItemRectT(mainLayout, heightScale: 11f))
{
OnSelected = (component, o) => false,
HoverCursor = CursorState.Default
@@ -31,11 +36,22 @@ namespace Barotrauma.Steam
var regularBox = new GUITextBlock(
new RectTransform((1.0f, 0.07f), regularList.Content.RectTransform), text: p.Name)
{
CanBeFocused = false
CanBeFocused = false,
UserData = p
};
}
filterBox = CreateSearchBox(mainLayout, width: 1.0f);
Label(mainLayout, TextManager.Get("CannotChangeMods"), GUIStyle.Font);
}
protected override void UpdateModListItemVisibility()
{
string str = filterBox.Text;
regularList.Content.Children
.ForEach(c => c.Visible = str.IsNullOrWhiteSpace()
|| (c.UserData is ContentPackage p
&& p.Name.Contains(str, StringComparison.OrdinalIgnoreCase)));
}
}
}
@@ -32,6 +32,7 @@ namespace Barotrauma.Steam
private readonly GUIListBox disabledRegularModsList;
private readonly Action<ItemOrPackage> onInstalledInfoButtonHit;
private readonly GUITextBox modsListFilter;
private readonly GUIButton bulkUpdateButton;
private CancellationTokenSource taskCancelSrc = new CancellationTokenSource();
private readonly HashSet<SteamManager.Workshop.ItemThumbnail> itemThumbnails = new HashSet<SteamManager.Workshop.ItemThumbnail>();
@@ -55,7 +56,8 @@ namespace Barotrauma.Steam
out enabledRegularModsList,
out disabledRegularModsList,
out onInstalledInfoButtonHit,
out modsListFilter);
out modsListFilter,
out bulkUpdateButton);
CreatePopularModsTab(out popularModsList);
CreatePublishTab(out selfModsList);
@@ -179,13 +181,35 @@ namespace Barotrauma.Steam
to.BarScroll *= (oldCount / newCount);
}
}
private Action? currentSwapFunc = null;
private void SetSwapFunc(GUIListBox from, GUIListBox to)
{
currentSwapFunc = () =>
{
to.Deselect();
var selected = from.AllSelected.ToArray();
foreach (var frame in selected)
{
frame.Parent.RemoveChild(frame);
frame.RectTransform.Parent = to.Content.RectTransform;
}
from.RecalculateChildren();
from.RectTransform.RecalculateScale(true);
to.RecalculateChildren();
to.RectTransform.RecalculateScale(true);
to.Select(selected);
};
}
private void CreateInstalledModsTab(
out GUIDropDown enabledCoreDropdown,
out GUIListBox enabledRegularModsList,
out GUIListBox disabledRegularModsList,
out Action<ItemOrPackage> onInstalledInfoButtonHit,
out GUITextBox modsListFilter)
out GUITextBox modsListFilter,
out GUIButton bulkUpdateButton)
{
GUIFrame content = CreateNewContentFrame(Tab.InstalledMods);
@@ -196,49 +220,72 @@ namespace Barotrauma.Steam
{
if (itemOrPackage.TryGet(out Steamworks.Ugc.Item item)) { PopulateFrameWithItemInfo(item, selectedFrame); }
},
onDeselected: PopulateInstalledModLists,
onDeselected: () => PopulateInstalledModLists(),
out onInstalledInfoButtonHit, out var deselect);
GUILayoutGroup mainLayout =
new GUILayoutGroup(new RectTransform(Vector2.One, outerContainer.Content.RectTransform), childAnchor: Anchor.TopCenter);
mainLayout.RectTransform.SetAsFirstChild();
GUILayoutGroup coreSelectionLayout =
new GUILayoutGroup(new RectTransform((0.5f, 0.15f), mainLayout.RectTransform));
Label(coreSelectionLayout, TextManager.Get("enabledcore"), GUIStyle.SubHeadingFont, heightScale: 1.0f / 0.15f);
enabledCoreDropdown = Dropdown<CorePackage>(coreSelectionLayout,
var (topLeft, _, topRight) = CreateSidebars(mainLayout, centerWidth: 0.05f, leftWidth: 0.475f, rightWidth: 0.475f, height: 0.13f);
topLeft.Stretch = true;
Label(topLeft, TextManager.Get("enabledcore"), GUIStyle.SubHeadingFont, heightScale: 1.0f);
enabledCoreDropdown = Dropdown<CorePackage>(topLeft,
(p) => p.Name,
ContentPackageManager.CorePackages.ToArray(),
ContentPackageManager.EnabledPackages.Core!,
(p) => { },
heightScale: 1.0f / 0.15f);
heightScale: 1.0f / 13.0f);
Label(topLeft, "", GUIStyle.SubHeadingFont, heightScale: 1.0f);
topRight.ChildAnchor = Anchor.CenterLeft;
var (left, center, right) = CreateSidebars(mainLayout, centerWidth: 0.05f, leftWidth: 0.475f, rightWidth: 0.475f, height: 0.78f);
right.ChildAnchor = Anchor.TopRight;
Action swapFunc(GUIListBox from, GUIListBox to)
var topRightButtons = new GUILayoutGroup(new RectTransform((1.0f, 0.5f), topRight.RectTransform),
isHorizontal: true, childAnchor: Anchor.CenterLeft)
{
return () =>
{
to.Deselect();
var selected = from.AllSelected.ToArray();
foreach (var frame in selected)
{
frame.Parent.RemoveChild(frame);
frame.RectTransform.Parent = to.Content.RectTransform;
}
from.RecalculateChildren();
from.RectTransform.RecalculateScale(true);
to.RecalculateChildren();
to.RectTransform.RecalculateScale(true);
to.Select(selected);
};
Stretch = true,
RelativeSpacing = 0.05f
};
void padTopRight(float width=1.0f)
{
new GUIFrame(new RectTransform((width, 1.0f), topRightButtons.RectTransform), style: null);
}
Action? currentCenterCallback = null;
padTopRight();
//TODO: put stuff here
padTopRight(width: 3.0f);
var refreshListsButton
= new GUIButton(
new RectTransform(Vector2.One, topRightButtons.RectTransform, scaleBasis: ScaleBasis.BothHeight),
text: "", style: "GUIReloadButton")
{
OnClicked = (b, o) =>
{
PopulateInstalledModLists();
return false;
},
ToolTip = TextManager.Get("RefreshModLists")
};
bulkUpdateButton
= new GUIButton(
new RectTransform(Vector2.One, topRightButtons.RectTransform, scaleBasis: ScaleBasis.BothHeight),
text: "", style: "GUIUpdateButton")
{
OnClicked = (b, o) =>
{
BulkDownloader.PrepareUpdates();
return false;
},
Enabled = false
};
padTopRight(width: 0.1f);
var (left, center, right) = CreateSidebars(mainLayout, centerWidth: 0.05f, leftWidth: 0.475f, rightWidth: 0.475f, height: 0.8f);
right.ChildAnchor = Anchor.TopRight;
//enabled mods
Label(left, TextManager.Get("enabledregular"), GUIStyle.SubHeadingFont);
var enabledModsList = new GUIListBox(new RectTransform((1.0f, 0.92f), left.RectTransform))
var enabledModsList = new GUIListBox(new RectTransform((1.0f, 0.93f), left.RectTransform))
{
CurrentDragMode = GUIListBox.DragMode.DragOutsideBox,
CurrentSelectMode = GUIListBox.SelectMode.RequireShiftToSelectMultiple,
@@ -248,7 +295,7 @@ namespace Barotrauma.Steam
//disabled mods
Label(right, TextManager.Get("disabledregular"), GUIStyle.SubHeadingFont);
var disabledModsList = new GUIListBox(new RectTransform((1.0f, 0.92f), right.RectTransform))
var disabledModsList = new GUIListBox(new RectTransform((1.0f, 0.93f), right.RectTransform))
{
CurrentDragMode = GUIListBox.DragMode.DragOutsideBox,
CurrentSelectMode = GUIListBox.SelectMode.RequireShiftToSelectMultiple,
@@ -265,7 +312,7 @@ namespace Barotrauma.Steam
Visible = false,
OnClicked = (button, o) =>
{
currentCenterCallback?.Invoke();
currentSwapFunc?.Invoke();
return false;
}
};
@@ -277,7 +324,7 @@ namespace Barotrauma.Steam
centerButton.Visible = true;
centerButton.ApplyStyle(GUIStyle.GetComponentStyle("GUIButtonToggleRight"));
currentCenterCallback = swapFunc(enabledModsList, disabledModsList);
SetSwapFunc(enabledModsList, disabledModsList);
return true;
};
@@ -288,30 +335,12 @@ namespace Barotrauma.Steam
centerButton.Visible = true;
centerButton.ApplyStyle(GUIStyle.GetComponentStyle("GUIButtonToggleLeft"));
currentCenterCallback = swapFunc(disabledModsList, enabledModsList);
SetSwapFunc(disabledModsList, enabledModsList);
return true;
};
var searchRectT = NewItemRectT(mainLayout, heightScale: 1.0f);
searchRectT.RelativeSize = (0.5f, searchRectT.RelativeSize.Y);
var searchHolder = new GUIFrame(searchRectT, style: null);
var searchBox = new GUITextBox(new RectTransform(Vector2.One, searchHolder.RectTransform), "", createClearButton: true);
var searchTitle = new GUITextBlock(new RectTransform(Vector2.One, searchHolder.RectTransform) {Anchor = Anchor.TopLeft},
textColor: Color.DarkGray * 0.6f,
text: TextManager.Get("Search") + "...",
textAlignment: Alignment.CenterLeft)
{
CanBeFocused = false
};
searchBox.OnSelected += (sender, userdata) => { searchTitle.Visible = false; };
searchBox.OnDeselected += (sender, userdata) => { searchTitle.Visible = searchBox.Text.IsNullOrWhiteSpace(); };
searchBox.OnTextChanged += (sender, str) =>
{
UpdateModListItemVisibility();
return true;
};
var searchBox = CreateSearchBox(mainLayout, width: 0.5f);
modsListFilter = searchBox;
new GUICustomComponent(new RectTransform(Vector2.Zero, content.RectTransform),
@@ -319,6 +348,18 @@ namespace Barotrauma.Steam
{
HandleDraggingAcrossModLists(enabledModsList, disabledModsList);
HandleDraggingAcrossModLists(disabledModsList, enabledModsList);
if (PlayerInput.PrimaryMouseButtonClicked()
&& !GUI.IsMouseOn(enabledModsList)
&& !GUI.IsMouseOn(disabledModsList)
&& GUIContextMenu.CurrentContextMenu is null)
{
enabledModsList.Deselect();
disabledModsList.Deselect();
}
else if (!PlayerInput.IsCtrlDown() && !PlayerInput.IsShiftDown() && PlayerInput.DoubleClicked())
{
currentSwapFunc?.Invoke();
}
},
onDraw: (spriteBatch, component) =>
{
@@ -327,7 +368,7 @@ namespace Barotrauma.Steam
});
}
private void UpdateModListItemVisibility()
protected override void UpdateModListItemVisibility()
{
string str = modsListFilter.Text;
enabledRegularModsList.Content.Children.Concat(disabledRegularModsList.Content.Children)
@@ -336,8 +377,21 @@ namespace Barotrauma.Steam
&& p.Name.Contains(str, StringComparison.OrdinalIgnoreCase)));
}
private void PopulateInstalledModLists()
private void PrepareToShowModInfo(ContentPackage mod)
{
TaskPool.Add($"PrepareToShow{mod.SteamWorkshopId}Info", SteamManager.Workshop.GetItem(mod.SteamWorkshopId),
t =>
{
if (!t.TryGetResult(out Steamworks.Ugc.Item? item)) { return; }
if (item is null) { return; }
onInstalledInfoButtonHit(item.Value);
});
}
public void PopulateInstalledModLists(bool forceRefreshEnabled = false, bool refreshDisabled = true)
{
bulkUpdateButton.Enabled = false;
bulkUpdateButton.ToolTip = "";
ContentPackageManager.UpdateContentPackageList();
SwapDropdownValues<CorePackage>(enabledCoreDropdown,
@@ -353,6 +407,39 @@ namespace Barotrauma.Steam
{
UserData = mod
};
var contextMenuHandler = new GUICustomComponent(new RectTransform(Vector2.Zero, modFrame.RectTransform),
onUpdate: (f, component) =>
{
var parentList = modFrame.Parent?.Parent?.Parent as GUIListBox; //lovely jank :)
if (parentList is null) { return; }
if (GUI.MouseOn == modFrame && parentList.DraggedElement is null && PlayerInput.SecondaryMouseButtonClicked())
{
if (!parentList.AllSelected.Contains(modFrame)) { parentList.Select(parentList.Content.GetChildIndex(modFrame)); }
static void noop() { }
List<ContextMenuOption> contextMenuOptions = new List<ContextMenuOption>();
if (ContentPackageManager.WorkshopPackages.Contains(mod))
{
contextMenuOptions.Add(
new ContextMenuOption("ViewWorkshopModDetails".ToIdentifier(), isEnabled: true, onSelected: () => PrepareToShowModInfo(mod)));
}
Identifier swapLabel
= ((parentList == enabledRegularModsList ? "Disable" : "Enable")
+ (parentList.AllSelected.Count > 1 ? "SelectedWorkshopMods" : "WorkshopMod"))
.ToIdentifier();
contextMenuOptions.Add(new ContextMenuOption(swapLabel,
isEnabled: true, onSelected: currentSwapFunc ?? noop));
GUIContextMenu.CreateContextMenu(
pos: PlayerInput.MousePosition,
header: ToolBox.LimitString(mod.Name, GUIStyle.SubHeadingFont, GUI.IntScale(300f)),
headerColor: null,
contextMenuOptions.ToArray());
}
});
var frameContent = new GUILayoutGroup(new RectTransform((0.95f, 0.9f), modFrame.RectTransform, Anchor.Center), isHorizontal: true, childAnchor: Anchor.CenterLeft)
{
@@ -392,20 +479,14 @@ namespace Barotrauma.Steam
{
var infoButton = new GUIButton(
new RectTransform(Vector2.One, frameContent.RectTransform, scaleBasis: ScaleBasis.Smallest), "",
style: "WorkshopMenu.InfoButton")
style: null)
{
CanBeSelected = false,
OnClicked = (button, o) =>
{
TaskPool.Add($"PrepareToShow{mod.SteamWorkshopId}Info", SteamManager.Workshop.GetItem(mod.SteamWorkshopId),
t =>
{
if (!t.TryGetResult(out Steamworks.Ugc.Item? item)) { return; }
if (item is null) { return; }
onInstalledInfoButtonHit(item.Value);
});
PrepareToShowModInfo(mod);
return false;
},
ToolTip = TextManager.Get("ViewModDetails")
}
};
if (!SteamManager.IsInitialized)
{
@@ -420,27 +501,69 @@ namespace Barotrauma.Steam
if (!isUpToDate)
{
infoButton.CanBeSelected = true;
infoButton.ApplyStyle(GUIStyle.ComponentStyles["WorkshopMenu.InfoButtonUpdate"]);
infoButton.ToolTip = TextManager.Get("ViewModDetailsUpdateAvailable");
bulkUpdateButton.Enabled = true;
bulkUpdateButton.ToolTip = TextManager.Get("ModUpdatesAvailable");
}
});
}
}
void addRegularModsToList(IEnumerable<RegularPackage> mods, GUIListBox list)
{
list.ClearChildren();
foreach (var mod in mods)
{
addRegularModToList(mod, list);
}
}
var enabledMods =
(forceRefreshEnabled || (enabledRegularModsList.Content.CountChildren + disabledRegularModsList.Content.CountChildren == 0)
? ContentPackageManager.EnabledPackages.Regular
: enabledRegularModsList.Content.Children
.Select(c => c.UserData)
.OfType<RegularPackage>()
.Where(p => ContentPackageManager.RegularPackages.Contains(p)))
.ToArray();
var disabledMods = ContentPackageManager.RegularPackages.Where(p => !enabledMods.Contains(p));
enabledRegularModsList.ClearChildren();
for (int i = 0; i < ContentPackageManager.EnabledPackages.Regular.Count; i++)
{
var mod = ContentPackageManager.EnabledPackages.Regular[i];
addRegularModToList(mod, enabledRegularModsList);
}
addRegularModsToList(enabledMods, enabledRegularModsList);
if (refreshDisabled) { addRegularModsToList(disabledMods, disabledRegularModsList); }
disabledRegularModsList.ClearChildren();
foreach (var mod in ContentPackageManager.RegularPackages)
{
if (ContentPackageManager.EnabledPackages.Regular.Contains(mod)) { continue; }
addRegularModToList(mod, disabledRegularModsList);
}
TaskPool.Add(
$"DetermineWorkshopModIcons",
SteamManager.Workshop.GetPublishedItems(),
t =>
{
if (!t.TryGetResult(out ISet<Steamworks.Ugc.Item> items)) { return; }
var ids = items.Select(it => it.Id).ToHashSet();
foreach (var child in enabledRegularModsList.Content.Children
.Concat(disabledRegularModsList.Content.Children))
{
var mod = child.UserData as RegularPackage;
if (mod is null || !ContentPackageManager.WorkshopPackages.Contains(mod)) { continue; }
var btn = child.GetChild<GUILayoutGroup>()?.GetAllChildren<GUIButton>().Last();
if (btn is null) { continue; }
if (btn.Style != null) { continue; }
btn.ApplyStyle(
GUIStyle.GetComponentStyle(
ids.Contains(mod.SteamWorkshopId)
? "WorkshopMenu.PublishedIcon"
: "WorkshopMenu.DownloadedIcon"));
btn.ToolTip = TextManager.Get(
ids.Contains(mod.SteamWorkshopId)
? "PublishedWorkshopMod"
: "DownloadedWorkshopMod");
btn.HoverCursor = CursorState.Default;
}
});
UpdateModListItemVisibility();
}
@@ -468,7 +591,8 @@ namespace Barotrauma.Steam
{
ContentPackageManager.EnabledPackages.SetCore(EnabledCorePackage);
ContentPackageManager.EnabledPackages.SetRegular(enabledRegularModsList.Content.Children
.Where(c => c.UserData is RegularPackage).Select(c => (RegularPackage)c.UserData).ToArray());
.Select(c => c.UserData as RegularPackage).OfType<RegularPackage>().ToArray());
PopulateInstalledModLists(forceRefreshEnabled: true, refreshDisabled: true);
}
}
}
@@ -105,5 +105,29 @@ namespace Barotrauma.Steam
protected GUIComponent CreateActionCarrier(GUIComponent parent, Identifier id, Action action)
=> new GUIFrame(new RectTransform(Vector2.Zero, parent.RectTransform), style: null)
{ UserData = new ActionCarrier(id, action) };
protected GUITextBox CreateSearchBox(GUILayoutGroup mainLayout, float width = 1.0f, float heightScale = 1.0f)
{
var searchRectT = NewItemRectT(mainLayout, heightScale: heightScale);
searchRectT.RelativeSize = (width, searchRectT.RelativeSize.Y);
var searchHolder = new GUIFrame(searchRectT, style: null);
var searchBox = new GUITextBox(new RectTransform(Vector2.One, searchHolder.RectTransform), "", createClearButton: true);
var searchTitle = new GUITextBlock(new RectTransform(Vector2.One, searchHolder.RectTransform) {Anchor = Anchor.TopLeft},
textColor: Color.DarkGray * 0.6f,
text: TextManager.Get("Search") + "...",
textAlignment: Alignment.CenterLeft)
{
CanBeFocused = false
};
searchBox.OnSelected += (sender, userdata) => { searchTitle.Visible = false; };
searchBox.OnDeselected += (sender, userdata) => { searchTitle.Visible = searchBox.Text.IsNullOrWhiteSpace(); };
searchBox.OnTextChanged += (sender, str) =>
{
UpdateModListItemVisibility();
return true;
};
return searchBox;
}
}
}
@@ -4,9 +4,8 @@ namespace Barotrauma.Steam
{
abstract partial class WorkshopMenu
{
public WorkshopMenu(GUIFrame parent)
{
}
public WorkshopMenu(GUIFrame parent) { }
protected abstract void UpdateModListItemVisibility();
}
}