use mcvm_core::net::game_files::version_manifest::VersionEntry;
use mcvm_core::net::minecraft::MinecraftUserProfile;
use mcvm_core::util::versions::MinecraftVersionDeser;
use mcvm_pkg::script_eval::AddonInstructionData;
use mcvm_pkg::{RecommendedPackage, RequiredPackage};
use mcvm_shared::lang::translate::LanguageMap;
use mcvm_shared::modifications::{ClientType, ServerType};
use mcvm_shared::pkg::PackageID;
use mcvm_shared::versions::VersionPattern;
use mcvm_shared::UpdateDepth;
use mcvm_shared::{output::MCVMOutput, versions::VersionInfo, Side};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use crate::hook_call::HookCallArg;
use crate::HookHandle;
pub trait Hook {
type Arg: Serialize + DeserializeOwned;
type Result: DeserializeOwned + Serialize + Default;
fn get_name(&self) -> &'static str {
Self::get_name_static()
}
fn get_name_static() -> &'static str;
fn get_takes_over() -> bool {
false
}
fn get_version() -> u16;
fn call(
&self,
arg: HookCallArg<'_, Self>,
o: &mut impl MCVMOutput,
) -> anyhow::Result<HookHandle<Self>>
where
Self: Sized,
{
crate::hook_call::call(self, arg, o)
}
}
macro_rules! def_hook {
($struct:ident, $name:literal, $desc:literal, $arg:ty, $res:ty, $version: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
}
$(
$extra
)*
}
};
}
def_hook!(
OnLoad,
"on_load",
"Hook for when a plugin is loaded",
(),
(),
1,
);
def_hook!(
Subcommand,
"subcommand",
"Hook for when a command's subcommands are run",
Vec<String>,
(),
1,
fn get_takes_over() -> bool {
true
}
);
def_hook!(
ModifyInstanceConfig,
"modify_instance_config",
"Hook for modifying an instance's configuration",
serde_json::Map<String, serde_json::Value>,
ModifyInstanceConfigResult,
1,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct ModifyInstanceConfigResult {
pub additional_jvm_args: Vec<String>,
}
def_hook!(
AddVersions,
"add_versions",
"Hook for adding extra versions to the version manifest",
(),
Vec<VersionEntry>,
1,
);
def_hook!(
OnInstanceSetup,
"on_instance_setup",
"Hook for doing work when setting up an instance for update or launch",
OnInstanceSetupArg,
OnInstanceSetupResult,
1,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct OnInstanceSetupArg {
pub id: String,
pub side: Option<Side>,
pub game_dir: String,
pub version_info: VersionInfo,
pub client_type: ClientType,
pub server_type: ServerType,
pub current_game_modification_version: Option<String>,
pub desired_game_modification_version: Option<VersionPattern>,
pub custom_config: serde_json::Map<String, serde_json::Value>,
pub internal_dir: String,
pub update_depth: UpdateDepth,
}
#[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 game_modification_version: Option<String>,
}
def_hook!(
RemoveGameModification,
"remove_game_modification",
"Hook for removing a game modification from an instance when the game modification or version changes",
OnInstanceSetupArg,
(),
1,
);
def_hook!(
OnInstanceLaunch,
"on_instance_launch",
"Hook for doing work before an instance is launched",
InstanceLaunchArg,
(),
1,
);
def_hook!(
WhileInstanceLaunch,
"while_instance_launch",
"Hook for running sibling processes with an instance when it is launched",
InstanceLaunchArg,
(),
1,
);
def_hook!(
OnInstanceStop,
"on_instance_stop",
"Hook for doing work when an instance is stopped gracefully",
InstanceLaunchArg,
(),
1,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct InstanceLaunchArg {
pub id: String,
pub side: Option<Side>,
pub dir: String,
pub game_dir: String,
pub version_info: VersionInfo,
pub custom_config: serde_json::Map<String, serde_json::Value>,
pub pid: Option<u32>,
}
def_hook!(
CustomPackageInstruction,
"custom_package_instruction",
"Hook for handling custom instructions in packages",
CustomPackageInstructionArg,
CustomPackageInstructionResult,
1,
);
#[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 user types",
HandleAuthArg,
HandleAuthResult,
1,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct HandleAuthArg {
pub user_id: String,
pub user_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 MCVM",
(),
LanguageMap,
1,
);
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 import: Option<InstanceTransferFormatDirection>,
pub export: Option<InstanceTransferFormatDirection>,
}
#[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,
(),
1,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct ExportInstanceArg {
pub format: String,
pub id: String,
pub name: Option<String>,
pub side: Option<Side>,
pub game_dir: String,
pub result_path: String,
pub minecraft_version: Option<MinecraftVersionDeser>,
pub client_type: Option<ClientType>,
pub server_type: Option<ServerType>,
}
def_hook!(
ImportInstance,
"import_instance",
"Hook for importing an instance",
ImportInstanceArg,
ImportInstanceResult,
1,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct ImportInstanceArg {
pub format: String,
pub id: String,
pub source_path: String,
pub result_path: String,
}
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct ImportInstanceResult {
pub format: String,
pub name: Option<String>,
pub side: Option<Side>,
pub version: Option<MinecraftVersionDeser>,
pub client_type: Option<ClientType>,
pub server_type: Option<ServerType>,
}
def_hook!(
AddSupportedGameModifications,
"add_supported_game_modifications",
"Tell MCVM that you support installing extra game modifications",
(),
SupportedGameModifications,
1,
);
#[derive(Serialize, Deserialize, Default)]
#[serde(default)]
pub struct SupportedGameModifications {
pub client_types: Vec<ClientType>,
pub server_types: Vec<ServerType>,
}