chore: refactor of object manager to use array of objects instead of untyped dictionary.
This commit is contained in:
committed by
Julian Murgia
parent
82acf8374d
commit
01d7d041cd
@@ -15,49 +15,63 @@ const RESERVED_OBJECTS = [
|
|||||||
CAMERA
|
CAMERA
|
||||||
]
|
]
|
||||||
|
|
||||||
# Separator to use for each room's entry in the objects dictionary.
|
# The array of registered objects (organized by room, incl. one "room" for
|
||||||
const SEPARATOR = "!!!!"
|
# reserved objects).
|
||||||
|
|
||||||
# Dictionary key for reserved objects.
|
|
||||||
const RESERVED_KEY = "reserved"
|
|
||||||
|
|
||||||
# The hash of registered objects (organized by room, with the object's global id
|
|
||||||
# serving as the object's key).
|
|
||||||
#
|
#
|
||||||
# Example structure:
|
# Example structure:
|
||||||
#
|
#
|
||||||
# {
|
# [
|
||||||
# "reserved":
|
# {
|
||||||
# {
|
# is_reserved: true,
|
||||||
# "_camera": camera
|
# room: "",
|
||||||
# },
|
# room_instance_id: "",
|
||||||
# "room1!!!!<instance_id>":
|
# objects:
|
||||||
# {
|
# {
|
||||||
# "obj1": val1,
|
# "_camera": camera
|
||||||
# "obj2": val2
|
# },
|
||||||
# }
|
# },
|
||||||
# }
|
# {
|
||||||
|
# is_reserved: false,
|
||||||
|
# room_global_id: "<room_global_id>",
|
||||||
|
# room_instance_id: "<room_object_instance_id>",
|
||||||
|
# objects:
|
||||||
|
# {
|
||||||
|
# "obj1": val1,
|
||||||
|
# "obj2": val2
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# ]
|
||||||
#
|
#
|
||||||
# Note that the "reserved" entry cannot be altered or otherwise changed and
|
# Note that the "is_reserved" entry cannot be altered or otherwise changed and
|
||||||
# that it belongs to no specific room.
|
# that it belongs to no specific room.
|
||||||
var objects: Dictionary = {RESERVED_KEY: {}}
|
var room_objects: Array = []
|
||||||
|
|
||||||
# We also store the current room's complete key in objects for convenience.
|
# We also store the current room's ids for retrieving the right objects.
|
||||||
var current_room_key: String = ""
|
var current_room_key: ESCRoomObjectsKey
|
||||||
|
|
||||||
|
# To avoid having to look this up all the time, we hold a reference.
|
||||||
|
var reserved_objects_container: ESCRoomObjects
|
||||||
|
|
||||||
# Use this to track the room we just exited for the purpose o
|
# Use this to track the room we just exited for the purpose o
|
||||||
var prev_room_key: String = ""
|
var prev_room_key: String = ""
|
||||||
|
|
||||||
|
|
||||||
|
func _init() -> void:
|
||||||
|
reserved_objects_container = ESCRoomObjects.new()
|
||||||
|
reserved_objects_container.is_reserved = true
|
||||||
|
reserved_objects_container.objects = {}
|
||||||
|
room_objects.push_back(reserved_objects_container)
|
||||||
|
|
||||||
|
current_room_key = ESCRoomObjectsKey.new()
|
||||||
|
|
||||||
|
|
||||||
# Make active objects in current room visible
|
# Make active objects in current room visible
|
||||||
func _process(_delta):
|
func _process(_delta):
|
||||||
for object in objects[current_room_key]:
|
for room in room_objects:
|
||||||
if (object as ESCObject).node:
|
if room.is_reserved or _is_current_room(room):
|
||||||
(object as ESCObject).node.visible = (object as ESCObject).active
|
for object in room.objects:
|
||||||
|
if (object as ESCObject).node:
|
||||||
for object in objects[RESERVED_KEY]:
|
(object as ESCObject).node.visible = (object as ESCObject).active
|
||||||
if (object as ESCObject).node:
|
|
||||||
(object as ESCObject).node.visible = (object as ESCObject).active
|
|
||||||
|
|
||||||
|
|
||||||
# Updates which object manager room is to be treated as the currently active one.
|
# Updates which object manager room is to be treated as the currently active one.
|
||||||
@@ -74,7 +88,8 @@ func set_current_room(room: ESCRoom) -> void:
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
current_room_key = _make_room_key(room)
|
current_room_key.room_global_id = room.global_id
|
||||||
|
current_room_key.room_instance_id = room.get_instance_id()
|
||||||
|
|
||||||
|
|
||||||
# Register the object in the manager
|
# Register the object in the manager
|
||||||
@@ -104,17 +119,20 @@ func register_object(object: ESCObject, room: ESCRoom = null, force: bool = fals
|
|||||||
# Note that we also don't allow it to auto unregister and, as such, we need
|
# Note that we also don't allow it to auto unregister and, as such, we need
|
||||||
# to make sure we clean these up when the application exits.
|
# to make sure we clean these up when the application exits.
|
||||||
if object.global_id in RESERVED_OBJECTS:
|
if object.global_id in RESERVED_OBJECTS:
|
||||||
objects[RESERVED_KEY][object.global_id] = object
|
reserved_objects_container.objects[object.global_id] = object
|
||||||
return
|
return
|
||||||
|
|
||||||
var room_key: String = ""
|
var room_key: ESCRoomObjectsKey = ESCRoomObjectsKey.new()
|
||||||
|
|
||||||
# If a room was passed in, then we're going to register the object with it;
|
# If a room was passed in, then we're going to register the object with it;
|
||||||
# otherwise, we register the object with the "current room".
|
# otherwise, we register the object with the "current room".
|
||||||
if room == null or room.global_id.empty():
|
if room == null or room.global_id.empty():
|
||||||
room_key = current_room_key
|
# We duplicate the key so as to not hold a reference when current_room_key
|
||||||
|
# changes.
|
||||||
|
room_key.room_global_id = current_room_key.room_global_id
|
||||||
|
room_key.room_instance_id = current_room_key.room_instance_id
|
||||||
|
|
||||||
if room_key.empty():
|
if not room_key.is_valid():
|
||||||
escoria.logger.report_errors(
|
escoria.logger.report_errors(
|
||||||
"ESCObjectManager:register_object()",
|
"ESCObjectManager:register_object()",
|
||||||
[
|
[
|
||||||
@@ -122,9 +140,11 @@ func register_object(object: ESCObject, room: ESCRoom = null, force: bool = fals
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
room_key = _make_room_key(room)
|
room_key = ESCRoomObjectsKey.new()
|
||||||
|
room_key.room_global_id = room.global_id
|
||||||
|
room_key.room_instance_id = room.get_instance_id()
|
||||||
|
|
||||||
if objects.has(room_key) and objects[room_key].has(object.global_id):
|
if _object_exists_in_room(object, room_key):
|
||||||
if force:
|
if force:
|
||||||
# If this ID already exists and we're about to overwrite it, do the
|
# If this ID already exists and we're about to overwrite it, do the
|
||||||
# safe thing and unregister the old object first
|
# safe thing and unregister the old object first
|
||||||
@@ -133,14 +153,16 @@ func register_object(object: ESCObject, room: ESCRoom = null, force: bool = fals
|
|||||||
escoria.logger.report_errors(
|
escoria.logger.report_errors(
|
||||||
"ESCObjectManager:register_object()",
|
"ESCObjectManager:register_object()",
|
||||||
[
|
[
|
||||||
"Object with global id %s in room %s already registered" %
|
"Object with global id %s in room (%s, %s) already registered" %
|
||||||
|
[
|
||||||
object.global_id,
|
object.global_id,
|
||||||
room_key
|
room_key.room_global_id,
|
||||||
|
room_key.room_instance_id
|
||||||
|
]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
# If the object is already connected, disconnect it for the case of
|
# If the object is already connected, disconnect it for the case of
|
||||||
# forcing the registration,since we don't know if this object will be
|
# forcing the registration,since we don't know if this object will be
|
||||||
@@ -174,10 +196,19 @@ func register_object(object: ESCObject, room: ESCRoom = null, force: bool = fals
|
|||||||
)
|
)
|
||||||
object.events = script.events
|
object.events = script.events
|
||||||
|
|
||||||
if not objects.has(room_key):
|
var objects: Dictionary = _get_room_objects_objects(room_key)
|
||||||
objects[room_key] = {}
|
objects[object.global_id] = object
|
||||||
|
|
||||||
objects[room_key][object.global_id] = object
|
# If this is the first object for the room, that means we have a brand new
|
||||||
|
# room and it needs to be setup and tracked.
|
||||||
|
if objects.size() == 1:
|
||||||
|
var room_container: ESCRoomObjects = ESCRoomObjects.new()
|
||||||
|
room_container.room_global_id = room_key.room_global_id
|
||||||
|
room_container.room_instance_id = room_key.room_instance_id
|
||||||
|
room_container.is_reserved = false
|
||||||
|
room_container.objects = objects
|
||||||
|
|
||||||
|
room_objects.push_back(room_container)
|
||||||
|
|
||||||
|
|
||||||
# Check whether an object was registered
|
# Check whether an object was registered
|
||||||
@@ -189,12 +220,12 @@ func register_object(object: ESCObject, room: ESCRoom = null, force: bool = fals
|
|||||||
# **Returns** Whether the object exists in the object registry
|
# **Returns** Whether the object exists in the object registry
|
||||||
func has(global_id: String, room: ESCRoom = null) -> bool:
|
func has(global_id: String, room: ESCRoom = null) -> bool:
|
||||||
if global_id in RESERVED_OBJECTS:
|
if global_id in RESERVED_OBJECTS:
|
||||||
if objects[RESERVED_KEY] == null:
|
if reserved_objects_container == null:
|
||||||
return false
|
return false
|
||||||
|
|
||||||
return objects[RESERVED_KEY].has(global_id)
|
return reserved_objects_container.objects.has(global_id)
|
||||||
|
|
||||||
var room_key: String = ""
|
var room_key: ESCRoomObjectsKey
|
||||||
|
|
||||||
if room == null:
|
if room == null:
|
||||||
escoria.logger.trace("ESCObjectManager.has(): No room specified." \
|
escoria.logger.trace("ESCObjectManager.has(): No room specified." \
|
||||||
@@ -203,12 +234,14 @@ func has(global_id: String, room: ESCRoom = null) -> bool:
|
|||||||
|
|
||||||
room_key = current_room_key
|
room_key = current_room_key
|
||||||
else:
|
else:
|
||||||
room_key = _make_room_key(room)
|
room_key = ESCRoomObjectsKey.new()
|
||||||
|
room_key.room_global_id = room.global_id
|
||||||
if objects[room_key] == null:
|
room_key.room_instance_id = room.get_instance_id()
|
||||||
|
|
||||||
|
if not _room_exists(room_key):
|
||||||
return false
|
return false
|
||||||
|
|
||||||
return objects[room_key].has(global_id)
|
return _object_exists_in_room(ESCObject.new(global_id, null), room_key)
|
||||||
|
|
||||||
|
|
||||||
# Get the object from the object registry
|
# Get the object from the object registry
|
||||||
@@ -220,8 +253,8 @@ func has(global_id: String, room: ESCRoom = null) -> bool:
|
|||||||
# **Returns** The retrieved object, or null if not found
|
# **Returns** The retrieved object, or null if not found
|
||||||
func get_object(global_id: String, room: ESCRoom = null) -> ESCObject:
|
func get_object(global_id: String, room: ESCRoom = null) -> ESCObject:
|
||||||
if global_id in RESERVED_OBJECTS:
|
if global_id in RESERVED_OBJECTS:
|
||||||
if objects[RESERVED_KEY].has(global_id):
|
if reserved_objects_container.objects.has(global_id):
|
||||||
return objects[RESERVED_KEY][global_id]
|
return reserved_objects_container.objects[global_id]
|
||||||
else:
|
else:
|
||||||
escoria.logger.report_warnings(
|
escoria.logger.report_warnings(
|
||||||
"ESCObjectManager:get_object()",
|
"ESCObjectManager:get_object()",
|
||||||
@@ -233,7 +266,7 @@ func get_object(global_id: String, room: ESCRoom = null) -> ESCObject:
|
|||||||
)
|
)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
var room_key: String = ""
|
var room_key: ESCRoomObjectsKey
|
||||||
|
|
||||||
if room == null:
|
if room == null:
|
||||||
escoria.logger.trace("ESCObjectManager.has(): No room specified." \
|
escoria.logger.trace("ESCObjectManager.has(): No room specified." \
|
||||||
@@ -242,28 +275,31 @@ func get_object(global_id: String, room: ESCRoom = null) -> ESCObject:
|
|||||||
|
|
||||||
room_key = current_room_key
|
room_key = current_room_key
|
||||||
else:
|
else:
|
||||||
room_key = _make_room_key(room)
|
room_key.room_global_id = room.global_id
|
||||||
|
room_key.room_instance_id = room.get_instance_id()
|
||||||
|
|
||||||
if objects[room_key] == null:
|
if not _room_exists(room_key):
|
||||||
escoria.logger.report_warnings(
|
escoria.logger.report_warnings(
|
||||||
"ESCObjectManager:get_object()",
|
"ESCObjectManager:get_object()",
|
||||||
[
|
[
|
||||||
"Specified room empty/not found.",
|
"Specified room empty/not found.",
|
||||||
"Object with global id %s in room instance %s not found"
|
"Object with global id %s in room instance (%s, %s) not found"
|
||||||
% global_id, room_key
|
% [global_id, room_key.room_global_id, room_key.room_instance_id]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
if objects[room_key].has(global_id):
|
var objects: Dictionary = _get_room_objects_objects(room_key)
|
||||||
return objects[room_key][global_id]
|
|
||||||
|
if objects.has(global_id):
|
||||||
|
return objects[global_id]
|
||||||
else:
|
else:
|
||||||
escoria.logger.report_warnings(
|
escoria.logger.report_warnings(
|
||||||
"ESCObjectManager:get_object()",
|
"ESCObjectManager:get_object()",
|
||||||
[
|
[
|
||||||
"Invalid object retrieved.",
|
"Invalid object retrieved.",
|
||||||
"Object with global id %s in room instance %s not found"
|
"Object with global id %s in room instance (%s, %s) not found"
|
||||||
% global_id, room_key
|
% [global_id, room_key.room_global_id, room_key.room_instance_id]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
return null
|
return null
|
||||||
@@ -275,26 +311,33 @@ func get_object(global_id: String, room: ESCRoom = null) -> ESCObject:
|
|||||||
#
|
#
|
||||||
# - object: The object to unregister
|
# - object: The object to unregister
|
||||||
# - room_key: The room under which the object should be unregistered.
|
# - room_key: The room under which the object should be unregistered.
|
||||||
func unregister_object(object: ESCObject, room_key: String) -> void:
|
func unregister_object(object: ESCObject, room_key: ESCRoomObjectsKey) -> void:
|
||||||
if objects[room_key] == null:
|
if not _object_exists_in_room(object, room_key):
|
||||||
escoria.logger.report_errors(
|
escoria.logger.report_errors(
|
||||||
"ESCObjectManager:unregister_object()",
|
"ESCObjectManager:unregister_object()",
|
||||||
[
|
[
|
||||||
"Unable to unregister object.",
|
"Unable to unregister object.",
|
||||||
"Room with key %s not found." % room_key
|
"Object with global ID %s room (%s, %s) not found." %
|
||||||
|
[
|
||||||
|
"?" if object == null else object.global_id,
|
||||||
|
room_key.room_global_id,
|
||||||
|
room_key.room_instance_id
|
||||||
|
]
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var objects = _get_room_objects_objects(room_key)
|
||||||
|
|
||||||
if not escoria.inventory_manager.inventory_has(object.global_id):
|
if not escoria.inventory_manager.inventory_has(object.global_id):
|
||||||
objects[room_key].erase(object.global_id)
|
objects.erase(object.global_id)
|
||||||
else:
|
else:
|
||||||
# Re-instance the node if it is an item present in inventory.
|
# Re-instance the node if it is an item present in inventory.
|
||||||
objects[room_key][object.global_id].node = \
|
objects[object.global_id].node = \
|
||||||
objects[room_key][object.global_id].node.duplicate()
|
objects[object.global_id].node.duplicate()
|
||||||
|
|
||||||
# If this room is truly empty, it's time to do away with it.
|
# If this room is truly empty, it's time to do away with it.
|
||||||
if objects[room_key].size() == 0:
|
if objects.size() == 0:
|
||||||
objects.erase(room_key)
|
_erase_room(room_key)
|
||||||
|
|
||||||
|
|
||||||
# Remove an object from the registry by global_id
|
# Remove an object from the registry by global_id
|
||||||
@@ -303,7 +346,7 @@ func unregister_object(object: ESCObject, room_key: String) -> void:
|
|||||||
#
|
#
|
||||||
# - global_id: The global_id of the object to unregister
|
# - global_id: The global_id of the object to unregister
|
||||||
# - room_key: The room under which the object should be unregistered.
|
# - room_key: The room under which the object should be unregistered.
|
||||||
func unregister_object_by_global_id(global_id: String, room_key: String) -> void:
|
func unregister_object_by_global_id(global_id: String, room_key: ESCRoomObjectsKey) -> void:
|
||||||
unregister_object(ESCObject.new(global_id, null), room_key)
|
unregister_object(ESCObject.new(global_id, null), room_key)
|
||||||
|
|
||||||
|
|
||||||
@@ -314,25 +357,28 @@ func unregister_object_by_global_id(global_id: String, room_key: String) -> void
|
|||||||
#
|
#
|
||||||
# - p_savegame: The savegame resource
|
# - p_savegame: The savegame resource
|
||||||
func save_game(p_savegame: ESCSaveGame) -> void:
|
func save_game(p_savegame: ESCSaveGame) -> void:
|
||||||
if current_room_key.empty() or objects[current_room_key] == null:
|
if not current_room_key.is_valid() or not _room_exists(current_room_key):
|
||||||
escoria.logger.report_errors(
|
escoria.logger.report_errors(
|
||||||
"ESCObjectManager:save_game()",
|
"ESCObjectManager:save_game()",
|
||||||
[
|
[
|
||||||
"No current room specified or found."
|
"No current room specified or found."
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var objects: Dictionary = _get_room_objects_objects(current_room_key)
|
||||||
|
|
||||||
p_savegame.objects = {}
|
p_savegame.objects = {}
|
||||||
for obj_global_id in objects[current_room_key]:
|
|
||||||
if !objects[current_room_key][obj_global_id] is ESCObject:
|
for obj_global_id in objects:
|
||||||
|
if not objects[obj_global_id] is ESCObject:
|
||||||
continue
|
continue
|
||||||
p_savegame.objects[current_room_key][obj_global_id] = \
|
p_savegame.objects[obj_global_id] = \
|
||||||
objects[current_room_key][obj_global_id].get_save_data()
|
objects[obj_global_id].get_save_data()
|
||||||
|
|
||||||
|
|
||||||
func get_start_location() -> ESCLocation:
|
func get_start_location() -> ESCLocation:
|
||||||
if objects.has(current_room_key):
|
if _room_exists(current_room_key):
|
||||||
for object in objects[current_room_key].values():
|
for object in _get_room_objects_objects(current_room_key).values():
|
||||||
if is_instance_valid(object.node) \
|
if is_instance_valid(object.node) \
|
||||||
and object.node is ESCLocation \
|
and object.node is ESCLocation \
|
||||||
and object.node.is_start_location:
|
and object.node.is_start_location:
|
||||||
@@ -348,6 +394,55 @@ func get_start_location() -> ESCLocation:
|
|||||||
return null
|
return null
|
||||||
|
|
||||||
|
|
||||||
# Utility function to fashion a room key for the object manager.
|
# TODO: Document signatures
|
||||||
func _make_room_key(room: ESCRoom) -> String:
|
#func _is_current_room(container: ESCRoomObjects) -> bool:
|
||||||
return room.global_id + SEPARATOR + str(room.get_instance_id())
|
func _is_current_room(container) -> bool:
|
||||||
|
return _compare_container_to_key(container, current_room_key)
|
||||||
|
|
||||||
|
|
||||||
|
func _compare_container_to_key(container: ESCRoomObjects, room_key: ESCRoomObjectsKey) -> bool:
|
||||||
|
return container.room_global_id == room_key.room_global_id \
|
||||||
|
and container.room_instance_id == room_key.room_instance_id
|
||||||
|
|
||||||
|
|
||||||
|
func _room_exists(room_key: ESCRoomObjectsKey) -> bool:
|
||||||
|
for room_container in room_objects:
|
||||||
|
if _compare_container_to_key(room_container, room_key):
|
||||||
|
return true
|
||||||
|
|
||||||
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
func _object_exists_in_room(object: ESCObject, room_key: ESCRoomObjectsKey) -> bool:
|
||||||
|
if object == null:
|
||||||
|
escoria.logger.report_warnings(
|
||||||
|
"ESCObjectManager:_object_exists_in_room()",
|
||||||
|
[
|
||||||
|
"Cannot check for null objects."
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
return false
|
||||||
|
|
||||||
|
for room_container in room_objects:
|
||||||
|
if _compare_container_to_key(room_container, room_key) \
|
||||||
|
and room_container.objects.has(object.global_id):
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
func _get_room_objects_objects(room_key: ESCRoomObjectsKey) -> Dictionary:
|
||||||
|
for room_container in room_objects:
|
||||||
|
if _compare_container_to_key(room_container, room_key):
|
||||||
|
return room_container.objects
|
||||||
|
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
func _erase_room(room_key: ESCRoomObjectsKey) -> void:
|
||||||
|
for room_container in room_objects:
|
||||||
|
if _compare_container_to_key(room_container, room_key):
|
||||||
|
room_objects.erase(room_container)
|
||||||
|
return
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Container for ESCObjects stored in the object manager.
|
||||||
|
extends Reference
|
||||||
|
class_name ESCRoomObjects
|
||||||
|
|
||||||
|
|
||||||
|
# Designated whether 'objects' is the container for all reserved objects.
|
||||||
|
var is_reserved: bool = false
|
||||||
|
|
||||||
|
# Global ID of the room to which the objects in 'objects' are registered.
|
||||||
|
var room_global_id: String = ""
|
||||||
|
|
||||||
|
# Instance ID of the room to which the objects in 'objects' are registered.
|
||||||
|
# This is used to disambiguate in cases where more than one of the same room
|
||||||
|
# exist in the object manager.
|
||||||
|
var room_instance_id: int = -1
|
||||||
|
|
||||||
|
# The hash of objects registered to the room specified above.
|
||||||
|
var objects: Dictionary = {}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Simple pair container to store a room's identifying information for use in
|
||||||
|
# the object manager.
|
||||||
|
extends Reference
|
||||||
|
class_name ESCRoomObjectsKey
|
||||||
|
|
||||||
|
|
||||||
|
var room_global_id: String = ""
|
||||||
|
var room_instance_id: int = -1
|
||||||
|
|
||||||
|
|
||||||
|
func is_valid():
|
||||||
|
return not room_global_id.empty() and room_instance_id > -1
|
||||||
Reference in New Issue
Block a user