use std::collections::{HashMap, HashSet};
use nitro_config::ConfigKind;
use nitro_config::instance::{InstanceConfig, WrapperCommand};
use nitro_config::template::TemplateConfig;
use nitro_instance::addon::Addon;
use nitro_pkg::repo::{PackageFlag, RepoMetadata};
use nitro_pkg::script_eval::AddonInstructionData;
use nitro_pkg::{PackageContentType, PackageSearchResults, RecommendedPackage, RequiredPackage};
use nitro_shared::UpdateDepth;
use nitro_shared::id::{InstanceID, TemplateID};
use nitro_shared::lang::translate::LanguageMap;
use nitro_shared::loaders::Loader;
use nitro_shared::minecraft::VersionEntry;
use nitro_shared::minecraft::{AddonKind, SkinVariant};
use nitro_shared::minecraft::{Cape, MinecraftUserProfile, Skin};
use nitro_shared::pkg::{PackageID, PackageQueryDepth, PackageSearchParameters};
use nitro_shared::versions::VersionPattern;
use nitro_shared::{Side, versions::VersionInfo};
use serde::{Deserialize, Serialize};
use crate::control::Control;
use super::Hook;
macro_rules! def_hook {
($struct:ident, $name:literal, $desc:literal, $arg:ty, $res:ty, $version:literal, $asynchronous:literal, $($extra:tt)*) => {
#[doc = $desc]
pub struct $struct;
impl Hook for $struct {
type Arg = $arg;
type Result = $res;
fn get_name_static() -> &'static str {
$name
}
fn get_version() -> u16 {
$version
}
fn is_asynchronous() -> bool {
$asynchronous
}
$(
$extra
)*
}
};
($struct:ident, $name:literal, $desc:literal, $arg:ty, $res:ty, $version:literal, $($extra:tt)*) => {
def_hook!($struct, $name, $desc, $arg, $res, $version, false, $($extra)*);
};
}
def_hook!(
OnLoad,
"on_load",
"Hook for when a plugin is loaded",
(),
(),
1,
true,
);
def_hook!(
StartWorker,
"start_worker",
"Hook for starting a long-running worker alongside the plugin runner",
(),
(),
1,
true,
);
def_hook!(
Subcommand,
"subcommand",
"Hook for when a command's subcommands are run",
SubcommandArg,
(),
3,
fn get_takes_over() -> bool {
true
}
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct SubcommandArg {
pub args: Vec<String>,
pub supercommand: Option<String>,
pub instances: HashMap<InstanceID, InstanceConfig>,
}
def_hook!(
AddVersions,
"add_versions",
"Hook for adding extra versions to the version manifest",
UpdateDepth,
Vec<VersionEntry>,
2,
true,
);
def_hook!(
OnInstanceSetup,
"on_instance_setup",
"Hook for doing work when setting up an instance for update or launch",
OnInstanceSetupArg,
OnInstanceSetupResult,
5,
);
def_hook!(
AfterInstanceSetup,
"after_instance_setup",
"Hook for doing instance setup work after the core instance has been created",
OnInstanceSetupArg,
OnInstanceSetupResult,
1,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct OnInstanceSetupArg {
pub id: String,
pub side: Option<Side>,
pub inst_dir: Option<String>,
pub version_info: VersionInfo,
pub old_version: Option<String>,
pub loader: Loader,
pub current_loader_version: Option<String>,
pub desired_loader_version: VersionPattern,
pub config: InstanceConfig,
pub internal_dir: String,
pub update_depth: UpdateDepth,
pub jvm_path: String,
pub game_jar_path: String,
pub classpath: Option<String>,
}
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct OnInstanceSetupResult {
pub main_class_override: Option<String>,
pub jar_path_override: Option<String>,
pub classpath_extension: Vec<String>,
pub loader_version: Option<String>,
pub jvm_args: Vec<String>,
pub game_args: Vec<String>,
pub wrappers: Vec<WrapperCommand>,
pub exclude_game_jar: bool,
}
def_hook!(
RemoveLoader,
"remove_loader",
"Hook for removing a loader from an instance when the loader or version changes",
OnInstanceSetupArg,
(),
1,
);
def_hook!(
AfterPackagesInstalled,
"after_packages_installed",
"Hook for doing work on an instance after packages are installed on that instance",
AfterPackagesInstalledArg,
(),
2,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct AfterPackagesInstalledArg {
pub id: String,
pub side: Option<Side>,
pub inst_dir: Option<String>,
pub version_info: VersionInfo,
pub loader: Loader,
pub config: InstanceConfig,
pub internal_dir: String,
pub update_depth: UpdateDepth,
}
def_hook!(
OnInstanceLaunch,
"on_instance_launch",
"Hook for doing work before an instance is launched",
InstanceLaunchArg,
(),
2,
);
def_hook!(
WhileInstanceLaunch,
"while_instance_launch",
"Hook for running sibling processes with an instance when it is launched",
InstanceLaunchArg,
(),
2,
true,
);
def_hook!(
OnInstanceStop,
"on_instance_stop",
"Hook for doing work when an instance is stopped gracefully",
InstanceLaunchArg,
(),
2,
);
def_hook!(
ReplaceInstanceLaunch,
"replace_instance_launch",
"Hook for replacing the launch behavior of an instance without a game dir",
InstanceLaunchArg,
Option<ReplaceInstanceLaunchResult>,
2,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct ReplaceInstanceLaunchResult {
pub pid: u32,
pub stdout_path: Option<String>,
}
def_hook!(
UpdateWorldFiles,
"update_world_files",
"Hook for when shared world files are updated",
InstanceLaunchArg,
(),
1,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct InstanceLaunchArg {
pub id: String,
pub side: Option<Side>,
pub inst_dir: Option<String>,
pub version_info: VersionInfo,
pub config: InstanceConfig,
pub pid: Option<u32>,
pub classpath: Option<String>,
pub stdout_path: Option<String>,
pub stdin_path: Option<String>,
}
def_hook!(
CustomPackageInstruction,
"custom_package_instruction",
"Hook for handling custom instructions in packages",
CustomPackageInstructionArg,
CustomPackageInstructionResult,
1,
true,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct CustomPackageInstructionArg {
pub pkg_id: String,
pub command: String,
pub args: Vec<String>,
}
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct CustomPackageInstructionResult {
pub handled: bool,
pub addon_reqs: Vec<AddonInstructionData>,
pub deps: Vec<Vec<RequiredPackage>>,
pub conflicts: Vec<PackageID>,
pub recommendations: Vec<RecommendedPackage>,
pub bundled: Vec<PackageID>,
pub compats: Vec<(PackageID, PackageID)>,
pub extensions: Vec<PackageID>,
pub notices: Vec<String>,
}
def_hook!(
HandleAuth,
"handle_auth",
"Hook for handling authentication for custom account types",
HandleAuthArg,
HandleAuthResult,
1,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct HandleAuthArg {
pub account_id: String,
pub account_type: String,
}
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct HandleAuthResult {
pub handled: bool,
pub profile: Option<MinecraftUserProfile>,
}
def_hook!(
AddTranslations,
"add_translations",
"Hook for adding extra translations to Nitrolaunch",
(),
LanguageMap,
1,
true,
);
def_hook!(
AddInstanceTransferFormats,
"add_instance_transfer_formats",
"Hook for adding information about instance transfer formats",
(),
Vec<InstanceTransferFormat>,
1,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct InstanceTransferFormat {
pub id: String,
pub name: String,
pub color: Option<String>,
pub import: Option<InstanceTransferFormatDirection>,
pub export: Option<InstanceTransferFormatDirection>,
pub migrate: Option<InstanceTransferFormatDirection>,
pub needs_import_side: bool,
}
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct InstanceTransferFormatDirection {
pub modloader: InstanceTransferFeatureSupport,
pub mods: InstanceTransferFeatureSupport,
pub launch_settings: InstanceTransferFeatureSupport,
}
#[derive(Serialize, Deserialize, Default, Clone, Copy)]
#[serde(rename_all = "snake_case")]
pub enum InstanceTransferFeatureSupport {
#[default]
Supported,
FormatUnsupported,
PluginUnsupported,
}
def_hook!(
ExportInstance,
"export_instance",
"Hook for exporting an instance",
ExportInstanceArg,
(),
3,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct ExportInstanceArg {
pub format: String,
pub id: String,
pub config: InstanceConfig,
pub minecraft_version: String,
pub loader_version: Option<String>,
pub inst_dir: String,
pub result_path: String,
}
def_hook!(
ImportInstance,
"import_instance",
"Hook for importing an instance",
ImportInstanceArg,
ImportInstanceResult,
2,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct ImportInstanceArg {
pub format: String,
pub id: String,
pub source_path: String,
pub result_path: String,
pub side: Option<Side>,
}
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct ImportInstanceResult {
pub format: String,
pub config: InstanceConfig,
}
def_hook!(
CheckMigration,
"check_migration",
"Hook for checking for presence of a launcher for migration",
String,
Option<CheckMigrationResult>,
1,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct CheckMigrationResult {
pub instances: Vec<String>,
}
def_hook!(
MigrateInstances,
"migrate_instances",
"Hook for migrating all instances from another launcher",
MigrateInstancesArg,
MigrateInstancesResult,
2,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct MigrateInstancesArg {
pub format: String,
pub instances: Option<Vec<String>>,
pub link: bool,
}
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct MigrateInstancesResult {
pub format: String,
pub instances: HashMap<String, InstanceConfig>,
}
#[derive(Serialize, Deserialize)]
pub struct MigratedAddon {
pub id: String,
pub paths: Vec<String>,
pub kind: AddonKind,
pub version: Option<String>,
}
def_hook!(
AddSupportedLoaders,
"add_supported_loaders",
"Tell Nitrolaunch that you support installing extra loaders",
(),
Vec<Loader>,
2,
);
def_hook!(
AddInstances,
"add_instances",
"Hook for adding new instances",
AddInstancesArg,
HashMap<InstanceID, InstanceConfig>,
1,
true,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct AddInstancesArg {}
def_hook!(
AddTemplates,
"add_templates",
"Hook for adding new templates",
AddInstancesArg,
HashMap<TemplateID, TemplateConfig>,
1,
true,
);
def_hook!(
InjectPageScript,
"inject_page_script",
"Hook for running JavaScript on GUI pages",
InjectPageScriptArg,
String,
1,
true,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct InjectPageScriptArg {
pub page: String,
pub object: Option<String>,
}
def_hook!(
AddSidebarButtons,
"add_sidebar_buttons",
"Hook for adding buttons to the GUI sidebar",
(),
Vec<SidebarButton>,
1,
true,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct SidebarButton {
pub html: String,
pub href: String,
pub selected_url: Option<String>,
pub selected_url_start: Option<String>,
pub color: String,
}
def_hook!(
GetPage,
"get_page",
"Hook for adding pages to the GUI",
String,
Option<String>,
1,
);
def_hook!(
AddCustomPackageRepositories,
"add_custom_package_repositories",
"Hook for adding custom package repositories",
(),
Vec<AddCustomPackageRepositoriesResult>,
1,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct AddCustomPackageRepositoriesResult {
pub is_preferred: bool,
pub id: String,
pub metadata: RepoMetadata,
}
def_hook!(
QueryCustomPackageRepository,
"query_custom_package_repository",
"Hook for getting packages from a custom repository",
QueryCustomPackageRepositoryArg,
Option<CustomRepoQueryResult>,
1,
);
#[derive(Serialize, Deserialize, Default)]
pub struct QueryCustomPackageRepositoryArg {
pub repository: String,
pub package: String,
pub depth: PackageQueryDepth,
}
#[derive(Serialize, Deserialize)]
pub struct CustomRepoQueryResult {
pub contents: String,
pub content_type: PackageContentType,
pub flags: HashSet<PackageFlag>,
}
def_hook!(
SearchCustomPackageRepository,
"search_custom_package_repository",
"Hook for searching or browsing a custom package repository",
SearchCustomPackageRepositoryArg,
PackageSearchResults,
1,
);
#[derive(Serialize, Deserialize, Default)]
pub struct SearchCustomPackageRepositoryArg {
pub repository: String,
pub parameters: PackageSearchParameters,
}
def_hook!(
PreloadPackages,
"preload_packages",
"Hook for loading multiple packages from a custom package repository",
PreloadPackagesArg,
(),
1,
);
#[derive(Serialize, Deserialize, Default)]
pub struct PreloadPackagesArg {
pub repository: String,
pub packages: Vec<String>,
}
def_hook!(
SyncCustomPackageRepository,
"sync_custom_package_repository",
"Hook for updating the cache of a custom package repository",
SyncCustomPackageRepositoryArg,
(),
1,
);
#[derive(Serialize, Deserialize, Default)]
pub struct SyncCustomPackageRepositoryArg {
pub repository: String,
}
def_hook!(
AddThemes,
"add_themes",
"Hook for adding new GUI themes",
(),
Vec<Theme>,
1,
true,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct Theme {
pub id: String,
pub name: String,
pub description: Option<String>,
pub r#type: ThemeType,
pub css: String,
pub color: String,
}
#[derive(Serialize, Deserialize, Default, Clone, Copy)]
#[serde(rename_all = "snake_case")]
pub enum ThemeType {
#[default]
Base,
Overlay,
}
def_hook!(
CustomAction,
"custom_action",
"Runs an arbitrary action on this plugin",
CustomActionArg,
serde_json::Value,
1,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct CustomActionArg {
pub id: String,
pub payload: serde_json::Value,
}
def_hook!(
AddDropdownButtons,
"add_dropdown_buttons",
"Adds buttons to dropdowns in the GUI",
(),
Vec<DropdownButton>,
1,
);
#[derive(Serialize, Deserialize)]
pub struct DropdownButton {
pub plugin: String,
pub location: DropdownButtonLocation,
pub icon: String,
pub text: String,
pub color: Option<String>,
pub tip: Option<String>,
pub action: Option<String>,
pub on_click: Option<String>,
}
#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
#[serde(rename_all = "snake_case")]
pub enum DropdownButtonLocation {
AddTemplateOrInstance,
InstanceLaunch,
InstanceUpdate,
InstanceMoreOptions,
}
def_hook!(
AddInstanceTiles,
"add_instance_tiles",
"Adds tiles to the instance page in the GUI",
String,
Vec<InstanceTile>,
1,
true,
);
#[derive(Serialize, Deserialize)]
pub struct InstanceTile {
pub id: String,
pub contents: String,
pub size: InstanceTileSize,
}
#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
#[serde(rename_all = "snake_case")]
pub enum InstanceTileSize {
Small,
Large,
}
def_hook!(
AddInstanceIcons,
"add_instance_icons",
"Adds default instance icons for the user to use",
(),
Vec<String>,
1,
true,
);
def_hook!(
GetLoaderVersions,
"get_loader_versions",
"Gets the list of versions for a loader",
GetLoaderVersionsArg,
Vec<String>,
1,
true,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct GetLoaderVersionsArg {
pub loader: Loader,
pub minecraft_version: String,
}
def_hook!(
AddAccountTypes,
"add_account_types",
"Adds new available account types",
(),
Vec<AccountTypeInfo>,
1,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct AccountTypeInfo {
pub id: String,
pub name: String,
pub color: String,
}
def_hook!(
AddJavaTypes,
"add_java_types",
"Adds new available Java types",
(),
Vec<JavaTypeInfo>,
1,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct JavaTypeInfo {
pub id: String,
pub name: String,
pub color: String,
}
def_hook!(
InstallCustomJava,
"install_custom_java",
"Installs a custom Java type",
InstallCustomJavaArg,
Option<InstallCustomJavaResult>,
1,
true,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct InstallCustomJavaArg {
pub kind: String,
pub major_version: String,
pub update_depth: UpdateDepth,
}
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct InstallCustomJavaResult {
pub path: String,
pub version: String,
}
def_hook!(
SaveInstanceConfig,
"save_instance_config",
"Creates or updates config for a plugin instance",
SaveInstanceConfigArg,
(),
1,
true,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct SaveInstanceConfigArg {
pub id: String,
pub config: InstanceConfig,
}
def_hook!(
SaveTemplateConfig,
"save_template_config",
"Creates or updates config for a plugin template",
SaveTemplateConfigArg,
(),
1,
true,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct SaveTemplateConfigArg {
pub id: String,
pub config: TemplateConfig,
}
def_hook!(
DeleteInstance,
"delete_instance",
"Deletes a plugin instance",
SaveInstanceConfigArg,
(),
1,
false,
);
def_hook!(
DeleteTemplate,
"delete_template",
"Deletes a plugin template",
SaveTemplateConfigArg,
(),
1,
false,
);
def_hook!(
GetInstanceLogs,
"get_instance_logs",
"Gets the list of available log IDs for an instance",
GetInstanceLogsArg,
Vec<String>,
1,
true,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct GetInstanceLogsArg {
pub id: String,
pub config: InstanceConfig,
}
def_hook!(
GetInstanceLog,
"get_instance_log",
"Gets the contents of a specific log for an instance",
GetInstanceLogArg,
String,
1,
true,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct GetInstanceLogArg {
pub instance_id: String,
pub log_id: String,
pub config: InstanceConfig,
}
def_hook!(
GetAccountCosmetics,
"get_account_cosmetics",
"Gets the available cosmetics for a custom account",
GetAccountCosmeticsArg,
GetAccountCosmeticsResult,
1,
true,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct GetAccountCosmeticsArg {
pub id: String,
pub kind: String,
}
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct GetAccountCosmeticsResult {
pub skins: Vec<Skin>,
pub capes: Vec<Cape>,
}
def_hook!(
UploadSkin,
"upload_skin",
"Uploads and activates a skin for a custom account",
UploadSkinArg,
(),
1,
true,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct UploadSkinArg {
pub id: String,
pub kind: String,
pub data: Vec<u8>,
pub variant: SkinVariant,
}
def_hook!(
ActivateCape,
"activate_cape",
"Activates a cape for a custom account",
ActivateCapeArg,
(),
1,
true,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct ActivateCapeArg {
pub id: String,
pub kind: String,
pub cape: Option<String>,
}
def_hook!(
AddSkinRepositories,
"add_skin_repositories",
"Adds repositories for searching custom skins",
(),
Vec<SkinRepository>,
1,
true,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct SkinRepository {
pub id: String,
pub name: String,
}
def_hook!(
SearchSkinRepository,
"search_skin_repository",
"Searches a skin repository for skins",
SearchSkinRepositoryArg,
Vec<Skin>,
1,
true,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct SearchSkinRepositoryArg {
pub repository: String,
pub search: Option<String>,
}
def_hook!(
AddInstanceConfigControls,
"add_instance_config_controls",
"Define additional config schema for instance or template config",
AddInstanceConfigControlsArg,
AddInstanceConfigControlsResult,
1,
true,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct AddInstanceConfigControlsArg {
pub id: Option<String>,
pub kind: ConfigKind,
pub plugin: Option<String>,
}
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct AddInstanceConfigControlsResult {
pub controls: Vec<Control>,
}
def_hook!(
AddPluginConfigControls,
"add_plugin_config_controls",
"Define config schema for this plugin",
(),
Vec<Control>,
1,
true,
);
def_hook!(
AddModpackFormats,
"add_modpack_formats",
"Add new formats for modpacks",
(),
Vec<ModpackFormat>,
1,
true,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct ModpackFormat {
pub id: String,
pub name: String,
pub transfer_format: Option<String>,
}
def_hook!(
InstallModpack,
"install_modpack",
"Installs a modpack",
InstallModpackArg,
InstallModpackResult,
1,
true,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct InstallModpackArg {
pub format: String,
pub path: String,
pub old_path: Option<String>,
pub target_path: String,
pub side: Side,
}
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct InstallModpackResult {
pub name: String,
pub packages: Vec<String>,
pub addons: Vec<Addon>,
}