Last active
July 11, 2024 23:17
-
-
Save theraot/31515e28e2d8bfea33f6c6d5bcd852f6 to your computer and use it in GitHub Desktop.
BinarySerializer for Godot 4.2+
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@tool | |
class_name BinarySerializer | |
## Utility class to save and load data from StreamPeerBuffer. | |
## Number of bytes in 32 bits. | |
const BITS32 := 4 | |
## Number of bytes in 64 bits. | |
const BITS64 := 8 | |
## Size in bytes of a bool. | |
const TYPE_BOOL_SIZE := 1 | |
## Size in bytes of an int. | |
const TYPE_INT_SIZE := BITS64 | |
## Size in bytes of a float. | |
const TYPE_FLOAT_SIZE := BITS32 # limited to single precision | |
## Size in bytes of a Vector2. | |
const TYPE_VECTOR2_SIZE := TYPE_FLOAT_SIZE * 2 | |
## Size in bytes of a Vector2i. | |
const TYPE_VECTOR2I_SIZE := BITS32 * 2 | |
## Size in bytes of a Rect2. | |
const TYPE_RECT2_SIZE := TYPE_VECTOR2_SIZE * 2 | |
## Size in bytes of a Rect2i. | |
const TYPE_RECT2I_SIZE := TYPE_VECTOR2I_SIZE * 2 | |
## Size in bytes of a Vector3. | |
const TYPE_VECTOR3_SIZE := TYPE_FLOAT_SIZE * 3 | |
## Size in bytes of a Vector3i. | |
const TYPE_VECTOR3I_SIZE := BITS32 * 3 | |
## Size in bytes of a Transform2D. | |
const TYPE_TRANSFORM2D_SIZE := TYPE_VECTOR2_SIZE * 3 | |
## Size in bytes of a Vector4. | |
const TYPE_VECTOR4_SIZE := TYPE_FLOAT_SIZE * 4 | |
## Size in bytes of a Vector4i. | |
const TYPE_VECTOR4I_SIZE := BITS32 * 4 | |
## Size in bytes of a Plane. | |
const TYPE_PLANE_SIZE := TYPE_FLOAT_SIZE * 4 | |
## Size in bytes of a Quaternion. | |
const TYPE_QUATERNION_SIZE := TYPE_FLOAT_SIZE * 4 | |
## Size in bytes of an AABB. | |
const TYPE_AABB_SIZE := TYPE_VECTOR3_SIZE * 2 | |
## Size in bytes of a Basis. | |
const TYPE_BASIS_SIZE := TYPE_VECTOR3_SIZE * 3 | |
## Size in bytes of a Transform3D. | |
const TYPE_TRANSFORM3D_SIZE := TYPE_VECTOR3_SIZE * 4 | |
## Size in bytes of a Projection. | |
const TYPE_PROJECTION_SIZE := TYPE_VECTOR4_SIZE * 4 | |
## Size in bytes of a Color. | |
const TYPE_COLOR_SIZE := TYPE_FLOAT_SIZE * 4 | |
# --------------------- | |
# BOOL | |
# --------------------- | |
## Saves a bool to the StreamPeerBuffer. | |
static func save_bool(buffer:StreamPeerBuffer, input:bool) -> void: | |
if input: | |
buffer.put_u8(1) | |
else: | |
buffer.put_u8(0) | |
## Loads a bool from the StreamPeerBuffer. | |
static func load_bool(buffer:StreamPeerBuffer) -> bool: | |
return buffer.get_u8() != 0 | |
# --------------------- | |
# INT | |
# --------------------- | |
## Saves an int to the StreamPeerBuffer. | |
static func save_int(buffer:StreamPeerBuffer, input:int) -> void: | |
buffer.put_64(input) | |
## Loads an int from the StreamPeerBuffer. | |
static func load_int(buffer:StreamPeerBuffer) -> int: | |
return buffer.get_64() | |
# --------------------- | |
# FLOAT | |
# --------------------- | |
## Saves a float to the StreamPeerBuffer. | |
static func save_float(buffer:StreamPeerBuffer, input:float) -> void: | |
buffer.put_float(input) | |
## Loads a float from the StreamPeerBuffer. | |
static func load_float(buffer:StreamPeerBuffer) -> float: | |
return buffer.get_float() | |
# --------------------- | |
# VECTOR2 | |
# --------------------- | |
## Saves a Vector2 to the StreamPeerBuffer. | |
static func save_vector2(buffer:StreamPeerBuffer, input:Vector2) -> void: | |
save_float(buffer, input.x) | |
save_float(buffer, input.y) | |
## Loads a Vector2 from the StreamPeerBuffer. | |
static func load_vector2(buffer:StreamPeerBuffer) -> Vector2: | |
return Vector2(load_float(buffer), load_float(buffer)) | |
# --------------------- | |
# VECTOR2I | |
# --------------------- | |
## Saves a Vector2i to the StreamPeerBuffer. | |
static func save_vector2i(buffer:StreamPeerBuffer, input:Vector2i) -> void: | |
buffer.put_32(input.x) | |
buffer.put_32(input.y) | |
## Loads a Vector2i from the StreamPeerBuffer. | |
static func load_vector2i(buffer:StreamPeerBuffer) -> Vector2i: | |
return Vector2i(buffer.get_32(), buffer.get_32()) | |
# --------------------- | |
# RECT2 | |
# --------------------- | |
## Saves a Rect2 to the StreamPeerBuffer. | |
static func save_rect2(buffer:StreamPeerBuffer, input:Rect2) -> void: | |
save_vector2(buffer, input.position) | |
save_vector2(buffer, input.size) | |
## Loads a Rect2 from the StreamPeerBuffer. | |
static func load_rect2(buffer:StreamPeerBuffer) -> Rect2: | |
return Rect2(load_vector2(buffer), load_vector2(buffer)) | |
# --------------------- | |
# RECT2I | |
# --------------------- | |
## Saves a Rect2i to the StreamPeerBuffer. | |
static func save_rect2i(buffer:StreamPeerBuffer, input:Rect2i) -> void: | |
save_vector2i(buffer, input.position) | |
save_vector2i(buffer, input.size) | |
## Loads a Rect2i from the StreamPeerBuffer. | |
static func load_rect2i(buffer:StreamPeerBuffer) -> Rect2i: | |
return Rect2i(load_vector2i(buffer), load_vector2i(buffer)) | |
# --------------------- | |
# VECTOR3 | |
# --------------------- | |
## Saves a Vector3 to the StreamPeerBuffer. | |
static func save_vector3(buffer:StreamPeerBuffer, input:Vector3) -> void: | |
save_float(buffer, input.x) | |
save_float(buffer, input.y) | |
save_float(buffer, input.z) | |
## Loads a Vector3 from the StreamPeerBuffer. | |
static func load_vector3(buffer:StreamPeerBuffer) -> Vector3: | |
return Vector3(load_float(buffer), load_float(buffer), load_float(buffer)) | |
# --------------------- | |
# VECTOR3I | |
# --------------------- | |
## Saves a Vector3i to the StreamPeerBuffer. | |
static func save_vector3i(buffer:StreamPeerBuffer, input:Vector3i) -> void: | |
buffer.put_32(input.x) | |
buffer.put_32(input.y) | |
buffer.put_32(input.z) | |
## Loads a Vector3i from the StreamPeerBuffer. | |
static func load_vector3i(buffer:StreamPeerBuffer) -> Vector3i: | |
return Vector3i(buffer.get_32(), buffer.get_32(), buffer.get_32()) | |
# --------------------- | |
# TRANSFORM2D | |
# --------------------- | |
## Saves a Transform2D to the StreamPeerBuffer. | |
static func save_transform2d(buffer:StreamPeerBuffer, input:Transform2D) -> void: | |
save_vector2(buffer, input.x) | |
save_vector2(buffer, input.y) | |
save_vector2(buffer, input.origin) | |
## Loads a Transform2D from the StreamPeerBuffer. | |
static func load_transform2d(buffer:StreamPeerBuffer) -> Transform2D: | |
return Transform2D(load_vector2(buffer), load_vector2(buffer), load_vector2(buffer)) | |
# --------------------- | |
# VECTOR4 | |
# --------------------- | |
## Saves a Vector4 to the StreamPeerBuffer. | |
static func save_vector4(buffer:StreamPeerBuffer, input:Vector4) -> void: | |
save_float(buffer, input.x) | |
save_float(buffer, input.y) | |
save_float(buffer, input.z) | |
save_float(buffer, input.w) | |
## Loads a Vector4 from the StreamPeerBuffer. | |
static func load_vector4(buffer:StreamPeerBuffer) -> Vector4: | |
return Vector4(load_float(buffer), load_float(buffer), load_float(buffer), load_float(buffer)) | |
# --------------------- | |
# VECTOR4I | |
# --------------------- | |
## Saves a Vector4i to the StreamPeerBuffer. | |
static func save_vector4i(buffer:StreamPeerBuffer, input:Vector4i) -> void: | |
buffer.put_32(input.x) | |
buffer.put_32(input.y) | |
buffer.put_32(input.z) | |
buffer.put_32(input.w) | |
## Loads a Vector4i from the StreamPeerBuffer. | |
static func load_vector4i(buffer:StreamPeerBuffer) -> Vector4i: | |
return Vector4i(buffer.get_32(), buffer.get_32(), buffer.get_32(), buffer.get_32()) | |
# --------------------- | |
# PLANE | |
# --------------------- | |
## Saves a Plane to the StreamPeerBuffer. | |
static func save_plane(buffer:StreamPeerBuffer, input:Plane) -> void: | |
save_vector3(buffer, input.normal) | |
save_float(buffer, input.d) | |
## Loads a Plane from the StreamPeerBuffer. | |
static func load_plane(buffer:StreamPeerBuffer) -> Plane: | |
return Plane(load_vector3(buffer), load_float(buffer)) | |
# --------------------- | |
# QUATERNION | |
# --------------------- | |
## Saves a Quaternion to the StreamPeerBuffer. | |
static func save_quaternion(buffer:StreamPeerBuffer, input:Quaternion) -> void: | |
save_float(buffer, input.x) | |
save_float(buffer, input.y) | |
save_float(buffer, input.z) | |
save_float(buffer, input.w) | |
## Loads a Quaternion from the StreamPeerBuffer. | |
static func load_quaternion(buffer:StreamPeerBuffer) -> Quaternion: | |
return Quaternion(load_float(buffer), load_float(buffer), load_float(buffer), load_float(buffer)) | |
# --------------------- | |
# AABB | |
# --------------------- | |
## Saves a AABB to the StreamPeerBuffer. | |
static func save_aabb(buffer:StreamPeerBuffer, input:AABB) -> void: | |
save_vector3(buffer, input.position) | |
save_vector3(buffer, input.size) | |
## Loads a AABB from the StreamPeerBuffer. | |
static func load_aabb(buffer:StreamPeerBuffer) -> AABB: | |
return AABB(load_vector3(buffer), load_vector3(buffer)) | |
# --------------------- | |
# BASIS | |
# --------------------- | |
## Saves a Basis to the StreamPeerBuffer. | |
static func save_basis(buffer:StreamPeerBuffer, input:Basis) -> void: | |
save_vector3(buffer, input.x) | |
save_vector3(buffer, input.y) | |
save_vector3(buffer, input.z) | |
## Loads a Basis from the StreamPeerBuffer. | |
static func load_basis(buffer:StreamPeerBuffer) -> Basis: | |
return Basis(load_vector3(buffer), load_vector3(buffer), load_vector3(buffer)) | |
# --------------------- | |
# TRANSFORM3D | |
# --------------------- | |
## Saves a Transform3D to the StreamPeerBuffer. | |
static func save_transform3d(buffer:StreamPeerBuffer, input:Transform3D) -> void: | |
save_vector3(buffer, input.basis.x) | |
save_vector3(buffer, input.basis.y) | |
save_vector3(buffer, input.basis.z) | |
save_vector3(buffer, input.origin) | |
## Loads a Transform3D from the StreamPeerBuffer. | |
static func load_transform3d(buffer:StreamPeerBuffer) -> Transform3D: | |
return Transform3D(load_vector3(buffer), load_vector3(buffer), load_vector3(buffer), load_vector3(buffer)) | |
# --------------------- | |
# PROJECTION | |
# --------------------- | |
## Saves a Projection to the StreamPeerBuffer. | |
static func save_projection(buffer:StreamPeerBuffer, input:Projection) -> void: | |
save_vector4(buffer, input.x) | |
save_vector4(buffer, input.y) | |
save_vector4(buffer, input.z) | |
save_vector4(buffer, input.w) | |
## Loads a Projection from the StreamPeerBuffer. | |
static func load_projection(buffer:StreamPeerBuffer) -> Projection: | |
return Projection(load_vector4(buffer), load_vector4(buffer), load_vector4(buffer), load_vector4(buffer)) | |
# --------------------- | |
# COLOR | |
# --------------------- | |
## Saves a Color to the StreamPeerBuffer. | |
static func save_color(buffer:StreamPeerBuffer, input:Color) -> void: | |
save_float(buffer, input.r) | |
save_float(buffer, input.g) | |
save_float(buffer, input.b) | |
save_float(buffer, input.a) | |
## Loads a Color from the StreamPeerBuffer. | |
static func load_color(buffer:StreamPeerBuffer) -> Color: | |
return Color(load_float(buffer), load_float(buffer), load_float(buffer), load_float(buffer)) | |
# --------------------- | |
# STRING | |
# --------------------- | |
## Saves a String to the StreamPeerBuffer. | |
static func save_string(buffer:StreamPeerBuffer, input:String) -> void: | |
save_byte_array(buffer, input.to_utf8_buffer()) | |
## Loads a String from the StreamPeerBuffer. | |
static func load_string(buffer:StreamPeerBuffer) -> String: | |
var utf8 := load_byte_array(buffer) | |
return utf8.get_string_from_utf8() | |
# --------------------- | |
# NODEPATH | |
# --------------------- | |
## Saves a StringName to the StreamPeerBuffer. | |
static func save_string_name(buffer:StreamPeerBuffer, input:StringName) -> void: | |
save_string(buffer, str(input)) | |
## Loads a StringName from the StreamPeerBuffer. | |
static func load_string_name(buffer:StreamPeerBuffer) -> StringName: | |
return StringName(load_string(buffer)) | |
# --------------------- | |
# NODEPATH | |
# --------------------- | |
## Saves a NodePath to the StreamPeerBuffer. | |
static func save_node_path(buffer:StreamPeerBuffer, input:NodePath) -> void: | |
save_string(buffer, str(input)) | |
## Loads a NodePath from the StreamPeerBuffer. | |
static func load_node_path(buffer:StreamPeerBuffer) -> NodePath: | |
return NodePath(load_string(buffer)) | |
# --------------------- | |
# RID | |
# --------------------- | |
## Saves a RID to the StreamPeerBuffer. | |
## @deprecated: not supported. | |
static func save_rid(_buffer:StreamPeerBuffer, _input:RID) -> void: | |
pass | |
## Loads a RID from the StreamPeerBuffer. | |
## @deprecated: not supported. | |
static func load_rid(_buffer:StreamPeerBuffer) -> RID: | |
return RID() | |
# --------------------- | |
# OBJECT | |
# --------------------- | |
## Saves a reference to a sub-object to the StreamPeerBuffer. | |
static func save_sub_object_reference(buffer:StreamPeerBuffer, input:Object, objects_to_save:Dictionary, can_save_class:Callable) -> void: | |
var obj := input as Object | |
if is_instance_valid(obj): | |
var name_of_class := obj.get_class() | |
if not can_save_class.is_valid() or can_save_class.call(name_of_class): | |
var x := obj.get_instance_id() | |
save_int(buffer, -2 * x - 1 if x < 0 else x * 2) | |
objects_to_save[obj] = true | |
return | |
save_int(buffer, -1) | |
## Loads a reference to a sub-object from the StreamPeerBuffer. | |
static func load_sub_object_reference(setter:Callable, buffer:StreamPeerBuffer, objects_to_load:Dictionary) -> void: | |
var id := load_int(buffer) | |
if objects_to_load.has(id): | |
var settersArray:Array[Callable] = objects_to_load[id] | |
settersArray.append(setter) | |
else: | |
var setters:Array[Callable] = [setter] | |
objects_to_load[id] = setters | |
# ------------------- | |
## Saves an object to the StreamPeerBuffer. | |
static func save_object(buffer:StreamPeerBuffer, input:Object, can_save_class:Callable) -> bool: | |
var saved_objects := {} | |
var objects_to_save := {} | |
if not save_sub_object(buffer, input, saved_objects, objects_to_save, can_save_class): | |
return false | |
while not objects_to_save.is_empty(): | |
var object:Object = objects_to_save.keys()[0] | |
if not save_sub_object(buffer, object, saved_objects, objects_to_save, can_save_class): | |
return false | |
return true | |
## Saves a sub-object to the StreamPeerBuffer. | |
static func save_sub_object(buffer:StreamPeerBuffer, input:Object, saved_objects:Dictionary, objects_to_save:Dictionary, can_save_class:Callable) -> bool: | |
if input == null: | |
return false | |
objects_to_save.erase(input) | |
if saved_objects.has(input): | |
return true | |
saved_objects[input] = true | |
var name_of_class := input.get_class() | |
if can_save_class.is_valid() and not can_save_class.call(name_of_class): | |
return false | |
@warning_ignore("unsafe_cast") | |
var found_script := input.get_script() as GDScript | |
if found_script != null: | |
name_of_class = ScriptHelper.get_class_name_by_script(found_script) | |
var sub_buffer := StreamPeerBuffer.new() | |
var x := input.get_instance_id() | |
var id := -2 * x - 1 if x < 0 else x * 2 | |
save_int(sub_buffer, id) | |
save_string(sub_buffer, name_of_class) | |
var properties := input.get_property_list() | |
for property in properties: | |
var type:Variant.Type = property["type"] | |
if type == TYPE_NIL: | |
continue | |
var usage:PropertyUsageFlags = property["usage"] | |
if usage & PROPERTY_USAGE_STORAGE == 0: | |
continue | |
var name := str(property["name"]) | |
if ( | |
name == "script" | |
or ( | |
input is Resource | |
and ( | |
name == "resource_local_to_scene" | |
or name == "resource_name" | |
) | |
) | |
): | |
continue | |
var value:Variant = input.get(name) | |
save_string(sub_buffer, name) | |
save_sub_value(sub_buffer, value, type, objects_to_save, can_save_class) | |
save_byte_array(buffer, sub_buffer.data_array) | |
return true | |
# ------------------- | |
## Loads an object from the StreamPeerBuffer. | |
static func load_object(buffer:StreamPeerBuffer, can_load_class:Callable) -> Object: | |
var loaded_objects := {} | |
var objects_to_load := {} | |
var result := load_sub_object(buffer, loaded_objects, objects_to_load, can_load_class) | |
if result == null: | |
return null | |
while ( | |
not objects_to_load.is_empty() | |
and buffer.get_available_bytes() > 0 | |
): | |
load_sub_object(buffer, loaded_objects, objects_to_load, can_load_class) | |
return result | |
## Loads a sub-object from the StreamPeerBuffer. | |
static func load_sub_object(buffer:StreamPeerBuffer, loaded_objects:Dictionary, objects_to_load:Dictionary, can_load_class:Callable) -> Object: | |
var sub_buffer := StreamPeerBuffer.new() | |
sub_buffer.data_array = load_byte_array(buffer) | |
if sub_buffer.get_size() == 0: | |
return null | |
var id := load_int(sub_buffer) | |
if loaded_objects.has(id): | |
var object:Object = loaded_objects[id] | |
return object | |
var name_of_class := load_string(sub_buffer) | |
if can_load_class.is_valid() and not can_load_class.call(name_of_class): | |
return null | |
var result:Object = null | |
if ClassDB.class_exists(name_of_class): | |
result = ClassDB.instantiate(name_of_class) | |
else: | |
var script := ScriptHelper.get_script_by_class_name(name_of_class) | |
if script is GDScript: | |
result = (script as GDScript).new() | |
else: | |
return null | |
var seen_properties := PackedStringArray([]) | |
while sub_buffer.get_available_bytes() > 0: | |
var name := load_string(sub_buffer) | |
seen_properties.append(name) | |
if ( | |
not name in result | |
or name == "script" | |
or ( | |
result is Resource | |
and ( | |
name == "resource_local_to_scene" | |
or name == "resource_name" | |
) | |
) | |
): | |
skip_var(sub_buffer) | |
else: | |
load_sub_value( | |
sub_buffer, | |
func(value:Variant) -> void: | |
result.set(name, value), | |
objects_to_load | |
) | |
var properties := result.get_property_list() | |
for property in properties: | |
var name := str(property["name"]) | |
if seen_properties.has(name): | |
continue | |
var type:Variant.Type = property["type"] | |
if type == TYPE_NIL: | |
continue | |
var usage:PropertyUsageFlags = property["usage"] | |
if usage & PROPERTY_USAGE_STORAGE == 0: | |
continue | |
if ( | |
name == "script" | |
or ( | |
result is Resource | |
and ( | |
name == "resource_local_to_scene" | |
or name == "resource_name" | |
) | |
) | |
): | |
continue | |
result.set(name, result.get(name)) | |
loaded_objects[id] = result | |
if objects_to_load.has(id): | |
var setters:Array[Callable] = objects_to_load[id] | |
for setter in setters: | |
(setter as Callable).call(result) | |
objects_to_load.erase(id) | |
return result | |
# --------------------- | |
# Callable | |
# --------------------- | |
## Saves a Callable to the StreamPeerBuffer. | |
static func save_sub_callable(buffer:StreamPeerBuffer, input:Callable, objects_to_save:Dictionary, can_save_class:Callable) -> void: | |
save_string(buffer, input.get_method()) | |
save_sub_array(buffer, input.get_bound_arguments(), objects_to_save, can_save_class) | |
save_sub_object_reference(buffer, input.get_object(), objects_to_save, can_save_class) | |
## Loads a Callable from the StreamPeerBuffer. | |
static func load_sub_callable(setter:Callable, buffer:StreamPeerBuffer, objects_to_load:Dictionary) -> void: | |
var name := load_string(buffer) | |
var bound_arguments := load_sub_array(buffer, objects_to_load) | |
load_sub_object_reference( | |
func(value:Object) -> void: | |
setter.call(Callable(value, name).bindv(bound_arguments)), | |
buffer, | |
objects_to_load | |
) | |
# --------------------- | |
# RID | |
# --------------------- | |
## Saves a sub-signal to the StreamPeerBuffer. | |
static func save_sub_signal(buffer:StreamPeerBuffer, input:Signal, objects_to_save:Dictionary, can_save_class:Callable) -> void: | |
save_string(buffer, input.get_name()) | |
save_sub_object_reference(buffer, input.get_object(), objects_to_save, can_save_class) | |
## Loads a sub-signal from the StreamPeerBuffer. | |
static func load_sub_signal(setter:Callable, buffer:StreamPeerBuffer, objects_to_load:Dictionary) -> void: | |
var name := load_string(buffer) | |
load_sub_object_reference( | |
func(value:Object) -> void: | |
setter.call(Signal(value, name)), | |
buffer, | |
objects_to_load | |
) | |
# --------------------- | |
# DICTIONARY | |
# --------------------- | |
## Loads a Dictionary to the StreamPeerBuffer. | |
static func save_dictionary(buffer:StreamPeerBuffer, input:Dictionary, can_save_class:Callable) -> bool: | |
var saved_objects := {} | |
var objects_to_save := {} | |
save_sub_dictionary(buffer, input, objects_to_save, can_save_class) | |
while not objects_to_save.is_empty(): | |
var object:Object = objects_to_save.keys()[0] | |
if not save_sub_object(buffer, object, saved_objects, objects_to_save, can_save_class): | |
return false | |
return true | |
## Loads a Dictionary from the StreamPeerBuffer. | |
static func load_dictionary(buffer:StreamPeerBuffer, can_load_class:Callable) -> Dictionary: | |
var loaded_objects := {} | |
var objects_to_load := {} | |
var result:Array = [{}] | |
var setter := func(value:Variant) -> void: | |
result[0] = value | |
load_sub_dictionary(setter, buffer, objects_to_load) | |
while ( | |
not objects_to_load.is_empty() | |
and buffer.get_available_bytes() > 0 | |
): | |
load_sub_object(buffer, loaded_objects, objects_to_load, can_load_class) | |
return result[0] | |
## Saves a Dictionary of a specific type to the StreamPeerBuffer. | |
static func save_dictionary_of(buffer:StreamPeerBuffer, input:Dictionary, value_type:Variant.Type) -> void: | |
match value_type: | |
TYPE_OBJECT: | |
return | |
TYPE_CALLABLE: | |
return | |
TYPE_SIGNAL: | |
return | |
TYPE_DICTIONARY: | |
return | |
TYPE_ARRAY: | |
return | |
var sub_buffer := StreamPeerBuffer.new() | |
for key:Variant in input.keys(): | |
var value:Variant = input[key] | |
save_string(sub_buffer, str(key)) | |
save_simple_value(sub_buffer, value, value_type) | |
save_byte_array(buffer, sub_buffer.data_array) | |
## Loads a Dictionary of a specific type from the StreamPeerBuffer. | |
static func load_dictionary_of(buffer:StreamPeerBuffer, value_type:Variant.Type) -> Dictionary: | |
match value_type: | |
TYPE_OBJECT: | |
return {} | |
TYPE_CALLABLE: | |
return {} | |
TYPE_SIGNAL: | |
return {} | |
TYPE_DICTIONARY: | |
return {} | |
TYPE_ARRAY: | |
return {} | |
var sub_buffer := StreamPeerBuffer.new() | |
sub_buffer.data_array = load_byte_array(buffer) | |
var result := {} | |
while sub_buffer.get_available_bytes() > 0: | |
var key := load_string(sub_buffer) | |
result[key] = load_simple_value(sub_buffer, value_type) | |
return result | |
## Saves a Dictionary to the StreamPeerBuffer. | |
static func save_sub_dictionary(buffer:StreamPeerBuffer, input:Dictionary, objects_to_save:Dictionary, can_save_class:Callable) -> void: | |
var sub_buffer := StreamPeerBuffer.new() | |
for key:Variant in input.keys(): | |
var value:Variant = input[key] | |
save_string(sub_buffer, str(key)) | |
save_sub_value(sub_buffer, value, -1, objects_to_save, can_save_class) | |
save_byte_array(buffer, sub_buffer.data_array) | |
## Loads a Dictionary from the StreamPeerBuffer. | |
static func load_sub_dictionary(setter:Callable, buffer:StreamPeerBuffer, objects_to_load:Dictionary) -> void: | |
var sub_buffer := StreamPeerBuffer.new() | |
sub_buffer.data_array = load_byte_array(buffer) | |
var result := {} | |
var count:Array[int] = [0] | |
while sub_buffer.get_available_bytes() > 0: | |
var key := load_string(sub_buffer) | |
count[0] += 1 | |
load_sub_value( | |
sub_buffer, | |
func(value:Variant) -> void: | |
result[key] = value | |
count[0] -= 1 | |
if count[0] == 0: | |
setter.call(result) | |
, | |
objects_to_load | |
) | |
# --------------------- | |
# ARRAY | |
# --------------------- | |
## Saves an Array to the StreamPeerBuffer. | |
static func save_array(buffer:StreamPeerBuffer, input:Array, can_save_class:Callable) -> bool: | |
var saved_objects := {} | |
var objects_to_save := {} | |
save_sub_array(buffer, input, objects_to_save, can_save_class) | |
while not objects_to_save.is_empty(): | |
var object:Object = objects_to_save.keys()[0] | |
if not save_sub_object(buffer, object, saved_objects, objects_to_save, can_save_class): | |
return false | |
return true | |
## Loads an Array from the StreamPeerBuffer. | |
static func load_array(buffer:StreamPeerBuffer, can_load_class:Callable) -> Array: | |
var loaded_objects := {} | |
var objects_to_load := {} | |
var result := load_sub_array(buffer, objects_to_load) | |
while ( | |
not objects_to_load.is_empty() | |
and buffer.get_available_bytes() > 0 | |
): | |
load_sub_object(buffer, loaded_objects, objects_to_load, can_load_class) | |
return result | |
## Saves an Array of a specific type to the StreamPeerBuffer. | |
static func save_array_of(buffer:StreamPeerBuffer, input:Array, value_type:Variant.Type) -> void: | |
match value_type: | |
TYPE_OBJECT: | |
return | |
TYPE_CALLABLE: | |
return | |
TYPE_SIGNAL: | |
return | |
TYPE_DICTIONARY: | |
return | |
TYPE_ARRAY: | |
return | |
var sub_buffer := StreamPeerBuffer.new() | |
for item:Variant in input: | |
save_simple_value(sub_buffer, item, -1) | |
save_byte_array(buffer, sub_buffer.data_array) | |
## Loads an Array of a specific type from the StreamPeerBuffer. | |
static func load_array_of(buffer:StreamPeerBuffer, value_type:Variant.Type) -> Array: | |
match value_type: | |
TYPE_OBJECT: | |
return [] | |
TYPE_CALLABLE: | |
return [] | |
TYPE_SIGNAL: | |
return [] | |
TYPE_DICTIONARY: | |
return [] | |
TYPE_ARRAY: | |
return [] | |
var sub_buffer := StreamPeerBuffer.new() | |
sub_buffer.data_array = load_byte_array(buffer) | |
var result := [] | |
while sub_buffer.get_available_bytes() > 0: | |
var index := result.size() | |
result.resize(index + 1) | |
result[index] = load_simple_value(sub_buffer, value_type) | |
return result | |
## Saves an Array to the StreamPeerBuffer. | |
static func save_sub_array(buffer:StreamPeerBuffer, input:Array, objects_to_save:Dictionary, can_save_class:Callable) -> void: | |
var sub_buffer := StreamPeerBuffer.new() | |
for item:Variant in input: | |
save_sub_value(sub_buffer, item, -1, objects_to_save, can_save_class) | |
save_byte_array(buffer, sub_buffer.data_array) | |
## Loads an Array from the StreamPeerBuffer. | |
static func load_sub_array(buffer:StreamPeerBuffer, objects_to_load:Dictionary) -> Array: | |
var sub_buffer := StreamPeerBuffer.new() | |
sub_buffer.data_array = load_byte_array(buffer) | |
var result := [] | |
while sub_buffer.get_available_bytes() > 0: | |
var index := result.size() | |
result.resize(index + 1) | |
load_sub_value( | |
sub_buffer, | |
func(value:Variant) -> void: | |
result[index] = value, | |
objects_to_load | |
) | |
return result | |
# --------------------- | |
# BYTE ARRAY | |
# --------------------- | |
## Saves a PackedByteArray to the StreamPeerBuffer. | |
static func save_byte_array(buffer:StreamPeerBuffer, input:PackedByteArray) -> void: | |
buffer.put_32(input.size()) | |
var err := buffer.put_data(input) | |
if err != OK: | |
push_error("Error saving data. Error: " + error_string(err)) | |
## Loads a PackedByteArray from the StreamPeerBuffer. | |
static func load_byte_array(buffer:StreamPeerBuffer) -> PackedByteArray: | |
var size := mini(buffer.get_32(), buffer.get_available_bytes()) | |
var position := buffer.get_position() | |
if position >= buffer.data_array.size(): | |
return PackedByteArray() | |
var result := buffer.data_array.slice(position, position + size) | |
buffer.seek(position + size) | |
return result | |
## Skips a byte array in the StreamPeerBuffer. | |
static func skip_byte_array(buffer:StreamPeerBuffer) -> bool: | |
var size := mini(buffer.get_32(), buffer.get_available_bytes()) | |
var position := buffer.get_position() | |
if position >= buffer.data_array.size(): | |
return false | |
buffer.seek(position + size) | |
return true | |
# --------------------- | |
# INT32 ARRAY | |
# --------------------- | |
## Saves a PackedInt32Array to the StreamPeerBuffer. | |
static func save_int32_array(buffer:StreamPeerBuffer, input:PackedInt32Array) -> void: | |
buffer.put_32(input.size() * BITS32) | |
for item in input: | |
buffer.put_32(item) | |
## Loads a PackedInt32Array from the StreamPeerBuffer. | |
static func load_int32_array(buffer:StreamPeerBuffer) -> PackedInt32Array: | |
var sub_buffer := StreamPeerBuffer.new() | |
sub_buffer.data_array = load_byte_array(buffer) | |
var result := PackedInt32Array() | |
@warning_ignore("integer_division") | |
result.resize(sub_buffer.data_array.size() / BITS32) | |
for index in result.size(): | |
result[index] = buffer.get_32() | |
return result | |
# --------------------- | |
# INT64 ARRAY | |
# --------------------- | |
## Saves a PackedInt64Array to the StreamPeerBuffer. | |
static func save_int64_array(buffer:StreamPeerBuffer, input:PackedInt64Array) -> void: | |
buffer.put_32(input.size() * BITS64) | |
for item in input: | |
buffer.put_64(item) | |
## Loads a PackedInt64Array from the StreamPeerBuffer. | |
static func load_int64_array(buffer:StreamPeerBuffer) -> PackedInt64Array: | |
var sub_buffer := StreamPeerBuffer.new() | |
sub_buffer.data_array = load_byte_array(buffer) | |
var result := PackedInt64Array() | |
@warning_ignore("integer_division") | |
result.resize(sub_buffer.data_array.size() / BITS64) | |
for index in result.size(): | |
result[index] = buffer.get_64() | |
return result | |
# --------------------- | |
# FLOAT32 ARRAY | |
# --------------------- | |
## Saves a PackedFloat32Array to the StreamPeerBuffer. | |
static func save_float32_array(buffer:StreamPeerBuffer, input:PackedFloat32Array) -> void: | |
buffer.put_32(input.size() * BITS32) | |
for item in input: | |
buffer.put_float(item) | |
## Loads a PackedFloat32Array from the StreamPeerBuffer. | |
static func load_float32_array(buffer:StreamPeerBuffer) -> PackedFloat32Array: | |
var sub_buffer := StreamPeerBuffer.new() | |
sub_buffer.data_array = load_byte_array(buffer) | |
var result := PackedFloat32Array() | |
@warning_ignore("integer_division") | |
result.resize(sub_buffer.data_array.size() / BITS32) | |
for index in result.size(): | |
result[index] = buffer.get_float() | |
return result | |
# --------------------- | |
# FLOAT64 ARRAY | |
# --------------------- | |
## Saves a PackedFloat64Array to the StreamPeerBuffer. | |
static func save_float64_array(buffer:StreamPeerBuffer, input:PackedFloat64Array) -> void: | |
buffer.put_32(input.size() * BITS64) | |
for item in input: | |
buffer.put_double(item) | |
## Loads a PackedFloat64Array from the StreamPeerBuffer. | |
static func load_float64_array(buffer:StreamPeerBuffer) -> PackedFloat64Array: | |
var sub_buffer := StreamPeerBuffer.new() | |
sub_buffer.data_array = load_byte_array(buffer) | |
var result := PackedFloat64Array() | |
@warning_ignore("integer_division") | |
result.resize(sub_buffer.data_array.size() / BITS64) | |
for index in result.size(): | |
result[index] = buffer.get_double() | |
return result | |
# --------------------- | |
# STRING ARRAY | |
# --------------------- | |
## Saves a PackedStringArray to the StreamPeerBuffer. | |
static func save_string_array(buffer:StreamPeerBuffer, input:PackedStringArray) -> void: | |
var sub_buffer := StreamPeerBuffer.new() | |
for item in input: | |
save_string(sub_buffer, str(item)) | |
save_byte_array(buffer, sub_buffer.data_array) | |
## Loads a PackedStringArray from the StreamPeerBuffer. | |
static func load_string_array(buffer:StreamPeerBuffer) -> PackedStringArray: | |
var sub_buffer := StreamPeerBuffer.new() | |
sub_buffer.data_array = load_byte_array(buffer) | |
var result := PackedStringArray() | |
while sub_buffer.get_available_bytes() > 0: | |
result.append(load_string(sub_buffer)) | |
return result | |
# --------------------- | |
# VECTOR2 ARRAY | |
# --------------------- | |
## Saves a PackedVector2Array to the StreamPeerBuffer. | |
static func save_vector2_array(buffer:StreamPeerBuffer, input:PackedVector2Array) -> void: | |
buffer.put_32(input.size() * TYPE_VECTOR2_SIZE) | |
for item in input: | |
save_vector2(buffer, item) | |
## Loads a PackedVector2Array from the StreamPeerBuffer. | |
static func load_vector2_array(buffer:StreamPeerBuffer) -> PackedVector2Array: | |
var sub_buffer := StreamPeerBuffer.new() | |
sub_buffer.data_array = load_byte_array(buffer) | |
var result := PackedVector2Array() | |
@warning_ignore("integer_division") | |
result.resize(sub_buffer.data_array.size() / TYPE_VECTOR2_SIZE) | |
for index in result.size(): | |
result[index] = load_vector2(buffer) | |
return result | |
# --------------------- | |
# VECTOR3 ARRAY | |
# --------------------- | |
## Saves a PackedVector3Array to the StreamPeerBuffer. | |
static func save_vector3_array(buffer:StreamPeerBuffer, input:PackedVector3Array) -> void: | |
buffer.put_32(input.size() * TYPE_VECTOR3_SIZE) | |
for item in input: | |
save_vector3(buffer, item) | |
## Loads a PackedVector3Array from the StreamPeerBuffer. | |
static func load_vector3_array(buffer:StreamPeerBuffer) -> PackedVector3Array: | |
var sub_buffer := StreamPeerBuffer.new() | |
sub_buffer.data_array = load_byte_array(buffer) | |
var result := PackedVector3Array() | |
@warning_ignore("integer_division") | |
result.resize(sub_buffer.data_array.size() / TYPE_VECTOR3_SIZE) | |
for index in result.size(): | |
result[index] = load_vector3(buffer) | |
return result | |
# --------------------- | |
# COLOR ARRAY | |
# --------------------- | |
## Saves a PackedColorArray to the StreamPeerBuffer. | |
static func save_color_array(buffer:StreamPeerBuffer, input:PackedColorArray) -> void: | |
buffer.put_32(input.size() * TYPE_COLOR_SIZE) | |
for item in input: | |
save_color(buffer, item) | |
## Loads a PackedColorArray from the StreamPeerBuffer. | |
static func load_color_array(buffer:StreamPeerBuffer) -> PackedColorArray: | |
var sub_buffer := StreamPeerBuffer.new() | |
sub_buffer.data_array = load_byte_array(buffer) | |
var result := PackedColorArray() | |
@warning_ignore("integer_division") | |
result.resize(sub_buffer.data_array.size() / TYPE_COLOR_SIZE) | |
for index in result.size(): | |
result[index] = load_color(buffer) | |
return result | |
# --------------------- | |
# VAR | |
# --------------------- | |
## Saves a simple value to the StreamPeerBuffer. | |
static func save_simple_value(buffer:StreamPeerBuffer, input:Variant, type:int) -> void: | |
match type: | |
TYPE_NIL: | |
pass | |
TYPE_BOOL: | |
var value:bool = input | |
save_bool(buffer, value) | |
TYPE_INT: | |
var value:int = input | |
save_int(buffer, value) | |
TYPE_FLOAT: | |
var value:float = input | |
save_float(buffer, value) | |
TYPE_STRING: | |
var value:String = input | |
save_string(buffer, value) | |
TYPE_VECTOR2: | |
var value:Vector2 = input | |
save_vector2(buffer, value) | |
TYPE_VECTOR2I: | |
var value:Vector2i = input | |
save_vector2i(buffer, value) | |
TYPE_RECT2: | |
var value:Rect2 = input | |
save_rect2(buffer, value) | |
TYPE_RECT2I: | |
var value:Rect2i = input | |
save_rect2i(buffer, value) | |
TYPE_VECTOR3: | |
var value:Vector3 = input | |
save_vector3(buffer, value) | |
TYPE_VECTOR3I: | |
var value:Vector3i = input | |
save_vector3i(buffer, value) | |
TYPE_TRANSFORM2D: | |
var value:Transform2D = input | |
save_transform2d(buffer, value) | |
TYPE_VECTOR4: | |
var value:Vector4 = input | |
save_vector4(buffer, value) | |
TYPE_VECTOR4I: | |
var value:Vector4i = input | |
save_vector4i(buffer, value) | |
TYPE_PLANE: | |
var value:Plane = input | |
save_plane(buffer, value) | |
TYPE_QUATERNION: | |
var value:Quaternion = input | |
save_quaternion(buffer, value) | |
TYPE_AABB: | |
var value:AABB = input | |
save_aabb(buffer, value) | |
TYPE_BASIS: | |
var value:Basis = input | |
save_basis(buffer, value) | |
TYPE_TRANSFORM3D: | |
var value:Transform3D = input | |
save_transform3d(buffer, value) | |
TYPE_PROJECTION: | |
var value:Projection = input | |
save_projection(buffer, value) | |
TYPE_COLOR: | |
var value:Color = input | |
save_color(buffer, value) | |
TYPE_STRING_NAME: | |
var value:StringName = input | |
save_string_name(buffer, value) | |
TYPE_NODE_PATH: | |
var value:NodePath = input | |
save_node_path(buffer, value) | |
TYPE_RID: | |
var value:RID = input | |
save_rid(buffer, value) | |
TYPE_OBJECT: | |
pass | |
TYPE_CALLABLE: | |
pass | |
TYPE_SIGNAL: | |
pass | |
TYPE_DICTIONARY: | |
pass | |
TYPE_ARRAY: | |
pass | |
TYPE_PACKED_BYTE_ARRAY: | |
var value:PackedByteArray = input | |
save_byte_array(buffer, value) | |
TYPE_PACKED_INT32_ARRAY: | |
var value:PackedInt32Array = input | |
save_int32_array(buffer, value) | |
TYPE_PACKED_INT64_ARRAY: | |
var value:PackedInt64Array = input | |
save_int64_array(buffer, value) | |
TYPE_PACKED_FLOAT32_ARRAY: | |
var value:PackedFloat32Array = input | |
save_float32_array(buffer, value) | |
TYPE_PACKED_FLOAT64_ARRAY: | |
var value:PackedFloat64Array = input | |
save_float64_array(buffer, value) | |
TYPE_PACKED_STRING_ARRAY: | |
var value:PackedStringArray = input | |
save_string_array(buffer, value) | |
TYPE_PACKED_VECTOR2_ARRAY: | |
var value:PackedVector2Array = input | |
save_vector2_array(buffer, value) | |
TYPE_PACKED_VECTOR3_ARRAY: | |
var value:PackedVector3Array = input | |
save_vector3_array(buffer, value) | |
TYPE_PACKED_COLOR_ARRAY: | |
var value:PackedColorArray = input | |
save_color_array(buffer, value) | |
_: | |
pass | |
## Saves a sub-value to the StreamPeerBuffer. | |
static func save_sub_value(buffer:StreamPeerBuffer, input:Variant, type:int, objects_to_save:Dictionary, can_save_class:Callable) -> void: | |
if type == -1: | |
type = typeof(input) | |
buffer.put_32(type) | |
match type: | |
TYPE_OBJECT: | |
var value:Object = input | |
save_sub_object_reference(buffer, value, objects_to_save, can_save_class) | |
TYPE_CALLABLE: | |
var value:Callable = input | |
save_sub_callable(buffer, value, objects_to_save, can_save_class) | |
TYPE_SIGNAL: | |
var value:Signal = input | |
save_sub_signal(buffer, value, objects_to_save, can_save_class) | |
TYPE_DICTIONARY: | |
var value:Dictionary = input | |
save_sub_dictionary(buffer, value, objects_to_save, can_save_class) | |
TYPE_ARRAY: | |
var value:Array = input | |
save_sub_array(buffer, value, objects_to_save, can_save_class) | |
_: | |
save_simple_value(buffer, input, type) | |
## Loads a simple value from the StreamPeerBuffer. | |
static func load_simple_value(buffer:StreamPeerBuffer, type:Variant.Type) -> Variant: | |
match type: | |
TYPE_NIL: | |
return null | |
TYPE_BOOL: | |
return load_bool(buffer) | |
TYPE_INT: | |
return load_int(buffer) | |
TYPE_FLOAT: | |
return load_float(buffer) | |
TYPE_STRING: | |
return load_string(buffer) | |
TYPE_VECTOR2: | |
return load_vector2(buffer) | |
TYPE_VECTOR2I: | |
return load_vector2i(buffer) | |
TYPE_RECT2: | |
return load_rect2(buffer) | |
TYPE_RECT2I: | |
return load_rect2i(buffer) | |
TYPE_VECTOR3: | |
return load_vector3(buffer) | |
TYPE_VECTOR3I: | |
return load_vector3i(buffer) | |
TYPE_TRANSFORM2D: | |
return load_transform2d(buffer) | |
TYPE_VECTOR4: | |
return load_vector4(buffer) | |
TYPE_VECTOR4I: | |
return load_vector4i(buffer) | |
TYPE_PLANE: | |
return load_plane(buffer) | |
TYPE_QUATERNION: | |
return load_quaternion(buffer) | |
TYPE_AABB: | |
return load_aabb(buffer) | |
TYPE_BASIS: | |
return load_basis(buffer) | |
TYPE_TRANSFORM3D: | |
return load_transform3d(buffer) | |
TYPE_PROJECTION: | |
return load_projection(buffer) | |
TYPE_COLOR: | |
return load_color(buffer) | |
TYPE_STRING_NAME: | |
return load_string_name(buffer) | |
TYPE_NODE_PATH: | |
return load_node_path(buffer) | |
TYPE_RID: | |
return load_rid(buffer) | |
TYPE_OBJECT: | |
return null | |
TYPE_CALLABLE: | |
return null | |
TYPE_SIGNAL: | |
return null | |
TYPE_DICTIONARY: | |
return null | |
TYPE_ARRAY: | |
return null | |
TYPE_PACKED_BYTE_ARRAY: | |
return load_byte_array(buffer) | |
TYPE_PACKED_INT32_ARRAY: | |
return load_int32_array(buffer) | |
TYPE_PACKED_INT64_ARRAY: | |
return load_int64_array(buffer) | |
TYPE_PACKED_FLOAT32_ARRAY: | |
return load_float32_array(buffer) | |
TYPE_PACKED_FLOAT64_ARRAY: | |
return load_float64_array(buffer) | |
TYPE_PACKED_STRING_ARRAY: | |
return load_string_array(buffer) | |
TYPE_PACKED_VECTOR2_ARRAY: | |
return load_vector2_array(buffer) | |
TYPE_PACKED_VECTOR3_ARRAY: | |
return load_vector3_array(buffer) | |
TYPE_PACKED_COLOR_ARRAY: | |
return load_color_array(buffer) | |
_: | |
return null | |
## Loads a sub-value from the StreamPeerBuffer. | |
static func load_sub_value(buffer:StreamPeerBuffer, setter:Callable, objects_to_load:Dictionary) -> void: | |
var type := buffer.get_32() | |
match type: | |
TYPE_NIL: | |
return | |
TYPE_OBJECT: | |
load_sub_object_reference(setter, buffer, objects_to_load) | |
TYPE_CALLABLE: | |
load_sub_callable(setter, buffer, objects_to_load) | |
TYPE_SIGNAL: | |
load_sub_signal(setter, buffer, objects_to_load) | |
TYPE_DICTIONARY: | |
load_sub_dictionary(setter, buffer, objects_to_load) | |
_: | |
setter.call(load_simple_value(buffer, type)) | |
## Skips a variable in the StreamPeerBuffer. | |
static func skip_var(buffer:StreamPeerBuffer) -> void: | |
var type := buffer.get_32() | |
var position := buffer.get_position() | |
var size := 0 | |
match type: | |
TYPE_NIL: | |
pass | |
TYPE_BOOL: | |
size = TYPE_BOOL_SIZE | |
TYPE_INT: | |
size = TYPE_INT_SIZE | |
TYPE_FLOAT: | |
size = TYPE_FLOAT_SIZE | |
TYPE_STRING: | |
size = buffer.get_32() | |
TYPE_VECTOR2: | |
size = TYPE_VECTOR2_SIZE | |
TYPE_VECTOR2I: | |
size = TYPE_VECTOR2I_SIZE | |
TYPE_RECT2: | |
size = TYPE_RECT2_SIZE | |
TYPE_RECT2I: | |
size = TYPE_RECT2I_SIZE | |
TYPE_VECTOR3: | |
size = TYPE_VECTOR3_SIZE | |
TYPE_VECTOR3I: | |
size = TYPE_VECTOR3I_SIZE | |
TYPE_TRANSFORM2D: | |
size = TYPE_TRANSFORM2D_SIZE | |
TYPE_VECTOR4: | |
size = TYPE_VECTOR4_SIZE | |
TYPE_VECTOR4I: | |
size = TYPE_VECTOR4I_SIZE | |
TYPE_PLANE: | |
size = TYPE_PLANE_SIZE | |
TYPE_QUATERNION: | |
size = TYPE_QUATERNION_SIZE | |
TYPE_AABB: | |
size = TYPE_AABB_SIZE | |
TYPE_BASIS: | |
size = TYPE_BASIS_SIZE | |
TYPE_TRANSFORM3D: | |
size = TYPE_TRANSFORM3D_SIZE | |
TYPE_PROJECTION: | |
size = TYPE_PROJECTION_SIZE | |
TYPE_COLOR: | |
size = TYPE_COLOR_SIZE | |
TYPE_NODE_PATH: | |
size = buffer.get_32() | |
TYPE_RID: | |
pass | |
TYPE_OBJECT: | |
size = buffer.get_32() | |
TYPE_CALLABLE: | |
pass | |
TYPE_SIGNAL: | |
pass | |
TYPE_DICTIONARY: | |
size = buffer.get_32() | |
TYPE_ARRAY: | |
size = buffer.get_32() | |
TYPE_PACKED_BYTE_ARRAY: | |
size = buffer.get_32() | |
TYPE_PACKED_INT32_ARRAY: | |
size = buffer.get_32() | |
TYPE_PACKED_INT64_ARRAY: | |
size = buffer.get_32() | |
TYPE_PACKED_FLOAT32_ARRAY: | |
size = buffer.get_32() | |
TYPE_PACKED_FLOAT64_ARRAY: | |
size = buffer.get_32() | |
TYPE_PACKED_STRING_ARRAY: | |
size = buffer.get_32() | |
TYPE_PACKED_VECTOR2_ARRAY: | |
size = buffer.get_32() | |
TYPE_PACKED_VECTOR3_ARRAY: | |
size = buffer.get_32() | |
TYPE_PACKED_COLOR_ARRAY: | |
size = buffer.get_32() | |
_: | |
pass | |
size = mini(size, buffer.get_available_bytes()) | |
buffer.seek(position + size) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@tool | |
class_name ScriptHelper | |
## Utility to facilitate script and class name management within Godot projects. | |
static var _populated_dictionaries := false | |
static var _script_path_by_class_name := {} | |
static var _class_name_by_script_path := {} | |
## Retrieves the script path associated with a given class name. | |
static func get_script_path_by_class_name(name_of_class:String) -> String: | |
if ClassDB.class_exists(name_of_class): | |
return "" | |
if name_of_class.begins_with("res://"): | |
if ResourceLoader.exists(name_of_class, "Script"): | |
return name_of_class | |
else: | |
return "" | |
_ensure_dictionaries_are_populated() | |
if _script_path_by_class_name.has(name_of_class): | |
var path:String = _script_path_by_class_name[name_of_class] | |
return path | |
return "" | |
## Retrieves the Script resource associated with a given class name. | |
static func get_script_by_class_name(name_of_class:String) -> Script: | |
if ClassDB.class_exists(name_of_class): | |
return null | |
var path := get_script_path_by_class_name(name_of_class) | |
if path.is_empty(): | |
return null | |
var result := ResourceLoader.load(path, "Script") as Script | |
return result | |
## Retrieves the class name associated with a given Script resource. | |
static func get_class_name_by_script(script:Script) -> String: | |
if script == null: | |
return "" | |
_ensure_dictionaries_are_populated() | |
var path := script.resource_path | |
if _class_name_by_script_path.has(path): | |
var name_of_class:String = _class_name_by_script_path[path] | |
return name_of_class | |
return script.resource_path | |
## Determines whether a class is derived from another class, either directly or indirectly. | |
## This method supports both built-in Godot classes and custom script classes. | |
static func is_class_derived(name_of_class:String, name_of_parent_class:String) -> bool: | |
if ClassDB.class_exists(name_of_class): | |
if ClassDB.class_exists(name_of_parent_class): | |
return name_of_class == name_of_parent_class or ClassDB.is_parent_class(name_of_class, name_of_parent_class) | |
return false | |
var class_script := get_script_by_class_name(name_of_class) | |
if class_script == null: | |
return false | |
if ClassDB.class_exists(name_of_parent_class): | |
name_of_class = class_script.get_instance_base_type() | |
return name_of_class == name_of_parent_class or ClassDB.is_parent_class(name_of_class, name_of_parent_class) | |
return is_script_derived(class_script, get_script_by_class_name(name_of_parent_class)) | |
## Determines whether a script is derived from another script, either directly or indirectly. | |
static func is_script_derived(script:Script, parent_script:Script) -> bool: | |
# MUST CHECK FOR NULL | |
if script == null or parent_script == null: | |
return false | |
while script != null: | |
if script == parent_script: | |
return true | |
script = script.get_base_script() | |
return false | |
static func _ensure_dictionaries_are_populated() -> void: | |
if _populated_dictionaries: | |
return | |
for global_class in ProjectSettings.get_global_class_list(): | |
var found_name_of_class:String = global_class["class"] | |
var found_path:String = global_class["path"] | |
_script_path_by_class_name[found_name_of_class] = found_path | |
_class_name_by_script_path[found_path] = found_name_of_class | |
_populated_dictionaries = true |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment