commonlibsse_ng_proc_macro_common\skse_plugin_main/
plugin_entry.rs1use 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}