Closed ddel-rio closed 7 months ago
The engine should detect when a terrain is not being used to stop using its file.
It already does, but the way it does that, is from Godot's resource reference counting. VoxelStreamSQLite
is a resource, and when nothing else references it, it should get destroyed, in turn destroying the SQLite connection. So either you have something in the game still referencing that instance of VoxelStreamSQLite
(in a preload
? Or a scene which in turn references it?), or there is some sort of leak.
From your scene_menu_manager.gd
:
@onready var game_scene: PackedScene = load("res://scenes/scene_game.tscn")
That scene contains an instance of VoxelStreamSQLite
embedded inside it, which means your variable is keeping it alive.
That resource otherwise has no way to tell when "terrain is no longer used". Streams are not tied to terrains, they are just resources that can be queried anytime to read and write chunks, even after a terrain has left the scene tree, or without terrain in the first place.
If you want to explicitely close it rather than ensuring all references are unloaded, one way could be to set the database_path
of the resource to empty string ""
. However, there is a caveat of doing this: saving happens asynchronously. So after you save the terrain with save_modified_blocks
for example, it takes some time for everything to save, it's not blocking the main thread. If you go back to main menu before that and close the stream, you would loose data. save_modified_blocks
returns an object you can use to check when saving is complete (note that this only tracks blocks that were modified at the time of the call, so your game should stop modifying anything past this point).
Although I have read the documentation, I did not realize that the VoxelSaveCompletionTracker class existed. Thanks for showing it to me.
Now I have been able to do the following code and it seems to work fine:
var tracker: VoxelSaveCompletionTracker = terrain_manager.terrain.save_modified_blocks()
while !tracker.is_complete():
await get_tree().process_frame
(terrain_manager.terrain.stream as VoxelStreamSQLite).database_path = ""
But now when I leave a world that is still loading chunks I get this error:
Should I ignore it or is it important?
Those errors might not prevent the game from running in this specific case, but could indicate problems otherwise.
One option that comes to mind is to simply create a new instance of VoxelStreamSQLite
and use it in the next world scene instance, while making sure nothing else references the old one (I would recommend not leaving that resource embedded in your scene). This way, the old one can just "die" off and close by itself, once all asynchronous tasks have finished referencing it. This also guarantees that the world you load next can't possibly be affected by the "previous" stream due to asynchronous tasks remaining to resolve. Unfortunately that doesn't go well with manual closing. You'd have to expect that deleting a world can be still locked for a little while after leaving a world.
If you still want to carry on with the manual "closing" approach to force the file to unlock, the engine would have to be changed to consider a "not configured" database as not being an error when loading blocks from it, and fail silently instead. But if you also intend to modify the same resource to set the path again to another world, you run the risk of asynchronous tasks remaining from the previous terrain running queries on it.
Thanks, it's already solved. It seems to save well and the errors no longer appear by making two changes:
#(terrain_manager.terrain.stream as VoxelStreamSQLite).database_path = ""
terrain_manager.terrain.stream = null
Unassign it from the terrain when saving instead of deleting the path:
Are you doing this only when leaving the world? If so, why not just destroy the terrain/scene? Because that would have the same effect, and I'd even recommend doing that rather than re-using the same terrain node with another world for example.
Yes, I do this only when leaving the world. And it's true, it really isn't necessary to unassign the stream. I just tried your recommendation and it works well.
Describe the bug When I try to delete a recently opened terrain I get an error saying that the file is still in use even though there is no longer any VoxelTerrain in the scene.
I'm using VoxelStreamSQLite. This bug causes me to be unable to delete saved games.
To reproduce I have simulated the behavior of my game in the attached MRP.
mrp.zip
Expected behavior The engine should detect when a terrain is not being used to stop using its file.
Screenshots
Environment