Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>0.31.0</Version>
<Version>0.32.0</Version>
<RootNamespace>MonkeyLoader.Resonite</RootNamespace>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>

Expand Down
2 changes: 2 additions & 0 deletions MonkeyLoader.Resonite.Core/MonkeyLoader.Resonite.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ For mods targetting ML, this library is part of the Resonite Game Pack.</Descrip
<ItemGroup>
<ResoniteReference Include="FrooxEngine" UsePublicized="true" />
<ResoniteReference Include="Elements.Core" />
<ResoniteReference Include="ProtoFlux.Core" />
<ResoniteReference Include="Renderite.Shared" />
<ResoniteReference Include="SkyFrost.Base.Models" />
</ItemGroup>
</Project>
5 changes: 0 additions & 5 deletions MonkeyLoader.Resonite.Core/UI/ButtonRefExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
using Elements.Core;
using FrooxEngine;
using FrooxEngine.UIX;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

#pragma warning disable CS1572 // XML comment has a param tag, but there is no parameter by that name
#pragma warning disable CS1573 // Parameter has no matching param tag in the XML comment (but other parameters do)
Expand Down
19 changes: 7 additions & 12 deletions MonkeyLoader.Resonite.Core/UI/LocalActionButtonExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
using FrooxEngine.UIX;
using FrooxEngine;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Elements.Core;
using System.Runtime.CompilerServices;

