1
0
Fork 0

Implement @no_storage annotation.

This commit is contained in:
Synzorasize 2025-01-03 19:47:33 -06:00
parent bdf625bd54
commit 0d17aa0c72
7 changed files with 87 additions and 4 deletions

View File

@ -643,10 +643,12 @@
<return type="void" />
<description>
Export a property with [constant PROPERTY_USAGE_STORAGE] flag. The property is not displayed in the editor, but it is serialized and stored in the scene or resource file. This can be useful for [annotation @tool] scripts. Also the property value is copied when [method Resource.duplicate] or [method Node.duplicate] is called, unlike non-exported variables.
See also [annotation @no_storage].
[codeblock]
var a # Not stored in the file, not displayed in the editor.
@export_storage var b # Stored in the file, not displayed in the editor.
@export var c: int # Stored in the file, displayed in the editor.
@export @no_storage var c: int # Not stored in the file, displayed in the editor.
@export var d: int # Stored in the file, displayed in the editor.
[/codeblock]
</description>
</annotation>
@ -729,6 +731,24 @@
[b]Note:[/b] Unlike most other annotations, the argument of the [annotation @icon] annotation must be a string literal (constant expressions are not supported).
</description>
</annotation>
<annotation name="@no_storage">
<return type="void" />
<description>
Marks the exported property as editor-only (not saved to disk). Can be applied to a variable with a regular export annotation applied. The property value will also not be copied when [method Resource.duplicate] or [method Node.duplicate] is called, unlike serialized variables. This can be useful for [annotation @tool] scripts.
See also [annotation @export_storage].
[codeblock]
@tool
@export var string = ""
# This variable can be used to edit "string" in the Inspector.
@export_range(0, 10) @no_storage var int_to_string: int:
set(value):
string = str(value)
get:
return string.to_int()
[/codeblock]
</description>
</annotation>
<annotation name="@onready">
<return type="void" />
<description>

View File

