Add Recipemanager that loads recipes from YAML

This commit is contained in:
JonShard
2026-07-17 13:54:14 +02:00
parent 840908e9ff
commit 4d06e72bc1
133 changed files with 9121 additions and 175 deletions
@@ -0,0 +1,3 @@
[gd_resource type="CanvasItemMaterial" format=3 uid="uid://g4tjqwskvd62"]
[resource]
@@ -0,0 +1,3 @@
[gd_resource type="Resource" format=3 uid="uid://pxagv74g8x67"]
[resource]
@@ -0,0 +1,21 @@
[gd_scene load_steps=3 format=3 uid="uid://cw7ukcablgkur"]
[ext_resource type="Material" uid="uid://g4tjqwskvd62" path="res://addons/yaml/examples/assets/material.tres" id="1_1ej5c"]
[ext_resource type="Texture2D" uid="uid://duefsqwwnmduy" path="res://icon.svg" id="1_t3dkf"]
[node name="Sprite" type="Sprite2D"]
material = ExtResource("1_1ej5c")
texture = ExtResource("1_t3dkf")
[node name="Label" type="Label" parent="."]
anchors_preset = 5
anchor_left = 0.5
anchor_right = 0.5
offset_left = -155.0
offset_top = -64.0
offset_right = 27.0
offset_bottom = -41.0
grow_horizontal = 2
text = "I was loaded with YAML"
horizontal_alignment = 1
vertical_alignment = 1
@@ -0,0 +1,53 @@
class_name MyCustomClass extends Node
@export var string_val: String
@export var int_val: int
@export var float_val: float
@export var color_val: Color
func _init(p_string := "", p_int := 0, p_float := 0.0, p_color = Color.WHITE) -> void:
string_val = p_string
int_val = p_int
float_val = p_float
color_val = p_color
func hello():
print(string_val)
static func deserialize(data: Variant):
if typeof(data) != TYPE_DICTIONARY:
return YAMLResult.error("Deserializing MyCustomClass expects Dictionary, received %s" % [type_string(typeof(data))])
var dict: Dictionary = data
if !dict.has("string_val"):
return YAMLResult.error("Missing string_val field")
if !dict.has("int_val"):
return YAMLResult.error("Missing int_val field")
if !dict.has("float_val"):
return YAMLResult.error("Missing float_val field")
if !dict.has("color_val"):
return YAMLResult.error("Missing color_val field")
var string_val: String = dict.get("string_val")
var int_val: int = dict.get("int_val")
var float_val: float = dict.get("float_val")
var color_val: Color = dict.get("color_val")
return MyCustomClass.new(
string_val,
int_val,
float_val,
color_val
)
func serialize() -> Dictionary:
return {
"string_val": string_val,
"int_val": int_val,
"float_val": float_val,
"color_val": color_val,
}
func _to_string() -> String:
return "MyCustomClass(%s)" % string_val
@@ -0,0 +1 @@
uid://c3bjbffcq7oc5
@@ -0,0 +1,53 @@
class_name MyCustomResource extends YAMLResource
@export var string_val: String
@export var int_val: int
@export var float_val: float
@export var color_val: Color
func _init(p_string := "", p_int := 0, p_float := 0.0, p_color = Color.WHITE) -> void:
string_val = p_string
int_val = p_int
float_val = p_float
color_val = p_color
func hello():
print(string_val)
static func deserialize(data: Variant):
if typeof(data) != TYPE_DICTIONARY:
return YAMLResult.error("Deserializing MyCustomResource expects Dictionary, received %s" % [type_string(typeof(data))])
var dict: Dictionary = data
if !dict.has("string_val"):
return YAMLResult.error("Missing string_val field")
if !dict.has("int_val"):
return YAMLResult.error("Missing int_val field")
if !dict.has("float_val"):
return YAMLResult.error("Missing float_val field")
if !dict.has("color_val"):
return YAMLResult.error("Missing color_val field")
var string_val: String = dict.get("string_val")
var int_val: int = dict.get("int_val")
var float_val: float = dict.get("float_val")
var color_val: Color = dict.get("color_val")
return MyCustomResource.new(
string_val,
int_val,
float_val,
color_val
)
func serialize() -> Dictionary:
return {
"string_val": string_val,
"int_val": int_val,
"float_val": float_val,
"color_val": color_val,
}
func _to_string() -> String:
return "MyCustomResource(%s)" % string_val
@@ -0,0 +1 @@
uid://dlwcjlb23nl02
@@ -0,0 +1,18 @@
class_name MyStringClass extends Object
@export var value: String
func _init(p_value := "") -> void:
value = p_value
static func deserialize(data: Variant):
if typeof(data) != TYPE_STRING:
return YAMLResult.error("Deserializing MyStringClass expects String, received %s" % [type_string(typeof(data))])
return MyStringClass.new(data)
func serialize() -> String:
return value
func _to_string() -> String:
return "MyStringClass(%s)" % value
@@ -0,0 +1 @@
uid://b6ljbsllu8xqn
@@ -0,0 +1,5 @@
!ruby:object/MyCustomClass
string_val: alternate tag
int_val: 42
float_val: 1.61803398875
color_val: !Color 000000
@@ -0,0 +1 @@
uid://deqds0xtv6aoi
@@ -0,0 +1,5 @@
title: Document 1
---
title: Document 2
---
title: Document 3
@@ -0,0 +1 @@
uid://cwyofk32x3sba
@@ -0,0 +1,16 @@
# The $id string is used as an identifier
$schema: "res://my_custom_class.yaml"
type: object
properties:
string_val:
type: string
minLength: 0
maxLength: 5
int_val:
type: int
max: 10
float_val:
type: float
min: 1
max: 999
@@ -0,0 +1 @@
uid://cpf0ajyys57i2
@@ -0,0 +1,17 @@
# The $id string is used as an identifier
$id: "res://my_custom_class_schema.yaml"
type: object
x-yaml-tag: foobar
properties:
string_val:
type: string
minLength: 1
maxLength: 5
int_val:
type: int
max: 10
float_val:
type: float
min: 0
max: 999
@@ -0,0 +1 @@
uid://fkxxl0sy2xrm
+7
View File
@@ -0,0 +1,7 @@
title: Godot YAML
author: FimbulWorks
release_year: 2025
features:
- Speaks fluent Variant and can be taught custom classes
- Strong document formatting capabilities
- Blazingly fast
@@ -0,0 +1 @@
uid://dn5kwv25bhn5g
@@ -0,0 +1,179 @@
# Strings
plain_string: Hello World
single_quoted_string: 'Hello, ''World'''
double_quoted_string: "Hello, World!"
literal_string: |
This is a long string
that will preserve
newlines
folded_string: >
This is a long string
that will be folded
into a single line
# Integer formats
integer: 42
hex: 0xff
octal: 0o700
binary: 0b1010
# Float formats
float: 3.14159
scientific_notation: 6.022e23
infinity: .inf
not_a_number: .nan
# Boolean types
boolean_true: true
boolean_false: false
# Null
null_value: null
null_value_2: ~
# Dates and times are treated as strings
date: 2023-04-01
canonical_datetime: 2023-04-01T12:00:00Z
iso8601_datetime: 2023-04-01t12:00:00.000-05:00
# Arrays
fruits:
- apple
- banana
- cherry
nested_array:
- - nested
- items
- - more
- nested
- items
## Dictionaries
person:
name: John Doe
age: 30
occupation: Developer
## Flow style array
flow_style_array: [1, 2, 3, 4, 5]
## Flow style dictionary
flow_style_dict: {key1: value1, key2: value2, key3: 124.5}
## Nested flow array
nested_flow_style_array: ["hello", 10, {foo: bar}, [4.20, 6.9]]
## Nested flow dictionary
nested_flow_style_dictionary: { key1: {foo: 'bar'}, key2: [4.20, 6.9] }
# Anchors and aliases get resolved during parsing
anchor_example: &anchor_name
key1: value1
key2: value2
alias_example: *anchor_name
# Merge keys are also resolved during parsing
base: &base
name: John Doe
age: 30
merge_example:
<<: *base
occupation: Developer
# Binary data - !!binary is converted to !PackedByteArray
binary_data: !!binary |
R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5
OTk6enp56enmleECcgggoBADs=
# Custom tags are preserved, and can describe Godot Variants,
# and classes registered using YAML.register_class()
game_object: !MyHeroClass
name: "Hero"
health: 100
inventory:
- sword
- shield
- potion_healing
# Variants
AABB: !AABB
position: {x: 1,y: 2,z: 4}
size: {x: 8,y: 16,z: 32}
Basis: !Basis
x: {x: 1,y: 2,z: 4}
y: {x: 8,y: 16,z: 32}
z: {x: 64,y: 128,z: 256}
Color: !Color ff804080
NodePath: !NodePath "root/level/player"
PackedByteArray: !PackedByteArray |
AQIECA==
PackedColorArray: !PackedColorArray
- ff0000
- 00ff00
- 0000ff
- red
- green
- blue
PackedFloat32Array: !PackedFloat32Array
- 3.1415927
- 6.2831855
- 12.566371
PackedFloat64Array: !PackedFloat64Array
- 3.141592653589793
- 6.283185307179586
- 12.566370614359172
PackedInt32Array: !PackedInt32Array
- 1
- 2
- 4
- 8
PackedInt64Array: !PackedInt64Array
- 1
- 2
- 4
- 8
PackedStringArray: !PackedStringArray
- "one"
- "one\ntwo"
- "one\ntwo\nthree"
PackedVector2Array: !PackedVector2Array
- {x: 1,y: 2}
- {x: 4,y: 8}
PackedVector3Array: !PackedVector3Array
- {x: 1,y: 2,z: 4}
- {x: 8,y: 16,z: 32}
Plane: !Plane
normal: {x: 1,y: 2,z: 4}
d: 3.1415927
Projection: !Projection
x: {x: 1,y: 2,z: 4,w: 8}
y: {x: 16,y: 32,z: 64,w: 128}
z: {x: 256,y: 512,z: 1024,w: 2048}
w: {x: 4096,y: 8192,z: 16384,w: 32768}
Quaternion: !Quaternion {x: 3.1415927,y: 6.2831855,z: 12.566371,w: 25.132742}
Rect2: !Rect2
position: {x: 1,y: 2}
size: {x: 4,y: 8}
Rect2i: !Rect2i
position: {x: 2,y: 4}
size: {x: 8,y: 16}
StringName: !StringName test_string_name
Transform2D: !Transform2D
x: {x: -1,y: -8.742278e-08}
y: {x: 8.742278e-08,y: -1}
origin: {x: 6.2831855,y: 12.566371}
Transform3D: !Transform3D
basis:
x: {x: 1,y: 0,z: 0}
y: {x: 0,y: 1,z: 0}
z: {x: 0,y: 0,z: 1}
origin: {x: 1,y: 2,z: 4}
Vector2: !Vector2 {x: 1,y: 2}
Vector2i: !Vector2i {x: 2,y: 4}
Vector3: !Vector3 {x: 1,y: 2,z: 4}
Vector3i: !Vector3i {x: 2,y: 4,z: 8}
Vector4: !Vector4 {x: 1,y: 2,z: 4,w: 8}
Vector4i: !Vector4i {x: 2,y: 4,z: 8,w: 16}
@@ -0,0 +1 @@
uid://b24xb1mhxmg8i
@@ -0,0 +1,50 @@
$schema: "res://addons/yaml/examples/data/fimbul.generator.schema.yaml"
params:
x: float
y: float
noiseScale: float
noise2D: Callable
functions:
- name: continentShape
params: ["x", "y"]
returns: float
code: abs(cos(x * PI * 2 + PI * 0.5) * sin(y * PI))
- name: heightNoise
params: ["x", "y", "noiseScale", "noise2D"]
returns: float
code: noise2D(x * noiseScale, y * noiseScale) * 0.5 + 0.5
- name: height
dependencies: ["continentShape", "heightNoise"]
returns: float
code: continentShape * heightNoise
- name: temperature
params: ["y"]
dependencies: ["height"]
returns: float
code: y - (height - 0.4) * 2 if height > 0.4 else y
- name: precipitation
params: ["y"]
dependencies: ["temperature"]
returns: float
code: 1 - temperature
- name: biome
returns: String
dependencies: ["height", "temperature", "precipitation"]
code: |
if height < 0.2023:
return 'ocean'
if temperature >= 0.666:
return 'desert'
if temperature > 0.42 && precipitation > 0.42:
return 'rainforest'
if temperature > 0.3 && precipitation > 0.3:
return 'forest'
if temperature <= 0.21:
return 'tundra'
return 'meadows'
@@ -0,0 +1 @@
uid://drfjm1uj06e4x
+66
View File
@@ -0,0 +1,66 @@
class_name ExampleBase extends Node2D
# Whether to show detailed logs
var LOG_VERBOSE := false
# Extra emoji to make logs visually distinct
var icon := ""
# Hook that runs all examples in the class
func _ready() -> void:
if !visible:
return
print_rich("\n[b][font_size=16]%s%s[/font_size][/b]" % [
"%s " % icon if icon.length() > 0 else "",
name
])
run_examples()
# Override this to run examples in your class
func run_examples() -> void:
# Child classes should override this method
pass
# Logging Helpers
func log_header(text: String) -> void:
print_rich("\n[b][font_size=16]%s[/font_size][/b]" % text)
func log_subheader(text: String) -> void:
print_rich("\n[b][font_size=14]%s[/font_size][/b]" % text)
func log_success(text: Variant) -> void:
print_rich("[color=green]✅ %s[/color]" % str(text))
func log_error(text: Variant) -> void:
print_rich("[color=red]❌ %s[/color]" % str(text))
func log_warning(text: Variant) -> void:
print_rich("[color=yellow]⚠️ %s[/color]" % str(text))
func log_info(text: Variant) -> void:
print_rich("%s" % str(text))
func log_code_block(code: String) -> void:
print_rich("\n[b]Code:[/b]")
print_rich("[color=#aaaaff]%s" % code)
func log_result(text: Variant) -> void:
print_rich("\n[b]Result:[/b]\n%s" % str(text))
# Run a single example with timing
func run_example(title: String, method: Callable) -> void:
print_rich("\n[b][font_size=14]%s[/font_size][/b]" % title)
var start_time := Time.get_ticks_usec()
method.call()
var elapsed := Time.get_ticks_usec() - start_time
var t: float = elapsed
var tl = "µsec"
if t > 1000:
t /= 1000.0
tl = "ms"
print_rich("\n[color=#888888]Completed in %.2f %s[/color]" % [t, tl])
+1
View File
@@ -0,0 +1 @@
uid://bfxd6dh800cuf
+140
View File
@@ -0,0 +1,140 @@
extends ExampleBase
const YAML_FILE = "res://addons/yaml/examples/data/supported_syntax.yaml"
const OUTPUT_FILE = "user://supported_syntax_copy.yaml"
var yaml_text := """
string: string_value
number: 1234
list:
- apples
- oranges
"""
var data
func _init() -> void:
icon = "📝"
func run_examples() -> void:
run_example("Validate YAML String Syntax", validate_yaml_string_syntax)
run_example("Parse YAML Text", parse_yaml_text)
run_example("Stringify Data", stringify_data)
run_example("Validate File Syntax", validate_file_syntax)
run_example("Load File", load_file)
run_example("Save File", save_file)
run_example("Load Saved File", load_saved_file)
func validate_yaml_string_syntax() -> void:
log_code_block(yaml_text)
log_info("Validating YAML string...")
var result := YAML.validate_syntax(yaml_text)
if result.has_error():
log_error("Validation failed: " + result.get_error())
return
log_success("YAML is valid!")
func parse_yaml_text() -> void:
log_info("Parsing YAML text...")
var result := YAML.parse(yaml_text)
if result.has_error():
log_error("Parse failed: " + result.get_error())
return
data = result.get_data()
log_success("YAML parsed successfully")
if LOG_VERBOSE:
log_result(str(data))
log_info("Accessing data values:")
log_info("• string value: " + data.string)
log_info("• number value: " + str(data.number))
log_info("• list items: " + str(data.list))
func stringify_data() -> void:
# First ensure we have data to stringify
if data == null:
data = YAML.parse(yaml_text).get_data()
log_info("Converting data structure to YAML string...")
var result := YAML.stringify(data)
if result.has_error():
log_error("Stringify failed: " + result.get_error())
return
log_success("Data converted to YAML successfully")
if LOG_VERBOSE:
log_result(result.get_data())
# Verify the round trip
var yaml_output = result.get_data().strip_edges()
var original = yaml_text.strip_edges()
if yaml_output == original:
log_success("Round-trip verification: Output matches original")
else:
log_warning("Round-trip produced different output (semantically equivalent)")
log_info("Original:\n" + original)
log_info("Output:\n" + yaml_output)
func validate_file_syntax() -> void:
log_info("Validating YAML file: " + YAML_FILE)
var result := YAML.validate_file_syntax(YAML_FILE)
if result.has_error():
log_error("File validation failed: " + result.get_error())
return
log_success("YAML file is valid")
func load_file() -> void:
log_info("Loading YAML file: " + YAML_FILE)
var result := YAML.load_file(YAML_FILE)
if result.has_error():
log_error("File loading failed: " + result.get_error())
return
data = result.get_data()
log_success("YAML file loaded successfully")
if LOG_VERBOSE:
log_info("File contains " + str(data.size()) + " keys")
log_result(str(data).substr(0, 500) + "...\n(output truncated)")
func save_file() -> void:
# Make sure we have data
if data == null:
data = {"example": "data", "created": "now", "values": [1, 2, 3]}
log_info("Saving data to YAML file: " + OUTPUT_FILE)
var result := YAML.save_file(data, OUTPUT_FILE)
if result.has_error():
log_error("File saving failed: " + result.get_error())
return
log_success("Data saved to YAML file successfully")
if LOG_VERBOSE:
log_result(result.get_data())
func load_saved_file() -> void:
log_info("Loading previously saved file: " + OUTPUT_FILE)
var result := YAML.load_file(OUTPUT_FILE)
if result.has_error():
log_error("File loading failed: " + result.get_error())
return
var loaded_data = result.get_data()
log_success("Saved file loaded successfully")
if LOG_VERBOSE:
log_result(str(loaded_data))
@@ -0,0 +1 @@
uid://cemrjp34s7ujk
@@ -0,0 +1,239 @@
extends ExampleBase
func _init() -> void:
icon = "🧩"
LOG_VERBOSE = true
func _enter_tree() -> void:
# Register our custom classes when the node enters the tree
YAML.register_class(MyCustomClass, "serialize", "deserialize", "ruby/object:MyCustomClass")
YAML.register_class(MyCustomResource)
YAML.register_class(MyStringClass)
func _exit_tree() -> void:
# Clean up registrations when the node exits the tree
YAML.unregister_class(MyCustomClass)
YAML.unregister_class(MyCustomResource)
YAML.unregister_class(MyStringClass)
func run_examples() -> void:
run_example("Custom Node Class", custom_node_class)
run_example("Custom Class Errors", custom_class_errors)
run_example("String-Based Custom Class", custom_string_class)
run_example("Custom Resource Class", custom_resource)
run_example("Custom Resource Errors", custom_resource_errors)
run_example("Class Registration Management", class_registration_management)
func custom_node_class() -> void:
log_info("Creating instance of MyCustomClass...")
var object = MyCustomClass.new("hello world", 123, PI)
log_info("Stringifying custom class instance to YAML...")
var str_result := YAML.stringify(object)
if str_result.has_error():
log_error("Stringify failed: " + str_result.get_error())
return
var yaml_text: String = str_result.get_data()
log_success("Custom class stringified successfully")
if LOG_VERBOSE:
log_info("MyCustomClass as YAML:\n" + yaml_text)
log_info("Parsing YAML back into MyCustomClass...")
var parse_result := YAML.parse(yaml_text)
if parse_result.has_error():
log_error("Parse failed: " + parse_result.get_error())
return
var obj: MyCustomClass = parse_result.get_data()
if obj is MyCustomClass:
log_success("YAML parsed back into MyCustomClass")
log_info("string_val: " + obj.string_val)
log_info("int_val: " + str(obj.int_val))
log_info("float_val: " + str(obj.float_val))
log_info("color_val: " + str(obj.color_val))
else:
log_error("Failed to parse back into MyCustomClass")
func custom_class_errors() -> void:
log_info("Testing error handling with invalid MyCustomClass YAML...")
# Missing required field
var yaml_text = """
!MyCustomClass
string_val: foo
"""
log_code_block(yaml_text)
log_info("Attempting to parse with missing required fields...")
var result := YAML.parse(yaml_text)
if result.has_error():
log_success("Correctly detected missing field error")
log_info("Error message: " + result.get_error())
else:
log_error("Failed to detect missing required field")
# Invalid data structure
var invalid_yaml_text = """
!MyCustomClass
[1, 2, 3]
"""
log_code_block(invalid_yaml_text)
log_info("Attempting to parse with wrong data structure...")
var bad_result := YAML.parse(invalid_yaml_text)
if bad_result.has_error():
log_success("Correctly detected wrong data structure error")
log_info("Error message: " + bad_result.get_error())
else:
log_error("Failed to detect wrong data structure")
func custom_string_class() -> void:
log_info("Creating instance of string-based MyStringClass...")
var object = MyStringClass.new("hello world")
log_info("Stringifying string-based class to YAML...")
var str_result := YAML.stringify(object)
if str_result.has_error():
log_error("Stringify failed: " + str_result.get_error())
return
var text: String = str_result.get_data()
log_success("String-based class stringified successfully")
if LOG_VERBOSE:
log_result("MyStringClass as YAML:\n" + text)
log_info("Parsing YAML back into MyStringClass...")
var parse_result := YAML.parse(text)
if parse_result.has_error():
log_error("Parse failed: " + parse_result.get_error())
return
var obj = parse_result.get_data()
if obj is MyStringClass:
log_success("YAML parsed back into MyStringClass")
log_info("Value: " + obj.value)
else:
log_error("Failed to parse back into MyStringClass")
func custom_resource() -> void:
log_info("Creating instance of MyCustomResource...")
var resource = MyCustomResource.new("I am resource", 42, 69.69)
log_info("Stringifying resource class to YAML...")
var str_result := YAML.stringify(resource)
if str_result.has_error():
log_error("Stringify failed: " + str_result.get_error())
return
var yaml_text: String = str_result.get_data()
log_success("Resource class stringified successfully")
if LOG_VERBOSE:
log_result("MyCustomResource as YAML:\n" + yaml_text)
log_info("Parsing YAML back into MyCustomResource...")
var parse_result := YAML.parse(yaml_text)
if parse_result.has_error():
log_error("Parse failed: " + parse_result.get_error())
return
var obj = parse_result.get_data()
if obj is MyCustomResource:
log_success("YAML parsed back into MyCustomResource")
log_info("string_val: " + obj.string_val)
log_info("int_val: " + str(obj.int_val))
log_info("float_val: " + str(obj.float_val))
log_info("color_val: " + str(obj.color_val))
else:
log_error("Failed to parse back into MyCustomResource")
func custom_resource_errors() -> void:
log_info("Testing error handling with invalid MyCustomResource YAML...")
# Missing required field
var yaml_text = """
!MyCustomResource
color_val: black
"""
log_code_block(yaml_text)
log_info("Attempting to parse with missing required fields...")
var result := YAML.parse(yaml_text)
if result.has_error():
log_success("Correctly detected missing field error")
log_info("Error message: " + result.get_error())
else:
log_error("Failed to detect missing required field")
# Invalid data structure
var invalid_yaml_text = """
!MyCustomResource
[1, 2, 3]
"""
log_code_block(invalid_yaml_text)
log_info("Attempting to parse with wrong data structure...")
var bad_result := YAML.parse(invalid_yaml_text)
if bad_result.has_error():
log_success("Correctly detected wrong data structure error")
log_info("Error message: " + bad_result.get_error())
else:
log_error("Failed to detect wrong data structure")
func class_registration_management() -> void:
log_subheader("Class Registration Management")
log_info("Checking if classes are registered...")
if YAML.has_registered_class("MyCustomClass2"):
log_success("MyCustomClass is registered")
else:
log_error("MyCustomClass is not registered properly")
if YAML.has_registered_class("MyCustomResource"):
log_success("MyCustomResource is registered")
else:
log_error("MyCustomResource is not registered properly")
if YAML.has_registered_class("MyStringClass"):
log_success("MyStringClass is registered")
else:
log_error("MyStringClass is not registered properly")
log_info("\nExample of registering with custom methods:")
var code = """
# Register with custom method names
YAML.register_class(MyCustomClass, "to_yaml", "from_yaml")
# Methods in the class would then be:
func to_yaml():
# Custom serialization code
return {...}
static func from_yaml(data):
# Custom deserialization code
return MyCustomClass.new(...)
"""
log_code_block(code)
log_info("\nBest practices for class registration:")
log_info("1. Register classes at startup in an autoload/singleton")
log_info("2. Use consistent naming for serialize/deserialize methods")
log_info("3. Implement thorough validation in deserialize methods")
log_info("4. For scripts that might be unloaded, register in _enter_tree and unregister in _exit_tree")
@@ -0,0 +1 @@
uid://ch12k840j6ak6
@@ -0,0 +1,161 @@
extends ExampleBase
func _init() -> void:
icon = ""
func run_examples() -> void:
run_example("Invalid Indentation", invalid_indentation)
run_example("Unmatched Quotes", unmatched_quotes)
run_example("Circular Reference", circular_reference)
run_example("Validation Example", validation_example)
run_example("Error Details", error_details)
run_example("Error Handling Patterns", error_handling_patterns)
func invalid_indentation() -> void:
var invalid_yaml := """
key: value
indentation: wrong
"""
log_code_block(invalid_yaml)
log_info("Parsing YAML with invalid indentation...")
var result := YAML.parse(invalid_yaml)
if result.has_error():
log_success("Correctly detected error: " + result.get_error())
log_info("Line: " + str(result.get_error_line()))
log_info("Column: " + str(result.get_error_column()))
return
log_error("Failed to detect invalid indentation")
func unmatched_quotes() -> void:
var unmatched_quotes := """
message: "This quote is not closed
next_line: value
"""
log_code_block(unmatched_quotes)
log_info("Parsing YAML with unmatched quotes...")
var result = YAML.parse(unmatched_quotes)
if result.has_error():
log_success("Correctly detected error: " + result.get_error())
return
log_error("Failed to detect unmatched quotes")
func circular_reference() -> void:
log_info("Creating circular reference in data structure...")
# Create a circular reference
var dict1 = {}
var dict2 = {"ref": dict1}
dict1["circular"] = dict2
log_info("Attempting to stringify circular reference...")
var result := YAML.stringify(dict1)
if result.has_error():
log_success("Correctly detected error: " + result.get_error())
return
log_error("Failed to detect circular reference")
func validation_example() -> void:
var invalid_yaml := """
key: value
- invalid
list
format
"""
log_code_block(invalid_yaml)
log_info("Validating incorrect YAML...")
var result = YAML.validate_syntax(invalid_yaml)
if result.has_error():
log_success("Validation correctly detected error: " + result.get_error())
return
log_error("Validation failed to detect invalid YAML")
func error_details() -> void:
var yaml_with_error := """
valid_line: value
- invalid line: value
another_line: value
"""
log_code_block(yaml_with_error)
log_info("Examining error details...")
var result := YAML.parse(yaml_with_error)
if result.has_error():
log_success("Error detected: " + result.get_error())
# Show detailed error information
log_info("Error message: " + result.get_error_message())
log_info("Error line: " + str(result.get_error_line()))
log_info("Error column: " + str(result.get_error_column()))
# Highlight the error line
var yaml_lines = yaml_with_error.split("\n")
if result.get_error_line() > 0 and result.get_error_line() <= yaml_lines.size():
var error_line = yaml_lines[result.get_error_line() - 1]
log_info("Line content: " + error_line)
if result.get_error_column() > 0:
var pointer = " ".repeat(result.get_error_column() - 1) + "^"
log_info(pointer + " Error position")
return
log_error("Failed to detect error")
func error_handling_patterns() -> void:
log_subheader("Error Handling Patterns")
# Pattern 1: Try-parse pattern
log_info("Pattern 1: Using try_parse for simplified error handling")
var yaml_text = """
name: Example
valid: true
"""
var data = YAML.try_parse(yaml_text)
if data:
log_success("try_parse succeeded")
log_info("Data: " + str(data))
else:
log_error("try_parse failed")
# Pattern 2: get_error vs get_error_message
log_info("\nPattern 2: Detailed vs Simple Error Messages")
var invalid_yaml = "key: [invalid"
var result = YAML.parse(invalid_yaml)
if result.has_error():
log_info("Detailed error: " + result.get_error())
log_info("Simple message: " + result.get_error_message())
# Pattern 3: Creating custom errors
log_info("\nPattern 3: Creating custom validation errors")
var config_yaml = """
name: MyApp
# version is missing
"""
var parsed = YAML.parse(config_yaml)
if !parsed.has_error():
var validation = validate_config(parsed.get_data())
if validation.has_error():
log_success("Custom validation error: " + validation.get_error_message())
else:
log_info("Config is valid")
else:
log_error("Parse error: " + parsed.get_error())
func validate_config(data):
if !data.has("name"):
return YAMLResult.error("Configuration missing 'name' field")
if !data.has("version"):
return YAMLResult.error("Configuration missing 'version' field")
return data
@@ -0,0 +1 @@
uid://d015opxjbyce4
@@ -0,0 +1,258 @@
extends ExampleBase
const MULTI_DOC_FILE = "res://addons/yaml/examples/data/multi_document.yaml"
const OUTPUT_FILE = "user://multi_document_copy.yaml"
var multi_doc_yaml := """
# Configuration Document
name: MyApplication
version: 1.2.3
environment: production
---
# Database Settings
database:
host: localhost
port: 5432
name: myapp_db
credentials:
username: admin
password: secret123
---
# Feature Flags
features:
enable_new_ui: true
enable_analytics: false
enable_caching: true
max_connections: 100
---
# Logging Configuration
logging:
level: INFO
handlers:
- console
- file
file_path: /var/log/myapp.log
""".replace(" ", " ") # Handle Godot's tab indentation
var parsed_documents
func _init() -> void:
icon = "📑"
func run_examples() -> void:
run_example("Validate Multi-Document YAML", validate_multi_document)
run_example("Parse Multi-Document YAML", parse_multi_document)
run_example("Access Individual Documents", access_individual_documents)
run_example("Work with Document Count", work_with_document_count)
run_example("Process All Documents", process_all_documents)
run_example("Create Multi-Document YAML", create_multi_document)
run_example("Save Multi-Document File", save_multi_document_file)
run_example("Load Multi-Document File", load_multi_document_file)
func validate_multi_document() -> void:
log_info("Validating multi-document YAML string...")
var result := YAML.validate_syntax(multi_doc_yaml)
if result.has_error():
log_error("Validation failed: " + result.get_error())
return
log_success("Multi-document YAML is valid!")
func parse_multi_document() -> void:
log_info("Parsing multi-document YAML...")
var result := YAML.parse(multi_doc_yaml)
if result.has_error():
log_error("Parse failed: " + result.get_error())
return
parsed_documents = result
log_success("Multi-document YAML parsed successfully")
if LOG_VERBOSE:
log_info("Has multiple documents: %s" % result.has_multiple_documents())
log_info("Found " + str(result.get_document_count()) + " documents")
func access_individual_documents() -> void:
# Ensure we have parsed documents
if parsed_documents == null:
parsed_documents = YAML.parse(multi_doc_yaml)
log_info("Accessing individual documents...")
# Access first document (configuration)
var config_doc = parsed_documents.get_document(0)
if config_doc != null:
log_success("Document 0 - Configuration:")
log_info("• App name: " + str(config_doc.name))
log_info("• Version: " + str(config_doc.version))
log_info("• Environment: " + str(config_doc.environment))
# Access second document (database settings)
var db_doc = parsed_documents.get_document(1)
if db_doc != null:
log_success("Document 1 - Database Settings:")
log_info("• Host: " + str(db_doc.database.host))
log_info("• Port: " + str(db_doc.database.port))
log_info("• Database: " + str(db_doc.database.name))
# Access third document (feature flags)
var features_doc = parsed_documents.get_document(2)
if features_doc != null:
log_success("Document 2 - Feature Flags:")
log_info("• New UI enabled: " + str(features_doc.features.enable_new_ui))
log_info("• Analytics enabled: " + str(features_doc.features.enable_analytics))
log_info("• Max connections: " + str(features_doc.features.max_connections))
# Try to access non-existent document
var non_existent = parsed_documents.get_document(10)
if non_existent == null:
log_info("Document 10 (non-existent): null")
func work_with_document_count() -> void:
if parsed_documents == null:
parsed_documents = YAML.parse(multi_doc_yaml)
var count = parsed_documents.get_document_count()
log_info("Total document count: " + str(count))
log_info("Iterating through all documents by index:")
for i in range(count):
var doc = parsed_documents.get_document(i)
var doc_type = "Unknown"
# Identify document type by its content
if doc.has("name") and doc.has("version"):
doc_type = "Configuration"
elif doc.has("database"):
doc_type = "Database Settings"
elif doc.has("features"):
doc_type = "Feature Flags"
elif doc.has("logging"):
doc_type = "Logging Configuration"
log_info("• Document " + str(i) + ": " + doc_type)
func process_all_documents() -> void:
if parsed_documents == null:
parsed_documents = YAML.parse(multi_doc_yaml)
log_info("Processing all documents at once...")
var all_docs = parsed_documents.get_documents()
log_success("Retrieved " + str(all_docs.size()) + " documents as array")
if LOG_VERBOSE:
for i in range(all_docs.size()):
log_info("Document " + str(i) + " keys: " + str(all_docs[i].keys()))
func create_multi_document() -> void:
log_info("Creating multi-document YAML from separate data structures...")
# Create individual document data
var user_doc = {
"user": {
"id": 12345,
"name": "John Doe",
"email": "john@example.com"
}
}
var preferences_doc = {
"preferences": {
"theme": "dark",
"language": "en",
"notifications": true
}
}
var session_doc = {
"session": {
"token": "abc123xyz",
"expires": "2024-12-31T23:59:59Z",
"permissions": ["read", "write"]
}
}
# Convert each to YAML and combine
var documents_yaml = []
for doc_data in [user_doc, preferences_doc, session_doc]:
var result = YAML.stringify(doc_data)
if result.has_error():
log_error("Failed to stringify document: " + result.get_error())
return
documents_yaml.append(result.get_data())
# Combine with document separator
var combined_yaml = "\n---\n".join(documents_yaml)
log_success("Created multi-document YAML successfully")
if LOG_VERBOSE:
log_result(combined_yaml)
# Verify by parsing it back
var verify_result = YAML.parse(combined_yaml)
if !verify_result.has_error():
log_success("Verification: " + str(verify_result.get_document_count()) + " documents parsed")
func save_multi_document_file() -> void:
log_info("Saving multi-document YAML to file: " + OUTPUT_FILE)
# Create sample multi-document data
var documents = [
{"metadata": {"created": "2024-01-01", "version": 1}},
{"data": {"items": [1, 2, 3], "total": 6}},
{"summary": {"status": "complete", "processed": true}}
]
var yaml_parts = []
for doc in documents:
var result = YAML.stringify(doc)
if result.has_error():
log_error("Failed to stringify document: " + result.get_error())
return
yaml_parts.append(result.get_data())
var multi_doc_content = "\n---\n".join(yaml_parts)
# Save to file (note: this saves as plain text, not using YAML.save_file)
var file = FileAccess.open(OUTPUT_FILE, FileAccess.WRITE)
if file == null:
log_error("Failed to open file for writing")
return
file.store_string(multi_doc_content)
file.close()
log_success("Multi-document YAML saved successfully")
if LOG_VERBOSE:
log_result("File content:\n" + multi_doc_content)
func load_multi_document_file() -> void:
log_info("Loading multi-document YAML file: " + OUTPUT_FILE)
# Check if file exists
if !FileAccess.file_exists(OUTPUT_FILE):
log_warning("File doesn't exist. Run 'Save Multi-Document File' first.")
return
var result := YAML.load_file(OUTPUT_FILE)
if result.has_error():
log_error("File loading failed: " + result.get_error())
return
log_success("Multi-document YAML file loaded successfully")
if LOG_VERBOSE:
var doc_count = result.get_document_count()
log_info("Loaded " + str(doc_count) + " documents from file")
for i in range(doc_count):
var doc = result.get_document(i)
log_info("Document " + str(i) + ": " + str(doc.keys()))
log_result(" " + str(doc))
@@ -0,0 +1 @@
uid://bpwc2ppvsfwo5
@@ -0,0 +1,174 @@
extends ExampleBase
# This example requires a local texture reference
# For real use, export a texture in your scene
@export var local_texture: Texture2D
func _init() -> void:
icon = "🔗"
func run_examples() -> void:
run_example("Parsing Resources", parsing_resources)
run_example("Stringifying Resources", stringifying_resources)
run_example("Resource Security", resource_security)
run_example("Resource Path Management", resource_path_management)
func parsing_resources() -> void:
var yaml_text := """
scene: !Resource 'res://addons/yaml/examples/assets/simple_scene.tscn'
texture: !Resource 'res://icon.svg'
yaml: !Resource 'res://addons/yaml/examples/data/simple.yaml'
"""
log_code_block(yaml_text)
log_info("Parsing YAML with resource references...")
var parse_result := YAML.parse(yaml_text)
if parse_result.has_error():
log_error("Parse failed: " + parse_result.get_error())
return
var data: Dictionary = parse_result.get_data()
log_success("YAML with resources parsed successfully")
if data.scene is PackedScene:
log_success("PackedScene loaded successfully")
var scene = data.scene.instantiate()
var screen_width: int = ProjectSettings.get_setting("display/window/size/viewport_width")
var screen_height: int = ProjectSettings.get_setting("display/window/size/viewport_height")
scene.position = Vector2(screen_width / 2, screen_height / 2)
add_child(scene)
else:
log_warning("PackedScene not loaded (might be missing file or security restrictions)")
if data.texture is Texture2D:
log_success("Texture loaded successfully")
else:
log_warning("Texture not loaded (might be missing file or security restrictions)")
if data.yaml is Dictionary:
log_success("Nested YAML loaded successfully")
else:
log_warning("Nested YAML not loaded (might be missing file or security restrictions)")
if LOG_VERBOSE:
log_info("Resource types:")
log_info("• scene type: " + str(typeof(data.scene)))
log_info("• texture type: " + str(typeof(data.texture)))
log_info("YAML resource:")
log_info(str(data.yaml))
func stringifying_resources() -> void:
log_info("Stringifying a resource...")
var resource = load("res://icon.svg") # Project icon should always exist
if !resource:
log_error("Could not load resource")
return
var str_result := YAML.stringify(resource)
if str_result.has_error():
log_error("Stringify failed: " + str_result.get_error())
return
log_success("Resource stringified successfully")
if LOG_VERBOSE:
log_result("Stringified Resource:\n" + str_result.get_data())
# Test stringifying local resource (should fail)
if local_texture:
log_info("Attempting to stringify local (non-file) resource...")
var invalid_result := YAML.stringify(local_texture)
if invalid_result.has_error():
log_success("Correctly failed to serialize local resource")
log_info("Error: " + invalid_result.get_error())
else:
log_error("Incorrectly serialized local resource")
else:
log_warning("No local texture assigned, skipping local resource test")
func resource_security() -> void:
log_info("Testing resource security...")
var yaml_text := """
script: !Resource 'res://addons/yaml/examples/scripts/dangerous_script.gd'
"""
log_code_block(yaml_text)
log_info("Parsing with default security...")
var parse_result := YAML.parse(yaml_text)
if parse_result.has_error():
log_success("Default security correctly blocked script resource")
log_info("Error: " + parse_result.get_error())
else:
log_error("Default security failed to block script resource")
log_info("Creating custom security with explicit type blocks...")
var security := YAML.create_security()
security.block_type("Script")
security.block_type("GDExtension")
security.allow_path("res://**", ["Texture2D", "PackedScene"])
log_info("Same file with custom security...")
parse_result = YAML.parse(yaml_text, security)
if parse_result.has_error():
log_success("Custom security correctly blocked script resource")
log_info("Error: " + parse_result.get_error())
else:
log_error("Custom security failed to block script resource")
func resource_path_management() -> void:
log_subheader("Resource Path Management")
log_info("Using relative paths vs absolute paths:")
var yaml_with_absolute_path := """
texture: !Resource 'res://icon.svg'
"""
log_code_block(yaml_with_absolute_path)
log_info("Absolute paths are fixed to specific locations")
var yaml_with_relative_path := """
# When file is in res://addons/yaml/examples/
texture: !Resource '../../../icon.svg'
"""
log_code_block(yaml_with_relative_path)
log_warning("Note: Godot doesn't natively support relative paths in Resource paths")
log_info("You need to implement custom path resolution for relative paths")
log_info("\nSuggested best practices:")
log_info("1. Use absolute paths (res://, user://) for resources")
log_info("2. Keep resources in a structured directory hierarchy")
log_info("3. Use security settings to limit resource access")
log_info("4. For mod support, create custom path remapping in your game code")
# Example of custom path handling
log_info("\nExample of custom path handling:")
var code := """
# Custom path resolver for mod resources
func resolve_mod_path(path: String, mod_id: String) -> String:
if path.begins_with("mod://"):
# Transform mod:// protocol to user://mods/{mod_id}/
return path.replace("mod://", "user://mods/" + mod_id + "/")
return path
# Example usage with YAML
func load_mod_config(mod_id: String) -> Dictionary:
var yaml_text = FileAccess.open("user://mods/" + mod_id + "/config.yaml", FileAccess.READ).get_as_text()
var data = YAML.parse(yaml_text).get_data()
# Process all resource paths in the data
for key in data:
if data[key] is String and data[key].begins_with("mod://"):
# Resolve the path
data[key] = resolve_mod_path(data[key], mod_id)
return data
"""
log_code_block(code)
@@ -0,0 +1 @@
uid://csoaahlo0042h
+206
View File
@@ -0,0 +1,206 @@
extends ExampleBase
func _init() -> void:
icon = "🔒"
func run_examples() -> void:
run_example("Default Security Behavior", default_security)
run_example("Custom Security: Allow Path", custom_security_allow_path)
run_example("Wildcard Path Patterns", wildcard_paths)
run_example("Blocking Resource Types", block_type)
run_example("Clearing Type Restrictions", clear_type_restrictions)
run_example("Resetting Security", reset_security)
run_example("Security Best Practices", security_best_practices)
func default_security() -> void:
log_info("Testing default security settings...")
# Default security should block Script and GDExtension
var yaml_text := """
dangerous: !Resource 'res://addons/yaml/examples/classes/my_custom_class.gd'
"""
log_code_block(yaml_text)
var result := YAML.parse(yaml_text)
if result.has_error():
log_success("Default security correctly blocked Script resource")
log_info("Error message: " + result.get_error())
return
log_error("Security failed to block unsafe resource")
func custom_security_allow_path() -> void:
log_info("Creating custom security policy...")
var security := YAML.create_security()
# Allow only textures from a specific path
security.allow_path("res://addons/yaml/examples/assets", ["Texture2D"])
log_info("Testing allowed path and type...")
var allowed_yaml := """
texture: !Resource 'res://addons/yaml/icon.svg'
"""
log_code_block(allowed_yaml)
var result := YAML.parse(allowed_yaml, security)
if !result.has_error():
log_success("Correctly allowed texture in permitted path")
else:
log_error("Incorrectly blocked permitted resource: " + result.get_error())
log_info("Testing incorrect path...")
var wrong_path_yaml := """
texture: !Resource 'res://addons/yaml/examples/wrong_path/test.png'
"""
log_code_block(wrong_path_yaml)
result = YAML.parse(wrong_path_yaml, security)
if result.has_error():
log_success("Correctly blocked resource outside allowed path")
log_info("Error message: " + result.get_error())
else:
log_error("Security failed to block resource outside allowed path")
log_info("Testing incorrect type...")
var wrong_type_yaml := """
scene: !Resource 'res://addons/yaml/examples/assets/textures/test.tscn'
"""
log_code_block(wrong_type_yaml)
result = YAML.parse(wrong_type_yaml, security)
if result.has_error():
log_success("Correctly blocked non-texture resource")
log_info("Error message: " + result.get_error())
else:
log_error("Security failed to block non-texture resource")
func wildcard_paths() -> void:
log_info("Testing wildcard path patterns...")
# Create security configuration
var security := YAML.create_security()
# Test single segment wildcard (*)
log_info("Single segment wildcard (*) example:")
security.allow_path("res://addons/yaml/*/assets", ["Texture2D"])
var single_wildcard_yaml := """
texture: !Resource 'res://addons/yaml/icon.svg'
"""
log_code_block(single_wildcard_yaml)
var result := YAML.parse(single_wildcard_yaml, security)
if !result.has_error():
log_success("Single wildcard pattern matched correctly")
else:
log_error("Single wildcard failed: " + result.get_error())
# Test recursive wildcard (**)
log_info("\nRecursive wildcard (**) example:")
security.clear_path_restrictions()
security.allow_path("res://**", ["PackedScene"])
var recursive_wildcard_yaml := """
scene: !Resource 'res://addons/yaml/examples/assets/simple_scene.tscn'
"""
log_code_block(recursive_wildcard_yaml)
result = YAML.parse(recursive_wildcard_yaml, security)
if !result.has_error():
log_success("Recursive wildcard pattern matched correctly")
else:
log_error("Recursive wildcard failed: " + result.get_error())
func block_type() -> void:
log_info("Testing type blocking functionality...")
var security := YAML.create_security()
security.allow_path("res://**") # Allow all paths
security.block_type("PackedScene") # But block all scenes
var blocked_yaml := """
scene: !Resource 'res://addons/yaml/examples/assets/test.tscn'
"""
log_code_block(blocked_yaml)
var result := YAML.parse(blocked_yaml, security)
if result.has_error():
log_success("Correctly blocked resource of blocked type")
log_info("Error message: " + result.get_error())
else:
log_error("Failed to block specified resource type")
func clear_type_restrictions() -> void:
log_info("Testing clearing type restrictions...")
var security := YAML.create_security()
security.allow_path("res://**")
security.clear_type_restrictions() # This removes default blocks on Script and GDExtension
var script_yaml := """
script: !Resource 'res://addons/yaml/examples/classes/my_custom_class.gd'
"""
log_code_block(script_yaml)
log_warning("Note: Allowing scripts can be dangerous with untrusted content")
var result := YAML.parse(script_yaml, security)
if !result.has_error():
log_success("Script resource allowed after clearing restrictions")
else:
log_error("Failed to allow script after clearing restrictions: " + result.get_error())
func reset_security() -> void:
log_info("Testing security reset functionality...")
var security := YAML.create_security()
security.allow_path("res://**")
security.clear_type_restrictions()
log_info("Before reset: All paths allowed, all types allowed")
security.reset() # Should revert to default security
log_info("After reset: Default restrictions should apply")
var script_yaml := """
script: !Resource 'res://addons/yaml/examples/assets/my_custom_class.gd'
"""
log_code_block(script_yaml)
var result := YAML.parse(script_yaml, security)
if result.has_error():
log_success("Script correctly blocked after security reset")
log_info("Error message: " + result.get_error())
else:
log_error("Security reset failed to restore default restrictions")
func security_best_practices() -> void:
log_subheader("Security Best Practices")
log_info("1. Default security blocks Script and GDExtension resources")
log_info("2. Only allow specific paths and types needed by your application")
log_info("3. Use the most specific path patterns possible")
log_info("4. For user content, create a dedicated directory and apply strict type limitations")
log_info("\nExample for mod content security:")
var code := """
# Create security for user mods
var mod_security = YAML.create_security()
# Only allow textures, audio, and text files
mod_security.allow_path("user://mods/**", [
"Texture2D",
"CompressedTexture2D",
"AudioStreamOggVorbis",
"AudioStreamMP3"
])
# Explicitly block potentially dangerous types
mod_security.block_type("Script")
mod_security.block_type("GDExtension")
mod_security.block_type("PackedScene")
# Use this security when loading mod content
var result = YAML.load_file("user://mods/my_mod/config.yaml", mod_security)
"""
log_code_block(code)
@@ -0,0 +1 @@
uid://bdbxqi1f27ndt
@@ -0,0 +1,283 @@
extends ExampleBase
## Number of iterations for each benchmark
const ITERATIONS: int = 10
## Thread counts for multithreaded benchmarks
const THREAD_COUNTS: Array = [1, 2, 4, 8, 16, 32, 64, 100]
## Path to the YAML file to benchmark
const YAML_PATH: String = "res://addons/yaml/examples/data/supported_syntax.yaml"
func _init() -> void:
icon = ""
func run_examples() -> void:
log_header("YAML Speed Benchmark")
print(YAML.version())
run_example("Load YAML File", load_yaml_file_benchmark)
run_example("Parse (No Style) Benchmark", parse_benchmark)
run_example("Parse (With Style) Benchmark", parse_with_style_benchmark)
run_example("Stringify (No Style) Benchmark", stringify_benchmark)
run_example("Stringify (With Style) Benchmark", stringify_with_style_benchmark)
run_example("Compare Results", compare_results)
run_example("Parse (Threaded) Bechmark", parse_threaded)
run_example("Stringify (Threaded) Benchmark", stringify_threaded)
var yaml_input: String
var parse_times := []
var style_parse_times := []
var stringify_times := []
var style_stringify_times := []
var data = null
var style = null
func load_yaml_file_benchmark() -> void:
log_info("Loading YAML file: " + YAML_PATH)
var file := FileAccess.open(YAML_PATH, FileAccess.READ)
if !file:
log_error("Could not open file: " + YAML_PATH)
return
yaml_input = file.get_as_text()
log_success("File loaded, size: " + str(yaml_input.length()) + " characters")
var result := YAML.parse(yaml_input)
data = result.get_data()
if LOG_VERBOSE:
log_result("First 200 characters:\n" + yaml_input.substr(0, 200) + "...")
func parse_benchmark() -> void:
if yaml_input.is_empty():
log_error("No YAML input loaded")
return
log_info("Running parse benchmark (" + str(ITERATIONS) + " iterations)...")
for i in range(ITERATIONS):
var start := Time.get_ticks_usec()
var result = YAML.parse(yaml_input)
var elapsed := Time.get_ticks_usec() - start
if result.has_error():
log_error("Iteration " + str(i + 1) + " failed: " + result.get_error())
continue
parse_times.append(elapsed)
log_info("Iteration " + str(i + 1) + ": " + str(elapsed) + " µs")
if parse_times.size() > 0:
var avg = float(parse_times.reduce(func(a, b): return a + b)) / parse_times.size()
log_success("Average parse time: " + str(avg) + " µs")
else:
log_error("No successful parse iterations")
func parse_with_style_benchmark() -> void:
if yaml_input.is_empty():
log_error("No YAML input loaded")
return
log_info("Running parse with style benchmark (" + str(ITERATIONS) + " iterations)...")
for i in range(ITERATIONS):
var start := Time.get_ticks_usec()
var result = YAML.parse(yaml_input, YAML.create_security(), true)
var elapsed := Time.get_ticks_usec() - start
if result.has_error():
log_error("Iteration " + str(i + 1) + " failed: " + result.get_error())
continue
if i == 0:
style = result.get_style()
style_parse_times.append(elapsed)
log_info("Iteration " + str(i + 1) + ": " + str(elapsed) + " µs")
if style_parse_times.size() > 0:
var avg = float(style_parse_times.reduce(func(a, b): return a + b)) / style_parse_times.size()
log_success("Average parse with style time: " + str(avg) + " µs")
else:
log_error("No successful parse with style iterations")
func stringify_benchmark() -> void:
if data == null:
log_error("No data available for stringify tests")
return
log_info("Running stringify benchmark (" + str(ITERATIONS) + " iterations)...")
for i in range(ITERATIONS):
var start := Time.get_ticks_usec()
var result = YAML.stringify(data)
var elapsed := Time.get_ticks_usec() - start
if result.has_error():
log_error("Iteration " + str(i + 1) + " failed: " + result.get_error())
continue
stringify_times.append(elapsed)
log_info("Iteration " + str(i + 1) + ": " + str(elapsed) + " µs")
if stringify_times.size() > 0:
var avg = float(stringify_times.reduce(func(a, b): return a + b)) / stringify_times.size()
log_success("Average stringify time: " + str(avg) + " µs")
else:
log_error("No successful stringify iterations")
func stringify_with_style_benchmark() -> void:
if data == null or style == null:
log_error("No data or style available for stringify tests")
return
log_info("Running stringify with style benchmark (" + str(ITERATIONS) + " iterations)...")
for i in range(ITERATIONS):
var start := Time.get_ticks_usec()
var result = YAML.stringify(data, style)
var elapsed := Time.get_ticks_usec() - start
if result.has_error():
log_error("Iteration " + str(i + 1) + " failed: " + result.get_error())
continue
style_stringify_times.append(elapsed)
log_info("Iteration " + str(i + 1) + ": " + str(elapsed) + " µs")
if style_stringify_times.size() > 0:
var avg = float(style_stringify_times.reduce(func(a, b): return a + b)) / style_stringify_times.size()
log_success("Average stringify with style time: " + str(avg) + " µs")
else:
log_error("No successful stringify with style iterations")
func compare_results() -> void:
log_subheader("Performance Comparison")
# Collect all test results
var all_tests = [
{
"name": "Parse (no style)",
"times": parse_times
},
{
"name": "Parse (with style)",
"times": style_parse_times
},
{
"name": "Stringify (no style)",
"times": stringify_times
},
{
"name": "Stringify (with style)",
"times": style_stringify_times
}
]
# Calculate and print stats
for test in all_tests:
var times = test.times
if times.is_empty():
log_warning(test.name + ": No valid results")
continue
var avg: float = float(times.reduce(func(a, b): return a + b)) / times.size()
var min_time: int = times.min()
var max_time: int = times.max()
log_info(test.name + ":")
log_info(" Average: %.2f µs" % avg)
log_info(" Min: %d µs" % min_time)
log_info(" Max: %d µs" % max_time)
log_info("\nPerformance Insights:")
# Compare parse with and without style
if !parse_times.is_empty() and !style_parse_times.is_empty():
var avg_parse = float(parse_times.reduce(func(a, b): return a + b)) / parse_times.size()
var avg_style_parse = float(style_parse_times.reduce(func(a, b): return a + b)) / style_parse_times.size()
var style_overhead = ((avg_style_parse / avg_parse) - 1.0) * 100.0
log_info("Style detection adds approximately %.1f%% overhead to parsing" % style_overhead)
# Compare stringify with and without style
if !stringify_times.is_empty() and !style_stringify_times.is_empty():
var avg_stringify = float(stringify_times.reduce(func(a, b): return a + b)) / stringify_times.size()
var avg_style_stringify = float(style_stringify_times.reduce(func(a, b): return a + b)) / style_stringify_times.size()
var style_overhead = ((avg_style_stringify / avg_stringify) - 1.0) * 100.0
log_info("Using style adds approximately %.1f%% overhead to stringify" % style_overhead)
func parse_threaded() -> void:
if yaml_input.is_empty():
log_error("No YAML input loaded")
return
log_subheader("Threaded Parse Benchmark")
for thread_count in THREAD_COUNTS:
var threads: Array[Thread] = []
var start := Time.get_ticks_usec()
for i in range(thread_count):
var thread := Thread.new()
thread.start(_parse_thread_func.bind(yaml_input))
threads.append(thread)
var total_parse_time := 0
for thread in threads:
total_parse_time += thread.wait_to_finish()
var wall_time := Time.get_ticks_usec() - start
var avg_thread_time := float(total_parse_time / thread_count)
log_info("%d thread(s): wall=%d µs | avg thread=%d µs | throughput=%.1f parses/ms" % [
thread_count,
wall_time,
avg_thread_time,
thread_count / (wall_time / 1000.0)
])
func stringify_threaded() -> void:
if data == null:
log_error("No data available for stringify tests")
return
log_subheader("Threaded Stringify Benchmark")
for thread_count in THREAD_COUNTS:
var threads: Array[Thread] = []
var start := Time.get_ticks_usec()
for i in range(thread_count):
var thread := Thread.new()
thread.start(_stringify_thread_func.bind(data))
threads.append(thread)
var total_stringify_time := 0
for thread in threads:
total_stringify_time += thread.wait_to_finish()
var wall_time := Time.get_ticks_usec() - start
var avg_thread_time := float(total_stringify_time / thread_count)
log_info("%d thread(s): wall=%d µs | avg thread=%d µs | throughput=%.1f stringifies/ms" % [
thread_count,
wall_time,
avg_thread_time,
thread_count / (wall_time / 1000.0)
])
static func _parse_thread_func(input: String) -> int:
var start := Time.get_ticks_usec()
YAML.parse(input)
return Time.get_ticks_usec() - start
static func _stringify_thread_func(input_data: Variant) -> int:
var start := Time.get_ticks_usec()
YAML.stringify(input_data)
return Time.get_ticks_usec() - start
@@ -0,0 +1 @@
uid://bcyghdxg5kxhk
@@ -0,0 +1,359 @@
extends ExampleBase
const YAML_FILE = "res://addons/yaml/examples/data/supported_syntax.yaml"
const STYLE_FILE = "user://supported_syntax.style.yaml"
var data
var style: YAMLStyle
func _init() -> void:
icon = "🎨"
func run_examples() -> void:
run_example("Style Extraction", style_extraction)
run_example("Stringify with Style", stringify_with_style)
run_example("Style Cloning", style_cloning)
run_example("Style Merging", style_merging)
run_example("Child Styles", child_styles)
run_example("Path-based Styles", get_at_path)
run_example("Style Propagation", propagate_scalar_styles)
run_example("Various Style Combinations", various_style_combinations)
run_example("Style Serialization", to_from_dictionary)
func style_extraction() -> void:
log_info("Loading YAML file with style detection...")
var result = YAML.load_file(YAML_FILE, null, true)
if result.has_error():
log_error("Failed to load file: " + result.get_error())
return
data = result.get_data()
style = result.get_style()
if !style:
log_error("Could not extract style")
return
log_success("Style extracted successfully")
if LOG_VERBOSE:
log_result("Extracted Styles:\n" + style.get_debug_string())
log_info("Saving style to file: " + STYLE_FILE)
var save_result = style.save_file(STYLE_FILE)
if save_result.has_error():
log_error("Failed to save style: " + save_result.get_error())
return
log_success("Style saved to file")
func stringify_with_style() -> void:
log_info("Loading style from file...")
var load_result = YAMLStyle.load_file(STYLE_FILE)
if load_result.has_error():
log_error("Failed to load style: " + load_result.get_error())
return
var load_style = load_result.get_style()
if style && load_style.hash() == style.hash():
log_success("Loaded style matches the original style")
else:
log_warning("Loaded style does not match the original style")
if data == null:
data = {"test": "value"}
log_info("Stringifying data with loaded style...")
var stringify_result = YAML.stringify(data, load_style)
if stringify_result.has_error():
log_error("Stringify failed: " + stringify_result.get_error())
return
log_success("Data stringified with style")
if LOG_VERBOSE:
log_result("Styled YAML output:\n" + stringify_result.get_data())
func style_cloning() -> void:
log_info("Creating and configuring base style...")
var style := YAML.create_style()
style.set_string_style(YAMLStyle.STRING_QUOTE_DOUBLE)
style.set_flow_style(YAMLStyle.FLOW_NONE)
log_info("Cloning style...")
var cloned_style := style.clone()
if style.get_string_style() == cloned_style.get_string_style() && \
style.get_flow_style() == cloned_style.get_flow_style():
log_success("Cloned style has same properties as original")
else:
log_error("Cloned style properties don't match original")
log_info("Modifying the cloned style...")
cloned_style.set_string_style(YAMLStyle.STRING_QUOTE_SINGLE)
if style.get_string_style() != cloned_style.get_string_style():
log_success("Modifying clone doesn't affect original")
else:
log_error("Modifying clone affected original")
if LOG_VERBOSE:
var test_data = {"message": "Hello, World!"}
var orig_result = YAML.stringify(test_data, style)
var clone_result = YAML.stringify(test_data, cloned_style)
log_result("Original style output:\n" + orig_result.get_data())
log_result("Cloned style output:\n" + clone_result.get_data())
func style_merging() -> void:
log_info("Creating two different styles...")
var style1 := YAML.create_style()
style1.set_string_style(YAMLStyle.STRING_QUOTE_DOUBLE)
var style2 := YAML.create_style()
style2.set_flow_style(YAMLStyle.FLOW_SINGLE)
log_info("Merging style2 into style1...")
style1.merge_with(style2)
if style1.get_string_style() == YAMLStyle.STRING_QUOTE_DOUBLE:
log_success("Original style properties preserved")
else:
log_error("Original style properties were lost")
if style1.get_flow_style() == YAMLStyle.FLOW_SINGLE:
log_success("Properties from merged style were added")
else:
log_error("Properties from merged style were not added")
if LOG_VERBOSE:
var test_data = {
"message": "Hello, World!",
"items": ["one", "two", "three"]
}
var result = YAML.stringify(test_data, style1)
log_result("Merged style output:\n" + result.get_data())
func child_styles() -> void:
log_info("Creating parent style with child styles...")
var style := YAML.create_style()
style.set_string_style(YAMLStyle.STRING_QUOTE_DOUBLE)
log_info("Creating child style for 'list' key...")
var list_style := style.create_child("list")
list_style.set_flow_style(YAMLStyle.FLOW_SINGLE)
if style.get_child("list") == list_style:
log_success("get_child() retrieves the correct child style")
else:
log_error("get_child() failed to retrieve the correct child style")
if style.has_child("list"):
log_success("has_child() correctly identifies existing child")
else:
log_error("has_child() failed to identify existing child")
var child_keys := style.list_children()
if child_keys.has("list"):
log_success("list_children() includes the child key")
else:
log_error("list_children() failed to include the child key")
if LOG_VERBOSE:
var test_data = {
"name": "Example",
"list": ["one", "two", "three"]
}
var result = YAML.stringify(test_data, style)
log_result("Output with child styles:\n" + result.get_data())
func get_at_path() -> void:
log_info("Creating nested style structure...")
var style := YAML.create_style()
# Create a nested style structure
var maps_style := style.create_child("maps")
var items_style := maps_style.create_child("items")
var first_item_style := items_style.create_child("0")
first_item_style.set_string_style(YAMLStyle.STRING_LITERAL)
log_info("Getting style at path 'maps/items/0'...")
var path_style := style.get_at_path("maps/items/0")
if path_style && path_style.get_string_style() == YAMLStyle.STRING_LITERAL:
log_success("get_at_path() correctly retrieved the style")
else:
log_error("get_at_path() failed to retrieve the correct style")
log_info("Creating missing path 'maps/items/1/properties'...")
var new_path_style := style.get_at_path("maps/items/1/properties", true)
if new_path_style != null:
log_success("Successfully created missing path nodes")
else:
log_error("Failed to create missing path nodes")
log_info("Getting non-existent path without creating...")
var missing_style := style.get_at_path("non/existent/path", false)
if missing_style == null:
log_success("Correctly returned null for non-existent path")
else:
log_error("Incorrectly returned non-null for non-existent path")
if LOG_VERBOSE:
var test_data = {
"maps": {
"items": [
{"name": "Item 1", "description": "Line 1\nLine 2\nLine 3"},
{"name": "Item 2", "properties": {"a": 1, "b": 2}}
]
}
}
var result = YAML.stringify(test_data, style)
log_result("Output with path-based styles:\n" + result.get_data())
func propagate_scalar_styles() -> void:
log_info("Creating parent style with scalar formats...")
var parent_style := YAML.create_style()
parent_style.set_string_style(YAMLStyle.STRING_QUOTE_DOUBLE)
parent_style.set_integer_format(YAMLStyle.INT_HEX)
parent_style.set_float_format(YAMLStyle.FLOAT_SCIENTIFIC)
log_info("Creating child style and propagating scalar styles...")
var child_style := YAML.create_style()
parent_style.propagate_scalar_styles(child_style)
if child_style.get_string_style() == YAMLStyle.STRING_QUOTE_DOUBLE:
log_success("String style was propagated")
else:
log_error("String style was not propagated")
if child_style.get_integer_format() == YAMLStyle.INT_HEX:
log_success("Integer format was propagated")
else:
log_error("Integer format was not propagated")
if child_style.get_float_format() == YAMLStyle.FLOAT_SCIENTIFIC:
log_success("Float format was propagated")
else:
log_error("Float format was not propagated")
if LOG_VERBOSE:
var test_data = {
"text": "Hello, World!",
"number": 255,
"decimal": 3.14159
}
var result = YAML.stringify(test_data, child_style)
log_result("Output with propagated styles:\n" + result.get_data())
func various_style_combinations() -> void:
log_info("Creating data with various types...")
var data := {
"string_value": "Test string with \"quotes\" and newlines\nto test",
"int_value": 255,
"float_value": 3.14159,
"list": ["item1", "item2", "item3"],
"dict": {"key1": "val1", "key2": "val2"}
}
log_info("Creating style with various formatting options...")
var style := YAML.create_style()
style.set_string_style(YAMLStyle.STRING_LITERAL)
style.set_integer_format(YAMLStyle.INT_HEX)
style.set_float_format(YAMLStyle.FLOAT_SCIENTIFIC)
# List should be compact
var list_style := style.create_child("list")
list_style.set_flow_style(YAMLStyle.FLOW_SINGLE)
# Dict should be expanded
var dict_style := style.create_child("dict")
dict_style.set_flow_style(YAMLStyle.FLOW_NONE)
log_info("Stringifying with custom styles...")
var result := YAML.stringify(data, style)
if result.has_error():
log_error("Stringify failed: " + result.get_error())
return
log_success("Data stringified with custom styles")
if LOG_VERBOSE:
log_result("Styled YAML output:\n" + result.get_data())
log_info("Parsing styled output with style detection...")
var parse_result := YAML.parse(result.get_data(), null, true)
if parse_result.has_error():
log_error("Parse failed: " + parse_result.get_error())
return
var detected_style := parse_result.get_style()
if detected_style != null:
log_success("Style was detected during parsing")
if LOG_VERBOSE:
log_result("Detected Style Tree:\n" + detected_style.get_debug_string())
else:
log_error("Style was not detected during parsing")
func to_from_dictionary() -> void:
log_info("Creating style for serialization...")
var style := YAML.create_style()
style.set_string_style(YAMLStyle.STRING_QUOTE_DOUBLE)
var child := style.create_child("child")
child.set_flow_style(YAMLStyle.FLOW_SINGLE)
log_info("Converting style to dictionary...")
var dict := style.to_dictionary()
if dict.has("string") && dict.has("children"):
log_success("Dictionary contains style properties and children")
else:
log_error("Dictionary missing expected keys")
log_info("Rebuilding style from dictionary...")
var rebuilt_style := YAMLStyle.from_dictionary(dict)
if rebuilt_style.get_string_style() == YAMLStyle.STRING_QUOTE_DOUBLE:
log_success("Rebuilt style maintained properties")
else:
log_error("Rebuilt style lost properties")
if rebuilt_style.has_child("child"):
log_success("Rebuilt style maintains children")
else:
log_error("Rebuilt style lost children")
var rebuilt_hash := rebuilt_style.hash()
var original_hash := style.hash()
if rebuilt_hash == original_hash:
log_success("Style hashes match")
else:
log_error("Style hashes don't match")
if LOG_VERBOSE:
log_result("Style dictionary:\n" + str(dict))
@@ -0,0 +1 @@
uid://00j04245e7jl
+107
View File
@@ -0,0 +1,107 @@
extends ExampleBase
var schema: Schema
func _init() -> void:
icon = "🛡️"
func run_examples() -> void:
run_example("Load YAML Schema", load_yaml_schema)
run_example("Validate Using Schema", validate_using_schema)
run_example("Validate While Parsing", validate_while_parsing)
run_example("Validate With Defaults", validate_with_defaults)
func load_yaml_schema() -> void:
var yaml_schema_text = """
# The $id string is used as an identifier
$id: "http://example.com/user.yaml"
# Definitions
$defs:
settings:
type: object
properties:
theme:
type: string
default: dark
type: object
properties:
username:
type: string
minLength: 3
maxLength: 20
email:
type: string
format: email
role:
type: string
default: user
x-yaml-tag: UserRole
settings:
$ref: "#/$defs/settings"
required:
- username
- email
""".replace("\t", " ")
schema = YAML.load_schema_from_string(yaml_schema_text)
if !schema:
log_error("Schema failed to load!")
else:
log_success("Schema '%s' loaded" % schema.get_schema_definition().get("$id"))
func validate_using_schema() -> void:
# Validate using the Schema object
log_subheader("Successful validation")
var result := schema.validate({
"username": "alice",
"email": "alice@example.com"
})
if result.is_valid():
log_success(result.get_summary())
else:
log_error(result.get_summary())
log_subheader("Failed validation")
result = schema.validate({
"username": "alice",
"email": "invalid email"
})
if !result.is_valid():
log_success(result.get_summary())
else:
log_error(result.get_summary())
func validate_while_parsing() -> void:
# YAML tag validation
var tagged_yaml = """
username: bob
email: bob@example.com
role: !UserRole admin
settings:
theme: white
"""
# Parse and validate using Schema $id property
var result := YAML.parse_and_validate(tagged_yaml, "http://example.com/user.yaml")
if result.has_validation_errors():
log_error(result.get_validation_summary())
return
log_success(result.get_data())
func validate_with_defaults() -> void:
# Default values
var yaml_str = """
$schema: "http://example.com/user.yaml" # This refers to the $id
username: alice
email: alice@example.com
settings: {} # Empty dictionary is required to set default values
"""
# Parse and validate using YAML $schema property
var result := YAML.parse_and_validate(yaml_str)
if result.has_validation_errors():
log_error(result.get_validation_summary())
return
log_success(result.get_data())
@@ -0,0 +1 @@
uid://eduyiegmiod
+163
View File
@@ -0,0 +1,163 @@
extends ExampleBase
const EPSILON := 0.000001 # Tolerance for floating point comparisons
func _init() -> void:
icon = "🧩"
func run_examples():
var variants := get_variant_dict()
# Test each type individually
for key in variants:
run_example(key, func(): run_variant_conversion(key, variants[key]))
# Test full dictionary conversion
print_rich("\n[b]Testing Full Dictionary Conversion:[/b]")
var yaml_result := YAML.stringify(variants)
if yaml_result.has_error():
print_rich("[color=red]Dictionary stringify failed: %s[/color]" % yaml_result.get_error())
return
var yaml_text = yaml_result.get_data()
var parse_result := YAML.parse(yaml_text)
if parse_result.has_error():
print_rich("[color=red]Dictionary parse failed: %s[/color]" % parse_result.get_error())
return
var decoded = parse_result.get_data()
var all_passed := true
for key in variants:
if !is_approximately_equal(variants[key], decoded[key]):
print_rich("[color=red]Dictionary value mismatch for %s:[/color]" % key)
print_rich(" Expected: %s" % variants[key])
print_rich(" Got: %s" % decoded[key])
all_passed = false
if all_passed:
print_rich("[color=green]✓ All variant type conversions passed![/color]")
func run_variant_conversion(type_name: String, value: Variant) -> void:
print_rich("\n[b]Testing %s:[/b]" % type_name)
print_rich("[i]Original:[/i] %s" % str(value))
# Test stringification
var yaml_result := YAML.stringify(value)
if yaml_result.has_error():
print_rich("[color=red]Stringify failed: %s[/color]" % yaml_result.get_error())
return
var yaml = yaml_result.get_data()
print_rich("[i]As YAML:[/i]\n%s" % yaml)
# Test parsing
var parse_result := YAML.parse(yaml)
if parse_result.has_error():
print_rich("[color=red]Parse failed: %s[/color]" % parse_result.get_error())
return
var decoded = parse_result.get_data()
print_rich("[i]Decoded:[/i] %s" % str(decoded))
# Verify value equality
if !is_approximately_equal(value, decoded):
print_rich("[color=red]Value mismatch:[/color]")
print_rich(" Expected: %s" % str(value))
print_rich(" Got: %s" % decoded)
else:
print_rich("[color=green]✓ Values match[/color]")
func is_approximately_equal(a: Variant, b: Variant) -> bool:
if typeof(b) == TYPE_STRING:
return str(a) == b
match typeof(a):
TYPE_STRING, TYPE_STRING_NAME:
return a == b
TYPE_FLOAT:
return abs(a - b) < EPSILON
TYPE_VECTOR2, TYPE_VECTOR3, TYPE_VECTOR4:
return a.is_equal_approx(b)
TYPE_ARRAY, TYPE_PACKED_FLOAT32_ARRAY, TYPE_PACKED_FLOAT64_ARRAY:
if a.size() != b.size():
return false
for i in a.size():
if not is_approximately_equal(a[i], b[i]):
return false
return true
TYPE_QUATERNION, TYPE_BASIS, TYPE_TRANSFORM2D, TYPE_TRANSFORM3D:
return a.is_equal_approx(b)
TYPE_COLOR:
var va = Vector4(a.r, a.g, a.b, a.a)
var vb = Vector4(b.r, b.g, b.b, b.a)
var dist = (va - vb).length()
return dist < 0.01
TYPE_DICTIONARY:
if a.size() != b.size():
return false
for key in a:
if not b.has(key) or not is_approximately_equal(a[key], b[key]):
return false
return true
_:
return a == b
func get_variant_dict() -> Dictionary:
return {
# Vector types
"Vector2": Vector2(1, 2),
"Vector2i": Vector2i(2, 4),
"Vector3": Vector3(1, 2, 4),
"Vector3i": Vector3i(2, 4, 8),
"Vector4": Vector4(1, 2, 4, 8),
"Vector4i": Vector4i(2, 4, 8, 16),
# Geometric types
"AABB": AABB(Vector3(1, 2, 4), Vector3(8, 16, 32)),
"Basis": Basis(Vector3(1, 2, 4), Vector3(8, 16, 32), Vector3(64, 128, 256)),
"Plane": Plane(Vector3(1, 2, 4), PI),
"Quaternion": Quaternion(PI, 2*PI, 4*PI, 8*PI),
"Rect2": Rect2(1, 2, 4, 8),
"Rect2i": Rect2i(2, 4, 8, 16),
"Transform2D": Transform2D(PI, Vector2(2*PI, 4*PI)),
"Transform3D": Transform3D(Basis(), Vector3(1, 2, 4)),
# Color types
"Color": Color(1.0, 0.5, 0.25, 1.0),
# Array types
"PackedByteArray": PackedByteArray([1, 2, 4, 8]),
"PackedColorArray": PackedColorArray([
Color(1, 0, 0),
Color(0, 1, 0),
Color(0, 0, 1)
]),
"PackedFloat32Array": PackedFloat32Array([PI, 2*PI, 4*PI]),
"PackedFloat64Array": PackedFloat64Array([PI, 2*PI, 4*PI]),
"PackedInt32Array": PackedInt32Array([1, 2, 4, 8]),
"PackedInt64Array": PackedInt64Array([1, 2, 4, 8]),
"PackedStringArray": PackedStringArray([
"one",
"one\ntwo",
"one\ntwo\nthree"
]),
"PackedVector2Array": PackedVector2Array([
Vector2(1, 2),
Vector2(4, 8)
]),
"PackedVector3Array": PackedVector3Array([
Vector3(1, 2, 4),
Vector3(8, 16, 32)
]),
# Matrix type
"Projection": Projection(
Vector4(1, 2, 4, 8),
Vector4(16, 32, 64, 128),
Vector4(256, 512, 1024, 2048),
Vector4(4096, 8192, 16384, 32768)
),
# Reference types
"NodePath": NodePath("root/level/player"),
"StringName": &"test_string_name",
}
@@ -0,0 +1 @@
uid://ba73ypvsmf88o
@@ -0,0 +1,26 @@
$schema: "http://json-schema.org/draft-07/schema#"
$id: "res://addons/yaml/examples/data/fimbul.generator.schema.yaml"
title: "Fimbul world generator schema definition"
params:
type: object
properties:
x: float
y: float
noiseScale: float
noise2D: Callable
functions:
type: array
items:
type: object
properties:
name:
type: string
params:
$ref: "http://json-schema.org/draft-07/schema#/definitions/stringArray"
dependencies:
$ref: "http://json-schema.org/draft-07/schema#/definitions/stringArray"
returns:
type: string
required: [name, code]
@@ -0,0 +1 @@
uid://st36arm7pgkb
+47
View File
@@ -0,0 +1,47 @@
[gd_scene load_steps=12 format=3 uid="uid://dogc1x0c3re7o"]
[ext_resource type="Script" uid="uid://cemrjp34s7ujk" path="res://addons/yaml/examples/example_basic_usage.gd" id="1_iyu1q"]
[ext_resource type="Script" uid="uid://ba73ypvsmf88o" path="res://addons/yaml/examples/example_variants.gd" id="4_4pc1t"]
[ext_resource type="Script" uid="uid://00j04245e7jl" path="res://addons/yaml/examples/example_style_system.gd" id="5_61ckj"]
[ext_resource type="Script" uid="uid://bpwc2ppvsfwo5" path="res://addons/yaml/examples/example_multi_document.gd" id="7_wcdgp"]
[ext_resource type="Script" uid="uid://bcyghdxg5kxhk" path="res://addons/yaml/examples/example_speed_benchmark.gd" id="9_eedai"]
[ext_resource type="Script" uid="uid://bdbxqi1f27ndt" path="res://addons/yaml/examples/example_security.gd" id="9_pih52"]
[ext_resource type="Script" uid="uid://eduyiegmiod" path="res://addons/yaml/examples/example_validation.gd" id="10_kxy66"]
[ext_resource type="Script" uid="uid://ch12k840j6ak6" path="res://addons/yaml/examples/example_custom_class.gd" id="33_2d3w6"]
[ext_resource type="Script" uid="uid://d015opxjbyce4" path="res://addons/yaml/examples/example_error_handling.gd" id="34_84xsb"]
[ext_resource type="Script" uid="uid://csoaahlo0042h" path="res://addons/yaml/examples/example_resource_referencing.gd" id="35_jnbc0"]
[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_grb45"]
[node name="Examples" type="Node2D"]
[node name="Basic Usage" type="Node2D" parent="."]
script = ExtResource("1_iyu1q")
[node name="Variants" type="Node2D" parent="."]
script = ExtResource("4_4pc1t")
[node name="Error Handling" type="Node2D" parent="."]
script = ExtResource("34_84xsb")
[node name="Custom Class" type="Node2D" parent="."]
script = ExtResource("33_2d3w6")
[node name="Style System" type="Node2D" parent="."]
script = ExtResource("5_61ckj")
[node name="Resource Referencing" type="Node2D" parent="."]
script = ExtResource("35_jnbc0")
local_texture = SubResource("PlaceholderTexture2D_grb45")
[node name="Security" type="Node2D" parent="."]
script = ExtResource("9_pih52")
[node name="Multiple Documents" type="Node2D" parent="."]
script = ExtResource("7_wcdgp")
[node name="Speech Benchmark" type="Node2D" parent="."]
script = ExtResource("9_eedai")
[node name="Schema Validation" type="Node2D" parent="."]
script = ExtResource("10_kxy66")