using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using JG224.AnyItemStands.Core; using JG224.AnyItemStands.Patches; using JG224.ModCore.API; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("AnyItemStands")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.5.0.0")] [assembly: AssemblyInformationalVersion("0.5.0")] [assembly: AssemblyProduct("AnyItemStands")] [assembly: AssemblyTitle("AnyItemStands")] [assembly: AssemblyVersion("0.5.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace JG224.AnyItemStands { internal sealed class AnyItemStandsConfig { internal ConfigEntry DebugLogging { get; } internal ConfigEntry TransformOverrides { get; } private AnyItemStandsConfig(ConfigFile file) { DebugLogging = file.Bind("Diagnostics", "DebugLogging", false, "Enable verbose AnyItemStands diagnostics."); TransformOverrides = file.Bind("Display", "TransformOverrides", "", "Per-item prefab=scale,x,y,z,pitch,yaw,roll; entries separated by semicolons. Offsets in metres and rotations in degrees. Example SwordIron=0.8,0,0.1,0,0,90,0. Scale 0.05-10, offsets +/-5, angles +/-360."); } internal static AnyItemStandsConfig Load(BaseUnityPlugin plugin, string configDirectory) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown if (!Directory.Exists(configDirectory)) { Directory.CreateDirectory(configDirectory); } return new AnyItemStandsConfig(PluginConfigFiles.Attach(plugin, new ConfigFile(Path.Combine(configDirectory, "jg224.AnyItemStands.cfg"), true, plugin.Info.Metadata))); } internal IEnumerable RegisterMetadata(ICoreServices services, ModuleId owner) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) yield return services.Configuration.Register(new ConfigSettingDescriptor(owner, ((ConfigEntryBase)TransformOverrides).Definition.Section, ((ConfigEntryBase)TransformOverrides).Definition.Key, (ConfigScope)1, (Func)(() => TransformOverrides.Value), 1)); yield return services.Configuration.Register(new ConfigSettingDescriptor(owner, ((ConfigEntryBase)DebugLogging).Definition.Section, ((ConfigEntryBase)DebugLogging).Definition.Key, (ConfigScope)5, (Func)(() => Convert.ToString(((ConfigEntryBase)DebugLogging).BoxedValue, CultureInfo.InvariantCulture)), 1)); } } [BepInPlugin("jg224.AnyItemStands", "AnyItemStands", "0.5.0")] [BepInProcess("valheim.exe")] [BepInDependency("com.jg224.modcore", "0.5.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "jg224.AnyItemStands"; public const string PluginName = "AnyItemStands"; public const string PluginVersion = "0.5.0"; public const string ModCoreGuid = "com.jg224.modcore"; public const string GeneralTweaksGuid = "JG224.GeneralTweaks"; public const int ProtocolVersion = 1; public static readonly ModuleId ModuleId = new ModuleId("anyitemstands"); private readonly List _registrations = new List(); private Harmony _harmony; private bool _shutDown; internal static ManualLogSource Log { get; private set; } internal static AnyItemStandsConfig Settings { get; private set; } internal static ICoreServices Core { get; private set; } private void Awake() { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Settings = AnyItemStandsConfig.Load((BaseUnityPlugin)(object)this, Paths.ConfigPath); try { if (!ModCoreApi.IsAvailable) { throw new InvalidOperationException("ModCore did not initialize before AnyItemStands."); } Core = ModCoreApi.Services; RegisterWithCore(); if (TryGetLegacyOwner(out var version)) { string text = "GeneralTweaks " + version?.ToString() + " still contains Any Item Stands; AnyItemStands is paused to prevent duplicate hooks."; Core.Modules.SetState(ModuleId, (ModuleRuntimeState)3, text); ((BaseUnityPlugin)this).Logger.LogWarning((object)(text + " Update GeneralTweaks to 3.0.0 or newer.")); } else { _harmony = new Harmony("jg224.AnyItemStands"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); Core.Modules.SetState(ModuleId, (ModuleRuntimeState)2, "Player item-stand attachment hooks ready."); Game.isModded = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("AnyItemStands 0.5.0 loaded; protocol " + 1 + ".")); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("AnyItemStands failed to initialize safely: " + ex)); if (Core != null) { Core.Modules.SetState(ModuleId, (ModuleRuntimeState)5, ex.Message); } Shutdown(); throw; } } private void OnDestroy() { Shutdown(); } private void RegisterWithCore() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Expected O, but got Unknown SemanticVersion val = default(SemanticVersion); if (!SemanticVersion.TryParse("0.5.0", ref val)) { throw new InvalidOperationException("Invalid plugin version."); } _registrations.Add(Core.Modules.Register(new ModuleDescriptor(ModuleId, "jg224.AnyItemStands", "AnyItemStands", val, 1, (ModuleSide)1, (ModuleRequirement)1, 0uL, 1, 1))); foreach (IDisposable item in Settings.RegisterMetadata(Core, ModuleId)) { _registrations.Add(item); } _registrations.Add(Core.Lifecycle.Subscribe(ModuleId, (LifecycleEventKind)9, (Action)delegate { SafeDisplayTemplates.Clear(); }, 0)); _registrations.Add(Core.Lifecycle.Subscribe(ModuleId, (LifecycleEventKind)3, (Action)delegate { SafeDisplayTemplates.Clear(); }, 0)); _registrations.Add(Core.Compatibility.Register(new CompatibilityRule("jg224.AnyItemStands", "item_stand_all_items", (CompatibilityRuleKind)2, (CompatibilitySeverity)2, "Both mods expand player item stands; remove one implementation.", "item-stands"))); } private static bool TryGetLegacyOwner(out Version version) { version = null; if (!Chainloader.PluginInfos.TryGetValue("JG224.GeneralTweaks", out var value)) { return false; } version = value.Metadata.Version; if (version != null) { return version.CompareTo(new Version(3, 0, 0)) < 0; } return false; } private void Shutdown() { //IL_009f: Unknown result type (might be due to invalid IL or missing references) if (_shutDown) { return; } _shutDown = true; Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } _harmony = null; ItemStandVisualContext.Current = null; SafeDisplayTemplates.Clear(); for (int num = _registrations.Count - 1; num >= 0; num--) { try { _registrations[num].Dispose(); } catch (Exception ex) { ManualLogSource logger = ((BaseUnityPlugin)this).Logger; if (logger != null) { logger.LogWarning((object)("Registration cleanup failed: " + ex.Message)); } } } _registrations.Clear(); if (Core != null) { Core.Metrics.RemoveOwner(ModuleId); } Core = null; Settings = null; Log = null; } } } namespace JG224.AnyItemStands.Patches { internal static class ItemStandVisualContext { internal sealed class Scope { internal ItemStand PreviousStand; internal bool PreviousForceDisable; internal bool ChangedForceDisable; internal bool Restored; } [ThreadStatic] internal static ItemStand Current; internal static bool IsPlayerStand(ItemStand stand) { Piece val = (Object.op_Implicit((Object)(object)stand) ? ((Component)stand).GetComponentInParent() : null); if (Object.op_Implicit((Object)(object)val)) { return val.IsPlacedByPlayer(); } return false; } internal static GameObject ResolveFallback(GameObject itemPrefab) { if (!Object.op_Implicit((Object)(object)itemPrefab)) { return null; } Transform val = itemPrefab.transform.Find("attach"); return (GameObject)(ItemStandRules.SelectFallback(Object.op_Implicit((Object)(object)val), Object.op_Implicit((Object)(object)itemPrefab.GetComponentInChildren(true)), itemPrefab.transform.childCount) switch { FallbackKind.NativeAttach => ((Component)val).gameObject, FallbackKind.Root => SafeDisplayTemplates.Get(itemPrefab), _ => null, }); } internal static Scope Enter(ItemStand stand, bool disableNetworkInit) { Scope scope = new Scope { PreviousStand = Current, PreviousForceDisable = ZNetView.m_forceDisableInit }; Current = stand; if (disableNetworkInit && IsPlayerStand(stand)) { ZNetView.m_forceDisableInit = true; scope.ChangedForceDisable = true; } return scope; } internal static void Exit(Scope scope) { if (scope != null && !scope.Restored) { if (scope.ChangedForceDisable) { ZNetView.m_forceDisableInit = scope.PreviousForceDisable; } Current = scope.PreviousStand; scope.Restored = true; } } } [HarmonyPatch(typeof(ItemStand), "CanAttach")] internal static class ItemStandCanAttachPatch { [HarmonyPrefix] private static void Prefix(ItemStand __instance, out ItemStandVisualContext.Scope __state) { __state = ItemStandVisualContext.Enter(__instance, disableNetworkInit: false); } [HarmonyPostfix] private static void Postfix(ItemStand __instance, ItemData item, ref bool __result, ItemStandVisualContext.Scope __state) { if (!__result && ItemStandVisualContext.IsPlayerStand(__instance) && item != null && Object.op_Implicit((Object)(object)ItemStandVisualContext.ResolveFallback(item.m_dropPrefab))) { __result = true; } ItemStandVisualContext.Exit(__state); } [HarmonyFinalizer] private static Exception Finalizer(Exception __exception, ItemStandVisualContext.Scope __state) { ItemStandVisualContext.Exit(__state); return __exception; } } [HarmonyPatch(typeof(ItemStand), "GetAttachPrefab")] internal static class ItemStandFallbackPrefabPatch { [HarmonyPostfix] private static void Postfix(GameObject item, ref GameObject __result) { if (!Object.op_Implicit((Object)(object)__result) && ItemStandVisualContext.IsPlayerStand(ItemStandVisualContext.Current)) { __result = ItemStandVisualContext.ResolveFallback(item); } } } [HarmonyPatch(typeof(ItemStand), "SetVisualItem", new Type[] { typeof(int), typeof(int), typeof(int), typeof(int) })] internal static class ItemStandVisualPatch { [HarmonyPrefix] private static void Prefix(ItemStand __instance, out ItemStandVisualContext.Scope __state) { __state = ItemStandVisualContext.Enter(__instance, disableNetworkInit: true); } [HarmonyPostfix] private static void Postfix(ItemStand __instance, int itemHash, ref GameObject ___m_visualItem, ItemStandVisualContext.Scope __state) { if (ItemStandVisualContext.IsPlayerStand(__instance)) { SanitizeFallback(ref ___m_visualItem); GameObject val = ((itemHash != 0 && Object.op_Implicit((Object)(object)ObjectDB.instance)) ? ObjectDB.instance.GetItemPrefab(itemHash) : null); SafeDisplayTemplates.ApplyTransform(___m_visualItem, Object.op_Implicit((Object)(object)val) ? ((Object)val).name : string.Empty); } ItemStandVisualContext.Exit(__state); } [HarmonyFinalizer] private static Exception Finalizer(Exception __exception, ItemStandVisualContext.Scope __state) { ItemStandVisualContext.Exit(__state); return __exception; } private static void SanitizeFallback(ref GameObject visualItem) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)visualItem)) { return; } SafeDisplayMarker component = visualItem.GetComponent(); if (Object.op_Implicit((Object)(object)component) && component.IsFallback) { DisableGameplayComponents(visualItem); } else { if (!Object.op_Implicit((Object)(object)visualItem.GetComponent())) { return; } if (Object.op_Implicit((Object)(object)visualItem.GetComponent())) { DisableGameplayComponents(visualItem); return; } Transform transform = visualItem.transform; GameObject val = new GameObject(((Object)transform).name + ".Display"); val.layer = visualItem.layer; Transform transform2 = val.transform; transform2.SetParent(transform.parent, false); transform2.localPosition = transform.localPosition; transform2.localRotation = transform.localRotation; transform2.localScale = transform.localScale; for (int num = transform.childCount - 1; num >= 0; num--) { Transform child = transform.GetChild(num); if (Object.op_Implicit((Object)(object)((Component)child).GetComponentInChildren(true))) { child.SetParent(transform2, false); } } Object.Destroy((Object)(object)visualItem); DisableGameplayComponents(val); visualItem = val; } } private static void DisableGameplayComponents(GameObject visual) { Collider[] componentsInChildren = visual.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].enabled = false; } Rigidbody[] componentsInChildren2 = visual.GetComponentsInChildren(true); for (int j = 0; j < componentsInChildren2.Length; j++) { componentsInChildren2[j].detectCollisions = false; componentsInChildren2[j].isKinematic = true; } MonoBehaviour[] componentsInChildren3 = visual.GetComponentsInChildren(true); for (int k = 0; k < componentsInChildren3.Length; k++) { if (!(componentsInChildren3[k] is SafeDisplayMarker)) { ((Behaviour)componentsInChildren3[k]).enabled = false; } } } } internal sealed class SafeDisplayMarker : MonoBehaviour { public string PrefabName; public bool IsFallback; internal bool Captured; internal Vector3 Position; internal Vector3 Scale; internal Quaternion Rotation; } internal static class SafeDisplayTemplates { private static readonly Dictionary Templates = new Dictionary(); private static GameObject _root; private static string _raw; private static Dictionary _overrides = DisplayTransform.Parse(""); internal static GameObject Get(GameObject prefab) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_01bf: Unknown result type (might be due to invalid IL or missing references) int instanceID = ((Object)prefab).GetInstanceID(); if (Templates.TryGetValue(instanceID, out var value)) { return value; } if (!Object.op_Implicit((Object)(object)_root)) { _root = new GameObject("JG224.AnyItemStands.Templates"); _root.SetActive(false); Object.DontDestroyOnLoad((Object)(object)_root); } Dictionary dictionary = new Dictionary(); Transform val = CopyHierarchy(prefab.transform, _root.transform, dictionary); int num = 0; foreach (KeyValuePair item in dictionary) { MeshFilter component = ((Component)item.Key).GetComponent(); MeshRenderer component2 = ((Component)item.Key).GetComponent(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.sharedMesh) && Object.op_Implicit((Object)(object)component2)) { ((Component)item.Value).gameObject.AddComponent().sharedMesh = component.sharedMesh; CopyRenderer((Renderer)(object)component2, (Renderer)(object)((Component)item.Value).gameObject.AddComponent()); num++; } SkinnedMeshRenderer component3 = ((Component)item.Key).GetComponent(); if (!Object.op_Implicit((Object)(object)component3) || !Object.op_Implicit((Object)(object)component3.sharedMesh)) { continue; } SkinnedMeshRenderer val2 = ((Component)item.Value).gameObject.AddComponent(); val2.sharedMesh = component3.sharedMesh; Transform[] bones = component3.bones; Transform[] array = (Transform[])(object)new Transform[bones.Length]; for (int i = 0; i < bones.Length; i++) { if (Object.op_Implicit((Object)(object)bones[i]) && dictionary.TryGetValue(bones[i], out var value2)) { array[i] = value2; } } val2.bones = array; if (Object.op_Implicit((Object)(object)component3.rootBone) && dictionary.TryGetValue(component3.rootBone, out var value3)) { val2.rootBone = value3; } ((Renderer)val2).localBounds = ((Renderer)component3).localBounds; val2.updateWhenOffscreen = true; for (int j = 0; j < component3.sharedMesh.blendShapeCount; j++) { val2.SetBlendShapeWeight(j, component3.GetBlendShapeWeight(j)); } CopyRenderer((Renderer)(object)component3, (Renderer)(object)val2); num++; } if (num == 0) { Templates[instanceID] = null; Object.Destroy((Object)(object)((Component)val).gameObject); return null; } Transform val3 = val.Find("attachobj"); if (Object.op_Implicit((Object)(object)val3)) { ((Object)val3).name = "attachobj.AnyItemStands"; } SafeDisplayMarker safeDisplayMarker = ((Component)val).gameObject.AddComponent(); safeDisplayMarker.PrefabName = ((Object)prefab).name.Replace("(Clone)", "").Trim(); safeDisplayMarker.IsFallback = true; ((Component)val).gameObject.SetActive(true); Templates[instanceID] = ((Component)val).gameObject; return ((Component)val).gameObject; } private static Transform CopyHierarchy(Transform source, Transform parent, Dictionary map) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(((Object)source).name) { layer = ((Component)source).gameObject.layer }; Transform transform = val.transform; transform.SetParent(parent, false); transform.localPosition = source.localPosition; transform.localRotation = source.localRotation; transform.localScale = source.localScale; val.SetActive(((Component)source).gameObject.activeSelf); map[source] = transform; for (int i = 0; i < source.childCount; i++) { CopyHierarchy(source.GetChild(i), transform, map); } return transform; } private static void CopyRenderer(Renderer source, Renderer target) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) target.sharedMaterials = source.sharedMaterials; target.enabled = source.enabled; target.shadowCastingMode = source.shadowCastingMode; target.receiveShadows = source.receiveShadows; } internal static void ApplyTransform(GameObject visual, string prefabName) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)visual)) { SafeDisplayMarker safeDisplayMarker = visual.GetComponent(); if (!Object.op_Implicit((Object)(object)safeDisplayMarker)) { safeDisplayMarker = visual.AddComponent(); safeDisplayMarker.PrefabName = (prefabName ?? "").Replace("(Clone)", "").Trim(); } Transform transform = visual.transform; if (!safeDisplayMarker.Captured) { safeDisplayMarker.Position = transform.localPosition; safeDisplayMarker.Rotation = transform.localRotation; safeDisplayMarker.Scale = transform.localScale; safeDisplayMarker.Captured = true; } string text = Plugin.Settings?.TransformOverrides.Value ?? ""; if (_raw != text) { _raw = text; _overrides = DisplayTransform.Parse(text); } transform.localPosition = safeDisplayMarker.Position; transform.localRotation = safeDisplayMarker.Rotation; transform.localScale = safeDisplayMarker.Scale; if (_overrides.TryGetValue(safeDisplayMarker.PrefabName, out var value)) { transform.localPosition += new Vector3(value.X, value.Y, value.Z); transform.localRotation *= Quaternion.Euler(value.Pitch, value.Yaw, value.Roll); transform.localScale *= value.Scale; } } } internal static void Clear() { if (Object.op_Implicit((Object)(object)_root)) { Object.Destroy((Object)(object)_root); } _root = null; Templates.Clear(); _raw = null; } } } namespace JG224.AnyItemStands.Core { internal readonly struct DisplayTransform { internal float Scale { get; } internal float X { get; } internal float Y { get; } internal float Z { get; } internal float Pitch { get; } internal float Yaw { get; } internal float Roll { get; } internal DisplayTransform(float[] values) { Scale = values[0]; X = values[1]; Y = values[2]; Z = values[3]; Pitch = values[4]; Yaw = values[5]; Roll = values[6]; } internal static Dictionary Parse(string raw) { Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); string[] array = (raw ?? "").Split(new char[1] { ';' }); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(new char[1] { '=' }); if (array2.Length != 2 || array2[0].Trim().Length == 0) { continue; } string[] array3 = array2[1].Split(new char[1] { ',' }); if (array3.Length != 7) { continue; } float[] array4 = new float[7]; bool flag = true; for (int j = 0; j < array4.Length; j++) { if (float.TryParse(array3[j], NumberStyles.Float, CultureInfo.InvariantCulture, out array4[j]) && !float.IsNaN(array4[j]) && !float.IsInfinity(array4[j])) { bool num; if (j != 0) { num = Math.Abs(array4[j]) > ((j < 4) ? 5f : 360f); } else { if (array4[j] < 0.05f) { goto IL_0105; } num = array4[j] > 10f; } if (!num) { continue; } } goto IL_0105; IL_0105: flag = false; } if (flag) { dictionary[array2[0].Trim()] = new DisplayTransform(array4); } } return dictionary; } } internal enum FallbackKind { None, NativeAttach, SingleChild, Root } internal static class ItemStandRules { internal static FallbackKind SelectFallback(bool hasNativeAttach, bool hasRenderer, int childCount) { if (hasNativeAttach) { return FallbackKind.NativeAttach; } if (!hasRenderer) { return FallbackKind.None; } return FallbackKind.Root; } } }