Skip to content

Instantly share code, notes, and snippets.

@danielocampo2
Last active June 16, 2024 01:19
Show Gist options
  • Save danielocampo2/ed9dbca9eaffeec4e2872631aa13e3b5 to your computer and use it in GitHub Desktop.
Save danielocampo2/ed9dbca9eaffeec4e2872631aa13e3b5 to your computer and use it in GitHub Desktop.
Serializable class for Godot
class_name Serializable
extends Object
# Serializable classes cannot have a constructor as an empty one is needed. Resort to static
# create function for easier object creation.
# Convert instance to a dictionary.
func to_dict() -> Dictionary:
var result = {
"_type": get_script().get_path() # This is a reference to the class/script type.
}
for property in self.get_property_list():
if property.usage & PROPERTY_USAGE_SCRIPT_VARIABLE:
if property.type == Variant.Type.TYPE_OBJECT:
var object = get(property.name)
if object is Serializable:
result[property.name] = object.to_dict()
elif property.type == Variant.Type.TYPE_DICTIONARY:
var dict = get(property.name)
var dict_result = _convert_dictionary(dict)
result[property.name] = dict_result
elif property.type == Variant.Type.TYPE_ARRAY:
var array = get(property.name)
result[property.name] = _convert_array(array)
else:
result[property.name] = get(property.name)
return result
# Array of dictionaries is not supported, use a Serializable object instead.
func _convert_array(array: Array):
var result_array = []
for i in array:
if i is Serializable:
result_array.append(i.to_dict())
else:
result_array.append(i)
return result_array
func _convert_dictionary(dict: Dictionary):
var dict_result = {}
for k in dict.keys():
var value = dict[k]
if value is Dictionary:
dict_result[k] = _convert_dictionary(value)
elif value is Array:
dict_result[k] = _convert_array(value)
elif value is Serializable:
dict_result[k] = value.to_dict()
else:
dict_result[k] = value
return dict_result
func to_json() -> String:
var dict = to_dict()
return JSON.stringify(dict)
# Populate the instance from a dictionary.
# Arrays included cannot be typed in their definition due to limitations with GDScript
# e.g: if you have an Array[CustomClass] you should change only its definition to be just Array
static func from_dict(data: Dictionary):
var instance
if data.has("_type"):
instance = load(data["_type"]).new()
else:
instance = {}
for key in data.keys():
if key != "_type":
var value = data[key]
if value is Dictionary:
var dict = from_dict(value)
set_value(instance, key, dict)
elif value is Array:
var result_array = []
for e in value:
if e is Dictionary:
var dict = from_dict(e)
result_array.append(dict)
else:
result_array.append(e)
set_value(instance, key, result_array)
else:
set_value(instance, key, data[key])
return instance
static func set_value(object, key, value):
if object is Dictionary:
object[key] = value
else:
object.set(key, value)
static func from_json(json_string: String):
var json = JSON.new()
var parse_result = json.parse(json_string)
if not parse_result == OK:
print("JSON Parse Error: ", json.get_error_message(), " in ", json_string, " at line ", json.get_error_line())
return null
var dict = from_dict(json.data)
return dict
@danielocampo2
Copy link
Author

I have expanded on alphahex_99 base script to support objects, dictionaries and arrays.
https://www.reddit.com/r/godot/comments/170r2pb/serializingdeserializing_custom_objects_fromto/

Credit to him/her for the original code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment