commonlibsse_ng_proc_macro_common\skse_plugin_main/
plugin_entry.rs

1use super::attr_args::MacroArgs;
2use super::logger::LoggerTokenStream;
3use quote::quote;
4
5struct PluginMetadata {
6    name: proc_macro2::TokenStream,
7    author: proc_macro2::TokenStream,
8    version: proc_macro2::TokenStream,
9}
10
11impl PluginMetadata {
12    fn from_args(args: &MacroArgs) -> Self {
13        Self {
14            name: args
15                .plugin_name
16                .as_deref()
17                .map_or_else(|| quote! { env!("CARGO_PKG_NAME") }, |name| quote! { #name }),
18            author: args
19                .plugin_author
20                .as_deref()
21                .map_or_else(|| quote! { env!("CARGO_PKG_AUTHORS") }, |author| quote! { #author }),
22            version: args.plugin_version.as_deref().map_or_else(
23                || quote! { env!("CARGO_PKG_VERSION") },
24                |version| quote! { #version },
25            ),
26        }
27    }
28}
29
30fn generate_main_code(enable_logger: bool, item_fn: syn::ItemFn) -> proc_macro2::TokenStream {
31    let fn_stmts = &item_fn.block.stmts;
32    let ret_ty = &item_fn.sig.output;
33    if enable_logger {
34        quote! {
35            if let Err(err) = std::panic::catch_unwind(|| #ret_ty {
36                commonlibsse_ng::skse::init(skse);
37                #(#fn_stmts)*
38            }) {
39                commonlibsse_ng::__private::tracing::error!("{err:?}");
40            }
41        }
42    } else {
43        quote! {
44            let _ = std::panic::catch_unwind(|| #ret_ty {
45                commonlibsse_ng::skse::init(skse);
46                #(#fn_stmts)*
47            });
48        }
49    }
50}
51
52pub(crate) fn generate_plugin_code(args: MacroArgs, item_fn: syn::ItemFn) -> proc_macro2::TokenStream {
53    #[cfg(feature = "tracing")]
54    let main_code = generate_main_code(true, item_fn);
55    #[cfg(not(feature = "tracing"))]
56    let main_code = generate_main_code(false, item_fn);
57
58    let PluginMetadata { name, author, version } = PluginMetadata::from_args(&args);
59    let LoggerTokenStream { init_logger, is_editor_log } = {
60        #[cfg(feature = "tracing")]
61        let tokens = super::logger::gen_logger_code(
62            args.logger,
63            args.plugin_name.as_deref(),
64            args.log_level,
65        );
66        #[cfg(not(feature = "tracing"))]
67        let tokens = LoggerTokenStream::default();
68        tokens
69    };
70
71    let expanded = quote! {
72        #[unsafe(no_mangle)]
73        #[allow(non_snake_case)]
74        pub extern "C" fn SKSEPlugin_Query(
75            skse: &commonlibsse_ng::skse::impls::stab::SKSEInterface,
76            info: &mut commonlibsse_ng::skse::impls::stab::PluginInfo,
77        ) -> bool {
78            use commonlibsse_ng::skse::impls::stab::PluginInfo;
79
80            const PKG_VERSION: commonlibsse_ng::rel::version::Version = commonlibsse_ng::rel::version::Version::from_str_const(#version);
81            *info = PluginInfo {
82                infoVersion: PluginInfo::VERSION,
83                name: commonlibsse_ng::skse::interfaces::new_cstr(concat!(#name, "\0")).as_ptr(),
84                version: PKG_VERSION.pack(),
85            };
86
87            if commonlibsse_ng::skse::interfaces::query::QueryInterface::is_editor(skse) {
88                #is_editor_log
89                return false;
90            }
91
92            true
93        }
94
95        #[unsafe(no_mangle)]
96        #[allow(non_upper_case_globals)]
97        pub static SKSEPlugin_Version: commonlibsse_ng::skse::interfaces::PluginVersionData = {
98            use commonlibsse_ng::skse::interfaces::PluginVersionData;
99            use commonlibsse_ng::skse::interfaces::to_fixed_str;
100
101            const PKG_VERSION: commonlibsse_ng::rel::version::Version = commonlibsse_ng::rel::version::Version::from_str_const(#version);
102            let mut compatible_versions = [0; 16];
103            compatible_versions[0] = commonlibsse_ng::skse::version::RUNTIME_SSE_LATEST.pack();
104
105            PluginVersionData {
106                data_version: PluginVersionData::VERSION,
107                plugin_version: PKG_VERSION.pack(),
108                plugin_name: to_fixed_str(#name),
109                author: to_fixed_str(#author),
110                support_email: [0; 252],
111                version_independence_ex: PluginVersionData::VERSION_INDEPENDENT_ADDRESS_LIBRARY_POST_AE,
112                version_independence: PluginVersionData::VERSION_INDEPENDENT_EX_NO_STRUCT_USE,
113                compatible_versions,
114                xse_minimum: 0,
115            }
116        };
117
118        #[unsafe(no_mangle)]
119        #[allow(clippy::not_unsafe_ptr_arg_deref)]
120        pub extern "C" fn SKSEPlugin_Load(skse: &commonlibsse_ng::skse::interfaces::load::LoadInterface) -> bool {
121            #init_logger
122            #main_code
123
124            true
125        }
126    };
127
128    expanded
129}