/// <summary> /// Register types attributed with `UIExtenderLibExtension`: /// 1. will add extensions to their respective components /// 2. will add standard patches and patch game /// 3. will force game to reload affected XMLs /// </summary> /// <param name="types"></param> public void Register(IEnumerable <Type> types) { foreach (var extensionType in types) { foreach (var baseAttribute in Attribute.GetCustomAttributes(extensionType, typeof(BaseUIExtenderAttribute))) { switch (baseAttribute) { case PrefabExtensionAttribute xmlExtension: { var constructor = extensionType.GetConstructor(Type.EmptyTypes); if (constructor == null) { Utils.Fail("Failed to find appropriate constructor for patch!"); continue; } // gauntlet xml extension switch (constructor.Invoke(Array.Empty <object>())) { case PrefabExtensionInsertPatch patch: PrefabComponent.RegisterPatch(xmlExtension.Movie, xmlExtension.XPath, patch); break; case PrefabExtensionReplacePatch patch: PrefabComponent.RegisterPatch(xmlExtension.Movie, xmlExtension.XPath, patch); break; case PrefabExtensionInsertAsSiblingPatch patch: PrefabComponent.RegisterPatch(xmlExtension.Movie, xmlExtension.XPath, patch); break; case CustomPatch <XmlDocument> patch: PrefabComponent.RegisterPatch(xmlExtension.Movie, patch.Apply); break; case CustomPatch <XmlNode> patch: PrefabComponent.RegisterPatch(xmlExtension.Movie, xmlExtension.XPath, patch.Apply); break; default: Utils.Fail($"Patch class is unsupported - {extensionType}!"); break; } break; } case ViewModelMixinAttribute viewModelExtension: // view model mixin ViewModelComponent.RegisterViewModelMixin(extensionType, viewModelExtension.RefreshMethodName); break; default: Utils.Fail($"Failed to find appropriate clause for base type {extensionType} with attribute {baseAttribute}!"); break; } } } }
protected override void OnBeforeInitialModuleScreenSetAsRoot() { base.OnBeforeInitialModuleScreenSetAsRoot(); /* * This method is run every time MainMenu appears, which could happen multiple times * during single application run. * * Code to apply extensions should be run after all of the mods has been loaded, therefore it could not * be placed in `OnSubModuleLoad`. * * In order to only run it once this flag is implemented. */ if (_processedExtensions) { return; } _processedExtensions = true; // apply registered extensions foreach (var extensionType in UIExtender.Extensions) { var baseAttribute = Attribute.GetCustomAttribute(extensionType, typeof(UIExtenderLibExtension)); if (baseAttribute is PrefabExtension xmlExtension) { var constructor = extensionType.GetConstructor(new Type[] { }); if (constructor == null) { Debug.Fail("Failed to find appropriate constructor for patch!"); } // gauntlet xml extension switch (constructor.Invoke(new object[] {})) { case PrefabExtensionInsertPatch patch: WidgetComponent.RegisterPatch(xmlExtension.Movie, xmlExtension.XPath, patch); break; case PrefabExtensionReplacePatch patch: WidgetComponent.RegisterPatch(xmlExtension.Movie, xmlExtension.XPath, patch); break; case PrefabExtensionInsertAsSiblingPatch patch: WidgetComponent.RegisterPatch(xmlExtension.Movie, xmlExtension.XPath, patch); break; case CustomPatch <XmlDocument> patch: WidgetComponent.RegisterPatch(xmlExtension.Movie, patch.Apply); break; case CustomPatch <XmlNode> patch: WidgetComponent.RegisterPatch(xmlExtension.Movie, xmlExtension.XPath, patch.Apply); break; default: Debug.Fail($"Patch class is unsupported - {extensionType}!"); break; } } else if (baseAttribute is ViewModelMixin) { // view model mixin ViewModelComponent.RegisterViewModelMixin(extensionType); } else { Debug.Fail($"Failed to find appropriate clause for base type {extensionType} with attribute {baseAttribute}!"); } } // apply patches var harmony = new Harmony("net.shdwp.UIExtenderLibModule"); harmony.PatchAll(); // save .runtime_dll for troubleshooting ViewModelComponent.SaveRuntimeImages(); // force reload movies that should be patched by extensions WidgetComponent.ForceReloadMovies(); }
protected override void OnBeforeInitialModuleScreenSetAsRoot() { base.OnBeforeInitialModuleScreenSetAsRoot(); // apply registered extensions foreach (var extensionType in UIExtender.Extensions) { var baseAttribute = Attribute.GetCustomAttribute(extensionType, typeof(UIExtenderLibExtension)); if (baseAttribute is PrefabExtension xmlExtension) { var constructor = extensionType.GetConstructor(new Type[] { }); if (constructor == null) { Debug.Fail("Failed to find appropriate constructor for patch!"); } // gauntlet xml extension switch (constructor.Invoke(new object[] {})) { case PrefabExtensionInsertPatch patch: WidgetComponent.RegisterPatch(xmlExtension.Movie, xmlExtension.XPath, patch); break; case PrefabExtensionReplacePatch patch: WidgetComponent.RegisterPatch(xmlExtension.Movie, xmlExtension.XPath, patch); break; case PrefabExtensionInsertAsSiblingPatch patch: WidgetComponent.RegisterPatch(xmlExtension.Movie, xmlExtension.XPath, patch); break; case CustomPatch <XmlDocument> patch: WidgetComponent.RegisterPatch(xmlExtension.Movie, patch.Apply); break; case CustomPatch <XmlNode> patch: WidgetComponent.RegisterPatch(xmlExtension.Movie, xmlExtension.XPath, patch.Apply); break; default: Debug.Fail($"Patch class is unsupported - {extensionType}!"); break; } } else if (baseAttribute is ViewModelMixin) { // view model mixin ViewModelComponent.RegisterViewModelMixin(extensionType); } else { Debug.Fail($"Failed to find appropriate clause for base type {extensionType} with attribute {baseAttribute}!"); } } // apply patches var harmony = new Harmony("net.shdwp.UIExtenderLibModule"); harmony.PatchAll(); // save .runtime_dll for troubleshooting ViewModelComponent.SaveRuntimeImages(); // force reload movies that should be patched by extensions WidgetComponent.ForceReloadMovies(); }
/// <summary> /// Register types attributed with `UIExtenderLibExtension`: /// 1. will add extensions to their respective components /// 2. will add standard patches and patch game /// 3. will force game to reload affected XMLs /// </summary> /// <param name="types"></param> internal void Register(IEnumerable <Type> types) { foreach (var extensionType in types) { var baseAttribute = Attribute.GetCustomAttribute(extensionType, typeof(UIExtenderLibExtension)); switch (baseAttribute) { case PrefabExtension xmlExtension: { var constructor = extensionType.GetConstructor(new Type[] { }); if (constructor == null) { Debug.Fail("Failed to find appropriate constructor for patch!"); } // gauntlet xml extension switch (constructor.Invoke(new object[] {})) { case PrefabExtensionInsertPatch patch: PrefabComponent.RegisterPatch(xmlExtension.Movie, xmlExtension.XPath, patch); break; case PrefabExtensionReplacePatch patch: PrefabComponent.RegisterPatch(xmlExtension.Movie, xmlExtension.XPath, patch); break; case PrefabExtensionInsertAsSiblingPatch patch: PrefabComponent.RegisterPatch(xmlExtension.Movie, xmlExtension.XPath, patch); break; case CustomPatch <XmlDocument> patch: PrefabComponent.RegisterPatch(xmlExtension.Movie, patch.Apply); break; case CustomPatch <XmlNode> patch: PrefabComponent.RegisterPatch(xmlExtension.Movie, xmlExtension.XPath, patch.Apply); break; default: Debug.Fail($"Patch class is unsupported - {extensionType}!"); break; } break; } case ViewModelMixin _: // view model mixin ViewModelComponent.RegisterViewModelMixin(extensionType); break; default: Debug.Fail($"Failed to find appropriate clause for base type {extensionType} with attribute {baseAttribute}!"); break; } } var patchingResult = ViewModelPatches.Result.Success; // add core patches (in order for UIExtender to actually work) if (!CorePatches.AddTo(CodePatcher)) { _userMessages.Add(new InformationMessage($"Failed to patch {ModuleName} (outdated).", Colors.Red)); return; } patchingResult = ViewModelPatches.AddTo(CodePatcher); switch (patchingResult) { case ViewModelPatches.Result.Success: break; case ViewModelPatches.Result.Partial: AddUserWarning($"There were errors on {ModuleName} patching. Some functionality may not work (module outdated)."); break; case ViewModelPatches.Result.Failure: AddUserError($"Failed to patch {ModuleName} (outdated)."); break; } // finalize code patcher and let harmony apply patches CodePatcher.ApplyPatches(); // save .dll for troubleshooting ViewModelComponent.SaveDebugImages(); // force reload movies that should be patched by extensions PrefabComponent.ForceReloadMovies(); }