Skip to content

Commit 819207d

Browse files
committed
Added @export_storage Export Type
1 parent d92c7d4 commit 819207d

File tree

7 files changed

+65
-12
lines changed

7 files changed

+65
-12
lines changed

godot-core/src/registry/property.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,7 @@ pub mod export_info_functions {
517517
// right side are the corresponding property hint. Godot is not always consistent between the two, such
518518
// as `export_multiline` being `PROPERTY_HINT_MULTILINE_TEXT`.
519519
default_export_funcs!(
520+
export_storage => NONE,
520521
export_flags_2d_physics => LAYERS_2D_PHYSICS,
521522
export_flags_2d_render => LAYERS_2D_RENDER,
522523
export_flags_2d_navigation => LAYERS_2D_NAVIGATION,

godot-macros/src/class/data_models/field_export.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ impl FieldExport {
2727
pub fn to_export_hint(&self) -> Option<TokenStream> {
2828
self.export_type.to_export_hint()
2929
}
30+
31+
pub fn to_export_usage(&self) -> Option<Ident> {
32+
self.export_type.to_export_usage()
33+
}
3034
}
3135

3236
/// Store info from `#[export]` attribute.
@@ -40,6 +44,16 @@ pub enum ExportType {
4044
/// Can become other property hints, depends on context.
4145
Default,
4246

47+
/// ### GDScript annotations
48+
/// - `@export_storage`
49+
///
50+
/// ### Property hints
51+
/// - `NONE`
52+
///
53+
/// This is used to indicate that the property should be exported
54+
/// but should not be visible in the editor.
55+
Storage,
56+
4357
/// ### GDScript annotations
4458
/// - `@export_range`
4559
///
@@ -150,6 +164,10 @@ impl ExportType {
150164
/// becomes
151165
/// `#[export(flags/enum = (elem1, elem2 = key2, ...))]`
152166
pub(crate) fn new_from_kv(parser: &mut KvParser) -> ParseResult<Self> {
167+
if parser.handle_alone("storage")? {
168+
return Self::new_storage();
169+
}
170+
153171
if let Some(list_parser) = parser.handle_list("range")? {
154172
return Self::new_range_list(list_parser);
155173
}
@@ -273,6 +291,10 @@ impl ExportType {
273291
Ok(Self::Default)
274292
}
275293

294+
fn new_storage() -> ParseResult<Self> {
295+
Ok(Self::Storage)
296+
}
297+
276298
fn new_range_list(mut parser: ListParser) -> ParseResult<Self> {
277299
const FLAG_OPTIONS: [&str; 7] = [
278300
"or_greater",
@@ -404,6 +426,8 @@ impl ExportType {
404426
match self {
405427
Self::Default => None,
406428

429+
Self::Storage => quote_export_func! { export_storage() },
430+
407431
Self::Range {
408432
min,
409433
max,
@@ -519,6 +543,13 @@ impl ExportType {
519543
Self::ColorNoAlpha => quote_export_func! { export_color_no_alpha() },
520544
}
521545
}
546+
547+
pub fn to_export_usage(&self) -> Option<Ident> {
548+
match self {
549+
Self::Storage => Some(Ident::new("STORAGE", Span::call_site())),
550+
_ => None,
551+
}
552+
}
522553
}
523554

524555
/// The dimension of a `@export_flags_{dimension}_{layer}` annotation.

godot-macros/src/class/data_models/property.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,17 @@ pub fn make_property_impl(class_name: &Ident, fields: &Fields) -> TokenStream {
5353

5454
// Ensure we add a var if the user only provided a `#[export]`.
5555
let var = match (export, var) {
56-
(Some(_), None) => Some(FieldVar {
57-
usage_flags: UsageFlags::InferredExport,
58-
..Default::default()
59-
}),
56+
(Some(export), None) => {
57+
let usage_flags = if let Some(usage) = export.to_export_usage() {
58+
UsageFlags::Custom(vec![usage])
59+
} else {
60+
UsageFlags::InferredExport
61+
};
62+
Some(FieldVar {
63+
usage_flags,
64+
..Default::default()
65+
})
66+
}
6067

6168
(_, var) => var.clone(),
6269
};

godot-macros/src/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,11 @@ use crate::util::{bail, ident, KvParser};
243243
/// // @export
244244
/// #[export]
245245
/// float: f64,
246-
///
246+
///
247+
/// // @export_storage
248+
/// #[export(storage)]
249+
/// hidden_string: GString,
250+
///
247251
/// // @export_range(0.0, 10.0, or_greater)
248252
/// #[export(range = (0.0, 10.0, or_greater))]
249253
/// range_f64: f64,

itest/rust/build.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,9 @@ fn generate_property_template(inputs: &[Input]) -> PropertyTests {
472472
TokenStream::new()
473473
} else {
474474
quote! {
475+
#[export(storage)]
476+
export_storage: GString,
477+
475478
#[export(file)]
476479
export_file_array: Array<GString>,
477480
#[export(file)]
@@ -597,6 +600,7 @@ fn generate_property_template(inputs: &[Input]) -> PropertyTests {
597600

598601
// Only available in Godot 4.3+.
599602
let advanced_exports_4_3 = r#"
603+
@export_storage var export_storage: String
600604
@export_file var export_file_array: Array[String]
601605
@export_file var export_file_parray: PackedStringArray
602606
@export_file("*.txt") var export_file_wildcard_array: Array[String]

itest/rust/src/object_tests/property_template_test.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,15 @@ fn property_template_test(ctx: &TestContext) {
7070

7171
let mut rust_usage = rust_prop.at("usage").to::<i64>();
7272

73-
// the GDSscript variables are script variables, and so have `PROPERTY_USAGE_SCRIPT_VARIABLE` set.
74-
if rust_usage == PropertyUsageFlags::STORAGE.ord() as i64 {
75-
// `PROPERTY_USAGE_SCRIPT_VARIABLE` does the same thing as `PROPERTY_USAGE_STORAGE` and so
76-
// GDScript doesn't set both if it doesn't need to.
77-
rust_usage = PropertyUsageFlags::SCRIPT_VARIABLE.ord() as i64
73+
// The GDSscript variables are script variables, and so have `PROPERTY_USAGE_SCRIPT_VARIABLE` set.
74+
// Before 4.3, `PROPERTY_USAGE_SCRIPT_VARIABLE` did the same thing as `PROPERTY_USAGE_STORAGE` and
75+
// so GDScript didn't set both if it didn't need to.
76+
if GdextBuild::before_api("4.3") {
77+
if rust_usage == PropertyUsageFlags::STORAGE.ord() as i64 {
78+
rust_usage = PropertyUsageFlags::SCRIPT_VARIABLE.ord() as i64
79+
} else {
80+
rust_usage |= PropertyUsageFlags::SCRIPT_VARIABLE.ord() as i64;
81+
}
7882
} else {
7983
rust_usage |= PropertyUsageFlags::SCRIPT_VARIABLE.ord() as i64;
8084
}
@@ -107,6 +111,9 @@ fn property_template_test(ctx: &TestContext) {
107111
}*/
108112
}
109113

114+
// Freeing this early to avoid leaks
115+
rust_properties.free();
116+
110117
assert!(
111118
properties.is_empty(),
112119
"not all properties were matched, missing: {properties:?}"
@@ -118,6 +125,4 @@ fn property_template_test(ctx: &TestContext) {
118125
errors.len(),
119126
errors.join("\n")
120127
);
121-
122-
rust_properties.free();
123128
}

rustfmt.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
hard_tabs = false

0 commit comments

Comments
 (0)