diff --git a/DynamicVariablePowerTools/ContextMenu/DVMA.References.cs b/DynamicVariablePowerTools/ContextMenu/DVMA.References.cs index f2f0337..98d1cae 100644 --- a/DynamicVariablePowerTools/ContextMenu/DVMA.References.cs +++ b/DynamicVariablePowerTools/ContextMenu/DVMA.References.cs @@ -1,17 +1,40 @@ using FrooxEngine; +using HarmonyLib; using MonkeyLoader.Resonite; - +using System.Reflection; using GenerationEvent = MonkeyLoader.Resonite.UI.Inspectors.InspectorMemberActionsMenuItemsGenerationEvent; namespace DynamicVariablePowerTools.ContextMenu { internal sealed partial class DynamicVariableMemberActions { - private static ButtonEventHandler GetDriveSyncRefFromVariable(GenerationEvent eventData, SyncRef syncRefTarget, string variable) + private static readonly MethodInfo _getDriveSyncRefWithCastFromVariableMethod = AccessTools.Method(typeof(DynamicVariableMemberActions), nameof(GetDriveSyncRefWithCastFromVariable)); + + private static ButtonEventHandler GetDriveSyncRefFromVariable(GenerationEvent eventData, SyncRef syncRefTarget, string variable, Type? variableType = null) where T : class, IWorldElement + { + if (variableType is null || variableType == syncRefTarget.TargetType) + { + return (button, args) => + { + syncRefTarget.DriveFromVariable(variable); + eventData.CloseContextMenu(); + }; + } + + var getMethod = _getDriveSyncRefWithCastFromVariableMethod.MakeGenericMethod(syncRefTarget.TargetType, variableType); + return (ButtonEventHandler)getMethod.Invoke(null, [eventData, syncRefTarget, variable])!; + } + + private static ButtonEventHandler GetDriveSyncRefWithCastFromVariable(GenerationEvent eventData, SyncRef syncRefTarget, string variable) + where TTarget : class, IWorldElement + where TVariable : class, IWorldElement => (button, args) => { - syncRefTarget.DriveFromVariable(variable); + var cast = syncRefTarget.Slot.AttachComponent>(); + cast.Target.Target = syncRefTarget; + cast.Source.DriveFromVariable(variable); + eventData.CloseContextMenu(); }; @@ -28,13 +51,32 @@ private static ButtonEventHandler GetOfferSyncRefDriveActions(GenerationEvent var blankVariableName = string.IsNullOrWhiteSpace(space.CurrentName) ? string.Empty : $"{space.CurrentName}/"; - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Drive.FromVariable", "variable", GetDisplayName(space, "")), DriveIcon, DriveColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Drive.FromVariable", "variable", GetDisplayName(space, "")), DriveIcon, DriveColor) .Button.LocalPressed += GetDriveSyncRefFromVariable(eventData, syncRefTarget, blankVariableName); - foreach (var variable in space.GetVariableIdentities().RemoveSharedConfigVariables()) + foreach (var variable in space.GetVariableIdentities().WithoutSharedConfigVariables()) { - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Drive.FromVariable", "variable", GetDisplayName(variable)), DriveIcon, DriveColor) - .Button.LocalPressed += GetDriveSyncRefFromVariable(eventData, syncRefTarget, variable.QualifiedName); + var couldDowncast = variable.Type.IsAssignableTo(syncRefTarget.TargetType); + var couldUpcast = syncRefTarget.TargetType.IsAssignableTo(variable.Type); + + // Variable and target are completely incompatible + if (!couldDowncast && !couldUpcast) + continue; + + // Variable and target are not the same but (potentially) compatible + if (couldDowncast ^ couldUpcast) + { + // Variable is more derived than target + if (!ConfigSection.AllowDowncastToDrive && couldDowncast) + continue; + + // Variable is less derived than target + if (!ConfigSection.AllowUpcastToDrive && couldUpcast) + continue; + } + + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Drive.FromVariable", "variable", GetDisplayName(variable)), DriveIcon, DriveColor) + .Button.LocalPressed += GetDriveSyncRefFromVariable(eventData, syncRefTarget, variable.QualifiedName, variable.Type); } }); }; @@ -50,14 +92,14 @@ private static ButtonEventHandler GetOfferSyncRefDriveSpaceActions(Generation if (await eventData.OpenContextMenuAsync(args.source.Slot) is null) return; - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Drive.FromBlank"), DriveIcon, DriveColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Drive.FromBlank"), DriveIcon, DriveColor) .Button.LocalPressed += GetDriveSyncRefFromVariable(eventData, syncRefTarget, string.Empty); foreach (var space in eventData.Slot!.GetAvailableSpaces()) { var spaceName = string.IsNullOrWhiteSpace(space.CurrentName) ? "null" : space.CurrentName; - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Drive.FromSpace", "space", spaceName), DriveIcon, DriveColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Drive.FromSpace", "space", spaceName), DriveIcon, DriveColor) .Button.LocalPressed += GetOfferSyncRefDriveActions(eventData, syncRefTarget, space); } }); @@ -74,7 +116,7 @@ private static ButtonEventHandler GetOfferSyncRefReferenceActions(GenerationE if (await eventData.OpenContextMenuAsync(args.source.Slot) is null) return; - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Reference.Blank"), ReferenceIcon, ReferenceColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Reference.Blank"), ReferenceIcon, ReferenceColor) .Button.LocalPressed += GetReferenceSyncRefForVariable(eventData, syncRefTarget, string.Empty); var spaces = eventData.Slot! @@ -82,7 +124,7 @@ private static ButtonEventHandler GetOfferSyncRefReferenceActions(GenerationE foreach (var space in spaces) { - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Reference.InSpace", "space", space.SpaceName), ReferenceIcon, ReferenceColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Reference.InSpace", "space", space.SpaceName), ReferenceIcon, ReferenceColor) .Button.LocalPressed += GetReferenceSyncRefForVariable(eventData, syncRefTarget, $"{space.SpaceName}/"); } }); @@ -99,7 +141,7 @@ private static ButtonEventHandler GetOfferSyncRefSourceActions(GenerationEven if (await eventData.OpenContextMenuAsync(args.source.Slot) is null) return; - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Source.Blank"), SourceIcon, SourceColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Source.Blank"), SourceIcon, SourceColor) .Button.LocalPressed += GetSourceSyncRefForVariable(eventData, syncRefTarget, string.Empty); var spaces = eventData.Slot! @@ -107,7 +149,7 @@ private static ButtonEventHandler GetOfferSyncRefSourceActions(GenerationEven foreach (var space in spaces) { - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Source.InSpace", "space", space.SpaceName), SourceIcon, SourceColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Source.InSpace", "space", space.SpaceName), SourceIcon, SourceColor) .Button.LocalPressed += GetSourceSyncRefForVariable(eventData, syncRefTarget, $"{space.SpaceName}/"); } }); @@ -140,14 +182,14 @@ private static void OfferSyncRefActions(GenerationEvent eventData) if (!syncRefTarget.IsLinked) { - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Drive"), DriveIcon, DriveColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Drive"), DriveIcon, DriveColor) .Button.LocalPressed += GetOfferSyncRefDriveSpaceActions(eventData, syncRefTarget); } - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Source", "type", "DynamicReference"), SourceIcon, SourceColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Source", "type", "DynamicReference"), SourceIcon, SourceColor) .Button.LocalPressed += GetOfferSyncRefSourceActions(eventData, syncRefTarget); - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Reference"), ReferenceIcon, ReferenceColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Reference"), ReferenceIcon, ReferenceColor) .Button.LocalPressed += GetOfferSyncRefReferenceActions(eventData, syncRefTarget); } } diff --git a/DynamicVariablePowerTools/ContextMenu/DVMA.Types.cs b/DynamicVariablePowerTools/ContextMenu/DVMA.Types.cs index 4bceeac..d39feb2 100644 --- a/DynamicVariablePowerTools/ContextMenu/DVMA.Types.cs +++ b/DynamicVariablePowerTools/ContextMenu/DVMA.Types.cs @@ -26,12 +26,12 @@ private static ButtonEventHandler GetOfferTypeFieldDriveActions(GenerationEvent var blankVariableName = string.IsNullOrWhiteSpace(space.CurrentName) ? string.Empty : $"{space.CurrentName}/"; - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Drive.FromVariable", "variable", GetDisplayName(space, "")), DriveIcon, DriveColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Drive.FromVariable", "variable", GetDisplayName(space, "")), DriveIcon, DriveColor) .Button.LocalPressed += GetDriveTypeFieldFromVariable(eventData, syncTypeTarget, blankVariableName); - foreach (var variable in space.GetVariableIdentities().RemoveSharedConfigVariables()) + foreach (var variable in space.GetVariableIdentities().WithoutSharedConfigVariables()) { - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Drive.FromVariable", "variable", GetDisplayName(variable)), DriveIcon, DriveColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Drive.FromVariable", "variable", GetDisplayName(variable)), DriveIcon, DriveColor) .Button.LocalPressed += GetDriveTypeFieldFromVariable(eventData, syncTypeTarget, variable.QualifiedName); } }); @@ -47,12 +47,12 @@ private static ButtonEventHandler GetOfferTypeFieldDriveSpaceActions(GenerationE if (await eventData.OpenContextMenuAsync(args.source.Slot) is null) return; - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Drive.FromBlank"), DriveIcon, DriveColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Drive.FromBlank"), DriveIcon, DriveColor) .Button.LocalPressed += GetDriveFieldFromVariable(eventData, syncTypeTarget, string.Empty); foreach (var space in eventData.Slot!.GetAvailableSpaces()) { - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Drive.FromSpace", "space", GetDisplayName(space)), DriveIcon, DriveColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Drive.FromSpace", "space", GetDisplayName(space)), DriveIcon, DriveColor) .Button.LocalPressed += GetOfferTypeFieldDriveActions(eventData, syncTypeTarget, space); } }); @@ -68,12 +68,12 @@ private static ButtonEventHandler GetOfferTypeFieldReferenceActions(GenerationEv if (await eventData.OpenContextMenuAsync(args.source.Slot) is null) return; - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Reference.Blank"), ReferenceIcon, ReferenceColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Reference.Blank"), ReferenceIcon, ReferenceColor) .Button.LocalPressed += GetReferenceTypeFieldForVariable(eventData, syncTypeTarget, string.Empty); foreach (var space in eventData.Slot!.GetAvailableSpaces(SpaceHasName)) { - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Reference.InSpace", "space", space.SpaceName), ReferenceIcon, ReferenceColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Reference.InSpace", "space", space.SpaceName), ReferenceIcon, ReferenceColor) .Button.LocalPressed += GetReferenceTypeFieldForVariable(eventData, syncTypeTarget, $"{space.SpaceName}/"); } }); @@ -89,12 +89,12 @@ private static ButtonEventHandler GetOfferTypeFieldSourceActions(GenerationEvent if (await eventData.OpenContextMenuAsync(args.source.Slot) is null) return; - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Source.Blank"), SourceIcon, SourceColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Source.Blank"), SourceIcon, SourceColor) .Button.LocalPressed += GetSourceTypeFieldForVariable(eventData, syncTypeTarget, string.Empty); foreach (var space in eventData.Slot!.GetAvailableSpaces(SpaceHasName)) { - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Source.InSpace", "space", space.SpaceName), SourceIcon, SourceColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Source.InSpace", "space", space.SpaceName), SourceIcon, SourceColor) .Button.LocalPressed += GetSourceTypeFieldForVariable(eventData, syncTypeTarget, $"{space.SpaceName}/"); } }); @@ -124,14 +124,14 @@ private static void OfferTypeFieldActions(GenerationEvent eventData) if (!syncTypeTarget.IsLinked) { - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Drive"), DriveIcon, DriveColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Drive"), DriveIcon, DriveColor) .Button.LocalPressed += GetOfferTypeFieldDriveSpaceActions(eventData, syncTypeTarget); } - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Source", "type", "DynamicTypeField"), SourceIcon, SourceColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Source", "type", "DynamicTypeField"), SourceIcon, SourceColor) .Button.LocalPressed += GetOfferTypeFieldSourceActions(eventData, syncTypeTarget); - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Reference"), ReferenceIcon, ReferenceColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Reference"), ReferenceIcon, ReferenceColor) .Button.LocalPressed += GetOfferTypeFieldReferenceActions(eventData, syncTypeTarget); } } diff --git a/DynamicVariablePowerTools/ContextMenu/DVMA.Values.cs b/DynamicVariablePowerTools/ContextMenu/DVMA.Values.cs index 8c4ca2a..660c3a3 100644 --- a/DynamicVariablePowerTools/ContextMenu/DVMA.Values.cs +++ b/DynamicVariablePowerTools/ContextMenu/DVMA.Values.cs @@ -7,6 +7,7 @@ namespace DynamicVariablePowerTools.ContextMenu { internal sealed partial class DynamicVariableMemberActions { + // TODO: private static ButtonEventHandler GetDriveFieldFromVariable(GenerationEvent eventData, IField fieldTarget, string variable) => (button, args) => { @@ -26,12 +27,12 @@ private static ButtonEventHandler GetOfferFieldDriveActions(GenerationEvent e var blankVariableName = string.IsNullOrWhiteSpace(space.CurrentName) ? string.Empty : $"{space.CurrentName}/"; - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Drive.FromVariable", "variable", GetDisplayName(space, "")), DriveIcon, DriveColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Drive.FromVariable", "variable", GetDisplayName(space, "")), DriveIcon, DriveColor) .Button.LocalPressed += GetDriveFieldFromVariable(eventData, fieldTarget, blankVariableName); - foreach (var variable in space.GetVariableIdentities().RemoveSharedConfigVariables()) + foreach (var variable in space.GetVariableIdentities().WithoutSharedConfigVariables()) { - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Drive.FromVariable", "variable", GetDisplayName(variable)), DriveIcon, DriveColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Drive.FromVariable", "variable", GetDisplayName(variable)), DriveIcon, DriveColor) .Button.LocalPressed += GetDriveFieldFromVariable(eventData, fieldTarget, variable.QualifiedName); } }); @@ -47,12 +48,12 @@ private static ButtonEventHandler GetOfferFieldDriveSpaceActions(GenerationEv if (await eventData.OpenContextMenuAsync(args.source.Slot) is null) return; - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Drive.FromBlank"), DriveIcon, DriveColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Drive.FromBlank"), DriveIcon, DriveColor) .Button.LocalPressed += GetDriveFieldFromVariable(eventData, fieldTarget, string.Empty); foreach (var space in eventData.Slot!.GetAvailableSpaces()) { - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Drive.FromSpace", "space", GetDisplayName(space)), DriveIcon, DriveColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Drive.FromSpace", "space", GetDisplayName(space)), DriveIcon, DriveColor) .Button.LocalPressed += GetOfferFieldDriveActions(eventData, fieldTarget, space); } }); @@ -68,12 +69,12 @@ private static ButtonEventHandler GetOfferFieldReferenceActions(GenerationEve if (await eventData.OpenContextMenuAsync(args.source.Slot) is null) return; - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Reference.Blank"), ReferenceIcon, ReferenceColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Reference.Blank"), ReferenceIcon, ReferenceColor) .Button.LocalPressed += GetReferenceFieldForVariable(eventData, fieldTarget, string.Empty); foreach (var space in eventData.Slot!.GetAvailableSpaces(SpaceHasName)) { - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Reference.InSpace", "space", space.CurrentName), ReferenceIcon, ReferenceColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Reference.InSpace", "space", space.CurrentName), ReferenceIcon, ReferenceColor) .Button.LocalPressed += GetReferenceFieldForVariable(eventData, fieldTarget, $"{space.CurrentName}/"); } }); @@ -89,12 +90,12 @@ private static ButtonEventHandler GetOfferFieldSourceActions(GenerationEvent if (await eventData.OpenContextMenuAsync(args.source.Slot) is null) return; - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Source.Blank"), SourceIcon, SourceColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Source.Blank"), SourceIcon, SourceColor) .Button.LocalPressed += GetSourceFieldForVariable(eventData, fieldTarget, string.Empty); foreach (var space in eventData.Slot!.GetAvailableSpaces(SpaceHasName)) { - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Source.InSpace", "space", space.CurrentName), SourceIcon, SourceColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Source.InSpace", "space", space.CurrentName), SourceIcon, SourceColor) .Button.LocalPressed += GetSourceFieldForVariable(eventData, fieldTarget, $"{space.CurrentName}/"); } }); @@ -124,14 +125,14 @@ private static void OfferFieldActions(GenerationEvent eventData) if (!fieldTarget.IsLinked) { - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Drive"), DriveIcon, DriveColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Drive"), DriveIcon, DriveColor) .Button.LocalPressed += GetOfferFieldDriveSpaceActions(eventData, fieldTarget); } - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Source", "type", "DynamicField"), SourceIcon, SourceColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Source", "type", "DynamicField"), SourceIcon, SourceColor) .Button.LocalPressed += GetOfferFieldSourceActions(eventData, fieldTarget); - eventData.ContextMenu.AddItem(Mod.GetLocaleString("Reference"), ReferenceIcon, ReferenceColor) + eventData.ContextMenu.AddItem(Instance.GetLocaleString("Reference"), ReferenceIcon, ReferenceColor) .Button.LocalPressed += GetOfferFieldReferenceActions(eventData, fieldTarget); } } diff --git a/DynamicVariablePowerTools/ContextMenu/DynamicVariableMemberActions.cs b/DynamicVariablePowerTools/ContextMenu/DynamicVariableMemberActions.cs index afd578b..f38e3c2 100644 --- a/DynamicVariablePowerTools/ContextMenu/DynamicVariableMemberActions.cs +++ b/DynamicVariablePowerTools/ContextMenu/DynamicVariableMemberActions.cs @@ -3,7 +3,6 @@ using HarmonyLib; using MonkeyLoader; using MonkeyLoader.Resonite; -using MonkeyLoader.Resonite.Configuration; using System.Reflection; using GenerationEvent = MonkeyLoader.Resonite.UI.Inspectors.InspectorMemberActionsMenuItemsGenerationEvent; @@ -11,7 +10,7 @@ namespace DynamicVariablePowerTools.ContextMenu { internal sealed partial class DynamicVariableMemberActions - : ResoniteAsyncEventHandlerMonkey + : ConfiguredResoniteAsyncEventHandlerMonkey { private static readonly Dictionary> _actionOfferersByType = new() { diff --git a/DynamicVariablePowerTools/ContextMenu/MemberActionsConfig.cs b/DynamicVariablePowerTools/ContextMenu/MemberActionsConfig.cs new file mode 100644 index 0000000..250e30a --- /dev/null +++ b/DynamicVariablePowerTools/ContextMenu/MemberActionsConfig.cs @@ -0,0 +1,26 @@ +using MonkeyLoader.Configuration; + +namespace DynamicVariablePowerTools.ContextMenu +{ + internal sealed class MemberActionsConfig : ConfigSection + { + private readonly DefiningConfigKey _allowDowncastToDrive = new("AllowDowncastToDrive", "Allows downcasting the type of the dynamic variable to the type required by the target reference.", () => true); + private readonly DefiningConfigKey _allowUpcastToDrive = new("AllowUpcastToDrive", "Allows upcasting the type of the dynamic variable to the type required by the target reference.", () => false); + + /// + /// Gets whether to allow downcasting the type of the dynamic variable's value to the type required by the target field. + /// + public bool AllowDowncastToDrive => _allowDowncastToDrive; + + /// + /// Gets whether to allow upcasting the type of the dynamic variable's value to the type required by the target field. + /// + public bool AllowUpcastToDrive => _allowUpcastToDrive; + + /// + public override string Id => "MemberActions"; + + /// + public override Version Version { get; } = new(1, 0, 0); + } +} \ No newline at end of file diff --git a/DynamicVariablePowerTools/DebugInfoConfig.cs b/DynamicVariablePowerTools/DebugInfoConfig.cs index 809e7ed..96cfbeb 100644 --- a/DynamicVariablePowerTools/DebugInfoConfig.cs +++ b/DynamicVariablePowerTools/DebugInfoConfig.cs @@ -1,11 +1,19 @@ using MonkeyLoader.Configuration; +using MonkeyLoader.Resonite.Configuration; +using MonkeyLoader.Resonite.UI.Inspectors; namespace DynamicVariablePowerTools { - internal sealed class DebugInfoConfig : ConfigSection + internal sealed class DebugInfoConfig : SingletonConfigSection { - private static readonly DefiningConfigKey _enableLinkedComponentHierarchy = new("EnableLinkedComponentHierarchy", "Allow generating a hierarchical list of all dynamic variable components linked to a space.", () => true); - private static readonly DefiningConfigKey _enableLinkedVariablesList = new("EnableLinkedVariablesList", "Allow generating a list of all dynamic variable definitions linked to a space.", () => true); + private readonly DefiningConfigKey _enableLinkedComponentHierarchy = new("EnableLinkedComponentHierarchy", "Allow generating a hierarchical list of all dynamic variable components linked to a space.", () => true); + private readonly DefiningConfigKey _enableLinkedVariablesList = new("EnableLinkedVariablesList", "Allow generating a list of all dynamic variable definitions linked to a space.", () => true); + + private readonly DefiningConfigKey _openLinkedSpaceOffset = new("OpenLinkedSpaceOffset", "The Order Offset of the buttons to open the linked dynamic variable space on Inspector Headers of dynamic variable components. Higher is further right.", () => 0) + { + DefaultInspectorHeaderConfig.OffsetRange, + DefaultInspectorHeaderConfig.MakeOffsetRangeShare(0) + }; public override string Description => "Contains the options for the available debug info buttons on DynamicVariableSpace Components."; @@ -15,6 +23,8 @@ internal sealed class DebugInfoConfig : ConfigSection public override string Id => "DebugInfo"; + public ConfigKeySessionShare OpenLinkedSpaceOffset => _openLinkedSpaceOffset.Components.Get>(); + public override Version Version { get; } = new Version(1, 0, 0); } } \ No newline at end of file diff --git a/DynamicVariablePowerTools/DynamicVariablePowerTools.csproj b/DynamicVariablePowerTools/DynamicVariablePowerTools.csproj index c810499..a6d84ba 100644 --- a/DynamicVariablePowerTools/DynamicVariablePowerTools.csproj +++ b/DynamicVariablePowerTools/DynamicVariablePowerTools.csproj @@ -1,16 +1,18 @@ - + True DynamicVariablePowerTools Dynamic Variable Power Tools Banane9 - 0.1.1-beta + 0.2.0-beta This MonkeyLoader mod for Resonite adds a variety of powerful functions to dynamic variables and their spaces. README.md LGPL-3.0-or-later https://github.com/ResoniteModdingGroup/DynamicVariablePowerTools $(PackageProjectUrl).git mod; mods; monkeyloader; resonite; contacts + + 0.33.0 diff --git a/DynamicVariablePowerTools/Locale/de.json b/DynamicVariablePowerTools/Locale/de.json index 56dcf1e..0b31095 100644 --- a/DynamicVariablePowerTools/Locale/de.json +++ b/DynamicVariablePowerTools/Locale/de.json @@ -2,7 +2,70 @@ "localeCode": "de", "authors": [ "Banane9" ], "messages": { - "FlexibleContactsSort.Pin": "Kontakt anheften", - "FlexibleContactsSort.Unpin": "Kontakt lösen" + "DynamicVariablePowerTools.Name": "Dynamic Variable Power Tools", + "DynamicVariablePowerTools.Description": "Diese Mod für verschiedene mächtige Funktionen für dynamische Variablen und ihre Spaces hinzu.", + + "DynamicVariablePowerTools.DebugInfoGenerator.Name": "Debug Info Generator", + "DynamicVariablePowerTools.DebugInfoGenerator.Description": "Fügt basierend auf den Debuginfo Einstellungen Knöpfe zu DynamicVariableSpace-Komponenten in Inspektoren hinzu, die es erlauben, Debuginformationen für den Space zu generieren.", + + "DynamicVariablePowerTools.OpenLinkedDynamicVariableSpace.Name": "Verbundenen DynamicVariableSpace öffnen", + "DynamicVariablePowerTools.OpenLinkedDynamicVariableSpace.Description": "Fügt Knöpfe zu den Kopfzeilen von verbundenen dynmischen Variablen Komponenten in Inspektoren hinzu, die es erlauben, den Space zu öffnen, mit dem sie verbunden sind.", + + "DynamicVariablePowerTools.RenameDirectlyLinkedVariables.Name": "Dynamische-Variablen-Spaces umbenennen", + "DynamicVariablePowerTools.RenameDirectlyLinkedVariables.Description": "Fügt einen Knopf zu DynamicVariableSpace-Komponenten in Inspektoren hinzu, der es erlaubt, den Space zusammen mit allen verbunden Variablen umzubenennen.", + + "DynamicVariablePowerTools.RenameDynamicVariables.Name": "Dynamische Variablen umbenennen", + "DynamicVariablePowerTools.RenameDynamicVariables.Description": "Fügt einen Knopf zu dynamischen Variablen Komponenten in Inspektoren hinzu, der es erlaubt, alle verbundenen Instanzen der Variable umzubennen.", + + "DynamicVariablePowerTools.DynamicVariableMemberActions.Name": "Member Actions für dynamische Variablen", + "DynamicVariablePowerTools.DynamicVariableMemberActions.Description": "Fügt Optionen, um dynamische Variablen Komponenten aufzusetzen, zu den Member Actions von Feldern in Inspektoren hinzu. Nutzt die Member Actions Einstellungen.", + + "DynamicVariablePowerTools.Config.RenameOptions.Name": "Umbenennen", + "DynamicVariablePowerTools.Config.RenameOptions.Description": "Optionen für das Umbenennen von dynamischen Variablen und ihren Spaces.", + "DynamicVariablePowerTools.Config.RenameOptions.ChangeProtoFluxStringInputs.Name": "ProtoFlux String-Inputs ändern", + "DynamicVariablePowerTools.Config.RenameOptions.ChangeProtoFluxStringInputs.Description": "Sucht ProtoFlux Inputs mit dem alten Namen in der Form AlterName/* und benennt diese um (Experimentell).", + "DynamicVariablePowerTools.Config.RenameOptions.ShowRenameDynamicVariable.Name": "Umbenennen bei dynamischen Variablen zeigen", + "DynamicVariablePowerTools.Config.RenameOptions.ShowRenameDynamicVariable.Description": "Umbenennen-Aktion bei dynamischen Variablen Komponenten zeigen.", + "DynamicVariablePowerTools.Config.RenameOptions.ShowRenameDynamicVariableSpace.Name": "Umbenennen bei dynamischen Variablen Spaces zeigen", + "DynamicVariablePowerTools.Config.RenameOptions.ShowRenameDynamicVariableSpace.Description": "Umbennen-Aktion bei DynamicVariableSpace-Komponenten zeigen.", + + "DynamicVariablePowerTools.Config.DebugInfo.Name": "Debuginfo", + "DynamicVariablePowerTools.Config.DebugInfo.EnableLinkedVariablesList.Name": "Variablendefinitionen", + "DynamicVariablePowerTools.Config.DebugInfo.EnableLinkedVariablesList.Description": "Fügt einen Knopf zu DynamicVariableSpace-Komponenten in Inspektoren hinzu, der es erlaubt, eine Liste aller mit dem Space verbundenen Definitionen dynamischer Variablen zu generieren.", + "DynamicVariablePowerTools.Config.DebugInfo.EnableLinkedComponentHierarchy.Name": "Komponentenhierarchie", + "DynamicVariablePowerTools.Config.DebugInfo.EnableLinkedComponentHierarchy.Description": "Fügt einen Knopf zu DynamicVariableSpace-Komponenten in Inspektoren hinzu, der es erlaubt, eine hierarchische Liste aller mit dem Space verbundenen dynamischer Variablenkomponenten zu generieren.", + "DynamicVariablePowerTools.Config.DebugInfo.OpenLinkedSpaceOffset.Name": "Verbunden-Space-Öffnen Offset", + "DynamicVariablePowerTools.Config.DebugInfo.OpenLinkedSpaceOffset.Description": "Das Order Offset der Knöpfe bei den Inspektor-Kopfzeilen von dynamischen Variablen Komponenten, die den verbundenen DynamicVariableSpace öffnen. Höher ist weiter rechts.", + + "DynamicVariablePowerTools.Config.MemberActions.Name": "Member Actions", + "DynamicVariablePowerTools.Config.MemberActions.AllowDowncastToDrive.Name": "Abwärtskonvertierung für Drive erlauben", + "DynamicVariablePowerTools.Config.MemberActions.AllowDowncastToDrive.Description": "Erlaubt es, den Typ der dynamischen Variable abwärts zum für die Zielreferenz gebrauchten Typ zu konvertieren.

Abwärts Konvertieren heißt, dass der Typ der Variable spezifischer als der der Zielreferenz ist - beispielsweise das Zuweisen einer SkinnedMeshRenderer-Variable zu einer MeshRenderer-Referenz. Dies wird immer erfolgreich sein.", + "DynamicVariablePowerTools.Config.MemberActions.AllowUpcastToDrive.Name": "Aufwärtskonvertierung für Drive erlauben", + "DynamicVariablePowerTools.Config.MemberActions.AllowUpcastToDrive.Description": "Erlaubt es, den Typ der dynamischen Variable aufwärts zum für die Zielreferenz gebrauchten Typ zu konvertieren.

Aufwärts Konvertieren heißt, dass der Typ der Variable weniger spezifisch als der der Zielreferenz ist - beispielsweise der Versuch, eine MeshRenderer-Variable einer SkinnedMeshRenderer-Referenz zuzuweisen. Dies wird nur erfolgreich sein, wenn der aktuelle Wert der dynamischen Variable tatsächlich ein SkinnedMeshRenderer ist; ansonsten wird die Zielreferenz auf null gesetzt.", + + "DynamicVariablePowerTools.EnableLinkedVariablesList.Button": "Variablendefinitionen ausgeben", + "DynamicVariablePowerTools.EnableLinkedVariablesList.Tooltip": "Generiert eine Liste aller mit dem Space verbundenen Definitioner dynamischer Variablen im Output Feld.", + + "DynamicVariablePowerTools.EnableLinkedComponentHierarchy.Button": "Komponentenhierarchie ausgeben", + "DynamicVariablePowerTools.EnableLinkedComponentHierarchy.Tooltip": "Generiert eine hierarchische Liste aller mit dem Space verbundenen dynamischer Variablenkomponenten im Output Feld.", + + "DynamicVariablePowerTools.RenameDirectlyLinkedVariables.Button": "Space umbenennen", + "DynamicVariablePowerTools.RenameDirectlyLinkedVariables.Tooltip": "Diesen Space und alle verbundenen Variablen umbenennen.", + + "DynamicVariablePowerTools.RenameDynamicVariables.Button": "Variable umbenennen", + "DynamicVariablePowerTools.RenameDynamicVariables.Tooltip": "Alle verbundenen Instanzen dieser Variable umbennen.", + + "DynamicVariablePowerTools.DynamicVariableMemberActions.Drive": "Von dynamischer Variable driven", + "DynamicVariablePowerTools.DynamicVariableMemberActions.Drive.FromBlank": "Von [Blank]", + "DynamicVariablePowerTools.DynamicVariableMemberActions.Drive.FromSpace": "Von Variable in {space}", + "DynamicVariablePowerTools.DynamicVariableMemberActions.Drive.FromVariable": "{variable}", + + "DynamicVariablePowerTools.DynamicVariableMemberActions.Source": "{type} aufsetzen", + "DynamicVariablePowerTools.DynamicVariableMemberActions.Source.Blank": "[Blank]", + "DynamicVariablePowerTools.DynamicVariableMemberActions.Source.InSpace": "Im Space {space}", + + "DynamicVariablePowerTools.DynamicVariableMemberActions.Reference": "Referenzvariable aufsetzen", + "DynamicVariablePowerTools.DynamicVariableMemberActions.Reference.Blank": "[Blank]", + "DynamicVariablePowerTools.DynamicVariableMemberActions.Reference.InSpace": "Im Space {space}" } } \ No newline at end of file diff --git a/DynamicVariablePowerTools/Locale/en.json b/DynamicVariablePowerTools/Locale/en.json index 8ad9602..9b1c73d 100644 --- a/DynamicVariablePowerTools/Locale/en.json +++ b/DynamicVariablePowerTools/Locale/en.json @@ -2,42 +2,70 @@ "localeCode": "en", "authors": [ "Banane9" ], "messages": { - "DynamicVariablePowerTools.EnableLinkedVariablesList.Name": "Variable Definitions", - "DynamicVariablePowerTools.EnableLinkedVariablesList.Description": "Allow generating a list of all dynamic variable definitions linked to a space.", - "DynamicVariablePowerTools.EnableLinkedVariablesList.Button": "Output Variable Definitions", - "DynamicVariablePowerTools.EnableLinkedVariablesList.Tooltip": "Generates a list of all dynamic variable definitions linked to this space in the Output field.", + "DynamicVariablePowerTools.Name": "Dynamic Variable Power Tools", + "DynamicVariablePowerTools.Description": "This mod adds a variety of powerful functions to dynamic variables and their spaces.", - "DynamicVariablePowerTools.EnableLinkedComponentHierarchy.Name": "Component Hierarchy", - "DynamicVariablePowerTools.EnableLinkedComponentHierarchy.Description": "Allow generating a hierarchical list of all dynamic variable components linked to a space.", - "DynamicVariablePowerTools.EnableLinkedComponentHierarchy.Button": "Output Component Hierarchy", - "DynamicVariablePowerTools.EnableLinkedComponentHierarchy.Tooltip": "Generates a hierarchical list of all dynamic variable components linked to this space in the Output field.", + "DynamicVariablePowerTools.DebugInfoGenerator.Name": "Debug Info Generator", + "DynamicVariablePowerTools.DebugInfoGenerator.Description": "Adds buttons to DynamicVariableSpace components in inspectors based on the Debug Info settings that allow generating debug information for the space.", + + "DynamicVariablePowerTools.OpenLinkedDynamicVariableSpace.Name": "Open Linked DynamicVariableSpace", + "DynamicVariablePowerTools.OpenLinkedDynamicVariableSpace.Description": "Adds buttons to the header of linked dynamic variable components in inspectors that allow opening the space they're linked to.", "DynamicVariablePowerTools.RenameDirectlyLinkedVariables.Name": "Rename Dynamic Variable Spaces", - "DynamicVariablePowerTools.RenameDirectlyLinkedVariables.Description": "Adds a button to dynamic variable spaces for renaming all linked variables.", - "DynamicVariablePowerTools.RenameDirectlyLinkedVariables.Button": "Rename", - "DynamicVariablePowerTools.RenameDirectlyLinkedVariables.Tooltip": "Renames all linked variables.", + "DynamicVariablePowerTools.RenameDirectlyLinkedVariables.Description": "Adds a button to DynamicVariableSpace components in inspectors that allows renaming the space together with all linked variables.", "DynamicVariablePowerTools.RenameDynamicVariables.Name": "Rename Dynamic Variables", - "DynamicVariablePowerTools.RenameDynamicVariables.Description": "Adds a button to dynamic variables for renaming all matching linked variables.", - "DynamicVariablePowerTools.RenameDynamicVariables.Button": "Rename", - "DynamicVariablePowerTools.RenameDynamicVariables.Tooltip": "Renames all matching linked variables.", + "DynamicVariablePowerTools.RenameDynamicVariables.Description": "Adds a button to dynamic variable components in inspectors that allows renaming all linked instances of that variable.", + + "DynamicVariablePowerTools.DynamicVariableMemberActions.Name": "Dynamic Variable Member Actions", + "DynamicVariablePowerTools.DynamicVariableMemberActions.Description": "Adds options to set up dynamic variable components to the Member Actions context menu for fields in inspectors. Uses the Member Actions settings.", + + "DynamicVariablePowerTools.Config.RenameOptions.Name": "Renaming", + "DynamicVariablePowerTools.Config.RenameOptions.Description": "Options for the renaming of dynamic variables and their spaces.", + "DynamicVariablePowerTools.Config.RenameOptions.ChangeProtoFluxStringInputs.Name": "Change ProtoFlux String Inputs", + "DynamicVariablePowerTools.Config.RenameOptions.ChangeProtoFluxStringInputs.Description": "Search and rename ProtoFlux inputs with the old name in the form OldName/* (Experimental).", + "DynamicVariablePowerTools.Config.RenameOptions.ShowRenameDynamicVariable.Name": "Show Rename Dynamic Variable", + "DynamicVariablePowerTools.Config.RenameOptions.ShowRenameDynamicVariable.Description": "Show rename action on dynamic variable components.", + "DynamicVariablePowerTools.Config.RenameOptions.ShowRenameDynamicVariableSpace.Name": "Show Rename Dynamic Variable Space", + "DynamicVariablePowerTools.Config.RenameOptions.ShowRenameDynamicVariableSpace.Description": "Show rename action on DynamicVariableSpace components.", + + "DynamicVariablePowerTools.Config.DebugInfo.Name": "Debug Info", + "DynamicVariablePowerTools.Config.DebugInfo.EnableLinkedVariablesList.Name": "Variable Definitions", + "DynamicVariablePowerTools.Config.DebugInfo.EnableLinkedVariablesList.Description": "Adds a button to DynamicVariableSpace components in inspectors that allows generating a list of all dynamic variable definitions linked to that space.", + "DynamicVariablePowerTools.Config.DebugInfo.EnableLinkedComponentHierarchy.Name": "Component Hierarchy", + "DynamicVariablePowerTools.Config.DebugInfo.EnableLinkedComponentHierarchy.Description": "Adds a button to DynamicVariableSpace components in inspectors that allows generating a hierarchical list of all dynamic variable components linked to a space.", + "DynamicVariablePowerTools.Config.DebugInfo.OpenLinkedSpaceOffset.Name": "Open Linked Space Offset", + "DynamicVariablePowerTools.Config.DebugInfo.OpenLinkedSpaceOffset.Description": "The Order Offset of the buttons to open the linked dynamic variable space on Inspector Headers of dynamic variable components. Higher is further right.", + + "DynamicVariablePowerTools.Config.MemberActions.Name": "Member Actions", + "DynamicVariablePowerTools.Config.MemberActions.AllowDowncastToDrive.Name": "Allow Downcast to Drive", + "DynamicVariablePowerTools.Config.MemberActions.AllowDowncastToDrive.Description": "Allow downcasting the type of the dynamic variable to the type required by the target reference.

Downcasting means that the variable's type is more specific than the target reference's - for example assigning a SkinnedMeshRenderer variable to a MeshRenderer reference. This will always be successful.", + "DynamicVariablePowerTools.Config.MemberActions.AllowUpcastToDrive.Name": "Allow Upcast to Drive", + "DynamicVariablePowerTools.Config.MemberActions.AllowUpcastToDrive.Description": "Allow upcasting the type of the dynamic variable to the type required by the target reference.

Upcasting means that the variable's type is less specific than the target reference's - for example trying to assign a MeshRenderer variable to a SkinnedMeshRenderer reference. This will only work if the current value of the dynamic variable is actually a SkinnedMeshRenderer; otherwise, the target reference will be set to null.", + + "DynamicVariablePowerTools.EnableLinkedVariablesList.Button": "Output Variable Definitions", + "DynamicVariablePowerTools.EnableLinkedVariablesList.Tooltip": "Generates a list of all dynamic variable definitions linked to this space in the Output field.", + + "DynamicVariablePowerTools.EnableLinkedComponentHierarchy.Button": "Output Component Hierarchy", + "DynamicVariablePowerTools.EnableLinkedComponentHierarchy.Tooltip": "Generates a hierarchical list of all dynamic variable components linked to this space in the Output field.", - "DynamicVariablePowerTools.Config.RenameOptions.Name": "Rename Options", - "DynamicVariablePowerTools.Config.RenameOptions.Description": "Options for how dynamic variables should be renamed.", + "DynamicVariablePowerTools.RenameDirectlyLinkedVariables.Button": "Rename Space", + "DynamicVariablePowerTools.RenameDirectlyLinkedVariables.Tooltip": "Rename this space and all linked variables.", - "DynamicVariablePowerTools.DebugInfo.Name": "Debug Info", + "DynamicVariablePowerTools.RenameDynamicVariables.Button": "Rename Variable", + "DynamicVariablePowerTools.RenameDynamicVariables.Tooltip": "Rename all linked instances of this variable.", - "DynamicVariablePowerTools.Drive": "Drive from Dynamic Variable", - "DynamicVariablePowerTools.Drive.FromBlank": "From [Blank]", - "DynamicVariablePowerTools.Drive.FromSpace": "From Variable in {space}", - "DynamicVariablePowerTools.Drive.FromVariable": "{variable}", + "DynamicVariablePowerTools.DynamicVariableMemberActions.Drive": "Drive from Dynamic Variable", + "DynamicVariablePowerTools.DynamicVariableMemberActions.Drive.FromBlank": "From [Blank]", + "DynamicVariablePowerTools.DynamicVariableMemberActions.Drive.FromSpace": "From Variable in {space}", + "DynamicVariablePowerTools.DynamicVariableMemberActions.Drive.FromVariable": "{variable}", - "DynamicVariablePowerTools.Source": "Set up {type}", - "DynamicVariablePowerTools.Source.Blank": "[Blank]", - "DynamicVariablePowerTools.Source.InSpace": "In space {space}", + "DynamicVariablePowerTools.DynamicVariableMemberActions.Source": "Set up {type}", + "DynamicVariablePowerTools.DynamicVariableMemberActions.Source.Blank": "[Blank]", + "DynamicVariablePowerTools.DynamicVariableMemberActions.Source.InSpace": "In space {space}", - "DynamicVariablePowerTools.Reference": "Set up Reference Variable", - "DynamicVariablePowerTools.Reference.Blank": "[Blank]", - "DynamicVariablePowerTools.Reference.InSpace": "In space {space}" + "DynamicVariablePowerTools.DynamicVariableMemberActions.Reference": "Set up Reference Variable", + "DynamicVariablePowerTools.DynamicVariableMemberActions.Reference.Blank": "[Blank]", + "DynamicVariablePowerTools.DynamicVariableMemberActions.Reference.InSpace": "In space {space}" } } \ No newline at end of file diff --git a/DynamicVariablePowerTools/OpenLinkedDynamicVariableSpace.cs b/DynamicVariablePowerTools/OpenLinkedDynamicVariableSpace.cs index 84b46c6..0c15c4a 100644 --- a/DynamicVariablePowerTools/OpenLinkedDynamicVariableSpace.cs +++ b/DynamicVariablePowerTools/OpenLinkedDynamicVariableSpace.cs @@ -1,5 +1,9 @@ using FrooxEngine; +using FrooxEngine.UIX; +using MonkeyLoader.Components; +using MonkeyLoader.Configuration; using MonkeyLoader.Resonite; +using MonkeyLoader.Resonite.Configuration; using MonkeyLoader.Resonite.UI.Inspectors; namespace DynamicVariablePowerTools @@ -7,6 +11,8 @@ namespace DynamicVariablePowerTools internal sealed class OpenLinkedDynamicVariableSpace : ResoniteInspectorMonkey { + private readonly ConfigKeySessionShare _enabledShare = new(true); + public override bool CanBeDisabled => true; public override int Priority => HarmonyLib.Priority.First; @@ -15,13 +21,32 @@ internal sealed class OpenLinkedDynamicVariableSpace public OpenLinkedDynamicVariableSpace() : base(typeof(IDynamicVariable)) { } + // Exclude Enabled check to always generate, but use session share for visibility + protected override bool AppliesTo(BuildInspectorHeaderEvent eventData) + => eventData.Worker is IDynamicVariable; + protected override void Handle(BuildInspectorHeaderEvent eventData) { - // Can safely cast since the base.AppliesTo method will ensure it's an IDynamicVariable + // Can safely cast since the AppliesTo method will ensure it's an IDynamicVariable if (!((IDynamicVariable)eventData.Worker).TryGetLinkedSpace(out var space)) return; + var horizontalLayout = eventData.UI.HorizontalLayout(4).Slot; + eventData.UI.FitContent(SizeFit.MinSize, SizeFit.Disabled); + + _enabledShare.DriveFromVariable(horizontalLayout.ActiveSelf_Field); + DebugInfoConfig.Instance.OpenLinkedSpaceOffset.DriveFromVariable(horizontalLayout.OrderOffset_Field); + InspectorUIHelper.BuildHeaderOpenParentButtons(eventData.UI, space); + + eventData.UI.NestOut(); + } + + protected override bool OnEngineReady() + { + ((IEntity>)EnabledToggle!).Components.Add(_enabledShare); + + return base.OnEngineReady(); } } } \ No newline at end of file diff --git a/DynamicVariablePowerTools/RenameButtonHelper.cs b/DynamicVariablePowerTools/RenameButtonHelper.cs index ea14e91..c1d4f47 100644 --- a/DynamicVariablePowerTools/RenameButtonHelper.cs +++ b/DynamicVariablePowerTools/RenameButtonHelper.cs @@ -2,15 +2,19 @@ using FrooxEngine; using FrooxEngine.UIX; using MonkeyLoader.Resonite; +using MonkeyLoader.Resonite.Configuration; using MonkeyLoader.Resonite.UI; namespace DynamicVariablePowerTools { internal static class RenameButtonHelper { - internal static void BuildRenameUI(this UIBuilder builder, IField nameField, Action onRename, LocaleString buttonText, LocaleString tooltipText) + internal static void BuildRenameUI(this UIBuilder builder, IField nameField, Action onRename, LocaleString buttonText, LocaleString tooltipText, ConfigKeySessionShare enabledShare) { - var layout = builder.HorizontalLayout(4).Slot.DestroyWhenLocalUserLeaves(); + var layoutSlot = builder.HorizontalLayout(4).Slot; + enabledShare.DriveFromVariable(layoutSlot.ActiveSelf_Field); + layoutSlot.DestroyWhenLocalUserLeaves(); + builder.PushStyle(); var style = builder.Style; @@ -19,7 +23,7 @@ internal static void BuildRenameUI(this UIBuilder builder, IField nameFi void ChangedListener(object _) => newNameField.Text.Content.Value = nameField.Value; nameField.Changed += ChangedListener; - layout.Destroyed += _ => nameField.Changed -= ChangedListener; + layoutSlot.Destroyed += _ => nameField.Changed -= ChangedListener; style.FlexibleWidth = -1; style.MinWidth = 256; diff --git a/DynamicVariablePowerTools/RenameConfig.cs b/DynamicVariablePowerTools/RenameConfig.cs index 26903f4..cb30e92 100644 --- a/DynamicVariablePowerTools/RenameConfig.cs +++ b/DynamicVariablePowerTools/RenameConfig.cs @@ -1,17 +1,44 @@ using MonkeyLoader.Configuration; +using MonkeyLoader.Resonite.Configuration; namespace DynamicVariablePowerTools { internal sealed class RenameConfig : SingletonConfigSection { - private static readonly DefiningConfigKey _changeProtoFluxStringInputs = new("ChangeProtoFluxStringInputs", "Search and rename ProtoFlux inputs with the old name in the form OldName/* (Experimental).", () => false); + private readonly DefiningConfigKey _changeProtoFluxStringInputs = new("ChangeProtoFluxStringInputs", "Search and rename ProtoFlux inputs with the old name in the form OldName/* (Experimental).", () => false); + private readonly DefiningConfigKey _showRenameDynamicVariable = new("ShowRenameDynamicVariable", "Show rename action on dynamic variable components.", () => true) + { + new ConfigKeySessionShare(true) + }; + + private readonly DefiningConfigKey _showRenameDynamicVariableSpace = new("ShowRenameDynamicVariableSpace", "Show rename action on DynamicVariableSpace components.", () => true) + { + new ConfigKeySessionShare(true) + }; + + /// + /// Gets whether to search and rename ProtoFlux inputs with the old name in the form OldName/* (Experimental). + /// public bool ChangeProtoFluxStringInputs => _changeProtoFluxStringInputs; + /// public override string Description => "Rename Options"; + /// public override string Id => "RenameOptions"; + /// + /// Gets whether to show the rename action on dynamic variable components. + /// + public ConfigKeySessionShare ShowRenameDynamicVariable => _showRenameDynamicVariable.Components.Get>(); + + /// + /// Gets whether to show the rename action on DynamicVariableSpace components. + /// + public ConfigKeySessionShare ShowRenameDynamicVariableSpace => _showRenameDynamicVariableSpace.Components.Get>(); + + /// public override Version Version { get; } = new(1, 0); } } \ No newline at end of file diff --git a/DynamicVariablePowerTools/RenameDirectlyLinkedVariables.cs b/DynamicVariablePowerTools/RenameDirectlyLinkedVariables.cs index bede8ac..37d95d8 100644 --- a/DynamicVariablePowerTools/RenameDirectlyLinkedVariables.cs +++ b/DynamicVariablePowerTools/RenameDirectlyLinkedVariables.cs @@ -1,6 +1,6 @@ using FrooxEngine; using FrooxEngine.ProtoFlux; -using HarmonyLib; +using MonkeyLoader; using MonkeyLoader.Resonite; using MonkeyLoader.Resonite.UI.Inspectors; @@ -19,53 +19,70 @@ protected override void Handle(BuildInspectorBodyEvent eventData) space.SpaceName, onRename: newName => RenameSpace(space, newName), buttonText: this.GetLocaleString("Button"), - tooltipText: this.GetLocaleString("Tooltip") + tooltipText: this.GetLocaleString("Tooltip"), + RenameConfig.Instance.ShowRenameDynamicVariableSpace ); } private static void RenameSpace(DynamicVariableSpace space, string newName) { + var currentName = space.CurrentName; newName = DynamicVariableHelper.ProcessName(newName); - var currentName = space.SpaceName.Value; - var prefixName = $"{currentName}/"; + Logger.Info(() => $"Renaming DynamicVariableSpace from {currentName} to {newName}!{Environment.NewLine}{space.ParentHierarchyToString()}"); - space.Slot.ForeachComponentInChildren(dynVar => + var currentNamePrefix = $"{currentName}/"; + var newNamePrefix = $"{newName}/"; + + foreach (var dynVar in space.GetAllLinkedVariables()) { - DynamicVariableHelper.ParsePath(dynVar.VariableName, out var spaceName, out var variableName); + try + { + DynamicVariableHelper.ParsePath(dynVar.VariableName, out var spaceName, out var variableName); - if (spaceName == null || Traverse.Create(dynVar).Field("handler").Field("_currentSpace").GetValue() != space) - return; + if (dynVar is ProtoFluxEngineProxy { Node.Target: IProtoFluxNode dynVarNode } + && dynVarNode.TryGetField("VariableName") is SyncRef> nameProxyRef + && nameProxyRef.Target is GlobalValue nameProxy) + { + var newVariableName = nameProxy.Value.Value.Replace(currentNamePrefix, newNamePrefix); + nameProxy.Value.Value = newVariableName; - // TODO: Move to helper method - var nameField = ((Worker)dynVar).TryGetField("VariableName") ?? ((Worker)dynVar).TryGetField("_variableName"); + if (nameProxy.Value.Value != newVariableName) + Logger.Warn(() => $"Failed to rename dynamic variable!{Environment.NewLine}{((Worker)nameProxy).ParentHierarchyToString()}"); - if (nameField is not null && nameField.Value.StartsWith(prefixName)) - { - nameField.Value = $"{newName}/{variableName}"; - return; - } + continue; + } + + // TODO: Move to helper method + var nameField = ((Worker)dynVar).TryGetField("VariableName") ?? ((Worker)dynVar).TryGetField("_variableName"); - if (dynVar is ProtoFluxEngineProxy { Node.Target: IProtoFluxNode dynVarNode } - && dynVarNode.TryGetField("VariableName") is SyncRef> nameProxyRef - && nameProxyRef.Target is GlobalValue nameProxy - && nameProxy.Value.Value.StartsWith(prefixName)) + if (nameField is not null) + { + var newVariableName = $"{newName}/{variableName}"; + nameField.Value = newVariableName; + + if (nameField.Value != newVariableName) + Logger.Warn(() => $"Failed to rename dynamic variable!{Environment.NewLine}{((Worker)dynVar).ParentHierarchyToString()}"); + + continue; + } + } + catch (Exception ex) { - nameProxy.Value.Value = $"{newName}/{variableName}"; - return; + Logger.Error(ex.LogFormat("Exception while trying to rename dynamic variable!")); } - }, includeLocal: true, cacheItems: true); + } if (ConfigSection.ChangeProtoFluxStringInputs) { space.Slot.ForeachComponentInChildren>(stringInput => { // this eats variables like: Space/{0} - so can't construct new name from {newName}/{variableName} - DynamicVariableHelper.ParsePath(stringInput.Value, out var spaceName, out var variableName); - if (spaceName == null || spaceName != currentName) + //DynamicVariableHelper.ParsePath(stringInput.Value, out var spaceName, out var variableName); + if (stringInput.Value is null || !stringInput.Value.StartsWith(currentNamePrefix)) return; - stringInput.Value = stringInput.Value.Replace(spaceName, newName); + stringInput.Value = stringInput.Value.Replace(currentNamePrefix, newNamePrefix); }, includeLocal: true, cacheItems: true); } diff --git a/DynamicVariablePowerTools/RenameDynamicVariables.cs b/DynamicVariablePowerTools/RenameDynamicVariables.cs index 07f4c26..6464e14 100644 --- a/DynamicVariablePowerTools/RenameDynamicVariables.cs +++ b/DynamicVariablePowerTools/RenameDynamicVariables.cs @@ -1,7 +1,9 @@ -using Elements.Core; -using FrooxEngine; +using FrooxEngine; using FrooxEngine.ProtoFlux; +using MonkeyLoader.Components; +using MonkeyLoader.Configuration; using MonkeyLoader.Resonite; +using MonkeyLoader.Resonite.Configuration; using MonkeyLoader.Resonite.UI.Inspectors; namespace DynamicVariablePowerTools @@ -22,16 +24,11 @@ protected override void Handle(BuildInspectorBodyEvent eventData) nameField, onRename: newName => RenameDynVar(dynVar, newName), buttonText: this.GetLocaleString("Button"), - tooltipText: this.GetLocaleString("Tooltip") + tooltipText: this.GetLocaleString("Tooltip"), + RenameConfig.Instance.ShowRenameDynamicVariable ); } - private static Type GetDynVarType(IDynamicVariable dynVar) - => dynVar.GetType().GetGenericArgumentsFromInterface(typeof(IDynamicVariable<>))[0]; - - private static bool IsDynVarOfType(IDynamicVariable dynVar, Type innerType) - => GetDynVarType(dynVar) == innerType; - private static void RenameDynVar(IDynamicVariable dynVar, string newName) { if (!dynVar.TryGetLinkedSpace(out var linkedSpace)) @@ -41,15 +38,10 @@ private static void RenameDynVar(IDynamicVariable dynVar, string newName) return; } - var dynVarType = GetDynVarType(dynVar); - var currentFullName = dynVar.VariableName; - DynamicVariableHelper.ParsePath(currentFullName, out var currentSpaceName, out var currentVariableName); - - Predicate predicate = linkedSpace.OnlyDirectBinding - ? (it => it.VariableName == currentFullName && IsDynVarOfType(it, dynVarType)) - : (it => (it.VariableName == currentFullName || it.VariableName == currentVariableName) && IsDynVarOfType(it, dynVarType)); + var oldIdentity = new DynamicVariableIdentity(linkedSpace, dynVar.GetVariableType(), dynVar.VariableName); + var oldQualifiedName = oldIdentity.QualifiedName; - foreach (var linkedVar in linkedSpace.GetLinkedVariables(predicate, true)) + foreach (var linkedVar in linkedSpace.GetAllLinkedVariablesMatching(oldIdentity)) { // TODO: Move to helper method var nameField = ((Worker)linkedVar).TryGetField("VariableName") ?? ((Worker)linkedVar).TryGetField("_variableName"); @@ -70,15 +62,11 @@ private static void RenameDynVar(IDynamicVariable dynVar, string newName) } // Only attempt rename when the new name is directly binding ("space/name") - if (RenameConfig.Instance.ChangeProtoFluxStringInputs && currentSpaceName != null) + if (RenameConfig.Instance.ChangeProtoFluxStringInputs) { - linkedSpace.Slot.ForeachComponentInChildren>(stringInput => - { - if (stringInput.Value != currentFullName) - return; - - stringInput.Value = newName; - }, includeLocal: true, cacheItems: true); + linkedSpace.Slot.ForeachComponentInChildren>( + stringInput => stringInput.Value = stringInput.Value.Replace(oldQualifiedName, newName), + includeLocal: true, cacheItems: true); } } }