From 7ee008e150bc5bcf76082d726f719ee0fdfda982 Mon Sep 17 00:00:00 2001 From: SulfurNitride Date: Wed, 11 Feb 2026 02:37:39 -0600 Subject: Fluorine Manager: full Linux port of Mod Organizer 2 Complete native Linux port with FUSE-based virtual filesystem, Proton/umu-run integration, and Flatpak packaging. Key features: - FUSE VFS replacing Windows USVFS (in-process + standalone helper for Flatpak) - Proton/GE-Proton/umu-run launcher with env var forwarding - Flatpak support (sandbox-aware VFS, NXM handler, umu-run) - Wine prefix management UI - Case-insensitive path resolution for Linux filesystems - QSettings-safe INI handling (avoids Bethesda INI corruption) - Portable instance support with auto-generated launcher scripts Co-Authored-By: Claude Opus 4.6 --- libs/installer_fomod_csharp/src/base_script.h | 552 ++++++++++++++++++++++++++ 1 file changed, 552 insertions(+) create mode 100644 libs/installer_fomod_csharp/src/base_script.h (limited to 'libs/installer_fomod_csharp/src/base_script.h') diff --git a/libs/installer_fomod_csharp/src/base_script.h b/libs/installer_fomod_csharp/src/base_script.h new file mode 100644 index 0000000..abfa152 --- /dev/null +++ b/libs/installer_fomod_csharp/src/base_script.h @@ -0,0 +1,552 @@ +/* +Copyright (C) 2020 Holt59. All rights reserved. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see . +*/ + +// clang-format off + +#ifndef BASE_SCRIPT_H +#define BASE_SCRIPT_H + +#using +#using +#using + +#include + +/** + * Note: The specification of BaseScript where taken from the Nexus-Mods installer_fomod extension + * for Vortex: https://github.com/Nexus-Mods/fomod-installer + */ +namespace CSharp { + + using namespace System; + using namespace System::Drawing; + using namespace System::Windows::Forms; + + /// + /// Describes the options to display in a select form. + /// + public ref struct SelectOption { + public: + /// + /// The name of the selection item. + /// + String^ Item; + + /// + /// The path to the preview image of the item. + /// + String^ Preview; + + /// + /// The description of the selection item. + /// + String^ Desc; + + /// + /// A simple constructor that initializes the struct with the given values. + /// + /// The name of the selection item. + /// The path to the preview image of the item. + /// The description of the selection item. + SelectOption(String^ item, String^ preview, String^ desc) { + Item = item; + Preview = preview; + Desc = desc; + } + }; + + /// + /// The base class for C# scripts. + /// + public ref class BaseScriptImpl { + public: + + static String^ LastError; + + /// + /// Returns the last error that occurred. + /// + /// The last error that occurred. + static String^ GetLastError() { + return LastError; + } + + /// + /// Performs a basic install of the mod. + /// + /// + /// A basic install installs all of the file in the mod to the Data directory + /// or activates all esp and esm files. + /// + /// true if the installation succeed; + /// false otherwise. + static bool PerformBasicInstall(); + + /// + /// Installs the specified file from the mod to the specified location on the file system. + /// + /// + /// This is the legacy form of . It now just calls + /// . + /// + /// The path of the file in the mod to install. + /// The path on the file system where the file is to be created. + /// true if the file was written; false otherwise. + /// + static bool CopyDataFile(String^ p_strFrom, String^ p_strTo) { + return InstallFileFromMod(p_strFrom, p_strTo); + } + + /// + /// Installs the specified file from the mod to the specified location on the file system. + /// + /// The path of the file in the mod to install. + /// The path on the file system where the file is to be created. + /// true if the file was written; false otherwise. + static bool InstallFileFromMod(String^ p_strFrom, String^ p_strTo); + + /// + /// Installs the speified file from the mod to the file system. + /// + /// The path of the file to install. + /// true if the file was written; false otherwise. + static bool InstallFileFromMod(String^ p_strFile) { + return InstallFileFromMod(p_strFile, p_strFile); + } + + /// + /// Installs the specified file from the mod to the specified location on the file system. + /// + /// The path of the file in the mod to install. + /// The path on the file system where the file is to be created. + /// true if the file was written; false otherwise. + static bool InstallFileFromFomod(String^ p_strFrom, String^ p_strTo) { + return InstallFileFromMod(p_strFrom, p_strTo); + } + + /// + /// Installs the speified file from the mod to the file system. + /// + /// The path of the file to install. + /// true if the file was written; false otherwise. + static bool InstallFileFromFomod(String^ p_strFile) { + return InstallFileFromMod(p_strFile, p_strFile); + } + + /// + /// Retrieves the list of files in the mod. + /// + /// The list of files in the mod. + static array^ GetModFileList(); + + /// + /// Retrieves the list of files in the mod. + /// + /// The list of files in the mod. + static array^ GetFomodFileList() { + return GetModFileList(); + } + + /// + /// Retrieves the specified file from the mod. + /// + /// The file to retrieve. + /// The requested file data. + static array^ GetFileFromMod(String^ p_strFile); + + /// + /// Retrieves the specified file from the mod. + /// + /// The file to retrieve. + /// The requested file data. + static array^ GetFileFromFomod(String^ p_strFile) { + return GetFileFromMod(p_strFile); + } + + /// + /// Gets a filtered list of all files in a user's Data directory. + /// + /// The subdirectory of the Data directory from which to get the listing. + /// The pattern against which to filter the file paths. + /// Whether or not to search through subdirectories. + /// A filtered list of all files in a user's Data directory. + static array^ GetExistingDataFileList(String^ p_strPath, String^ p_strPattern, bool p_booAllFolders); + + /// + /// Determines if the specified file exists in the user's Data directory. + /// + /// The path of the file whose existence is to be verified. + /// true if the specified file exists; false + /// otherwise. + static bool DataFileExists(String^ p_strPath); + + /// + /// Gets the speified file from the user's Data directory. + /// + /// The path of the file to retrieve. + /// The specified file, or null if the file does not exist. + static array^ GetExistingDataFile(String^ p_strPath); + + /// + /// Writes the file represented by the given byte array to the given path. + /// + /// + /// This method writes the given data as a file at the given path. If the file + /// already exists the user is prompted to overwrite the file. + /// + /// The path where the file is to be created. + /// The data that is to make up the file. + /// true if the file was written; false otherwise. + static bool GenerateDataFile(String^ p_strPath, array^ p_bteData); + + /// + /// Shows a message box with the given message. + /// + /// The message to display in the message box. + static void MessageBox(String^ p_strMessage) { + MessageBox(p_strMessage, nullptr); + } + + /// + /// Shows a message box with the given message and title. + /// + /// The message to display in the message box. + /// The message box's title, display in the title bar. + static void MessageBox(String^ p_strMessage, String^ p_strTitle) { + MessageBox(p_strMessage, p_strTitle, MessageBoxButtons::OK); + } + + /// + /// Shows a message box with the given message, title, and buttons. + /// + /// The message to display in the message box. + /// The message box's title, display in the title bar. + /// The buttons to show in the message box. + static DialogResult MessageBox(String^ p_strMessage, String^ p_strTitle, MessageBoxButtons p_mbbButtons) { + return MessageBox(p_strMessage, p_strTitle, p_mbbButtons, MessageBoxIcon::Information); + } + + static DialogResult MessageBox(String^ p_strMessage, String^ p_strTitle, MessageBoxButtons p_mbbButtons, MessageBoxIcon p_mdiIcon) { + return ExtendedMessageBox(p_strMessage, p_strTitle, nullptr, p_mbbButtons, p_mdiIcon); + } + + /// + /// Shows an extended message box with the given message, title, details, buttons, and icon. + /// + /// The message to display in the message box. + /// The message box's title, displayed in the title bar. + /// The message box's details, displayed in the details area. + /// The buttons to show in the message box. + /// The icon to display in the message box. + static DialogResult ExtendedMessageBox(String^ p_strMessage, String^ p_strTitle, String^ p_strDetails, MessageBoxButtons p_mbbButtons, MessageBoxIcon p_mdiIcon); + + /// + /// Displays a selection form to the user. + /// + /// The options from which to select. + /// The title of the selection form. + /// Whether more than one item can be selected. + /// The indices of the selected items. + static array^ Select(array^ p_sopOptions, String^ p_strTitle, bool p_booSelectMany); + + /// + /// Displays a selection form to the user. + /// + /// + /// The items, previews, and descriptions are repectively ordered. In other words, + /// the i-th item in uses the i-th preview in + /// and the i-th description in . + /// + /// Similarly, the idices return as results correspond to the indices of the items in + /// . + /// + /// The items from which to select. + /// The preview image file names for the items. + /// The descriptions of the items. + /// The title of the selection form. + /// Whether more than one item can be selected. + /// The indices of the selected items. + static array^ Select(array^ p_strItems, array^ p_strPreviewPaths, array^ p_strDescriptions, String^ p_strTitle, bool p_booSelectMany) { + const int size = p_strItems->GetLength(0); + array^ options = gcnew array(size); + for (int i = 0; i < size; ++i) { + options[i] = gcnew SelectOption(p_strItems[i], p_strPreviewPaths[i], p_strDescriptions[i]); + } + return Select(options, p_strTitle, p_booSelectMany); + } + + /// + /// Displays a selection form to the user. + /// + /// + /// The items, previews, and descriptions are repectively ordered. In other words, + /// the i-th item in uses the i-th preview in + /// and the i-th description in . + /// + /// Similarly, the idices return as results correspond to the indices of the items in + /// . + /// + /// The items from which to select. + /// The preview images for the items. + /// The descriptions of the items. + /// The title of the selection form. + /// Whether more than one item can be selected. + /// The indices of the selected items. + static array^ ImageSelect(array^ p_strItems, array^ /* p_imgPreviews */, array^ p_strDescriptions, String^ p_strTitle, bool p_booSelectMany) { + return Select(p_strItems, gcnew array(p_strItems->Length), p_strDescriptions, p_strTitle, p_booSelectMany); + } + + /// + /// Creates a form that can be used in custom mod scripts. + /// + /// A form that can be used in custom mod scripts. + static Form^ CreateCustomForm() { + Form^ form = gcnew Form; + return form; + } + + /// + /// Gets the version of the mod manager. + /// + /// The version of the mod manager. + static System::Version^ GetModManagerVersion(); + + /// + /// Gets the version of the game that is installed. + /// + /// The version of the game, or null if Fallout + /// is not installed. + static System::Version^ GetGameVersion(); + + // This is not in the spec., but I do not see a point in checking each + // script extender in a different way. + static System::Version^ GetScriptExtenderVersion(); + + /// + /// Gets the script extender version or null if it's not installed + /// + /// + static System::Version^ GetSkseVersion() { + return GetScriptExtenderVersion(); + } + + /// + /// Gets the script extender version or null if it's not installed + /// + /// + static System::Version^ GetFoseVersion() { + return GetScriptExtenderVersion(); + } + + /// + /// Gets the script extender version or null if it's not installed + /// + /// + static System::Version^ GetNvseVersion() { + return GetScriptExtenderVersion(); + } + + /// + /// Gets the version of the mod manager. + /// + /// The version of the mod manager. + static System::Version^ GetFommVersion() { + return GetModManagerVersion(); + } + + /// + /// Gets the version of the game that is installed. + /// + /// The version of the game, or null if Fallout + /// is not installed. + static System::Version^ GetFalloutVersion() { + // I think this is an old function... What Fallout anyway? So just going + // to return the game version, whatever current game. + return GetGameVersion(); + } + + /// + /// Determins if the script extender for the game is installed + /// (this checks for the script extender of the game for which the + /// mod is being installed) + /// + /// + static bool ScriptExtenderPresent(); + + /// + /// Gets a list of all install plugins. + /// + /// A list of all install plugins. + static array^ GetAllPlugins(); + + /// + /// Retrieves a list of currently active plugins. + /// + /// A list of currently active plugins. + static array^ GetActivePlugins(); + + /// + /// Sets the activated status of a plugin (i.e., and esp or esm file). + /// + /// The path to the plugin to activate or deactivate. + /// Whether to activate the plugin. + static void SetPluginActivation(String^ /* p_strPluginPath */, bool /* p_booActivate */) { + // throw gcnew NotImplementedException("SetPluginActivation"); + } + + /// + /// Sets the load order of the specifid plugin. + /// + /// The path to the plugin file whose load order is to be set. + /// The new load order index of the plugin. + static void SetPluginOrderIndex(String^ /* p_strPlugin */, int /* p_intNewIndex */) { + // throw gcnew NotImplementedException("SetPluginOrderIndex"); + } + + /// + /// Sets the load order of the plugins. + /// + /// + /// Each plugin will be moved from its current index to its indices' position + /// in . + /// + /// The new load order of the plugins. Each entry in this array + /// contains the current index of a plugin. This array must contain all current indices. + static void SetLoadOrder(array^ /* p_intPlugins */) { + // throw gcnew NotImplementedException("SetLoadOrder"); + } + + /// + /// Moves the specified plugins to the given position in the load order. + /// + /// + /// Note that the order of the given list of plugins is not maintained. They are re-ordered + /// to be in the same order as they are in the before-operation load order. This, I think, + /// is somewhat counter-intuitive and may change, though likely not so as to not break + /// backwards compatibility. + /// + /// The list of plugins to move to the given position in the + /// load order. Each entry in this array contains the current index of a plugin. + /// The position in the load order to which to move the specified + /// plugins. + static void SetLoadOrder(array^ /* p_intPlugins */, int /* p_intPosition */) { + // throw gcnew NotImplementedException("SetLoadOrder"); + } + + /// + /// Retrieves the specified settings value as a string. + /// + /// The name of the settings file from which to retrieve the value. + /// The section containing the value to retrieve. + /// The key of the value to retrieve. + /// The specified value as a string. + static String^ GetIniString(String^ settingsFileName, String^ section, String^ key); + + /// + /// Retrieves the specified settings value as an integer. + /// + /// The name of the settings file from which to retrieve the value. + /// The section containing the value to retrieve. + /// The key of the value to retrieve. + /// The specified value as an integer. + static int GetIniInt(String^ settingsFileName, String^ section, String^ key); + + /// + /// Retrieves the specified Fallout.ini value as a string. + /// + /// The section containing the value to retrieve. + /// The key of the value to retrieve. + /// The specified value as a string. + /// + static String^ GetFalloutIniString(String^ section, String^ key) { + return GetIniString("Fallout.ini", section, key); + } + + /// + /// Retrieves the specified Fallout.ini value as an integer. + /// + /// The section containing the value to retrieve. + /// The key of the value to retrieve. + /// + static int GetFalloutIniInt(String^ section, String^ key) { + return GetIniInt("Fallout.ini", section, key); + } + + /// + /// Retrieves the specified FalloutPrefs.ini value as a string. + /// + /// The section containing the value to retrieve. + /// The key of the value to retrieve. + /// The specified value as a string. + /// + static String^ GetPrefsIniString(String^ p_strSection, String^ p_strKey) { + // This looks wrong? Yes! But that's what used in other mod managers... + return GetIniString("FalloutPrefs.ini", p_strSection, p_strKey); + } + + /// + /// Retrieves the specified FalloutPrefs.ini value as an integer. + /// + /// The section containing the value to retrieve. + /// The key of the value to retrieve. + /// The specified value as an integer. + /// + static int GetPrefsIniInt(String^ p_strSection, String^ p_strKey) { + // This looks wrong? Yes! But that's what used in other mod managers... + return GetIniInt("FalloutPrefs.ini", p_strSection, p_strKey); + } + + /// + /// Sets the specified value in the specified Ini file to the given value. + /// + /// The name of the settings file to edit. + /// The section in the Ini file to edit. + /// The key in the Ini file to edit. + /// The value to which to set the key. + /// true if the value was set; false + /// if the user chose not to overwrite the existing value. + static bool EditIni(String^ p_strSettingsFileName, String^ p_strSection, String^ p_strKey, String^ p_strValue); + + /// + /// Sets the specified value in the Fallout.ini file to the given value. + /// + /// The section in the Ini file to edit. + /// The key in the Ini file to edit. + /// The value to which to set the key. + /// Not used. + /// true if the value was set; false + /// if the user chose not to overwrite the existing value. + static bool EditFalloutINI(String^ p_strSection, String^ p_strKey, String^ p_strValue, bool /* p_booSaveOld */) { + return EditIni("Fallout.ini", p_strSection, p_strKey, p_strValue); + } + + }; + + /** + * @brief Post-install script. + */ + MOBase::IPluginInstaller::EInstallResult postInstall(std::shared_ptr& tree); +} + +// BaseScript cannot be in a namespace: +public ref struct SelectOption: public CSharp::SelectOption { + SelectOption(System::String^ item, System::String^ preview, System::String^ desc) : + CSharp::SelectOption(item, preview, desc) { } +}; +public ref class BaseScript: public CSharp::BaseScriptImpl { }; + +#endif -- cgit v1.3.1