Unstable 0.17.6.0
This commit is contained in:
@@ -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: () =>
|
||||
{
|
||||
|
||||
125
Barotrauma/BarotraumaClient/ClientSource/Steam/BulkDownloader.cs
Normal file
125
Barotrauma/BarotraumaClient/ClientSource/Steam/BulkDownloader.cs
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.17.5.0</Version>
|
||||
<Version>0.17.6.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>Barotrauma</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.17.5.0</Version>
|
||||
<Version>0.17.6.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>Barotrauma</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma</Product>
|
||||
<Version>0.17.5.0</Version>
|
||||
<Version>0.17.6.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>Barotrauma</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma Dedicated Server</Product>
|
||||
<Version>0.17.5.0</Version>
|
||||
<Version>0.17.6.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma Dedicated Server</Product>
|
||||
<Version>0.17.5.0</Version>
|
||||
<Version>0.17.6.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
|
||||
@@ -1116,7 +1116,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Server.SendTraitorMessage(client, string.Format("- Traitor {0} has no current objective.", "", t.Character.Name), Identifier.Empty, TraitorMessageType.Console);
|
||||
GameMain.Server.SendTraitorMessage(client, string.Format("- Traitor {0} has no current objective.", t.Character.Name), Identifier.Empty, TraitorMessageType.Console);
|
||||
}
|
||||
}
|
||||
//GameMain.Server.SendTraitorMessage(client, "The code words are: " + traitorManager.CodeWords + ", response: " + traitorManager.CodeResponse + ".", TraitorMessageType.Console);
|
||||
@@ -2234,11 +2234,6 @@ namespace Barotrauma
|
||||
if (args.Length < 2)
|
||||
{
|
||||
GameMain.Server.SendConsoleMessage("Invalid parameters. The command should be formatted as \"setclientcharacter [client] [character]\". If the names consist of multiple words, you should surround them with quotation marks.", senderClient, Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Length < 2)
|
||||
{
|
||||
ThrowError("Invalid parameters. The command should be formatted as \"setclientcharacter [client] [character]\". If the names consist of multiple words, you should surround them with quotation marks.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Barotrauma
|
||||
{
|
||||
partial class CargoManager
|
||||
{
|
||||
public void SellBackPurchasedItems(Identifier storeIdentifier, List<PurchasedItem> itemsToSell, Client client = null)
|
||||
public void SellBackPurchasedItems(Identifier storeIdentifier, List<PurchasedItem> itemsToSell, Client client)
|
||||
{
|
||||
// Check all the prices before starting the transaction to make sure the modifiers stay the same for the whole transaction
|
||||
var buyValues = GetBuyValuesAtCurrentLocation(storeIdentifier, itemsToSell.Select(i => i.ItemPrefab));
|
||||
@@ -40,7 +40,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void SellItems(Identifier storeIdentifier, List<SoldItem> itemsToSell, Client client)
|
||||
public void SellItems(Identifier storeIdentifier, List<SoldItem> itemsToSell)
|
||||
{
|
||||
var store = Location.GetStore(storeIdentifier);
|
||||
if (store == null) { return; }
|
||||
|
||||
@@ -564,6 +564,21 @@ namespace Barotrauma
|
||||
msg.Write((byte)selectedMissionIndex);
|
||||
}
|
||||
|
||||
var subList = GameMain.NetLobbyScreen.GetSubList();
|
||||
List<int> ownedSubmarineIndices = new List<int>();
|
||||
for (int i = 0; i < subList.Count; i++)
|
||||
{
|
||||
if (GameMain.GameSession.OwnedSubmarines.Any(s => s.Name == subList[i].Name))
|
||||
{
|
||||
ownedSubmarineIndices.Add(i);
|
||||
}
|
||||
}
|
||||
msg.Write((ushort)ownedSubmarineIndices.Count);
|
||||
foreach (int index in ownedSubmarineIndices)
|
||||
{
|
||||
msg.Write((ushort)index);
|
||||
}
|
||||
|
||||
msg.Write(map.AllowDebugTeleport);
|
||||
msg.Write(reputation != null);
|
||||
if (reputation != null) { msg.Write(reputation.Value); }
|
||||
@@ -768,8 +783,12 @@ namespace Barotrauma
|
||||
if (Map.SelectedConnection != null) { Map.SelectMission(selectedMissionIndices); }
|
||||
CheckTooManyMissions(Map.CurrentLocation, sender);
|
||||
}
|
||||
|
||||
var prevBuyCrateItems = new Dictionary<Identifier, List<PurchasedItem>>(CargoManager.ItemsInBuyCrate);
|
||||
|
||||
var prevBuyCrateItems = new Dictionary<Identifier, List<PurchasedItem>>();
|
||||
foreach (var kvp in CargoManager.ItemsInBuyCrate)
|
||||
{
|
||||
prevBuyCrateItems.Add(kvp.Key, new List<PurchasedItem>(kvp.Value));
|
||||
}
|
||||
foreach (var store in prevBuyCrateItems)
|
||||
{
|
||||
foreach (var item in store.Value)
|
||||
@@ -784,10 +803,15 @@ namespace Barotrauma
|
||||
CargoManager.ModifyItemQuantityInBuyCrate(store.Key, item.ItemPrefab, item.Quantity, sender);
|
||||
}
|
||||
}
|
||||
var prevPurchasedItems = new Dictionary<Identifier, List<PurchasedItem>>(CargoManager.PurchasedItems);
|
||||
|
||||
var prevPurchasedItems = new Dictionary<Identifier, List<PurchasedItem>>();
|
||||
foreach (var kvp in CargoManager.PurchasedItems)
|
||||
{
|
||||
prevPurchasedItems.Add(kvp.Key, new List<PurchasedItem>(kvp.Value));
|
||||
}
|
||||
foreach (var store in prevPurchasedItems)
|
||||
{
|
||||
CargoManager.SellBackPurchasedItems(store.Key, store.Value);
|
||||
CargoManager.SellBackPurchasedItems(store.Key, store.Value, sender);
|
||||
}
|
||||
foreach (var store in purchasedItems)
|
||||
{
|
||||
@@ -813,6 +837,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool allowedToSellInventoryItems = AllowedToManageCampaign(sender, ClientPermissions.SellInventoryItems);
|
||||
if (allowedToSellInventoryItems && allowedToSellSubItems)
|
||||
{
|
||||
@@ -825,7 +850,7 @@ namespace Barotrauma
|
||||
}
|
||||
foreach (var store in soldItems)
|
||||
{
|
||||
CargoManager.SellItems(store.Key, store.Value, sender);
|
||||
CargoManager.SellItems(store.Key, store.Value);
|
||||
}
|
||||
}
|
||||
else if (allowedToSellInventoryItems || allowedToSellSubItems)
|
||||
@@ -842,7 +867,7 @@ namespace Barotrauma
|
||||
}
|
||||
foreach (var store in soldItems)
|
||||
{
|
||||
CargoManager.SellItems(store.Key, store.Value, sender);
|
||||
CargoManager.SellItems(store.Key, store.Value);
|
||||
}
|
||||
bool predicate(SoldItem i) => allowedToSellInventoryItems != (i.Origin == SoldItem.SellOrigin.Character);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
@@ -15,7 +12,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
item.CreateServerEvent(this);
|
||||
|
||||
if (!item.CanClientAccess(c)) return;
|
||||
if (!item.CanClientAccess(c)) { return; }
|
||||
|
||||
if (recipeHash == 0)
|
||||
{
|
||||
@@ -64,6 +61,13 @@ namespace Barotrauma.Items.Components
|
||||
msg.Write(recipeHash);
|
||||
UInt16 userID = fabricatedItem is null || user is null ? (UInt16)0 : user.ID;
|
||||
msg.Write(userID);
|
||||
|
||||
var reachedLimits = fabricationLimits.Where(kvp => kvp.Value <= 0);
|
||||
msg.Write((ushort)reachedLimits.Count());
|
||||
foreach (var kvp in reachedLimits)
|
||||
{
|
||||
msg.Write(kvp.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
public bool CompareTo(string endpointCompare)
|
||||
{
|
||||
if (string.IsNullOrEmpty(EndPoint) || string.IsNullOrEmpty(EndPoint)) { return false; }
|
||||
if (string.IsNullOrEmpty(EndPoint) || string.IsNullOrEmpty(endpointCompare)) { return false; }
|
||||
if (!IsRangeBan)
|
||||
{
|
||||
return endpointCompare == EndPoint;
|
||||
|
||||
@@ -173,13 +173,14 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
OnStarted(transfer);
|
||||
GameMain.Server.LastClientListUpdateID++;
|
||||
|
||||
return transfer;
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
activeTransfers.RemoveAll(t => t.Connection.Status != NetworkConnectionStatus.Connected);
|
||||
int numRemoved = activeTransfers.RemoveAll(t => t.Connection.Status != NetworkConnectionStatus.Connected);
|
||||
|
||||
var endedTransfers = activeTransfers.FindAll(t =>
|
||||
t.Connection.Status != NetworkConnectionStatus.Connected ||
|
||||
@@ -202,6 +203,11 @@ namespace Barotrauma.Networking
|
||||
Send(transfer);
|
||||
}
|
||||
}
|
||||
|
||||
if (numRemoved > 0 || endedTransfers.Count > 0)
|
||||
{
|
||||
GameMain.Server.LastClientListUpdateID++;
|
||||
}
|
||||
}
|
||||
|
||||
private void Send(FileTransferOut transfer)
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Barotrauma.Networking
|
||||
string resultFileName
|
||||
= dir.StartsWith(ContentPackage.LocalModsDir)
|
||||
? $"Local_{mod.Name}"
|
||||
: $"Workshop_{mod.Name}";
|
||||
: $"Workshop_{mod.Name}_{mod.SteamWorkshopId}";
|
||||
resultFileName = ToolBox.RemoveInvalidFileNameChars(resultFileName.Replace('\\', '_').Replace('/', '_'));
|
||||
resultFileName = $"{resultFileName}{Extension}";
|
||||
return Path.Combine(UploadFolder, resultFileName);
|
||||
|
||||
@@ -1587,25 +1587,6 @@ namespace Barotrauma.Networking
|
||||
outmsg.Write(serverSettings.AllowSpectating);
|
||||
|
||||
c.WritePermissions(outmsg);
|
||||
|
||||
if (gameStarted)
|
||||
{
|
||||
string ownedSubmarineIndexes = string.Empty;
|
||||
for (int i = 0; i < subList.Count; i++)
|
||||
{
|
||||
if (GameMain.GameSession.OwnedSubmarines.Contains(subList[i]))
|
||||
{
|
||||
ownedSubmarineIndexes += i.ToString();
|
||||
ownedSubmarineIndexes += ";";
|
||||
}
|
||||
}
|
||||
|
||||
if (ownedSubmarineIndexes.Length > 0)
|
||||
{
|
||||
ownedSubmarineIndexes.Trim(';');
|
||||
}
|
||||
outmsg.Write(ownedSubmarineIndexes);
|
||||
}
|
||||
}
|
||||
|
||||
private void ClientWriteIngame(Client c)
|
||||
@@ -1807,29 +1788,30 @@ namespace Barotrauma.Networking
|
||||
outmsg.Write((byte)connectedClients.Count);
|
||||
foreach (Client client in connectedClients)
|
||||
{
|
||||
outmsg.Write(client.ID);
|
||||
outmsg.Write(client.SteamID);
|
||||
outmsg.Write(client.NameID);
|
||||
outmsg.Write(client.Name);
|
||||
outmsg.Write(client.Character?.Info?.Job != null && gameStarted ? client.Character.Info.Job.Prefab.Identifier : client.PreferredJob);
|
||||
outmsg.Write((byte)client.PreferredTeam);
|
||||
outmsg.Write(client.Character == null || !gameStarted ? (ushort)0 : client.Character.ID);
|
||||
if (c.HasPermission(ClientPermissions.ServerLog))
|
||||
var tempClientData = new TempClient
|
||||
{
|
||||
outmsg.Write(client.Karma);
|
||||
}
|
||||
else
|
||||
{
|
||||
outmsg.Write(100.0f);
|
||||
}
|
||||
outmsg.Write(client.Muted);
|
||||
outmsg.Write(client.InGame);
|
||||
outmsg.Write(client.Permissions != ClientPermissions.None);
|
||||
outmsg.Write(client.Connection == OwnerConnection);
|
||||
outmsg.Write(client.Connection != OwnerConnection &&
|
||||
!client.HasPermission(ClientPermissions.Ban) &&
|
||||
!client.HasPermission(ClientPermissions.Kick) &&
|
||||
!client.HasPermission(ClientPermissions.Unban)); //is kicking the player allowed
|
||||
ID = client.ID,
|
||||
SteamID = client.SteamID,
|
||||
NameID = client.NameID,
|
||||
Name = client.Name,
|
||||
PreferredJob = client.Character?.Info?.Job != null && gameStarted
|
||||
? client.Character.Info.Job.Prefab.Identifier
|
||||
: client.PreferredJob,
|
||||
PreferredTeam = client.PreferredTeam,
|
||||
CharacterID = client.Character == null || !gameStarted ? (ushort)0 : client.Character.ID,
|
||||
Karma = c.HasPermission(ClientPermissions.ServerLog) ? client.Karma : 100.0f,
|
||||
Muted = client.Muted,
|
||||
InGame = client.InGame,
|
||||
HasPermissions = client.Permissions != ClientPermissions.None,
|
||||
IsOwner = client.Connection == OwnerConnection,
|
||||
AllowKicking = client.Connection != OwnerConnection &&
|
||||
!client.HasPermission(ClientPermissions.Ban) &&
|
||||
!client.HasPermission(ClientPermissions.Kick) &&
|
||||
!client.HasPermission(ClientPermissions.Unban),
|
||||
IsDownloading = FileSender.ActiveTransfers.Any(t => t.Connection == client.Connection)
|
||||
};
|
||||
|
||||
outmsg.Write(tempClientData);
|
||||
outmsg.WritePadBits();
|
||||
}
|
||||
}
|
||||
@@ -3218,7 +3200,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
Voting.ActiveVote.Finish(Voting, passed: false);
|
||||
}
|
||||
else if (yes / max >= serverSettings.VoteRequiredRatio)
|
||||
else if (yes / (float)max >= serverSettings.VoteRequiredRatio)
|
||||
{
|
||||
Voting.ActiveVote.Finish(Voting, passed: true);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<RootNamespace>Barotrauma</RootNamespace>
|
||||
<Authors>FakeFish, Undertow Games</Authors>
|
||||
<Product>Barotrauma Dedicated Server</Product>
|
||||
<Version>0.17.5.0</Version>
|
||||
<Version>0.17.6.0</Version>
|
||||
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
<AssemblyName>DedicatedServer</AssemblyName>
|
||||
|
||||
@@ -3450,7 +3450,7 @@ namespace Barotrauma
|
||||
{
|
||||
ChangeParams("wall", state, priority / 2);
|
||||
}
|
||||
if (canAttackDoors)
|
||||
if (canAttackDoors && IsAggressiveBoarder)
|
||||
{
|
||||
ChangeParams("door", state, priority / 2);
|
||||
}
|
||||
|
||||
@@ -376,19 +376,17 @@ namespace Barotrauma
|
||||
{
|
||||
Vector2 diff = currentPath.CurrentNode.WorldPosition - pos;
|
||||
bool nextLadderSameAsCurrent = IsNextLadderSameAsCurrent;
|
||||
if (nextLadderSameAsCurrent)
|
||||
if (nextLadderSameAsCurrent || currentLadder != null && nextLadder != null && Math.Abs(currentLadder.Item.Position.X - nextLadder.Item.Position.X) < 50)
|
||||
{
|
||||
//climbing ladders -> don't move horizontally
|
||||
diff.X = 0.0f;
|
||||
}
|
||||
//at the same height as the waypoint
|
||||
if (Math.Abs(collider.SimPosition.Y - currentPath.CurrentNode.SimPosition.Y) < (collider.height / 2 + collider.radius) * 1.25f)
|
||||
float heightDiff = Math.Abs(collider.SimPosition.Y - currentPath.CurrentNode.SimPosition.Y);
|
||||
float colliderSize = (collider.height / 2 + collider.radius) * 1.25f;
|
||||
if (heightDiff < colliderSize)
|
||||
{
|
||||
float heightFromFloor = character.AnimController.GetHeightFromFloor();
|
||||
if (heightFromFloor <= 0.0f)
|
||||
{
|
||||
diff.Y = Math.Max(diff.Y, 100);
|
||||
}
|
||||
// We need some margin, because if a hatch has closed, it's possible that the height from floor is slightly negative.
|
||||
bool isAboveFloor = heightFromFloor > -0.1f;
|
||||
// If the next waypoint is horizontally far, we don't want to keep holding the ladders
|
||||
@@ -402,7 +400,10 @@ namespace Barotrauma
|
||||
// Try to change the ladder (hatches between two submarines)
|
||||
if (character.SelectedConstruction != nextLadder.Item && nextLadder.Item.IsInsideTrigger(character.WorldPosition))
|
||||
{
|
||||
nextLadder.Item.TryInteract(character, forceSelectKey: true);
|
||||
if (nextLadder.Item.TryInteract(character, forceSelectKey: true))
|
||||
{
|
||||
NextNode(!doorsChecked);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isAboveFloor || nextLadderSameAsCurrent)
|
||||
@@ -461,12 +462,16 @@ namespace Barotrauma
|
||||
bool isTargetTooLow = currentPath.CurrentNode.SimPosition.Y < colliderBottom.Y;
|
||||
var door = currentPath.CurrentNode.ConnectedDoor;
|
||||
float margin = MathHelper.Lerp(1, 10, MathHelper.Clamp(Math.Abs(velocity.X) / 5, 0, 1));
|
||||
if (currentPath.CurrentNode.Stairs != null && currentPath.NextNode?.Stairs == null)
|
||||
if (currentPath.CurrentNode.Stairs != null)
|
||||
{
|
||||
margin = 1;
|
||||
if (currentPath.CurrentNode.SimPosition.Y < colliderBottom.Y + character.AnimController.ColliderHeightFromFloor * 0.25f)
|
||||
bool isNextNodeInSameStairs = currentPath.NextNode?.Stairs == currentPath.CurrentNode.Stairs;
|
||||
if (!isNextNodeInSameStairs)
|
||||
{
|
||||
isTargetTooLow = true;
|
||||
margin = 1;
|
||||
if (currentPath.CurrentNode.SimPosition.Y < colliderBottom.Y + character.AnimController.ColliderHeightFromFloor * 0.25f)
|
||||
{
|
||||
isTargetTooLow = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
float targetDistance = Math.Max(colliderSize.X / 2 * margin, minWidth / 2);
|
||||
|
||||
@@ -630,7 +630,7 @@ namespace Barotrauma
|
||||
public bool IsActiveObjective<T>() where T : AIObjective => GetActiveObjective() is T;
|
||||
|
||||
public AIObjective GetActiveObjective() => CurrentObjective?.GetActiveObjective();
|
||||
public T GetOrder<T>() where T : AIObjective => CurrentOrders.FirstOrDefault(o => o.Objective is T).Objective as T;
|
||||
public T GetOrder<T>() where T : AIObjective => CurrentOrders.FirstOrDefault(o => o.Objective is T)?.Objective as T;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the last active objective of the specific type.
|
||||
|
||||
@@ -24,6 +24,8 @@ namespace Barotrauma
|
||||
public bool IsAiming => wasAiming;
|
||||
public bool IsAimingMelee => wasAimingMelee;
|
||||
|
||||
protected bool Aiming => aiming || aimingMelee;
|
||||
|
||||
public float ArmLength => upperArmLength + forearmLength;
|
||||
|
||||
public abstract GroundedMovementParams WalkParams { get; set; }
|
||||
|
||||
@@ -193,7 +193,7 @@ namespace Barotrauma
|
||||
strongestImpact = 0.0f;
|
||||
}
|
||||
|
||||
if (aiming)
|
||||
if (Aiming)
|
||||
{
|
||||
TargetMovement = TargetMovement.ClampLength(2);
|
||||
}
|
||||
@@ -233,7 +233,7 @@ namespace Barotrauma
|
||||
//don't flip when simply physics is enabled
|
||||
if (SimplePhysicsEnabled) { return; }
|
||||
|
||||
if (!character.IsRemotelyControlled && (character.AIController == null || character.AIController.CanFlip) && !aiming)
|
||||
if (!character.IsRemotelyControlled && (character.AIController == null || character.AIController.CanFlip) && !Aiming)
|
||||
{
|
||||
if (!inWater || (CurrentSwimParams != null && CurrentSwimParams.Mirror))
|
||||
{
|
||||
|
||||
@@ -597,11 +597,11 @@ namespace Barotrauma
|
||||
{
|
||||
float torsoAngle = TorsoAngle.Value;
|
||||
float herpesStrength = character.CharacterHealth.GetAfflictionStrength("spaceherpes");
|
||||
if (Crouching && !movingHorizontally && !aiming) { torsoAngle -= HumanCrouchParams.ExtraTorsoAngleWhenStationary; }
|
||||
if (Crouching && !movingHorizontally && !Aiming) { torsoAngle -= HumanCrouchParams.ExtraTorsoAngleWhenStationary; }
|
||||
torsoAngle -= herpesStrength / 150.0f;
|
||||
torso.body.SmoothRotate(torsoAngle * Dir, CurrentGroundedParams.TorsoTorque);
|
||||
}
|
||||
if (!aiming && CurrentGroundedParams.FixedHeadAngle && HeadAngle.HasValue)
|
||||
if (!Aiming && CurrentGroundedParams.FixedHeadAngle && HeadAngle.HasValue)
|
||||
{
|
||||
float headAngle = HeadAngle.Value;
|
||||
if (Crouching && !movingHorizontally) { headAngle -= HumanCrouchParams.ExtraHeadAngleWhenStationary; }
|
||||
@@ -817,48 +817,16 @@ namespace Barotrauma
|
||||
Limb torso = GetLimb(LimbType.Torso);
|
||||
if (head == null) { return; }
|
||||
if (torso == null) { return; }
|
||||
|
||||
//check both hulls: the hull whose coordinate space the ragdoll is in, and the hull whose bounds the character's origin actually is inside
|
||||
|
||||
const float DisableMovementAboveSurfaceThreshold = 50.0f;
|
||||
|
||||
if (currentHull != null && character.CurrentHull != null)
|
||||
{
|
||||
float surfacePos = currentHull.Surface;
|
||||
float surfacePos = GetSurfaceY();
|
||||
float surfaceThreshold = ConvertUnits.ToDisplayUnits(Collider.SimPosition.Y + 1.0f);
|
||||
//if the hull is almost full of water, check if there's a water-filled hull above it
|
||||
//and use its water surface instead of the current hull's
|
||||
if (currentHull.Rect.Y - currentHull.Surface < 5.0f)
|
||||
{
|
||||
GetSurfacePos(currentHull, ref surfacePos);
|
||||
void GetSurfacePos(Hull hull, ref float prevSurfacePos)
|
||||
{
|
||||
if (prevSurfacePos > surfaceThreshold) { return; }
|
||||
foreach (Gap gap in hull.ConnectedGaps)
|
||||
{
|
||||
if (gap.IsHorizontal || gap.Open <= 0.0f || gap.WorldPosition.Y < hull.WorldPosition.Y) { continue; }
|
||||
if (Collider.SimPosition.X < ConvertUnits.ToSimUnits(gap.Rect.X) || Collider.SimPosition.X > ConvertUnits.ToSimUnits(gap.Rect.Right)) { continue; }
|
||||
|
||||
//if the gap is above us and leads outside, there's no surface to limit the movement
|
||||
if (!gap.IsRoomToRoom && gap.Position.Y > hull.Position.Y)
|
||||
{
|
||||
prevSurfacePos += 100000.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var linkedTo in gap.linkedTo)
|
||||
{
|
||||
if (linkedTo is Hull otherHull && otherHull != hull && otherHull != currentHull)
|
||||
{
|
||||
prevSurfacePos = Math.Max(surfacePos, otherHull.Surface);
|
||||
GetSurfacePos(otherHull, ref prevSurfacePos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
surfaceLimiter = Math.Max(1.0f, surfaceThreshold - surfacePos);
|
||||
if (surfaceLimiter > 50.0f) { return; }
|
||||
}
|
||||
if (surfaceLimiter > DisableMovementAboveSurfaceThreshold) { return; }
|
||||
}
|
||||
|
||||
Limb leftHand = GetLimb(LimbType.LeftHand);
|
||||
Limb rightHand = GetLimb(LimbType.RightHand);
|
||||
@@ -872,25 +840,30 @@ namespace Barotrauma
|
||||
{
|
||||
rotation += 360;
|
||||
}
|
||||
if (!character.IsRemotelyControlled && !aiming && Anim != Animation.UsingConstruction &&
|
||||
!(character.SelectedConstruction?.GetComponent<Controller>()?.ControlCharacterPose ?? false))
|
||||
float targetSpeed = TargetMovement.Length();
|
||||
if (targetSpeed > 0.1f && !character.IsRemotelyControlled && !character.IsKeyDown(InputType.Aim))
|
||||
{
|
||||
if (rotation > 20 && rotation < 170)
|
||||
if (Anim != Animation.UsingConstruction && !(character.SelectedConstruction?.GetComponent<Controller>()?.ControlCharacterPose ?? false))
|
||||
{
|
||||
TargetDir = Direction.Left;
|
||||
}
|
||||
else if (rotation > 190 && rotation < 340)
|
||||
{
|
||||
TargetDir = Direction.Right;
|
||||
if (rotation > 20 && rotation < 170)
|
||||
{
|
||||
TargetDir = Direction.Left;
|
||||
}
|
||||
else if (rotation > 190 && rotation < 340)
|
||||
{
|
||||
TargetDir = Direction.Right;
|
||||
}
|
||||
}
|
||||
}
|
||||
float targetSpeed = TargetMovement.Length();
|
||||
if (aiming)
|
||||
if (Aiming)
|
||||
{
|
||||
Vector2 mousePos = ConvertUnits.ToSimUnits(character.CursorPosition);
|
||||
Vector2 diff = (mousePos - torso.SimPosition) * Dir;
|
||||
float newRotation = MathUtils.VectorToAngle(diff);
|
||||
Collider.SmoothRotate(newRotation, CurrentSwimParams.SteerTorque * character.SpeedMultiplier);
|
||||
if (diff.LengthSquared() > MathUtils.Pow2(0.4f))
|
||||
{
|
||||
float newRotation = MathHelper.WrapAngle(MathUtils.VectorToAngle(diff) - MathHelper.PiOver4 * Dir);
|
||||
Collider.SmoothRotate(newRotation, CurrentSwimParams.SteerTorque * character.SpeedMultiplier);
|
||||
}
|
||||
}
|
||||
else if (targetSpeed > 0.1f)
|
||||
{
|
||||
@@ -911,7 +884,7 @@ namespace Barotrauma
|
||||
torso.body.SmoothRotate(Collider.Rotation, CurrentSwimParams.TorsoTorque);
|
||||
}
|
||||
|
||||
if (!aiming && CurrentSwimParams.FixedHeadAngle && HeadAngle.HasValue)
|
||||
if (!Aiming && CurrentSwimParams.FixedHeadAngle && HeadAngle.HasValue)
|
||||
{
|
||||
head.body.SmoothRotate(Collider.Rotation + HeadAngle.Value * Dir, CurrentSwimParams.HeadTorque);
|
||||
}
|
||||
@@ -940,7 +913,7 @@ namespace Barotrauma
|
||||
head.body.ApplyTorque(Dir);
|
||||
}
|
||||
|
||||
movement.Y = movement.Y * (1.0f - ((surfaceLimiter - 1.0f) / 50.0f));
|
||||
movement.Y = movement.Y * (1.0f - ((surfaceLimiter - 1.0f) / DisableMovementAboveSurfaceThreshold));
|
||||
}
|
||||
|
||||
bool isNotRemote = true;
|
||||
@@ -1141,10 +1114,9 @@ namespace Barotrauma
|
||||
bottomPos + torsoPos + movement.Y * 0.1f - ladderSimPos.Y);
|
||||
if (climbFast) { handPos.Y -= stepHeight; }
|
||||
|
||||
bool aiming = this.aiming || aimingMelee;
|
||||
//prevent the hands from going above the top of the ladders
|
||||
handPos.Y = Math.Min(-0.5f, handPos.Y);
|
||||
if (!aiming || !(character.Inventory?.GetItemInLimbSlot(InvSlotType.RightHand)?.GetComponent<Holdable>()?.ControlPose ?? false) || Math.Abs(movement.Y) > 0.01f)
|
||||
if (!Aiming || !(character.Inventory?.GetItemInLimbSlot(InvSlotType.RightHand)?.GetComponent<Holdable>()?.ControlPose ?? false) || Math.Abs(movement.Y) > 0.01f)
|
||||
{
|
||||
MoveLimb(rightHand,
|
||||
new Vector2(slide ? handPos.X + ladderSimSize.X * 0.5f : handPos.X,
|
||||
@@ -1152,7 +1124,7 @@ namespace Barotrauma
|
||||
5.2f);
|
||||
rightHand.body.ApplyTorque(Dir * 2.0f);
|
||||
}
|
||||
if (!aiming || !(character.Inventory?.GetItemInLimbSlot(InvSlotType.LeftHand)?.GetComponent<Holdable>()?.ControlPose ?? false) || Math.Abs(movement.Y) > 0.01f)
|
||||
if (!Aiming || !(character.Inventory?.GetItemInLimbSlot(InvSlotType.LeftHand)?.GetComponent<Holdable>()?.ControlPose ?? false) || Math.Abs(movement.Y) > 0.01f)
|
||||
{
|
||||
MoveLimb(leftHand,
|
||||
new Vector2(handPos.X - ladderSimSize.X * 0.5f,
|
||||
@@ -1235,7 +1207,7 @@ namespace Barotrauma
|
||||
|
||||
//apply forces to the collider to move the Character up/down
|
||||
Collider.ApplyForce((climbForce * 20.0f + subSpeed * 50.0f) * Collider.Mass);
|
||||
if (aiming)
|
||||
if (Aiming)
|
||||
{
|
||||
RotateHead(head);
|
||||
}
|
||||
@@ -1526,11 +1498,14 @@ namespace Barotrauma
|
||||
return;
|
||||
}
|
||||
Limb targetTorso = target.AnimController.GetLimb(LimbType.Torso);
|
||||
if (targetTorso == null) targetTorso = target.AnimController.MainLimb;
|
||||
|
||||
if (targetTorso == null)
|
||||
{
|
||||
targetTorso = target.AnimController.MainLimb;
|
||||
}
|
||||
if (target.AnimController.Dir != Dir)
|
||||
{
|
||||
target.AnimController.Flip();
|
||||
|
||||
}
|
||||
Vector2 transformedTorsoPos = torso.SimPosition;
|
||||
if (character.Submarine == null && target.Submarine != null)
|
||||
{
|
||||
@@ -1574,7 +1549,10 @@ namespace Barotrauma
|
||||
{
|
||||
//only grab with one hand when swimming
|
||||
leftHand.Disabled = true;
|
||||
if (!inWater) rightHand.Disabled = true;
|
||||
if (!inWater)
|
||||
{
|
||||
rightHand.Disabled = true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
|
||||
@@ -1193,13 +1193,9 @@ namespace Barotrauma
|
||||
headInWater = false;
|
||||
inWater = false;
|
||||
RefreshFloorY(ignoreStairs: Stairs == null);
|
||||
if (currentHull.WaterVolume > currentHull.Volume * 0.95f)
|
||||
if (currentHull.WaterPercentage > 0.001f)
|
||||
{
|
||||
inWater = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
float waterSurface = ConvertUnits.ToSimUnits(currentHull.Surface);
|
||||
float waterSurface = ConvertUnits.ToSimUnits(GetSurfaceY());
|
||||
if (targetMovement.Y < 0.0f)
|
||||
{
|
||||
Vector2 colliderBottom = GetColliderBottom();
|
||||
@@ -1212,11 +1208,8 @@ namespace Barotrauma
|
||||
if (lowerHull != null) floorY = ConvertUnits.ToSimUnits(lowerHull.Rect.Y - lowerHull.Rect.Height);
|
||||
}
|
||||
}
|
||||
float standHeight =
|
||||
HeadPosition.HasValue ? HeadPosition.Value :
|
||||
TorsoPosition.HasValue ? TorsoPosition.Value :
|
||||
Collider.GetMaxExtent() * 0.5f;
|
||||
if (Collider.SimPosition.Y < waterSurface && waterSurface - floorY > standHeight * 0.95f)
|
||||
float standHeight = HeadPosition ?? TorsoPosition ?? Collider.GetMaxExtent() * 0.5f;
|
||||
if (Collider.SimPosition.Y < waterSurface && waterSurface - floorY > standHeight * 0.8f)
|
||||
{
|
||||
inWater = true;
|
||||
}
|
||||
@@ -1521,7 +1514,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private float GetFloorY(Vector2 simPosition, bool ignoreStairs = false)
|
||||
{
|
||||
onGround = false;
|
||||
@@ -1640,6 +1632,51 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public float GetSurfaceY()
|
||||
{
|
||||
//check both hulls: the hull whose coordinate space the ragdoll is in, and the hull whose bounds the character's origin actually is inside
|
||||
if (currentHull == null || character.CurrentHull == null)
|
||||
{
|
||||
return float.PositiveInfinity;
|
||||
}
|
||||
|
||||
float surfacePos = currentHull.Surface;
|
||||
float surfaceThreshold = ConvertUnits.ToDisplayUnits(Collider.SimPosition.Y + 1.0f);
|
||||
//if the hull is almost full of water, check if there's a water-filled hull above it
|
||||
//and use its water surface instead of the current hull's
|
||||
if (currentHull.Rect.Y - currentHull.Surface < 5.0f)
|
||||
{
|
||||
GetSurfacePos(currentHull, ref surfacePos);
|
||||
void GetSurfacePos(Hull hull, ref float prevSurfacePos)
|
||||
{
|
||||
if (prevSurfacePos > surfaceThreshold) { return; }
|
||||
foreach (Gap gap in hull.ConnectedGaps)
|
||||
{
|
||||
if (gap.IsHorizontal || gap.Open <= 0.0f || gap.WorldPosition.Y < hull.WorldPosition.Y) { continue; }
|
||||
if (Collider.SimPosition.X < ConvertUnits.ToSimUnits(gap.Rect.X) || Collider.SimPosition.X > ConvertUnits.ToSimUnits(gap.Rect.Right)) { continue; }
|
||||
|
||||
//if the gap is above us and leads outside, there's no surface to limit the movement
|
||||
if (!gap.IsRoomToRoom && gap.Position.Y > hull.Position.Y)
|
||||
{
|
||||
prevSurfacePos += 100000.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var linkedTo in gap.linkedTo)
|
||||
{
|
||||
if (linkedTo is Hull otherHull && otherHull != hull && otherHull != currentHull)
|
||||
{
|
||||
prevSurfacePos = Math.Max(surfacePos, otherHull.Surface);
|
||||
GetSurfacePos(otherHull, ref prevSurfacePos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return surfacePos;
|
||||
}
|
||||
|
||||
public void SetPosition(Vector2 simPosition, bool lerp = false, bool ignorePlatforms = true, bool forceMainLimbToCollider = false, bool detachProjectiles = true)
|
||||
{
|
||||
if (!MathUtils.IsValid(simPosition))
|
||||
|
||||
@@ -349,7 +349,6 @@ namespace Barotrauma
|
||||
DamageRange = range;
|
||||
StructureDamage = LevelWallDamage = structureDamage;
|
||||
ItemDamage = itemDamage;
|
||||
Penetration = Penetration;
|
||||
}
|
||||
|
||||
public Attack(ContentXElement element, string parentDebugName, Item sourceItem) : this(element, parentDebugName)
|
||||
@@ -359,7 +358,7 @@ namespace Barotrauma
|
||||
|
||||
public Attack(ContentXElement element, string parentDebugName)
|
||||
{
|
||||
Deserialize(element);
|
||||
Deserialize(element, parentDebugName);
|
||||
|
||||
if (element.GetAttribute("damage") != null ||
|
||||
element.GetAttribute("bluntdamage") != null ||
|
||||
@@ -423,7 +422,7 @@ namespace Barotrauma
|
||||
}
|
||||
partial void InitProjSpecific(ContentXElement element);
|
||||
|
||||
public void ReloadAfflictions(XElement element)
|
||||
public void ReloadAfflictions(XElement element, string parentDebugName)
|
||||
{
|
||||
Afflictions.Clear();
|
||||
foreach (var subElement in element.GetChildElements("affliction"))
|
||||
@@ -431,6 +430,11 @@ namespace Barotrauma
|
||||
AfflictionPrefab afflictionPrefab;
|
||||
Affliction affliction;
|
||||
Identifier afflictionIdentifier = subElement.GetAttributeIdentifier("identifier", "");
|
||||
if (!AfflictionPrefab.Prefabs.ContainsKey(afflictionIdentifier))
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in an Attack defined in \"{parentDebugName}\" - could not find an affliction with the identifier \"{afflictionIdentifier}\".");
|
||||
continue;
|
||||
}
|
||||
afflictionPrefab = AfflictionPrefab.Prefabs[afflictionIdentifier];
|
||||
affliction = afflictionPrefab.Instantiate(0.0f);
|
||||
affliction.Deserialize(subElement);
|
||||
@@ -456,10 +460,10 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void Deserialize(XElement element)
|
||||
public void Deserialize(XElement element, string parentDebugName)
|
||||
{
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this, element);
|
||||
ReloadAfflictions(element);
|
||||
ReloadAfflictions(element, parentDebugName);
|
||||
}
|
||||
|
||||
public AttackResult DoDamage(Character attacker, IDamageable target, Vector2 worldPosition, float deltaTime, bool playSound = true, PhysicsBody sourceBody = null, Limb sourceLimb = null)
|
||||
|
||||
@@ -556,6 +556,12 @@ namespace Barotrauma
|
||||
|
||||
#if CLIENT
|
||||
CharacterHealth.SetHealthBarVisibility(value == null);
|
||||
#elif SERVER
|
||||
if (value is { IsDead: true, Wallet: { Balance: var balance } grabbedWallet })
|
||||
{
|
||||
Wallet.Give(balance);
|
||||
grabbedWallet.Deduct(balance);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1180,7 +1186,7 @@ namespace Barotrauma
|
||||
CharacterHealth = new CharacterHealth(selectedHealthElement, this, limbHealthElement);
|
||||
}
|
||||
|
||||
if (Params.Husk)
|
||||
if (Params.Husk && speciesName != "husk")
|
||||
{
|
||||
// Get the non husked name and find the ragdoll with it
|
||||
var matchingAffliction = AfflictionPrefab.List
|
||||
@@ -1764,26 +1770,44 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
if (!aiControlled &&
|
||||
AnimController.OnGround &&
|
||||
!AnimController.InWater &&
|
||||
AnimController.Anim != AnimController.Animation.UsingConstruction &&
|
||||
AnimController.Anim != AnimController.Animation.CPR &&
|
||||
(GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient || Controlled == this))
|
||||
(GameMain.NetworkMember == null || !GameMain.NetworkMember.IsClient || Controlled == this) &&
|
||||
(AnimController.OnGround && !AnimController.InWater || IsKeyDown(InputType.Aim) && HeldItems.None(i => i.RequireAimToUse)))
|
||||
{
|
||||
//Limb head = AnimController.GetLimb(LimbType.Head);
|
||||
// Values lower than this seem to cause constantious flipping when the mouse is near the player and the player is running, because the root collider moves after flipping.
|
||||
float followMargin = 40;
|
||||
if (dontFollowCursor)
|
||||
{
|
||||
AnimController.TargetDir = Direction.Right;
|
||||
}
|
||||
else if (cursorPosition.X < AnimController.Collider.Position.X - followMargin)
|
||||
else
|
||||
{
|
||||
AnimController.TargetDir = Direction.Left;
|
||||
}
|
||||
else if (cursorPosition.X > AnimController.Collider.Position.X + followMargin)
|
||||
{
|
||||
AnimController.TargetDir = Direction.Right;
|
||||
// Values lower than this seem to cause constantious flipping when the mouse is near the player and the player is running, because the root collider moves after flipping.
|
||||
float followMargin = 40;
|
||||
Vector2 diff = CursorPosition - AnimController.Collider.Position;
|
||||
if (InWater)
|
||||
{
|
||||
followMargin = 80;
|
||||
diff = Vector2.Transform(diff, Matrix.CreateRotationZ(-AnimController.Collider.Rotation));
|
||||
if (diff.X < followMargin)
|
||||
{
|
||||
AnimController.TargetDir = Direction.Left;
|
||||
}
|
||||
else if (diff.X > followMargin)
|
||||
{
|
||||
AnimController.TargetDir = Direction.Right;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CursorPosition.X < AnimController.Collider.Position.X - followMargin)
|
||||
{
|
||||
AnimController.TargetDir = Direction.Left;
|
||||
}
|
||||
else if (CursorPosition.X > AnimController.Collider.Position.X + followMargin)
|
||||
{
|
||||
AnimController.TargetDir = Direction.Right;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,16 +53,18 @@ namespace Barotrauma
|
||||
continue;
|
||||
}
|
||||
var vitalityMultipliers = subElement.GetAttributeIdentifierArray("identifier", null) ?? subElement.GetAttributeIdentifierArray("identifiers", null);
|
||||
if (vitalityMultipliers == null)
|
||||
{
|
||||
vitalityMultipliers = subElement.GetAttributeIdentifierArray("type", null) ?? subElement.GetAttributeIdentifierArray("types", null);
|
||||
}
|
||||
if (vitalityMultipliers != null)
|
||||
{
|
||||
float multiplier = subElement.GetAttributeFloat("multiplier", 1.0f);
|
||||
vitalityMultipliers.ForEach(i => VitalityMultipliers.Add(i, multiplier));
|
||||
}
|
||||
else
|
||||
var vitalityTypeMultipliers = subElement.GetAttributeIdentifierArray("type", null) ?? subElement.GetAttributeIdentifierArray("types", null);
|
||||
if (vitalityTypeMultipliers != null)
|
||||
{
|
||||
float multiplier = subElement.GetAttributeFloat("multiplier", 1.0f);
|
||||
vitalityTypeMultipliers.ForEach(i => VitalityTypeMultipliers.Add(i, multiplier));
|
||||
}
|
||||
if (vitalityMultipliers == null && VitalityTypeMultipliers == null)
|
||||
{
|
||||
DebugConsole.ThrowError($"Error in character health config {characterHealth.Character.Name}: affliction identifier(s) or type(s) not defined in the \"VitalityMultiplier\" elements!");
|
||||
}
|
||||
|
||||
@@ -1116,14 +1116,13 @@ namespace Barotrauma
|
||||
|
||||
public AttackParams(ContentXElement element, RagdollParams ragdoll) : base(element, ragdoll)
|
||||
{
|
||||
var prefab = CharacterPrefab.Prefabs[ragdoll.SpeciesName];
|
||||
Attack = new Attack(element, ragdoll.SpeciesName.Value);
|
||||
}
|
||||
|
||||
public override bool Deserialize(XElement element = null, bool recursive = true)
|
||||
{
|
||||
base.Deserialize(element, recursive);
|
||||
Attack.Deserialize(element ?? Element);
|
||||
Attack.Deserialize(element ?? Element, parentDebugName: Ragdoll?.SpeciesName.ToString() ?? "null");
|
||||
return SerializableProperties != null;
|
||||
}
|
||||
|
||||
@@ -1137,8 +1136,8 @@ namespace Barotrauma
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
Attack.Deserialize(OriginalElement);
|
||||
Attack.ReloadAfflictions(OriginalElement);
|
||||
Attack.Deserialize(OriginalElement, parentDebugName: Ragdoll?.SpeciesName.ToString() ?? "null");
|
||||
Attack.ReloadAfflictions(OriginalElement, parentDebugName: Ragdoll?.SpeciesName.ToString() ?? "null");
|
||||
}
|
||||
|
||||
public bool AddNewAffliction()
|
||||
@@ -1149,7 +1148,7 @@ namespace Barotrauma
|
||||
new XAttribute("strength", 0f),
|
||||
new XAttribute("probability", 1.0f));
|
||||
Element.Add(subElement);
|
||||
Attack.ReloadAfflictions(Element);
|
||||
Attack.ReloadAfflictions(Element, parentDebugName: Ragdoll?.SpeciesName.ToString() ?? "null");
|
||||
Serialize();
|
||||
return true;
|
||||
}
|
||||
@@ -1158,7 +1157,7 @@ namespace Barotrauma
|
||||
{
|
||||
Serialize();
|
||||
affliction.Remove();
|
||||
Attack.ReloadAfflictions(Element);
|
||||
Attack.ReloadAfflictions(Element, parentDebugName: Ragdoll?.SpeciesName.ToString() ?? "null");
|
||||
return Serialize();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
[NotSyncedInMultiplayer]
|
||||
sealed class ItemAssemblyFile : GenericPrefabFile<ItemAssemblyPrefab>
|
||||
{
|
||||
public ItemAssemblyFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { }
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
@@ -156,6 +156,19 @@ namespace Barotrauma
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static void DisableMods(IReadOnlyCollection<ContentPackage> mods)
|
||||
{
|
||||
if (Core != null && mods.Contains(Core))
|
||||
{
|
||||
var newCore = ContentPackageManager.CorePackages.FirstOrDefault(p => !mods.Contains(p));
|
||||
if (newCore != null)
|
||||
{
|
||||
SetCore(newCore);
|
||||
}
|
||||
}
|
||||
SetRegular(Regular.Where(p => !mods.Contains(p)).ToArray());
|
||||
}
|
||||
|
||||
public static void DisableRemovedMods()
|
||||
{
|
||||
if (Core != null && !ContentPackageManager.CorePackages.Contains(Core))
|
||||
|
||||
@@ -40,22 +40,25 @@ namespace Barotrauma
|
||||
|
||||
public readonly static PrefabCollection<EventSet> Prefabs = new PrefabCollection<EventSet>();
|
||||
#if CLIENT
|
||||
private static readonly Dictionary<string, Sprite> EventSprites = new Dictionary<string, Sprite>();
|
||||
|
||||
public static Sprite GetEventSprite(string identifier)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(identifier)) { return null; }
|
||||
|
||||
foreach (var (key, value) in EventSprites)
|
||||
if (EventSprite.Prefabs.TryGet(identifier.ToIdentifier(), out EventSprite sprite))
|
||||
{
|
||||
if (key.Equals(identifier, StringComparison.OrdinalIgnoreCase)) { return value; }
|
||||
return sprite.Sprite;
|
||||
}
|
||||
|
||||
#if DEBUG || UNSTABLE
|
||||
DebugConsole.ThrowError($"Could not find the event sprite \"{identifier}\"");
|
||||
#else
|
||||
DebugConsole.AddWarning($"Could not find the event sprite \"{identifier}\"");
|
||||
#endif
|
||||
return null;
|
||||
}
|
||||
#endif
|
||||
|
||||
public static List<EventPrefab> GetAllEventPrefabs()
|
||||
public static List<EventPrefab> GetAllEventPrefabs()
|
||||
{
|
||||
List<EventPrefab> eventPrefabs = EventPrefab.Prefabs.ToList();
|
||||
foreach (var eventSet in Prefabs)
|
||||
|
||||
@@ -172,7 +172,7 @@ namespace Barotrauma
|
||||
ChangeLocationType(Prefab.LocationTypeChangeOnCompleted);
|
||||
}
|
||||
GiveReward();
|
||||
if (level?.LevelData != null)
|
||||
if (level.LevelData != null)
|
||||
{
|
||||
level.LevelData.IsBeaconActive = true;
|
||||
}
|
||||
|
||||
@@ -95,23 +95,10 @@ namespace Barotrauma
|
||||
|
||||
partial void InitProjSpecific();
|
||||
|
||||
private GameSession(SubmarineInfo submarineInfo, List<SubmarineInfo>? ownedSubmarines = null)
|
||||
private GameSession(SubmarineInfo submarineInfo)
|
||||
{
|
||||
InitProjSpecific();
|
||||
SubmarineInfo = submarineInfo;
|
||||
|
||||
#if CLIENT
|
||||
if (ownedSubmarines == null && GameMode is MultiPlayerCampaign && GameMain.NetLobbyScreen.ServerOwnedSubmarines != null)
|
||||
{
|
||||
ownedSubmarines = GameMain.NetLobbyScreen.ServerOwnedSubmarines;
|
||||
}
|
||||
#endif
|
||||
|
||||
OwnedSubmarines = ownedSubmarines ?? new List<SubmarineInfo>();
|
||||
if (!OwnedSubmarines.Any(s => s.Name == submarineInfo.Name))
|
||||
{
|
||||
OwnedSubmarines.Add(submarineInfo);
|
||||
}
|
||||
GameMain.GameSession = this;
|
||||
EventManager = new EventManager();
|
||||
}
|
||||
@@ -125,6 +112,7 @@ namespace Barotrauma
|
||||
this.SavePath = savePath;
|
||||
CrewManager = new CrewManager(gameModePreset.IsSinglePlayer);
|
||||
GameMode = InstantiateGameMode(gameModePreset, seed, submarineInfo, settings, missionType: missionType);
|
||||
InitOwnedSubs(submarineInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -135,12 +123,13 @@ namespace Barotrauma
|
||||
{
|
||||
CrewManager = new CrewManager(gameModePreset.IsSinglePlayer);
|
||||
GameMode = InstantiateGameMode(gameModePreset, seed, submarineInfo, CampaignSettings.Empty, missionPrefabs: missionPrefabs);
|
||||
InitOwnedSubs(submarineInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load a game session from the specified XML document. The session will be saved to the specified path.
|
||||
/// </summary>
|
||||
public GameSession(SubmarineInfo submarineInfo, List<SubmarineInfo> ownedSubmarines, XDocument doc, string saveFile) : this(submarineInfo, ownedSubmarines)
|
||||
public GameSession(SubmarineInfo submarineInfo, List<SubmarineInfo> ownedSubmarines, XDocument doc, string saveFile) : this(submarineInfo)
|
||||
{
|
||||
this.SavePath = saveFile;
|
||||
GameMain.GameSession = this;
|
||||
@@ -173,6 +162,16 @@ namespace Barotrauma
|
||||
break;
|
||||
}
|
||||
}
|
||||
InitOwnedSubs(submarineInfo);
|
||||
}
|
||||
|
||||
private void InitOwnedSubs(SubmarineInfo submarineInfo, List<SubmarineInfo>? ownedSubmarines = null)
|
||||
{
|
||||
OwnedSubmarines = ownedSubmarines ?? new List<SubmarineInfo>();
|
||||
if (submarineInfo != null && !OwnedSubmarines.Any(s => s.Name == submarineInfo.Name))
|
||||
{
|
||||
OwnedSubmarines.Add(submarineInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private GameMode InstantiateGameMode(GameModePreset gameModePreset, string? seed, SubmarineInfo selectedSub, CampaignSettings settings, IEnumerable<MissionPrefab>? missionPrefabs = null, MissionType missionType = MissionType.None)
|
||||
@@ -295,7 +294,8 @@ namespace Barotrauma
|
||||
Campaign!.GetWallet(client).TryDeduct(cost);
|
||||
}
|
||||
GameAnalyticsManager.AddMoneySpentEvent(cost, GameAnalyticsManager.MoneySink.SubmarineSwitch, newSubmarine.Name);
|
||||
|
||||
Campaign!.PendingSubmarineSwitch = newSubmarine;
|
||||
|
||||
return newSubmarine;
|
||||
}
|
||||
|
||||
|
||||
@@ -116,8 +116,6 @@ namespace Barotrauma.Items.Components
|
||||
this.fabricationRecipes = fabricationRecipes.ToImmutableDictionary();
|
||||
|
||||
state = FabricatorState.Stopped;
|
||||
|
||||
InitProjSpecific();
|
||||
}
|
||||
|
||||
public override void OnItemLoaded()
|
||||
@@ -146,9 +144,6 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
partial void OnItemLoadedProjSpecific();
|
||||
|
||||
|
||||
partial void InitProjSpecific();
|
||||
|
||||
public override bool Select(Character character)
|
||||
{
|
||||
SelectProjSpecific(character);
|
||||
@@ -192,7 +187,7 @@ namespace Barotrauma.Items.Components
|
||||
if (!isClient)
|
||||
{
|
||||
MoveIngredientsToInputContainer(selectedItem);
|
||||
if (selectedItem.RequiredMoney > 0)
|
||||
if (selectedItem.RequiredMoney > 0 && CanBeFabricated(fabricatedItem, availableIngredients, user))
|
||||
{
|
||||
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign)
|
||||
{
|
||||
@@ -395,14 +390,17 @@ namespace Barotrauma.Items.Components
|
||||
var fabricationitemAmount = new AbilityFabricationItemAmount(fabricatedItem.TargetItem, fabricatedItem.Amount);
|
||||
|
||||
int quality = 0;
|
||||
if (user?.Info != null)
|
||||
if (fabricatedItem.Quality.HasValue)
|
||||
{
|
||||
quality = fabricatedItem.Quality.Value;
|
||||
}
|
||||
else if (user?.Info != null)
|
||||
{
|
||||
foreach (Character character in Character.GetFriendlyCrew(user))
|
||||
{
|
||||
character.CheckTalents(AbilityEffectType.OnAllyItemFabricatedAmount, fabricationitemAmount);
|
||||
}
|
||||
user.CheckTalents(AbilityEffectType.OnItemFabricatedAmount, fabricationitemAmount);
|
||||
|
||||
user.CheckTalents(AbilityEffectType.OnItemFabricatedAmount, fabricationitemAmount);
|
||||
quality = GetFabricatedItemQuality(fabricatedItem, user);
|
||||
}
|
||||
|
||||
|
||||
@@ -1196,7 +1196,7 @@ namespace Barotrauma
|
||||
drawableComponents.Add(drawable);
|
||||
hasComponentsToDraw = true;
|
||||
#if CLIENT
|
||||
cachedVisibleSize = null;
|
||||
cachedVisibleExtents = null;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1208,7 +1208,7 @@ namespace Barotrauma
|
||||
drawableComponents.Remove(drawable);
|
||||
hasComponentsToDraw = drawableComponents.Count > 0;
|
||||
#if CLIENT
|
||||
cachedVisibleSize = null;
|
||||
cachedVisibleExtents = null;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,6 +118,7 @@ namespace Barotrauma
|
||||
public readonly ImmutableArray<Skill> RequiredSkills;
|
||||
public readonly uint RecipeHash;
|
||||
public readonly int Amount;
|
||||
public readonly int? Quality;
|
||||
|
||||
/// <summary>
|
||||
/// How many of this item the fabricator can create (< 0 = unlimited)
|
||||
@@ -150,6 +151,11 @@ namespace Barotrauma
|
||||
FabricationLimitMin = element.GetAttributeInt(nameof(FabricationLimitMin), limitDefault);
|
||||
FabricationLimitMax = element.GetAttributeInt(nameof(FabricationLimitMax), limitDefault);
|
||||
|
||||
if (element.GetAttribute(nameof(Quality)) != null)
|
||||
{
|
||||
Quality = element.GetAttributeInt(nameof(Quality), 0);
|
||||
}
|
||||
|
||||
foreach (var subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
|
||||
@@ -15,7 +15,6 @@ namespace Barotrauma
|
||||
public static readonly PrefabCollection<ItemAssemblyPrefab> Prefabs = new PrefabCollection<ItemAssemblyPrefab>();
|
||||
|
||||
public static readonly string VanillaSaveFolder = Path.Combine("Content", "Items", "Assemblies");
|
||||
public static readonly string SaveFolder = "ItemAssemblies";
|
||||
|
||||
private readonly XElement configElement;
|
||||
|
||||
|
||||
@@ -282,7 +282,7 @@ namespace Barotrauma
|
||||
private void PlaceObject(LevelObjectPrefab prefab, SpawnPosition spawnPosition, Level level, Level.Cave parentCave = null)
|
||||
{
|
||||
float rotation = 0.0f;
|
||||
if (prefab.AlignWithSurface && spawnPosition.Normal.LengthSquared() > 0.001f && spawnPosition != null)
|
||||
if (prefab.AlignWithSurface && spawnPosition != null && spawnPosition.Normal.LengthSquared() > 0.001f)
|
||||
{
|
||||
rotation = MathUtils.VectorToAngle(new Vector2(spawnPosition.Normal.Y, spawnPosition.Normal.X));
|
||||
}
|
||||
|
||||
@@ -359,8 +359,8 @@ namespace Barotrauma
|
||||
/// How many map progress steps it takes before the discounts should be updated.
|
||||
/// </summary>
|
||||
private const int SpecialsUpdateInterval = 3;
|
||||
private int DailySpecialsCount => Type.DailySpecialsCount;
|
||||
private int RequestedGoodsCount => Type.RequestedGoodsCount;
|
||||
public int DailySpecialsCount => Type.DailySpecialsCount;
|
||||
public int RequestedGoodsCount => Type.RequestedGoodsCount;
|
||||
private int StepsSinceSpecialsUpdated { get; set; }
|
||||
public HashSet<Identifier> StoreIdentifiers { get; } = new HashSet<Identifier>();
|
||||
|
||||
@@ -1138,7 +1138,7 @@ namespace Barotrauma
|
||||
{
|
||||
store.Balance = Math.Min(store.Balance + (int)(StoreInitialBalance / 10.0f), StoreInitialBalance);
|
||||
}
|
||||
var stock = store.Stock;
|
||||
var stock = new List<PurchasedItem>(store.Stock);
|
||||
var stockToRemove = new List<PurchasedItem>();
|
||||
foreach (var item in stock)
|
||||
{
|
||||
|
||||
@@ -89,22 +89,18 @@ namespace Barotrauma
|
||||
{
|
||||
backwardsCompatibleIdentifier = $"merchant{backwardsCompatibleIdentifier}";
|
||||
}
|
||||
string[] storeIdentifiers = childElement.GetAttributeStringArray("storeidentifiers", new string[1] { backwardsCompatibleIdentifier });
|
||||
foreach (string id in storeIdentifiers)
|
||||
{
|
||||
if (string.IsNullOrEmpty(id)) { continue; }
|
||||
// TODO: Add some error messages if we have defined the min or max amount while the item is not sold
|
||||
var priceInfo = new PriceInfo((int)(priceMultiplier * basePrice),
|
||||
sold,
|
||||
sold ? GetMinAmount(childElement, minAmount) : 0,
|
||||
sold ? GetMaxAmount(childElement, maxAmount) : 0,
|
||||
canBeSpecial,
|
||||
storeMinLevelDifficulty,
|
||||
storeBuyingMultiplier,
|
||||
displayNonEmpty,
|
||||
id);
|
||||
priceInfos.Add(priceInfo);
|
||||
}
|
||||
string storeIdentifier = childElement.GetAttributeString("storeidentifier", backwardsCompatibleIdentifier);
|
||||
// TODO: Add some error messages if we have defined the min or max amount while the item is not sold
|
||||
var priceInfo = new PriceInfo((int)(priceMultiplier * basePrice),
|
||||
sold,
|
||||
sold ? GetMinAmount(childElement, minAmount) : 0,
|
||||
sold ? GetMaxAmount(childElement, maxAmount) : 0,
|
||||
canBeSpecial,
|
||||
storeMinLevelDifficulty,
|
||||
storeBuyingMultiplier,
|
||||
displayNonEmpty,
|
||||
storeIdentifier);
|
||||
priceInfos.Add(priceInfo);
|
||||
}
|
||||
bool soldElsewhere = soldByDefault && element.GetAttributeBool("soldelsewhere", element.GetAttributeBool("soldeverywhere", false));
|
||||
defaultPrice = new PriceInfo(basePrice,
|
||||
|
||||
@@ -313,7 +313,16 @@ namespace Barotrauma
|
||||
for (float x = hull.Rect.X + diffFromHullEdge; x <= hull.Rect.Right - diffFromHullEdge; x += minDist)
|
||||
{
|
||||
var wayPoint = new WayPoint(new Vector2(x, hull.Rect.Y - hull.Rect.Height + waypointHeight), SpawnType.Path, submarine);
|
||||
if (previousWaypoint != null) { wayPoint.ConnectTo(previousWaypoint); }
|
||||
// Too close to stairs, will be assigned as a stair point -> remove
|
||||
if (wayPoint.FindStairs() != null)
|
||||
{
|
||||
removals.Add(wayPoint);
|
||||
continue;
|
||||
}
|
||||
if (previousWaypoint != null)
|
||||
{
|
||||
wayPoint.ConnectTo(previousWaypoint);
|
||||
}
|
||||
previousWaypoint = wayPoint;
|
||||
}
|
||||
if (previousWaypoint == null)
|
||||
@@ -510,25 +519,29 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
removals.ForEach(wp => wp.Remove());
|
||||
removals.Clear();
|
||||
// Stairs
|
||||
foreach (MapEntity mapEntity in mapEntityList.ToList())
|
||||
{
|
||||
if (!(mapEntity is Structure structure)) { continue; }
|
||||
if (structure.StairDirection == Direction.None) { continue; }
|
||||
WayPoint[] stairPoints = new WayPoint[3];
|
||||
float margin = -32;
|
||||
|
||||
stairPoints[0] = new WayPoint(
|
||||
new Vector2(structure.Rect.X - 32.0f,
|
||||
structure.Rect.Y - (structure.StairDirection == Direction.Left ? 80 : structure.Rect.Height) + heightFromFloor), SpawnType.Path, submarine);
|
||||
stairPoints[0] = new WayPoint(new Vector2(
|
||||
structure.Rect.X + 5,
|
||||
structure.Rect.Y - (structure.StairDirection == Direction.Left ? margin : structure.Rect.Height - 100)), SpawnType.Path, submarine);
|
||||
|
||||
stairPoints[1] = new WayPoint(
|
||||
new Vector2(structure.Rect.Right + 32.0f,
|
||||
structure.Rect.Y - (structure.StairDirection == Direction.Left ? structure.Rect.Height : 80) + heightFromFloor), SpawnType.Path, submarine);
|
||||
stairPoints[1] = new WayPoint(new Vector2(
|
||||
structure.Rect.Right - 5,
|
||||
structure.Rect.Y - (structure.StairDirection == Direction.Left ? structure.Rect.Height - 100 : margin)), SpawnType.Path, submarine);
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
for (int dir = -1; dir <= 1; dir += 2)
|
||||
{
|
||||
WayPoint closest = stairPoints[i].FindClosest(dir, horizontalSearch: true, new Vector2(100, 70));
|
||||
WayPoint closest = stairPoints[i].FindClosest(dir, horizontalSearch: true, new Vector2(minDist * 1.5f, minDist / 2));
|
||||
if (closest == null) { continue; }
|
||||
stairPoints[i].ConnectTo(closest);
|
||||
}
|
||||
@@ -537,9 +550,8 @@ namespace Barotrauma
|
||||
stairPoints[2] = new WayPoint((stairPoints[0].Position + stairPoints[1].Position) / 2, SpawnType.Path, submarine);
|
||||
stairPoints[0].ConnectTo(stairPoints[2]);
|
||||
stairPoints[2].ConnectTo(stairPoints[1]);
|
||||
stairPoints.ForEach(wp => wp.FindStairs());
|
||||
}
|
||||
removals.ForEach(wp => wp.Remove());
|
||||
removals.Clear();
|
||||
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
@@ -840,7 +852,11 @@ namespace Barotrauma
|
||||
var body = Submarine.CheckVisibility(SimPosition, wp.SimPosition, ignoreLevel: true, ignoreSubs: true, ignoreSensors: false);
|
||||
if (body != null && body != ignoredBody && !(body.UserData is Submarine))
|
||||
{
|
||||
if (body.UserData is Structure || body.FixtureList[0].CollisionCategories.HasFlag(Physics.CollisionWall))
|
||||
if (body.UserData is Structure)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (body.FixtureList[0].CollisionCategories.HasFlag(Physics.CollisionWall) && body.UserData is Item i && i.GetComponent<Door>() != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -960,14 +976,15 @@ namespace Barotrauma
|
||||
FindStairs();
|
||||
}
|
||||
|
||||
private void FindStairs()
|
||||
private Structure FindStairs()
|
||||
{
|
||||
Stairs = null;
|
||||
Body pickedBody = Submarine.PickBody(SimPosition, SimPosition - Vector2.UnitY * 2.0f, null, Physics.CollisionStairs);
|
||||
Body pickedBody = Submarine.PickBody(SimPosition, SimPosition - new Vector2(0, 1.2f), null, Physics.CollisionStairs);
|
||||
if (pickedBody != null && pickedBody.UserData is Structure structure && structure.StairDirection != Direction.None)
|
||||
{
|
||||
Stairs = structure;
|
||||
Stairs = structure;
|
||||
}
|
||||
return Stairs;
|
||||
}
|
||||
|
||||
public void InitializeLinks()
|
||||
|
||||
@@ -6,6 +6,25 @@ using System.Linq;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
[NetworkSerialize]
|
||||
struct TempClient : INetSerializableStruct
|
||||
{
|
||||
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;
|
||||
public bool IsDownloading;
|
||||
}
|
||||
|
||||
partial class Client : IDisposable
|
||||
{
|
||||
public const int MaxNameLength = 32;
|
||||
|
||||
@@ -58,10 +58,13 @@ namespace Barotrauma
|
||||
cam.Position = Submarine.MainSub.WorldPosition;
|
||||
cam.UpdateTransform(true);
|
||||
}
|
||||
GameMain.GameSession?.CrewManager?.AutoShowCrewList();
|
||||
#endif
|
||||
|
||||
foreach (MapEntity entity in MapEntity.mapEntityList)
|
||||
{
|
||||
entity.IsHighlighted = false;
|
||||
}
|
||||
|
||||
#if RUN_PHYSICS_IN_SEPARATE_THREAD
|
||||
var physicsThread = new Thread(ExecutePhysics)
|
||||
@@ -78,6 +81,10 @@ namespace Barotrauma
|
||||
base.Deselect();
|
||||
|
||||
#if CLIENT
|
||||
var config = GameSettings.CurrentConfig;
|
||||
config.CrewMenuOpen = CrewManager.PreferCrewMenuOpen;
|
||||
config.ChatOpen = ChatBox.PreferChatBoxOpen;
|
||||
GameSettings.SetCurrentConfig(config);
|
||||
GameSettings.SaveCurrentConfig();
|
||||
GameMain.SoundManager.SetCategoryMuffle("default", false);
|
||||
GUI.ClearMessages();
|
||||
|
||||
@@ -112,15 +112,17 @@ namespace Barotrauma.Steam
|
||||
var toUninstall
|
||||
= ContentPackageManager.WorkshopPackages.Where(p => p.SteamWorkshopId == workshopItem.Id)
|
||||
.ToHashSet();
|
||||
ContentPackageManager.EnabledPackages.DisableMods(toUninstall);
|
||||
toUninstall.Select(p => p.Dir).ForEach(d => Directory.Delete(d));
|
||||
ContentPackageManager.WorkshopPackages.Refresh();
|
||||
ContentPackageManager.EnabledPackages.DisableRemovedMods();
|
||||
}
|
||||
|
||||
public static async Task ForceRedownload(Steamworks.Ugc.Item item)
|
||||
public static async Task ForceRedownload(Steamworks.Ugc.Item item, CancellationTokenSource? cancellationTokenSrc = null)
|
||||
{
|
||||
NukeDownload(item);
|
||||
await item.DownloadAsync();
|
||||
cancellationTokenSrc ??= new CancellationTokenSource();
|
||||
await item.DownloadAsync(ct: cancellationTokenSrc.Token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -57,6 +57,20 @@ namespace Barotrauma
|
||||
return isCJK.IsMatch(text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the currently selected language is available, and switch to English if not
|
||||
/// </summary>
|
||||
public static void VerifyLanguageAvailable()
|
||||
{
|
||||
if (!TextPacks.ContainsKey(GameSettings.CurrentConfig.Language))
|
||||
{
|
||||
DebugConsole.ThrowError($"Could not find the language \"{GameSettings.CurrentConfig.Language}\". Trying to switch to English...");
|
||||
var config = GameSettings.CurrentConfig;
|
||||
config.Language = "English".ToLanguageIdentifier();;
|
||||
GameSettings.SetCurrentConfig(config);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ContainsTag(string tag)
|
||||
{
|
||||
return ContainsTag(tag.ToIdentifier());
|
||||
|
||||
@@ -1,3 +1,65 @@
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
v0.17.6.0
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
|
||||
Changes:
|
||||
- Buffed ethanol's and tobacco's effects.
|
||||
- Renamed "details" to "manage" and "permissions" to "rank" in the client management context menu to make them a little more clear.
|
||||
- Added an indicator for when players are downloading files from the server to the player list in the lobby.
|
||||
- Adjustments, tweaks, and polish for the new abyss monster, now called "Latcher". Updated texture.
|
||||
- Adjusted the kill hammerhead missions.
|
||||
- Changes to character aiming behavior.
|
||||
- Giant Spineling doesn't flee anymore when being shot with coilgun, chaingun, or small arms.
|
||||
|
||||
Changes (unstable only):
|
||||
- Added separate icons for mods that you've published and mods that you've subscribed to.
|
||||
- Added a button to the prompt asking you to download mods from the server that will subscribe to missing Workshop items.
|
||||
- Added a context menu to the items in the Installed Mods tab.
|
||||
- Added a button to update all mods that are out of date.
|
||||
- Added a search box to the locked mods list.
|
||||
- Added a search box to the required mods list in the submarine editor.
|
||||
- Double-clicking now enables/disables items in the Installed Mods tab.
|
||||
|
||||
Fixes:
|
||||
- Fixed swimming characters sometimes being unable to stand up on stairs/platforms even if the water is shallow enough.
|
||||
- Fixed guitar and harmonica being rendered on top of the water effect.
|
||||
- Fixed guitar, harmonica, accordion and captains pipe having neutral buoyancy.
|
||||
- Fixed mid-round joining clients not seeing subs purchased during that round.
|
||||
- Fixed research station being repairable by clicking on it instead of pressing E.
|
||||
- Fixed medical curtains disappearing before they're off-screen.
|
||||
- Fixed karma preset being forced to default when starting a new server.
|
||||
- Fixed calyxanide not damaging the "naturally spawning" husks.
|
||||
- Fixed Herja's rear motion detector being connected to an incorrect display, and the bottom turret display having an incorrect text.
|
||||
- Fixed crash caused by selection not being cleared when autocompleting or running a console command.
|
||||
- Waypointfixes on abandoned outpost modules, some regular outpost modules, and Winterhalter.
|
||||
- Fixed bots occasionally getting stuck while climbing ladders connecting outpost modules.
|
||||
- Fixes to waypoint generator, mainly on stairs.
|
||||
- Fixed a null reference exception when a bot is dismissed while being told to follow the player and still in the combat state.
|
||||
- Fixed Giant Spineling targeting doors after being attacked, which it shouldn't do by design. Might affect other creatures too.
|
||||
|
||||
Fixes (unstable only):
|
||||
- Fixes and improvements to colony modules.
|
||||
- Fixed items in vending machines not being displayed as "out of stock" client-side, fixed money getting deducted when trying to buy an item that's out of stock.
|
||||
- Fixed crashing on startup if the selected language cannot be found (e.g. if you've previously used a modded language and no longer have that mod installed).
|
||||
- Fixed chat messages about money transfer votes not showing up.
|
||||
- Fixed voting not finishing until the timer has elapsed even if there's already enough yes/no votes.
|
||||
- Fixed vitality multipliers not working (e.g. damage to the head not having a bigger effect than damage to the limbs).
|
||||
- Fixed "create level object" crashing the level editor.
|
||||
- Fixed crashing when trying to save a sub with whitespace at the end of the name.
|
||||
- Fixed sub editor's tag picker not working.
|
||||
- Fixed event sprites not appearing.
|
||||
- Fixed submarine switching not working.
|
||||
- Fixed crew list and chatbox refusing to stay closed.
|
||||
- Fixed character names being in upper case when using the health scanner.
|
||||
- Fixed explosive coilgun ammo not being sold by armory merchants.
|
||||
- Fixed physicorium not being sold at research outposts.
|
||||
- Fixed issues with store interface displaying incorrect information.
|
||||
- Fixed issues with buying items in multiplayer campaign.
|
||||
- Fixed issues with generating daily specials and requested goods for campaign stores.
|
||||
- Fixed double title in mod download prompt.
|
||||
- Fixed mod transfer skipping item assemblies.
|
||||
- Waypoint fixes on new colony modules.
|
||||
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
v0.17.5.0
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -99,11 +99,22 @@ namespace Steamworks
|
||||
onDownloadStarted = (r, id) => downloadStarted = true;
|
||||
OnDownloadItemResult += onDownloadStarted;
|
||||
|
||||
int iters = 0;
|
||||
while ( downloadStarted == false )
|
||||
{
|
||||
if ( ct.IsCancellationRequested )
|
||||
break;
|
||||
ct.ThrowIfCancellationRequested();
|
||||
|
||||
iters++;
|
||||
if (iters >= 1000 / milisecondsUpdateDelay)
|
||||
{
|
||||
if (!item.IsDownloading && !item.IsInstalled)
|
||||
{
|
||||
//force download to start if it's not started
|
||||
if ( Download( fileId, highPriority: true ) == false )
|
||||
return item.IsInstalled;
|
||||
}
|
||||
iters = 0;
|
||||
}
|
||||
await Task.Delay( milisecondsUpdateDelay );
|
||||
}
|
||||
}
|
||||
@@ -120,8 +131,7 @@ namespace Steamworks
|
||||
{
|
||||
while ( true )
|
||||
{
|
||||
if ( ct.IsCancellationRequested )
|
||||
break;
|
||||
ct.ThrowIfCancellationRequested();
|
||||
|
||||
progress?.Invoke( 0.2f + item.DownloadAmount * 0.8f );
|
||||
|
||||
|
||||
Reference in New Issue
Block a user