-
Notifications
You must be signed in to change notification settings - Fork 17
Persistence
A persistence system has been created for the Godot XR Template project which can save items, inventory, and state information when switching between zones, and when loading and saving the game.
The persistence system consists of the following main types:
- PersistentWorld - a data storage system with file load/save support
- PersistentItem - a interactable item that synchronizes its state to the PersistentWorld
- PersistentPocket - a snap-zone that synchronizes its contents to the PersistentWorld
- PersistentZone - a scene that synchronizes its state to the PersistentWorld
Creating a new item involves:
- Creating a PersistentItemType resource defining the type information for every type of item
- Creating a scene extending from PersistentItem defining the item instance (shape, collision, grab-points, pockets, etc.)
- Adding the PersistentItemType to the PersistentItemDatabase resource for the application
If the item is unique (only one in the entire game) then its unique item_id
can be set once in the item scene.
If multiple instances of the item will be scattered throughout the world, then the item_id
should be left blank in the item scene, and instead unique item_id
values should be set for every instance dropped into zones.
Before creating zones, the application should:
- Create a new ZoneBase scene extending from the PersistentZone scene (persistent_zone.tscn)
- Set the
item_database
to refer to the applications PersistentItemDatabase resource - Configure the XROrigin3D with all the standard player movement options and pockets
This ZoneBase scene becomes the base for all zones in the game, and therefore all zones inherit the same player configuration, and the player configuration can be managed in a single location.
Creating a new zone involves:
- Creating a PersistentZoneInfo resource defining the zone information
- Creating a scene extending from ZoneBase, populated with the appropriate environment, objects and items
- Adding the PersistentZoneInfo to the PersistentZoneDatabase resource for the application
Every PersistentItem should have a unique item_id
in the world. This ID is used to persist the items state in the PersistentWorld database.
Every PersistentZone should have a unique zone_id
defined in its PersistentZoneInfo. This ID is used to persist the state of the zone in the PersistentWorld database.
Every PersistentPocket should have a unique pocket_id
. This ID is used to persist the pocket contents in the PersistentWorld database.
A zone may have any number of PersistentPocket instances, but each one must have a different pocket_id
; however pockets in different zones are allowed to reuse the same pocket_id
.
An example of shared pockets is the pockets put on the player body. For example if the player puts an item into their "left_pocket" in zone 1 and then steps into zone 2; the "left_pocket" in zone 2 will synchronize its contents to hold the same item.
Shared pockets also works for pockets on items - for example a unique backpack can have pockets, and the pockets will synchronize as the backpack is carried from one zone to the next.
Shared pockets can also be static and used like a bank - for example zones containing a bank vault can have "bank_slot_1" which synchronizes its contents as the player moves to the different zones.
The following UML diagram shows the relationship between the resource definitions.
---
Class Diagram
---
classDiagram
class PersistentWorld {
+PersistentWorld instance$
+String save_file_password
+PersistentZoneDatabase zone_database
+PersistentItemDatabase item_database
}
class PersistentZoneDatabase~Resource~ {
+Array~PersistentZoneInfo~ zones
}
class PersistentItemDatabase~Resource~ {
+Array~PersistentItemType~ items
}
class PersistentZoneInfo~Resource~ {
+String zone_id
+String instance_scene
}
class PersistentItemType~Resource~ {
+String type_id
+String instance_scene
}
PersistentWorld ..> PersistentZoneDatabase : Refers
PersistentWorld ..> PersistentItemDatabase : Refers
PersistentZoneDatabase ..> "many" PersistentZoneInfo : Refers
PersistentItemDatabase ..> "many" PersistentItemType : Refers
The PersistentWorld (extended by the custom GameState and configured by the developer) refers to the zone and item databases. As the PersistentWorld has a static instance
refence, it means any persistence object can access the database of zones and items.
The following UML diagram shows the relationship between running objects.
---
Class Diagram
---
classDiagram
class PersistentWorld {
+PersistentWorld instance$
-Dictionary data
}
class GameState {
+PersistentZone current_zone
}
class PersistentStaging {
+PersistentStaging instance$
}
class PersistentZone~XRToolsSceneBase~ {
+PersistentZoneInfo zone_info
}
class PersistentItem~XRToolsPickable~ {
+String item_id
+PersistentItemType item_type
}
class PersistentPocket~XRToolsSnapZone~ {
+String pocket_id
+PersistentItem picked_up_object
}
PersistentWorld <|-- GameState : Inheritance
GameState <..> PersistentZone : Refers
PersistentZone ..> "many" PersistentItem : Contains
PersistentItem ..> "many" PersistentPocket : Contains
PersistentItem <.. PersistentPocket : Holds
GameState..> PersistentStaging : Uses
PersistentZone <..> PersistentStaging : Refers
Both the PersistentWorld and PersistentStaging have static instance
references, so any class can trigger a scene transition and manipulate the game state. PersistentZones, PersistentItems and PersistentPockets read and write their state information to the PersistentWorld.