added firebase and rudimentary leaderboard support

This commit is contained in:
derek
2025-04-09 11:19:02 -05:00
parent ce08df66e6
commit 25eb9e725a
121 changed files with 4987 additions and 4 deletions

View File

@@ -0,0 +1,185 @@
## @meta-authors Kyle Szklenski
## @meta-version 2.2
## A reference to a Firestore Document.
## Documentation TODO.
@tool
class_name FirestoreDocument
extends Node
# A FirestoreDocument objects that holds all important values for a Firestore Document,
# @doc_name = name of the Firestore Document, which is the request PATH
# @doc_fields = fields held by Firestore Document, in APIs format
# created when requested from a `collection().get()` call
var document : Dictionary # the Document itself
var doc_name : String # only .name
var create_time : String # createTime
var collection_name : String # Name of the collection to which it belongs
var _transforms : FieldTransformArray # The transforms to apply
signal changed(changes)
func _init(doc : Dictionary = {}):
_transforms = FieldTransformArray.new()
if doc.has("fields"):
document = doc.fields
if doc.has("name"):
doc_name = doc.name
if doc_name.count("/") > 2:
doc_name = (doc_name.split("/") as Array).back()
if doc.has("createTime"):
self.create_time = doc.createTime
func replace(with : FirestoreDocument, is_listener := false) -> void:
var current = document.duplicate()
document = with.document
var changes = {
"added": [], "removed": [], "updated": [], "is_listener": is_listener
}
for key in current.keys():
if not document.has(key):
changes.removed.push_back({ "key" : key })
else:
var new_value = Utilities.from_firebase_type(document[key])
var old_value = Utilities.from_firebase_type(current[key])
if typeof(new_value) != typeof(old_value) or new_value != old_value:
if old_value == null:
changes.removed.push_back({ "key" : key }) # ??
else:
changes.updated.push_back({ "key" : key, "old": old_value, "new" : new_value })
for key in document.keys():
if not current.has(key):
changes.added.push_back({ "key" : key, "new" : Utilities.from_firebase_type(document[key]) })
if not (changes.added.is_empty() and changes.removed.is_empty() and changes.updated.is_empty()):
changed.emit(changes)
func new_document(base_document: Dictionary) -> void:
var current = document.duplicate()
document = {}
for key in base_document.keys():
document[key] = Utilities.to_firebase_type(key)
var changes = {
"added": [], "removed": [], "updated": [], "is_listener": false
}
for key in current.keys():
if not document.has(key):
changes.removed.push_back({ "key" : key })
else:
var new_value = Utilities.from_firebase_type(document[key])
var old_value = Utilities.from_firebase_type(current[key])
if typeof(new_value) != typeof(old_value) or new_value != old_value:
if old_value == null:
changes.removed.push_back({ "key" : key }) # ??
else:
changes.updated.push_back({ "key" : key, "old": old_value, "new" : new_value })
for key in document.keys():
if not current.has(key):
changes.added.push_back({ "key" : key, "new" : Utilities.from_firebase_type(document[key]) })
if not (changes.added.is_empty() and changes.removed.is_empty() and changes.updated.is_empty()):
changed.emit(changes)
func is_null_value(key) -> bool:
return document.has(key) and Utilities.from_firebase_type(document[key]) == null
# As of right now, we do not track these with track changes; instead, they'll come back when the document updates from the server.
# Until that time, it's expected if you want to track these types of changes that you commit for the transforms and then get the document yourself.
func add_field_transform(transform : FieldTransform) -> void:
_transforms.push_back(transform)
func remove_field_transform(transform : FieldTransform) -> void:
_transforms.erase(transform)
func clear_field_transforms() -> void:
_transforms.transforms.clear()
func remove_field(field_path : String) -> void:
if document.has(field_path):
document[field_path] = Utilities.to_firebase_type(null)
var changes = {
"added": [], "removed": [], "updated": [], "is_listener": false
}
changes.removed.push_back({ "key" : field_path })
changed.emit(changes)
func _erase(field_path : String) -> void:
document.erase(field_path)
func add_or_update_field(field_path : String, value : Variant) -> void:
var changes = {
"added": [], "removed": [], "updated": [], "is_listener": false
}
var existing_value = get_value(field_path)
var has_field_path = existing_value != null and not is_null_value(field_path)
var converted_value = Utilities.to_firebase_type(value)
document[field_path] = converted_value
if has_field_path:
changes.updated.push_back({ "key" : field_path, "old" : existing_value, "new" : value })
else:
changes.added.push_back({ "key" : field_path, "new" : value })
changed.emit(changes)
func on_snapshot(when_called : Callable, poll_time : float = 1.0) -> FirestoreListener.FirestoreListenerConnection:
if get_child_count() >= 1: # Only one listener per
assert(false, "Multiple listeners not allowed for the same document yet")
return
changed.connect(when_called, CONNECT_REFERENCE_COUNTED)
var listener = preload("res://addons/godot-firebase/firestore/firestore_listener.tscn").instantiate()
add_child(listener)
listener.initialize_listener(collection_name, doc_name, poll_time)
listener.owner = self
var result = listener.enable_connection()
return result
func get_value(property : StringName) -> Variant:
if property == "doc_name":
return doc_name
elif property == "collection_name":
return collection_name
elif property == "create_time":
return create_time
if document.has(property):
var result = Utilities.from_firebase_type(document[property])
return result
return null
func _get(property: StringName) -> Variant:
return get_value(property)
func _set(property: StringName, value: Variant) -> bool:
assert(value != null, "When using the dictionary setter, the value cannot be null; use erase_field instead.")
document[property] = Utilities.to_firebase_type(value)
return true
func get_unsafe_document() -> Dictionary:
var result = {}
for key in keys():
result[key] = Utilities.from_firebase_type(document[key])
return result
func keys():
return document.keys()
# Call print(document) to return directly this document formatted
func _to_string() -> String:
return ("doc_name: {doc_name}, \ndata: {data}, \ncreate_time: {create_time}\n").format(
{doc_name = self.doc_name,
data = document,
create_time = self.create_time})