695 lines
33 KiB
C#
695 lines
33 KiB
C#
#nullable enable
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Barotrauma.Extensions;
|
|
using Barotrauma.IO;
|
|
using Microsoft.Xna.Framework;
|
|
using Microsoft.Xna.Framework.Graphics;
|
|
using ItemOrPackage = Barotrauma.Either<Steamworks.Ugc.Item, Barotrauma.ContentPackage>;
|
|
|
|
namespace Barotrauma.Steam
|
|
{
|
|
public partial class WorkshopMenu
|
|
{
|
|
private string ExtractTitle(ItemOrPackage itemOrPackage)
|
|
=> itemOrPackage.TryGet(out ContentPackage package)
|
|
? package.Name
|
|
: ((Steamworks.Ugc.Item)itemOrPackage).Title;
|
|
|
|
private void CreateWorkshopItemDetailContainer(
|
|
GUIFrame parent,
|
|
out GUIListBox outerContainer,
|
|
Action<ItemOrPackage, GUIFrame> onSelected,
|
|
Action onDeselected,
|
|
out Action<ItemOrPackage> select,
|
|
out Action deselect)
|
|
{
|
|
ItemOrPackage? selectedItemOrPackage = null;
|
|
|
|
GUIListBox outContainer = new GUIListBox(new RectTransform(Vector2.One, parent.RectTransform),
|
|
isHorizontal: true,
|
|
style: null)
|
|
{
|
|
ScrollBarEnabled = false,
|
|
ScrollBarVisible = false,
|
|
HoverCursor = CursorState.Default
|
|
};
|
|
outerContainer = outContainer;
|
|
|
|
var selectedLayout =
|
|
new GUILayoutGroup(new RectTransform(Vector2.One, outerContainer.Content.RectTransform));
|
|
var selectedHeaderLayout =
|
|
new GUILayoutGroup(new RectTransform((1.0f, 0.05f), selectedLayout.RectTransform),
|
|
isHorizontal: true,
|
|
childAnchor: Anchor.CenterLeft);
|
|
|
|
void deselectMethod()
|
|
{
|
|
if (selectedItemOrPackage is null) { return; }
|
|
selectedItemOrPackage = null;
|
|
onDeselected();
|
|
}
|
|
|
|
deselect = deselectMethod;
|
|
|
|
var backButton =
|
|
new GUIButton(new RectTransform((0.04f, 1.0f), selectedHeaderLayout.RectTransform),
|
|
style: "GUIButtonToggleLeft")
|
|
{
|
|
OnClicked = (button, o) =>
|
|
{
|
|
deselectMethod();
|
|
return false;
|
|
}
|
|
};
|
|
var padding = new GUIFrame(new RectTransform((1.0f, 0.005f), selectedLayout.RectTransform), style: null);
|
|
var selectedFrame = new GUIFrame(new RectTransform((1.0f, 0.945f), selectedLayout.RectTransform),
|
|
style: null);
|
|
|
|
var selectionScroller = new GUICustomComponent(
|
|
new RectTransform(Vector2.Zero, outerContainer.Parent.RectTransform),
|
|
onUpdate: (deltaTime, component) =>
|
|
{
|
|
float targetScroll = selectedItemOrPackage is null
|
|
? 0.0f
|
|
: 1.0f;
|
|
outContainer.ScrollBar.BarScroll
|
|
= MathUtils.NearlyEqual(targetScroll, outContainer.ScrollBar.BarScroll)
|
|
? targetScroll
|
|
: MathHelper.Lerp(outContainer.ScrollBar.BarScroll, targetScroll, 0.3f);
|
|
});
|
|
|
|
select = itemOrPackage =>
|
|
{
|
|
//showInSteamButton.Visible = itemOrPackage.TryGet(out Steamworks.Ugc.Item _);
|
|
//selectedItem = itemOrPackage;
|
|
//selectedTitle.Text = ExtractTitle(itemOrPackage);
|
|
selectedFrame.ClearChildren();
|
|
|
|
//Jank to fix mouserect not clamping properly
|
|
//when shifting all elements to the left
|
|
var dropdowns = outContainer.Content.GetAllChildren<GUIDropDown>().ToArray();
|
|
var allChildren = outContainer.Content.GetAllChildren()
|
|
.Concat(selectedFrame.GetAllChildren());
|
|
allChildren.ForEach(c =>
|
|
{
|
|
//c.CascadingMouseRectClamp = !dropdowns.Any(dd => dd.IsParentOf(c) || dd.ListBox.IsParentOf(c));
|
|
//c.CanBeFocused = c.CanBeFocused || !c.CascadingMouseRectClamp;
|
|
c.ClampMouseRectToParent = !(c.Parent?.Parent is GUIDropDown);
|
|
}
|
|
);
|
|
|
|
selectedItemOrPackage = itemOrPackage;
|
|
onSelected(itemOrPackage, selectedFrame);
|
|
};
|
|
}
|
|
|
|
private void CreateWorkshopItemList(
|
|
GUIFrame parent,
|
|
out GUIListBox outerContainer,
|
|
out GUIListBox workshopItemList,
|
|
Action<Steamworks.Ugc.Item, GUIFrame> onSelected)
|
|
=> CreateWorkshopItemOrPackageList(
|
|
parent,
|
|
out outerContainer,
|
|
out workshopItemList,
|
|
onSelected: (ItemOrPackage itemOrPackage, GUIFrame frame)
|
|
=> onSelected((Steamworks.Ugc.Item)itemOrPackage, frame));
|
|
|
|
private GUIButton CreateShowInSteamButton(Steamworks.Ugc.Item workshopItem, RectTransform rectT)
|
|
=> new GUIButton(
|
|
rectT,
|
|
TextManager.Get("WorkshopShowItemInSteam"), style: "GUIButtonSmall")
|
|
{
|
|
OnClicked = (button, o) =>
|
|
{
|
|
SteamManager.OverlayCustomURL(workshopItem.Url);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
private GUIButton? CreateShowInSteamButton(ItemOrPackage itemOrPackage)
|
|
=> itemOrPackage.TryGet(out Steamworks.Ugc.Item workshopItem)
|
|
? CreateShowInSteamButton(workshopItem)
|
|
: null;
|
|
|
|
private void CreateWorkshopItemOrPackageList(
|
|
GUIFrame parent,
|
|
out GUIListBox outerContainer,
|
|
out GUIListBox workshopItemList,
|
|
Action<ItemOrPackage, GUIFrame> onSelected)
|
|
{
|
|
GUIListBox? itemList = null;
|
|
|
|
CreateWorkshopItemDetailContainer(
|
|
parent,
|
|
out outerContainer,
|
|
onSelected: onSelected,
|
|
onDeselected: () => itemList?.Deselect(),
|
|
out var select, out var deselect);
|
|
|
|
itemList = new GUIListBox(new RectTransform(Vector2.One, outerContainer.Content.RectTransform));
|
|
itemList.RectTransform.SetAsFirstChild();
|
|
workshopItemList = itemList;
|
|
|
|
var deselectCarrier
|
|
= CreateActionCarrier(outerContainer.Content, nameof(deselect).ToIdentifier(), deselect);
|
|
|
|
itemList.OnSelected = (component, userData) =>
|
|
{
|
|
//Don't select if hitting the subscribe button
|
|
if (GUI.MouseOn.Parent != itemList.Content) { return false; }
|
|
|
|
if (!(userData is ItemOrPackage itemOrPackage)) { return false; }
|
|
|
|
select(itemOrPackage);
|
|
|
|
return true;
|
|
};
|
|
}
|
|
|
|
private void AddUnpublishedMods(ISet<Steamworks.Ugc.Item> workshopItems)
|
|
{
|
|
//Users that don't have a proper license cannot publish Workshop items
|
|
//(see https://partner.steamgames.com/doc/features/workshop#15)
|
|
void clearWithMessage(LocalizedString message)
|
|
{
|
|
selfModsList.ClearChildren();
|
|
var messageFrame = new GUIFrame(new RectTransform(Vector2.One, selfModsList.Content.RectTransform),
|
|
style: null)
|
|
{
|
|
CanBeFocused = false
|
|
};
|
|
new GUITextBlock(new RectTransform((0.5f, 1.0f), messageFrame.RectTransform, Anchor.Center),
|
|
text: message,
|
|
textAlignment: Alignment.Center,
|
|
wrap: true,
|
|
font: GUIStyle.Font);
|
|
}
|
|
|
|
if (SteamManager.IsFreeWeekend())
|
|
{
|
|
clearWithMessage(TextManager.Get("FreeWeekendCantPublish"));
|
|
return;
|
|
}
|
|
if (SteamManager.IsFamilyShared())
|
|
{
|
|
clearWithMessage(TextManager.Get("FamilySharedCantPublish"));
|
|
return;
|
|
}
|
|
|
|
DateTime getEditTime(ContentPackage p)
|
|
=> File.GetLastWriteTime(Path.GetDirectoryName(p.Path)!);
|
|
|
|
//Find local packages associated with the Workshop items if available
|
|
(Steamworks.Ugc.Item WorkshopItem, ContentPackage? LocalPackage)[] publishedItems = workshopItems
|
|
.Select(item => (item,
|
|
(ContentPackage?)ContentPackageManager.LocalPackages.FirstOrDefault(p
|
|
=> p.SteamWorkshopId != 0 && p.SteamWorkshopId == item.Id)))
|
|
//Sort the pairs by last local edit time if available
|
|
.OrderBy(t => t.Item2 == null)
|
|
.ThenByDescending(t => t.Item2 is { } p ? getEditTime(p) : t.Item1.LatestUpdateTime)
|
|
.ToArray();
|
|
|
|
int indexOfUserDataInPublishedItemsArray(object userData)
|
|
=> publishedItems.IndexOf(t
|
|
=> t.WorkshopItem.Id == ((Steamworks.Ugc.Item)(userData as ItemOrPackage)).Id);
|
|
|
|
//Take the existing GUI items that are in the list and sort to match the order of publishedItems
|
|
var publishedGuiComponents = selfModsList.Content.Children.OrderBy(c => indexOfUserDataInPublishedItemsArray(c.UserData)).ToArray();
|
|
|
|
//Get mods that haven't been published and add them to the list
|
|
var unpublishedMods = ContentPackageManager.LocalPackages
|
|
.Where(p => p.SteamWorkshopId == 0 || !publishedItems.Any(item => item.WorkshopItem.Id == p.SteamWorkshopId))
|
|
.OrderByDescending(getEditTime).ToArray();
|
|
|
|
if (unpublishedMods.Any())
|
|
{
|
|
var unpublishedHeader
|
|
= new GUITextBlock(new RectTransform((1.0f, 1.0f / 11.0f), selfModsList.Content.RectTransform),
|
|
TextManager.Get("UnpublishedModsHeader"), font: GUIStyle.SubHeadingFont) { CanBeFocused = false };
|
|
}
|
|
|
|
foreach (var unpublishedMod in unpublishedMods)
|
|
{
|
|
var unpublishedFrame = new GUIFrame(
|
|
new RectTransform((1.0f, 1.0f / 5.5f), selfModsList.Content.RectTransform),
|
|
style: "ListBoxElement")
|
|
{
|
|
UserData = (ItemOrPackage)unpublishedMod
|
|
};
|
|
var unpublishedLayout
|
|
= new GUILayoutGroup(new RectTransform(Vector2.One, unpublishedFrame.RectTransform),
|
|
isHorizontal: true)
|
|
{
|
|
Stretch = true,
|
|
RelativeSpacing = 0.02f
|
|
};
|
|
var unpublishedPadding
|
|
= new GUIFrame(
|
|
new RectTransform(Vector2.One, unpublishedLayout.RectTransform,
|
|
scaleBasis: ScaleBasis.BothHeight), style: null)
|
|
{
|
|
CanBeFocused = false
|
|
};
|
|
var unpublishedTextBlock
|
|
= new GUITextBlock(new RectTransform(Vector2.One, unpublishedLayout.RectTransform),
|
|
$"{unpublishedMod.Name}\n\n" +
|
|
TextManager.GetWithVariable("LastLocalEditTime",
|
|
"[datetime]",
|
|
getEditTime(unpublishedMod).ToString()),
|
|
font: GUIStyle.Font)
|
|
{
|
|
CanBeFocused = false
|
|
};
|
|
}
|
|
|
|
if (publishedGuiComponents.Any())
|
|
{
|
|
var publishedHeader
|
|
= new GUITextBlock(new RectTransform((1.0f, 1.0f / 11.0f), selfModsList.Content.RectTransform),
|
|
TextManager.Get("PublishedModsHeader"), font: GUIStyle.SubHeadingFont) { CanBeFocused = false };
|
|
}
|
|
|
|
foreach (var c in publishedGuiComponents)
|
|
{
|
|
c.SetAsLastChild();
|
|
var textBlock = (c.FindChild(b => b is GUITextBlock, recursive: true) as GUITextBlock)!;
|
|
textBlock.Text += $"\n";
|
|
|
|
int index = indexOfUserDataInPublishedItemsArray(c.UserData);
|
|
(Steamworks.Ugc.Item workshopItem, ContentPackage? localMod) = publishedItems[index];
|
|
if (localMod != null)
|
|
{
|
|
textBlock.Text += $"\n" + TextManager.GetWithVariable("LastLocalEditTime", "[datetime]", getEditTime(localMod).ToString());
|
|
}
|
|
textBlock.Text += $"\n" + TextManager.GetWithVariable("LatestPublishTime", "[datetime]", workshopItem.LatestUpdateTime.ToLocalTime().ToString());
|
|
}
|
|
}
|
|
|
|
private static (GUIButton Button, GUIFrame Sprite) CreatePaddedButton(RectTransform rectT, string style, float spriteScale)
|
|
{
|
|
var button = new GUIButton(
|
|
rectT,
|
|
style: null);
|
|
|
|
var sprite = new GUIFrame(
|
|
new RectTransform(Vector2.One * spriteScale, button.RectTransform, Anchor.Center),
|
|
style: style)
|
|
{
|
|
CanBeFocused = false
|
|
};
|
|
|
|
return (button, sprite);
|
|
}
|
|
|
|
private static void CreateSubscribeButton(Steamworks.Ugc.Item workshopItem, RectTransform rectT, float spriteScale)
|
|
{
|
|
const string plusButton = "GUIPlusButton";
|
|
const string minusButton = "GUIMinusButton";
|
|
|
|
LocalizedString subscribeTooltip = TextManager.Get("DownloadButton");
|
|
LocalizedString unsubscribeTooptip = TextManager.Get("WorkshopItemUnsubscribe");
|
|
|
|
var (subscribeButton, subscribeButtonSprite) = CreatePaddedButton(rectT, plusButton, spriteScale);
|
|
subscribeButton.ToolTip = subscribeTooltip;
|
|
|
|
subscribeButton.OnClicked = (button, o) =>
|
|
{
|
|
if (!workshopItem.IsSubscribed)
|
|
{
|
|
workshopItem.Subscribe();
|
|
TaskPool.Add($"DownloadSubscribedItem{workshopItem.Id}",
|
|
SteamManager.Workshop.ForceRedownload(workshopItem),
|
|
t => { });
|
|
}
|
|
else
|
|
{
|
|
workshopItem.Unsubscribe();
|
|
SteamManager.Workshop.Uninstall(workshopItem);
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
var buttonStyleUpdater = new GUICustomComponent(
|
|
new RectTransform(Vector2.Zero, subscribeButton.RectTransform),
|
|
onUpdate: (deltaTime, component) =>
|
|
{
|
|
if (subscribeButtonSprite.Style is { Identifier: { } styleId })
|
|
{
|
|
if (workshopItem.IsSubscribed && styleId != minusButton)
|
|
{
|
|
subscribeButtonSprite.ApplyStyle(GUIStyle.GetComponentStyle(minusButton));
|
|
subscribeButton.ToolTip = unsubscribeTooptip;
|
|
}
|
|
if (!workshopItem.IsSubscribed && styleId != plusButton)
|
|
{
|
|
subscribeButtonSprite.ApplyStyle(GUIStyle.GetComponentStyle(plusButton));
|
|
subscribeButton.ToolTip = subscribeTooltip;
|
|
}
|
|
}
|
|
});
|
|
|
|
float displayedDownloadAmount = workshopItem.DownloadAmount;
|
|
var downloadProgressBar = new GUICustomComponent(
|
|
new RectTransform((1.22f, 1.22f), subscribeButtonSprite.RectTransform, Anchor.Center),
|
|
onDraw: (spriteBatch, component) =>
|
|
{
|
|
bool visible = workshopItem.IsSubscribed
|
|
&& (workshopItem.IsDownloading
|
|
|| workshopItem.IsDownloadPending
|
|
|| !MathUtils.NearlyEqual(workshopItem.DownloadAmount, displayedDownloadAmount));
|
|
if (!visible) { return; }
|
|
|
|
void drawSection(float amount, Color color, float thickness)
|
|
=> GUI.DrawDonutSection(
|
|
spriteBatch,
|
|
component.Rect.Center.ToVector2() + (0, 1),
|
|
new Range<float>(component.Rect.Width * 0.55f - thickness * 0.5f, component.Rect.Width * 0.55f + thickness * 0.5f),
|
|
amount * MathF.PI * 2.0f,
|
|
color);
|
|
|
|
void drawSectionFuzzy(float amount, Color color, float thickness)
|
|
{
|
|
drawSection(amount, color, thickness);
|
|
drawSection(amount, color * 0.6f, thickness + 0.5f);
|
|
drawSection(amount, color * 0.3f, thickness + 1.0f);
|
|
}
|
|
|
|
drawSectionFuzzy(1.0f, Color.Lerp(Color.Black, GUIStyle.Blue, 0.2f), component.Rect.Width * 0.25f);
|
|
drawSectionFuzzy(1.0f, Color.Black, component.Rect.Width * 0.15f);
|
|
drawSectionFuzzy(displayedDownloadAmount, GUIStyle.Green, component.Rect.Width * 0.08f);
|
|
},
|
|
onUpdate: (deltaTime, component) =>
|
|
{
|
|
displayedDownloadAmount = Math.Min(
|
|
workshopItem.DownloadAmount,
|
|
MathHelper.Lerp(displayedDownloadAmount, workshopItem.DownloadAmount, 0.05f));
|
|
})
|
|
{
|
|
CanBeFocused = false
|
|
};
|
|
}
|
|
|
|
private void PopulateItemList(GUIListBox itemListBox, Task<ISet<Steamworks.Ugc.Item>> items, bool includeSubscribeButton, Action<ISet<Steamworks.Ugc.Item>>? onFill = null)
|
|
{
|
|
itemListBox.ClearChildren();
|
|
itemListBox.Deselect();
|
|
itemListBox.ScrollBar.BarScroll = 0.0f;
|
|
TaskPool.Add("PopulateTabWithItemList", items,
|
|
(t) =>
|
|
{
|
|
taskCancelSrc = taskCancelSrc.IsCancellationRequested ? new CancellationTokenSource() : taskCancelSrc;
|
|
itemListBox.ClearChildren();
|
|
var workshopItems = ((Task<ISet<Steamworks.Ugc.Item>>)t).Result;
|
|
foreach (var workshopItem in workshopItems)
|
|
{
|
|
var itemFrame = new GUIFrame(
|
|
new RectTransform((1.0f, 1.0f / 5.5f), itemListBox.Content.RectTransform),
|
|
style: "ListBoxElement")
|
|
{
|
|
UserData = (ItemOrPackage)workshopItem
|
|
};
|
|
var itemLayout = new GUILayoutGroup(
|
|
new RectTransform(Vector2.One, itemFrame.RectTransform),
|
|
isHorizontal: true, childAnchor: Anchor.CenterLeft)
|
|
{
|
|
Stretch = true
|
|
};
|
|
|
|
var thumbnailContainer
|
|
= CreateThumbnailContainer(itemLayout, Vector2.One, ScaleBasis.BothHeight);
|
|
CreateItemThumbnail(workshopItem, taskCancelSrc.Token, thumbnailContainer);
|
|
thumbnailContainer.CanBeFocused = false;
|
|
thumbnailContainer.GetAllChildren().ForEach(c => c.CanBeFocused = false);
|
|
|
|
var title = new GUITextBlock(
|
|
new RectTransform(Vector2.One, itemLayout.RectTransform),
|
|
workshopItem.Title, font: GUIStyle.Font)
|
|
{
|
|
CanBeFocused = false
|
|
};
|
|
|
|
if (includeSubscribeButton)
|
|
{
|
|
CreateSubscribeButton(workshopItem, new RectTransform(Vector2.One, itemLayout.RectTransform, scaleBasis: ScaleBasis.BothHeight), spriteScale: 0.4f);
|
|
}
|
|
}
|
|
onFill?.Invoke(workshopItems);
|
|
});
|
|
}
|
|
|
|
private GUIFrame CreateThumbnailContainer(
|
|
GUIComponent parent,
|
|
Vector2 relativeSize,
|
|
ScaleBasis scaleBasis)
|
|
=> new GUIFrame(new RectTransform(relativeSize, parent.RectTransform, scaleBasis: scaleBasis),
|
|
style: "GUIFrameListBox");
|
|
|
|
private SteamManager.Workshop.ItemThumbnail CreateItemThumbnail(
|
|
in Steamworks.Ugc.Item workshopItem,
|
|
CancellationToken cancellationToken,
|
|
GUIFrame thumbnailContainer)
|
|
{
|
|
var thumbnail = new SteamManager.Workshop.ItemThumbnail(workshopItem, cancellationToken);
|
|
itemThumbnails.Add(thumbnail);
|
|
CreateAsyncThumbnailComponent(thumbnailContainer, () => thumbnail.Texture, () => thumbnail.Loading);
|
|
return thumbnail;
|
|
}
|
|
|
|
private GUICustomComponent CreateAsyncThumbnailComponent(GUIFrame thumbnailContainer, Func<Texture2D?> textureGetter, Func<bool> throbberEnabled)
|
|
{
|
|
int randomThrobberOffset = Rand.Range(0, 10, Rand.RandSync.Unsynced);
|
|
return new GUICustomComponent(
|
|
new RectTransform(Vector2.One, thumbnailContainer.RectTransform, Anchor.Center),
|
|
onDraw: (spriteBatch, component) =>
|
|
{
|
|
Rectangle rect = component.Rect;
|
|
Texture2D? texture = textureGetter();
|
|
if (texture != null)
|
|
{
|
|
rect.Location += (4, 4);
|
|
rect.Size -= (8, 8);
|
|
Point destinationSizeMaxWidth = (rect.Width, rect.Width * texture.Height / texture.Width);
|
|
Point destinationSizeMaxHeight = (rect.Height * texture.Width / texture.Height, rect.Height);
|
|
Point destinationSize = destinationSizeMaxHeight.X > rect.Width
|
|
? destinationSizeMaxWidth
|
|
: destinationSizeMaxHeight;
|
|
Rectangle destinationRectangle = new Rectangle(
|
|
rect.Center.X - destinationSize.X / 2,
|
|
rect.Center.Y - destinationSize.Y / 2,
|
|
destinationSize.X,
|
|
destinationSize.Y);
|
|
spriteBatch.Draw(texture, destinationRectangle, Color.White);
|
|
}
|
|
else if (throbberEnabled())
|
|
{
|
|
var sheet = GUIStyle.GenericThrobber;
|
|
Vector2 pos = rect.Center.ToVector2() - Vector2.One * rect.Height * 0.4f;
|
|
sheet.Draw(spriteBatch, ((int)Math.Floor(Timing.TotalTime * 24.0f) + randomThrobberOffset) % sheet.FrameCount, pos, Color.White,
|
|
origin: Vector2.Zero, rotate: 0.0f,
|
|
scale: Vector2.One * component.Rect.Height / sheet.FrameSize.ToVector2() * 0.8f);
|
|
}
|
|
});
|
|
}
|
|
|
|
private GUIListBox CreateTagsList(IEnumerable<Identifier> tags, RectTransform rectT, bool canBeFocused)
|
|
{
|
|
var tagsList
|
|
= new GUIListBox(rectT, style: null, isHorizontal: false)
|
|
{
|
|
UseGridLayout = true,
|
|
ScrollBarEnabled = false,
|
|
ScrollBarVisible = false,
|
|
HideChildrenOutsideFrame = false,
|
|
Spacing = GUI.IntScale(4)
|
|
};
|
|
tagsList.Content.ClampMouseRectToParent = false;
|
|
foreach (Identifier tag in tags)
|
|
{
|
|
var tagBtn = new GUIButton(
|
|
new RectTransform(new Vector2(0.25f, 1.0f / 8.0f), tagsList.Content.RectTransform,
|
|
anchor: Anchor.TopLeft),
|
|
TextManager.Get($"workshop.contenttag.{tag.Value.RemoveWhitespace()}")
|
|
.Fallback(tag.Value.CapitaliseFirstInvariant()), style: "GUIButtonRound")
|
|
{
|
|
CanBeFocused = canBeFocused,
|
|
Selected = !canBeFocused,
|
|
UserData = tag
|
|
};
|
|
tagBtn.RectTransform.NonScaledSize
|
|
= tagBtn.Font.MeasureString(tagBtn.Text).ToPoint() + new Point(GUI.IntScale(15), GUI.IntScale(5));
|
|
tagBtn.RectTransform.IsFixedSize = true;
|
|
tagBtn.ClampMouseRectToParent = false;
|
|
}
|
|
|
|
return tagsList;
|
|
}
|
|
|
|
private void PopulateFrameWithItemInfo(Steamworks.Ugc.Item workshopItem, GUIFrame parentFrame)
|
|
{
|
|
taskCancelSrc = taskCancelSrc.IsCancellationRequested ? new CancellationTokenSource() : taskCancelSrc;
|
|
|
|
var verticalLayout = new GUILayoutGroup(new RectTransform(Vector2.One, parentFrame.RectTransform));
|
|
|
|
var headerLayout = new GUILayoutGroup(new RectTransform((1.0f, 0.1f), verticalLayout.RectTransform),
|
|
isHorizontal: true) { Stretch = true };
|
|
|
|
var titleAndAuthorLayout = new GUILayoutGroup(new RectTransform(Vector2.One, headerLayout.RectTransform));
|
|
|
|
var selectedTitle =
|
|
new GUITextBlock(new RectTransform((1.0f, 0.5f), titleAndAuthorLayout.RectTransform), workshopItem.Title,
|
|
font: GUIStyle.LargeFont);
|
|
|
|
var author = workshopItem.Owner;
|
|
var authorButton = new GUIButton(new RectTransform((1.0f, 0.5f),
|
|
titleAndAuthorLayout.RectTransform),
|
|
style: null,
|
|
textAlignment: Alignment.CenterLeft)
|
|
{
|
|
ForceUpperCase = ForceUpperCase.No,
|
|
Font = GUIStyle.SubHeadingFont,
|
|
TextColor = GUIStyle.TextColorNormal,
|
|
HoverTextColor = Color.White,
|
|
SelectedTextColor = GUIStyle.TextColorNormal,
|
|
OnClicked = (button, o) =>
|
|
{
|
|
SteamManager.OverlayCustomURL(
|
|
$"https://steamcommunity.com/profiles/{author.Id}/myworkshopfiles/?appid={SteamManager.AppID}");
|
|
return false;
|
|
}
|
|
};
|
|
var authorPadding = authorButton.GetChild<GUITextBlock>().Padding;
|
|
|
|
RectTransform rightSideButtonRectT()
|
|
=> new RectTransform(Vector2.One, headerLayout.RectTransform, scaleBasis: ScaleBasis.BothHeight);
|
|
|
|
var (reinstallButton, reinstallSprite) = CreatePaddedButton(
|
|
rightSideButtonRectT(),
|
|
"GUIReloadButton",
|
|
spriteScale: 0.8f);
|
|
reinstallButton.ToolTip = TextManager.Get("WorkshopItemReinstall");
|
|
reinstallButton.OnClicked += (button, o) =>
|
|
{
|
|
SteamManager.Workshop.Uninstall(workshopItem);
|
|
TaskPool.Add($"Reinstall{workshopItem.Id}", SteamManager.Workshop.ForceRedownload(workshopItem), t => { });
|
|
return false;
|
|
};
|
|
var reinstallButtonUpdater = new GUICustomComponent(
|
|
new RectTransform(Vector2.Zero, reinstallButton.RectTransform),
|
|
onUpdate: (f, component) =>
|
|
{
|
|
reinstallButton.Visible = workshopItem.IsSubscribed;
|
|
reinstallButton.Enabled = !workshopItem.IsDownloading && !workshopItem.IsDownloadPending &&
|
|
!SteamManager.Workshop.IsInstalling(workshopItem);
|
|
reinstallSprite.Color = reinstallButton.Enabled
|
|
? reinstallSprite.Style.Color
|
|
: Color.DimGray;
|
|
});
|
|
CreateSubscribeButton(workshopItem,
|
|
rightSideButtonRectT(),
|
|
spriteScale: 0.8f);
|
|
|
|
var padding = new GUIFrame(new RectTransform((1.0f, 0.015f), verticalLayout.RectTransform), style: null);
|
|
|
|
var horizontalLayout = new GUILayoutGroup(new RectTransform((1.0f, 0.45f), verticalLayout.RectTransform),
|
|
isHorizontal: true)
|
|
{
|
|
Stretch = true
|
|
};
|
|
|
|
TaskPool.Add($"Request username for {author.Id}", author.RequestInfoAsync(), (t) =>
|
|
{
|
|
authorButton.Text = author.Name;
|
|
authorButton.RectTransform.NonScaledSize =
|
|
((int)(authorButton.Font.MeasureString(author.Name).X + authorPadding.X + authorPadding.Z),
|
|
authorButton.RectTransform.NonScaledSize.Y);
|
|
});
|
|
|
|
var thumbnailSuperContainer = new GUIFrame(
|
|
new RectTransform(Vector2.One, horizontalLayout.RectTransform, scaleBasis: ScaleBasis.BothHeight),
|
|
style: null);
|
|
GUIFrame thumbnailContainer = CreateThumbnailContainer(thumbnailSuperContainer, Vector2.One,
|
|
scaleBasis: ScaleBasis.BothHeight);
|
|
CreateItemThumbnail(workshopItem, taskCancelSrc.Token, thumbnailContainer);
|
|
thumbnailContainer.RectTransform.Anchor = Anchor.Center;
|
|
thumbnailContainer.RectTransform.Pivot = Pivot.Center;
|
|
|
|
var statsBox = new GUIFrame(new RectTransform((0.6f, 1.0f), horizontalLayout.RectTransform),
|
|
style: "GUIFrameListBox");
|
|
|
|
#region Stats box
|
|
var statsHorizontalLayout = new GUILayoutGroup(new RectTransform(Vector2.One, statsBox.RectTransform), isHorizontal: true);
|
|
var statsVertical0
|
|
= new GUILayoutGroup(new RectTransform((1.0f, 1.0f), statsHorizontalLayout.RectTransform), childAnchor: Anchor.TopCenter);
|
|
|
|
statFrame("", ""); //padding
|
|
|
|
var scoreFrame = new GUIFrame(new RectTransform((1.0f, 0.12f), statsVertical0.RectTransform), style: null);
|
|
var scoreLabel = new GUITextBlock(new RectTransform((0.4f, 1.0f), scoreFrame.RectTransform),
|
|
TextManager.Get("WorkshopItemScore"), font: GUIStyle.SubHeadingFont);
|
|
var scoreStarContainer
|
|
= new GUILayoutGroup(
|
|
new RectTransform((0.6f, 1.0f), scoreFrame.RectTransform, Anchor.CenterRight),
|
|
isHorizontal: true,
|
|
childAnchor: Anchor.CenterLeft) { Stretch = true };
|
|
var starColor = Color.Lerp(
|
|
Color.Lerp(Color.Red, Color.Yellow, Math.Min(workshopItem.Score * 2.0f, 1.0f)),
|
|
Color.Lime, Math.Max(0.0f, (workshopItem.Score - 0.5f) * 2.0f));
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
bool isStarLit = i <= Round(workshopItem.Score * 5.0f);
|
|
var star = new GUIFrame(new RectTransform(Vector2.One, scoreStarContainer.RectTransform, scaleBasis: ScaleBasis.BothHeight),
|
|
style: isStarLit ? "GUIStarIconBright" : "GUIStarIconDark");
|
|
if (isStarLit)
|
|
{
|
|
star.Color = starColor;
|
|
star.HoverColor = starColor;
|
|
star.SelectedColor = starColor;
|
|
}
|
|
}
|
|
var scoreVoteCountPadding = new GUIFrame(new RectTransform((0.5f, 1.0f), scoreStarContainer.RectTransform, scaleBasis: ScaleBasis.BothHeight),
|
|
style: null);
|
|
var scoreVoteCount = new GUITextBlock(
|
|
new RectTransform(Vector2.One, scoreStarContainer.RectTransform),
|
|
TextManager.GetWithVariable("WorkshopItemVotes", "[VoteCount]",
|
|
(workshopItem.VotesUp + workshopItem.VotesDown).ToString()), textAlignment: Alignment.CenterLeft)
|
|
{
|
|
Padding = Vector4.Zero
|
|
};
|
|
|
|
void statFrame(LocalizedString labelText, LocalizedString dataText)
|
|
{
|
|
var frame = new GUIFrame(new RectTransform((1.0f, 0.12f), statsVertical0!.RectTransform), style: null);
|
|
var label = new GUITextBlock(new RectTransform((0.4f, 1.0f), frame.RectTransform),
|
|
labelText, font: GUIStyle.SubHeadingFont);
|
|
var data = new GUITextBlock(new RectTransform((0.6f, 1.0f), frame.RectTransform, Anchor.CenterRight),
|
|
dataText, font: GUIStyle.Font)
|
|
{
|
|
Padding = Vector4.Zero
|
|
};
|
|
}
|
|
|
|
statFrame(TextManager.Get("WorkshopItemFileSize"), MathUtils.GetBytesReadable(workshopItem.SizeOfFileInBytes));
|
|
statFrame(TextManager.Get("WorkshopItemCreationDate"), workshopItem.Created.ToShortDateString());
|
|
statFrame(TextManager.Get("WorkshopItemModificationDate"), workshopItem.Updated.ToShortDateString());
|
|
|
|
var tagsLabel = new GUITextBlock(new RectTransform((1.0f, 0.12f), statsVertical0.RectTransform),
|
|
TextManager.Get("WorkshopItemTags"), font: GUIStyle.SubHeadingFont);
|
|
CreateTagsList(workshopItem.Tags.ToIdentifiers(), new RectTransform((0.97f, 0.3f), statsVertical0.RectTransform), canBeFocused: false);
|
|
#endregion
|
|
|
|
var descriptionListBox = new GUIListBox(new RectTransform((1.0f, 0.38f), verticalLayout.RectTransform));
|
|
CreateBBCodeElement(workshopItem.Description, descriptionListBox);
|
|
|
|
var showInSteamContainer
|
|
= new GUIFrame(new RectTransform((1.0f, 0.05f), verticalLayout.RectTransform), style: null);
|
|
CreateShowInSteamButton(workshopItem, new RectTransform((0.2f, 1.0f), showInSteamContainer.RectTransform, Anchor.CenterRight));
|
|
}
|
|
}
|
|
}
|