namespace MonkeyLoader.Resonite.UI
{
/// <summary>
/// Contains extension methods to setup locally defined actions for <see cref="IButton"/>s which are triggerable by anyone.
/// Contains extension methods to setup locally defined actions for <see cref="IButton"/>s, which are triggerable by anyone.
/// </summary>
/// <remarks>
/// Due to their nature, they will only work while the <see cref="User"/> that creates them hasn't left the session.<br/>
Expand Down Expand Up @@ -156,11 +151,11 @@ public static Button LocalActionButton<T>(this UIBuilder builder, IAssetProvider
public static TButton WithLocalAction<TButton>(this TButton button, Action<TButton> action)
where TButton : IButton
{
var valueField = button.Slot.AttachComponent<ValueField<bool>>().Value;
valueField.OnValueChange += field => action(button);
var valueTag = button.Slot.AttachComponent<ValueTag<bool>>().Value;
valueTag.OnValueChange += field => action(button);

var toggle = button.Slot.AttachComponent<ButtonToggle>();
toggle.TargetValue.Target = valueField;
toggle.TargetValue.Target = valueTag;

button.Slot.DestroyWhenLocalUserLeaves();

Expand All @@ -183,11 +178,11 @@ public static TButton WithLocalAction<TButton>(this TButton button, Action<TButt
public static TButton WithLocalAction<TButton, TArgument>(this TButton button, TArgument argument, Action<TButton, TArgument> action)
where TButton : IButton
{
var valueField = button.Slot.AttachComponent<ValueField<bool>>().Value;
valueField.OnValueChange += field => action(button, argument);
var valueTag = button.Slot.AttachComponent<ValueTag<bool>>().Value;
valueTag.OnValueChange += field => action(button, argument);

var toggle = button.Slot.AttachComponent<ButtonToggle>();
toggle.TargetValue.Target = valueField;
toggle.TargetValue.Target = valueTag;

button.Slot.DestroyWhenLocalUserLeaves();

Expand Down
149 changes: 149 additions & 0 deletions MonkeyLoader.Resonite.Core/UI/WikiLinkButtonExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
using Elements.Core;
using FrooxEngine;
using FrooxEngine.ProtoFlux;
using ProtoFlux.Core;
using System.Reflection;

namespace MonkeyLoader.Resonite.UI
{
/// <summary>
/// Contains extension methods to setup <see cref="IButton"/>s with links to the Resonite Wiki, which are triggerable by anyone.
/// </summary>
public static class WikiLinkButtonExtensions
{
private static readonly Dictionary<string, string> _nameOverrides = new()
{
{ "Engine.DynamicVariables.Input", "DynamicVariableInput" },
{ "Engine.DynamicVariables.InputWithEvents", "DynamicVariableInputWithEvents" },
};

internal static LocaleString ComponentLocale { get; set; }

internal static LocaleString ProtoFluxLocale { get; set; }

/// <summary>
/// Sets up an <see cref="IButton"/> with a <see cref="Hyperlink"/> to the given wiki <paramref name="page"/>,
/// optionally setting the <paramref name="reason"/> for opening it.
/// </summary>
/// <typeparam name="TButton">The specific type of the button.</typeparam>
/// <param name="button">The button to set up with a wiki link.</param>
/// <param name="page">The wiki page to link to.</param>
/// <param name="reason">The optional reason for opening the link.</param>
/// <returns>The unchanged button.</returns>
public static TButton WithWikiLink<TButton>(this TButton button, string page, in LocaleString reason = default)
where TButton : IButton
{
var hyperlink = button.Slot.AttachComponent<Hyperlink>();
hyperlink.URL.Value = new Uri($"{button.Slot.Engine.PlatformProfile.Wiki}/{page}");
hyperlink.Reason.AssignLocaleString(reason);

return button;
}

//private static readonly Type _componentType = typeof(Component);
//private static readonly Type _protoFluxNodeType = typeof(ProtoFluxNode);
//public static TButton WithWikiLinkFor<TButton>(this TButton button, Type workerType)
// where TButton : IButton
//{
// while (workerType.IsNested)
// workerType = workerType.DeclaringType!;

// var pagePrefix = workerType.GetCustomAttribute<WikiPrefixAttribute>(inherit: true)?.Prefix ?? "";

// string wikiPage;
// LocaleString reason;

// if (workerType.IsAssignableTo(_protoFluxNodeType))
// {
// var nodeName = node.NodeName;
// var overload = NodeMetadataHelper.GetMetadata(node.NodeType).Overload;

// if (!string.IsNullOrEmpty(overload))
// {
// if (_nameOverrides.TryGetValue(overload, out var overrideName))
// {
// nodeName = overrideName;
// }
// else
// {
// var dotIndex = overload.LastIndexOf('.');

// nodeName = dotIndex > 0 ? overload[(dotIndex + 1)..] : nodeName;
// }
// }

// wikiPage = $"{pagePrefix}{nodeName.Replace(' ', '_')}";
// reason = ProtoFluxLocale;
// }
// else
// {
// var workerName = worker.WorkerType.Name;

// // Don't need to remove the `1 on generics - they redirect and may actually be different
// wikiPage = $"{pagePrefix}{workerName}";
// reason = ComponentLocale;
// }

// return button
// .WithTooltip(reason)
// .WithWikiLink(wikiPage, reason);
//}

/// <summary>
/// Sets up an <see cref="IButton"/> with a <see cref="Hyperlink"/> to the wiki page for the given <paramref name="worker"/>.
/// </summary>
/// <remarks>
/// This method automatically sets a tooltip and reason for opening the link.
/// </remarks>
/// <typeparam name="TButton">The specific type of the button.</typeparam>
/// <param name="button">The button to set up with a wiki link.</param>
/// <param name="worker">The worker to the link the wiki page for.</param>
/// <returns>The unchanged button.</returns>
public static TButton WithWikiLinkFor<TButton>(this TButton button, IWorker worker)
where TButton : IButton
{
if (worker is ProtoFluxEngineProxy proxy)
worker = proxy.Node.Target ?? worker;

var pagePrefix = worker.GetType().GetCustomAttribute<WikiPrefixAttribute>(inherit: true)?.Prefix ?? "";

string wikiPage;
LocaleString reason;

if (worker is ProtoFluxNode node)
{
var nodeName = node.NodeName;
var overload = NodeMetadataHelper.GetMetadata(node.NodeType).Overload;

if (!string.IsNullOrEmpty(overload))
{
if (_nameOverrides.TryGetValue(overload, out var overrideName))
{
nodeName = overrideName;
}
else
{
var dotIndex = overload.LastIndexOf('.');

nodeName = dotIndex > 0 ? overload[(dotIndex + 1)..] : nodeName;
}
}

wikiPage = $"{pagePrefix}{nodeName.Replace(' ', '_')}";
reason = ProtoFluxLocale;
}
else
{
var workerName = worker.WorkerType.Name;

// Don't need to remove the `1 on generics - they redirect and may actually be different
wikiPage = $"{pagePrefix}{workerName}";
reason = ComponentLocale;
}

return button
.WithTooltip(reason)
.WithWikiLink(wikiPage, reason);
}
}
}
10 changes: 6 additions & 4 deletions MonkeyLoader.Resonite.Integration/Locale/Config/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,17 @@

"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.Name": "Inspektor-Kopfzeile",
"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.DestroyOffset.Name": "Löschen Offset",
"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.DestroyOffset.Description": "Das Order Offset des Löschen-Knopfs bei Inspektor-Kopfzeilen. Erlaubter Wert: 0-16 - Höher ist weiter rechts.",
"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.DestroyOffset.Description": "Das Order Offset des Löschen-Knopfs bei Inspektor-Kopfzeilen. Höher ist weiter rechts.",
"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.DuplicateOffset.Name": "Duplizieren Offset",
"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.DuplicateOffset.Description": "Das Order Offset des Duplizieren-Knopfs bei Inspektor-Kopfzeilen. Erlaubter Wert: 0-16 - Höher ist weiter rechts.",
"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.DuplicateOffset.Description": "Das Order Offset des Duplizieren-Knopfs bei Inspektor-Kopfzeilen. Höher ist weiter rechts.",
"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.OpenContainerOffset.Name": "Container-Öffnen Offset",
"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.OpenContainerOffset.Description": "Das Order Offset des Container-Öffnen-Knopfs bei Inspektor-Kopfzeilen. Erlaubter Wert: 0-16 - Höher ist weiter rechts.",
"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.OpenContainerOffset.Description": "Das Order Offset des Container-Öffnen-Knopfs bei Inspektor-Kopfzeilen. Höher ist weiter rechts.",
"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.StartHeaderTextExpanded.Name": "Starte Kopfzeilentext Expandiert",
"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.StartHeaderTextExpanded.Description": "Zeigt den Kopfzeilentext in Inspektoren standardmäßig an.",
"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.NameOffset.Name": "Name Offset",
"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.NameOffset.Description": "Das Order Offset des Worker-Name-Knopfs bei Inspektor-Kopfzeilen. Erlaubter Wert: 0-16 - Höher ist weiter rechts.",
"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.NameOffset.Description": "Das Order Offset des Worker-Name-Knopfs bei Inspektor-Kopfzeilen. Höher ist weiter rechts.",
"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.WikiLinkOffset.Name": "Wikilink Offset",
"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.WikiLinkOffset.Description": "Das Order Offset des Wikilink-Knopfs bei Inspektor-Kopfzeilen. Höher ist weiter rechts.<size=50%><br/><br/></size>Nutzt den konfigurierten Wert der ursprünglichen Wiki Integration Mod als Standardwert, falls vorhanden.",

"MonkeyLoader.GamePacks.Resonite.Config.Loading.Name": "Ladevorgang",
"MonkeyLoader.GamePacks.Resonite.Config.Loading.HijackLoadProgressIndicator.Name": "Ladefortschrittsanzeige übernehmen",
Expand Down
2 changes: 2 additions & 0 deletions MonkeyLoader.Resonite.Integration/Locale/Config/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@
"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.StartHeaderTextExpanded.Description": "Shows the inspector header text by default.",
"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.NameOffset.Name": "Name Offset",
"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.NameOffset.Description": "The Order Offset of the Worker Name button on Inspector Headers. Higher is further right.",
"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.WikiLinkOffset.Name": "Wiki Link Offset",
"MonkeyLoader.GamePacks.Resonite.Config.DefaultInspectorHeader.WikiLinkOffset.Description": "The Order Offset of the Wiki Link button on Inspector Headers. Higher is further right.<size=50%><br/><br/></size>Uses the configured value of the original Wiki Integration mod as a default, if available.",

"MonkeyLoader.GamePacks.Resonite.Config.Loading.Name": "Loading",
"MonkeyLoader.GamePacks.Resonite.Config.Loading.HijackLoadProgressIndicator.Name": "Hijack Load Progress Indicator",
Expand Down
5 changes: 4 additions & 1 deletion MonkeyLoader.Resonite.Integration/Locale/General/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
"MonkeyLoader.GamePacks.Resonite.Tooltip.RefreshFacet": "Aktualisiert diese Facet auf die neueste Version.",

"MonkeyLoader.GamePacks.Resonite.Tooltip.OpenHyperlink.Direct": "Versucht einen Hyperlink zu öffnen.<size=50%><br/><br/></size><b>Grund:</b> <i>{reason}</i><br/><b>URL:</b> <i>{url}</i>",
"MonkeyLoader.GamePacks.Resonite.Tooltip.OpenHyperlink.WithLabel": "{label}<size=50%><br/><br/></size><b>Grund:</b> <i>{reason}</i><br/><b>URL:</b> <i>{url}</i>"
"MonkeyLoader.GamePacks.Resonite.Tooltip.OpenHyperlink.WithLabel": "{label}<size=50%><br/><br/></size><b>Grund:</b> <i>{reason}</i><br/><b>URL:</b> <i>{url}</i>",

"MonkeyLoader.GamePacks.Resonite.Tooltip.WikiHyperlink.Component": "Öffnet den Resonite Wiki Artikel über diese Komponente.",
"MonkeyLoader.GamePacks.Resonite.Tooltip.WikiHyperlink.ProtoFlux": "Öffnet den Resonite Wiki Artikel über diese ProtoFlux Node."
}
}
5 changes: 4 additions & 1 deletion MonkeyLoader.Resonite.Integration/Locale/General/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
"MonkeyLoader.GamePacks.Resonite.Tooltip.RefreshFacet": "Refreshes this facet to the latest version.",

"MonkeyLoader.GamePacks.Resonite.Tooltip.OpenHyperlink.Direct": "Attempts to open a hyperlink.<size=50%><br/><br/></size><b>Reason:</b> <i>{reason}</i><br/><b>URL:</b> <i>{url}</i>",
"MonkeyLoader.GamePacks.Resonite.Tooltip.OpenHyperlink.WithLabel": "{label}<size=50%><br/><br/></size><b>Reason:</b> <i>{reason}</i><br/><b>URL:</b> <i>{url}</i>"
"MonkeyLoader.GamePacks.Resonite.Tooltip.OpenHyperlink.WithLabel": "{label}<size=50%><br/><br/></size><b>Reason:</b> <i>{reason}</i><br/><b>URL:</b> <i>{url}</i>",

"MonkeyLoader.GamePacks.Resonite.Tooltip.WikiHyperlink.Component": "Opens the Resonite Wiki article about this Component.",
"MonkeyLoader.GamePacks.Resonite.Tooltip.WikiHyperlink.ProtoFlux": "Opens the Resonite Wiki article about this ProtoFlux node."
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ public sealed class BuildInspectorHeaderEvent : BuildInspectorEvent
/// </summary>
public const string OpenContainerButtonName = "OpenContainer";

/// <summary>
/// The name for the <see cref="WikiLinkButton">Wiki Link button</see>.
/// </summary>
public const string WikiLinkButtonName = "WikiLink";

/// <summary>
/// The name for the <see cref="WorkerNameButton">Worker Name button</see>.
/// </summary>
Expand All @@ -149,6 +154,12 @@ public sealed class BuildInspectorHeaderEvent : BuildInspectorEvent
/// </summary>
public bool CreateOpenContainerButton => AllowContainer && !HasOpenContainerButton && Worker.FindNearestParent<Slot>() != null;

/// <summary>
/// Gets whether the inspector header that's currently being build
/// still needs to have a <see cref="WikiLinkButton">Wiki Link button</see> created.
/// </summary>
public bool CreateWikiLinkButton => !HasWikiLinkButton;

/// <summary>
/// Gets whether the inspector header that's currently being build
/// still needs to have a <see cref="WorkerNameButton">Worker Name button</see> created.
Expand Down Expand Up @@ -181,24 +192,35 @@ public IButton DuplicateButton
/// Gets whether the inspector header that's currently being build
/// already has a <see cref="DestroyButton">Destroy</see> button.
/// </summary>
[MemberNotNullWhen(true, nameof(DestroyButton))]
public bool HasDestroyButton => HasButton(DestroyButtonName);

/// <summary>
/// Gets whether the inspector header that's currently being build
/// already has a <see cref="DuplicateButton">Duplicate</see> button.
/// </summary>
[MemberNotNullWhen(true, nameof(DuplicateButton))]
public bool HasDuplicateButton => HasButton(DuplicateButtonName);

/// <summary>
/// Gets whether the inspector header that's currently being build
/// already has an <see cref="OpenContainerButton">Open Container</see> button.
/// </summary>
[MemberNotNullWhen(true, nameof(OpenContainerButton))]
public bool HasOpenContainerButton => HasButton(OpenContainerButtonName);

/// <summary>
/// Gets whether the inspector header that's currently being build
/// already has a <see cref="WikiLinkButton">Wiki Link</see> button.
/// </summary>
[MemberNotNullWhen(true, nameof(WikiLinkButton))]
public bool HasWikiLinkButton => HasButton(WikiLinkButtonName);

/// <summary>
/// Gets whether the inspector header that's currently being build
/// already has a <see cref="WorkerNameButton">Worker Name</see> button.
/// </summary>
[MemberNotNullWhen(true, nameof(WorkerNameButton))]
public bool HasWorkerNameButton => HasButton(WorkerNameButtonName);

/// <summary>
Expand All @@ -212,6 +234,17 @@ public IButton OpenContainerButton
set => SetButton(OpenContainerButtonName, value);
}

/// <summary>
/// Gets the Wiki Link button of the inspector header that's currently being build.
/// </summary>
/// <value>The button or <c>null</c> if there is none yet.</value>
[MaybeNull]
public IButton WikiLinkButton
{
get => GetButton(WikiLinkButtonName);
set => SetButton(WikiLinkButtonName, value);
}

/// <summary>
/// Gets the Worker Name button of the inspector header that's currently being build.
/// </summary>
Expand Down
Loading
Loading