@ -121,6 +121,7 @@ GDScriptParser::GDScriptParser() {
register_annotation(MethodInfo("@export_flags_avoidance"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_AVOIDANCE, Variant::INT>);
register_annotation(MethodInfo("@export_storage"), AnnotationInfo::VARIABLE, &GDScriptParser::export_storage_annotation);
register_annotation(MethodInfo("@export_custom", PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_CLASS_IS_ENUM, "PropertyHint"), PropertyInfo(Variant::STRING, "hint_string"), PropertyInfo(Variant::INT, "usage", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_CLASS_IS_BITFIELD, "PropertyUsageFlags")), AnnotationInfo::VARIABLE, &GDScriptParser::export_custom_annotation, varray(PROPERTY_USAGE_DEFAULT));
register_annotation(MethodInfo("@no_storage"), AnnotationInfo::VARIABLE, &GDScriptParser::no_storage_annotation);
register_annotation(MethodInfo("@export_tool_button", PropertyInfo(Variant::STRING, "text"), PropertyInfo(Variant::STRING, "icon")), AnnotationInfo::VARIABLE, &GDScriptParser::export_tool_button_annotation, varray(""));
// Export grouping annotations.
register_annotation(MethodInfo("@export_category", PropertyInfo(Variant::STRING, "name")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_CATEGORY>);
@ -4404,7 +4405,7 @@ bool GDScriptParser::export_annotations(AnnotationNode *p_annotation, Node *p_ta
return false;
}
if (variable->exported) {
push_error(vformat(R"(Annotation "%s" cannot be used with another "@export" annotation.)", p_annotation->name), p_annotation);
push_error(vformat(R"(Annotation "%s" cannot be used with another export annotation.)", p_annotation->name), p_annotation);
return false;
}
@ -4739,7 +4740,7 @@ bool GDScriptParser::export_storage_annotation(AnnotationNode *p_annotation, Nod
return false;
}
if (variable->exported) {
push_error(vformat(R"(Annotation "%s" cannot be used with another "@export" annotation.)", p_annotation->name), p_annotation);
push_error(vformat(R"(Annotation "%s" cannot be used with another export annotation.)", p_annotation->name), p_annotation);
return false;
}
@ -4762,7 +4763,7 @@ bool GDScriptParser::export_custom_annotation(AnnotationNode *p_annotation, Node
return false;
}
if (variable->exported) {
push_error(vformat(R"(Annotation "%s" cannot be used with another "@export" annotation.)", p_annotation->name), p_annotation);
push_error(vformat(R"(Annotation "%s" cannot be used with another export annotation.)", p_annotation->name), p_annotation);
return false;
}
@ -4780,6 +4781,31 @@ bool GDScriptParser::export_custom_annotation(AnnotationNode *p_annotation, Node
return true;
}
bool GDScriptParser::no_storage_annotation(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class) {
ERR_FAIL_COND_V_MSG(p_target->type != Node::VARIABLE, false, vformat(R"("%s" annotation can only be applied to variables.)", p_annotation->name));
VariableNode *variable = static_cast<VariableNode *>(p_target);
for (const AnnotationNode *annotation_node : variable->annotations) {
if (annotation_node->name == SNAME("@export_storage") || annotation_node->name == SNAME("@export_custom") || annotation_node->name == SNAME("@export_tool_button")) {
push_error(vformat(R"(Annotation "%s" cannot be used with "%s".)", p_annotation->name, annotation_node->name), p_annotation);
return false;
}
}
if (!variable->exported) {
push_error(vformat(R"(Annotation "%s" must be placed after an export annotation.)", p_annotation->name), p_annotation);
return false;
}
if (variable->exported_no_storage) {
push_error(vformat(R"(Annotation "%s" should only be used once.)", p_annotation->name), p_annotation);
return false;
}
// Set variable to only show in editor and keep the previous annotation's export_info changes.
variable->export_info.usage &= ~PROPERTY_USAGE_STORAGE;
variable->exported_no_storage = true;
return true;
}
bool GDScriptParser::export_tool_button_annotation(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class) {
#ifdef TOOLS_ENABLED
ERR_FAIL_COND_V_MSG(p_target->type != Node::VARIABLE, false, vformat(R"("%s" annotation can only be applied to variables.)", p_annotation->name));

View File

@ -1262,6 +1262,7 @@ public:
};
bool exported = false;
bool exported_no_storage = false;
bool onready = false;
PropertyInfo export_info;
int assignments = 0;
@ -1513,6 +1514,7 @@ private:
bool export_annotations(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class);
bool export_storage_annotation(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class);
bool export_custom_annotation(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class);
bool no_storage_annotation(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class);
bool export_tool_button_annotation(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class);
template <PropertyUsageFlags t_usage>
bool export_group_annotations(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class);

View File

@ -0,0 +1,11 @@
@tool
@export_storage @no_storage var int_number = 0
@export_custom(PROPERTY_HINT_NONE, "") @no_storage var float_number = 0.0
@export_tool_button("") @no_storage var callable = test
@no_storage var string = ""
@no_storage @export var string_name = &""
@export @no_storage @no_storage var bool_var = false
func test():
pass

View File

@ -0,0 +1,7 @@
GDTEST_ANALYZER_ERROR
>> ERROR at line 3: Annotation "@no_storage" cannot be used with "@export_storage".
>> ERROR at line 4: Annotation "@no_storage" cannot be used with "@export_custom".
>> ERROR at line 5: Annotation "@no_storage" cannot be used with "@export_tool_button".
>> ERROR at line 6: Annotation "@no_storage" must be placed after an export annotation.
>> ERROR at line 7: Annotation "@no_storage" must be placed after an export annotation.
>> ERROR at line 8: Annotation "@no_storage" should only be used once.

View File

@ -48,6 +48,13 @@ const PreloadedUnnamedClass = preload("./export_variable_unnamed.notest.gd")
@export_custom(PROPERTY_HINT_ENUM, "A,B,C") var test_export_custom_weak_int = 5
@export_custom(PROPERTY_HINT_ENUM, "A,B,C") var test_export_custom_hard_int: int = 6
# `@no_storage`.
@export @no_storage var test_no_storage_int = 1
@export_range(0, 10) @no_storage var test_no_storage_range = 1
@export_enum("A", "B", "C") @no_storage var test_range_no_storage_enum = "A"
@export @no_storage var test_no_storage_array = []
@export @no_storage var test_no_storage_dictionary = {}
# `@export_tool_button`.
@export_tool_button("Click me!") var test_tool_button_1: Callable
@export_tool_button("Click me!", "ColorRect") var test_tool_button_2: Callable

View File

@ -55,6 +55,16 @@ var test_export_custom_weak_int: int = 5
hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
var test_export_custom_hard_int: int = 6
hint=ENUM hint_string="A,B,C" usage=DEFAULT|SCRIPT_VARIABLE class_name=&""
var test_no_storage_int: int = 1
hint=NONE hint_string="" usage=EDITOR|SCRIPT_VARIABLE class_name=&""
var test_no_storage_range: int = 1
hint=RANGE hint_string="0.0,10.0" usage=EDITOR|SCRIPT_VARIABLE class_name=&""
var test_range_no_storage_enum: String = "A"
hint=ENUM hint_string="A,B,C" usage=EDITOR|SCRIPT_VARIABLE class_name=&""
var test_no_storage_array: Array = []
hint=NONE hint_string="" usage=EDITOR|SCRIPT_VARIABLE class_name=&""
var test_no_storage_dictionary: Dictionary = {}
hint=NONE hint_string="" usage=EDITOR|SCRIPT_VARIABLE class_name=&""
var test_tool_button_1: Callable = Callable()
hint=TOOL_BUTTON hint_string="Click me!" usage=EDITOR|SCRIPT_VARIABLE class_name=&""
var test_tool_button_2: Callable = Callable()