-
Notifications
You must be signed in to change notification settings - Fork 140
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
C# Garbage collection clears storage.region_offsets #393
Comments
0.9.0 and 0.9.2 are a world apart. Please test 0.9.1, or preferably bisect between the two and you can narrow down the exact commit that caused the problem. I don't use C#, so you'll need to do the heavy lifting. I can support the back end. Do you know how to use git bisect? It's very easy and more useful than an MRP. I assume you're using the same version of Godot, and hopefully godot-cpp, since those are what C# interfaces with. |
@TokisanGames thanks for your patience while I dug into this. The commit causing the issue is unfortunately the big one 5835e41 The MRP (too large to upload here) contains a git branch called To try the MRP run the project, and use the SPAWN, REMOVE and GC(Garbage Collection) buttons in that order. After pressing the GC button once press SPAWN again and the terrain will appear but none of the balls will be visible nor will the debug collision be visible. You can also notice errors pile up in the Debugger dock. Here is an interesting part of the puzzle, if you press the GC button multiple times after removing the terrain from the scene, you will notice that more objects get deleted. After pressing REMOVE
After pressing GC once
After pressing GC twice
After pressing GC twice, pressing SPAWN again will work without issue.
Let me know what you think. I am unfortunately not super involved with the deeper way of how C# interacts with Godot internals, but worst comes to worst perhaps we can summon one of the C# maintainers here to shed some light. |
First, storage is going away as a resource in PR #374, in lieu of a directory of resources. Second, dynamic collision will fix a lot of issues in PR #278. I ran your demos. First thing I noticed looking at the storage resource in the inspector: in 0.9.1 you have 4 region offsets, heightmaps, control maps, colormaps. In the other version you have 2 region offsets, 2 heightmaps, 5 control maps, 5 colormaps. This storage file is messed up. I replaced the broken storage.res with the fixed one. Running the recent version with new storage, after the 2nd spawn it has nothing to do with collision. After GC Storage thinks that there are no regions, even though I can see the 4 region offsets in the inspector at runtime. Attaching this to terrain3d:
After spawn, reports: After gc/spawn, reports: I suspect there's a bug in Godot's garbage collection. I should not have to do anything in C++ to accommodate for C#'s garbage collection. The commit you found only has a few changes to terrain3d and storage, so finding the exact line that triggers the engine bug won't be difficult. Ultimately, we'll have to take that to the C# guys to learn what they are doing. |
I spent a bit of time exploring this, first breaking up the commit you found, and then in the main branch. The change that caused the broken respawning is calling Terrain3D/src/terrain_3d_material.cpp Line 421 in a9bd1e8
The function passes data to the shader so its not flat. But by calling it there, it causes your C# code to instantiate a terrain where The storage instance is the same. The So I believe the GC problem always existed but it wasn't visible because of a different structure and the new structure exposes it. In C# I retrieved If I duplicate the using Godot;
using System;
using System.Collections.Generic;
public partial class Main : Node3D
{
[Export(PropertyHint.File)]
private string terrainScenePath;
private readonly List<Node3D> meshes = new();
private Node terrain;
// private Resource storage;
private Godot.Collections.Array region_offsets = new();
public void SpawnTerrain() {
GD.Print("**- Spawn start: local region_offsets: ", region_offsets, " **-");
terrain = ResourceLoader.Load<PackedScene>(terrainScenePath, cacheMode: ResourceLoader.CacheMode.Ignore).Instantiate();
var storage = terrain.Get("storage").As<Resource>();
GD.Print("*** storage.region_offsets: ", storage.Call("get_region_offsets").AsGodotArray(), " ***");
if(region_offsets.Count > 0 && storage.Call("get_region_offsets").AsGodotArray().Count == 0) {
GD.Print("--- storage.region_offsets is empty, assigning backup with count: ", region_offsets.Count);
storage.Call("set_region_offsets", region_offsets);
GD.Print("--- storage.region_offsets: ", storage.Call("get_region_offsets").AsGodotArray());
}
region_offsets = storage.Call("get_region_offsets").AsGodotArray().Duplicate();
AddChild(terrain);
var cam = GetViewport().GetCamera3D();
for (int i = 0; i < 25; i++) {
var pos = cam.GlobalPosition + new Vector3(GD.Randf() * 25f, 0f, GD.Randf() * 25f) + -cam.GlobalBasis.Z * (float)GD.RandRange(10f, 25f);
pos.Y = (float)(storage.Call("get_height", pos).AsDouble() + 1.0);
var mi = new MeshInstance3D {
Mesh = new SphereMesh { Radius = 1, Height = 2 },
Position = pos,
};
AddChild(mi);
meshes.Add(mi);
}
GD.Print("--- Spawn end: local region_offsets: ", region_offsets);
}
public void RemoveTerrain() {
GD.Print("--- Remove start: local region_offsets: ", region_offsets);
foreach (var mi in meshes) {
mi.QueueFree();
}
meshes.Clear();
terrain.QueueFree();
terrain = null;
// storage = null;
GD.Print("--- Remove end: local region_offsets: ", region_offsets);
}
public void ForceGC() {
GD.Print("--- GC start: local region_offsets: ", region_offsets);
GC.Collect();
GD.Print("--- GC end: local region_offsets: ", region_offsets);
}
} With Duplicate()
Without Duplicate()
I can confirm that pressing GC twice also addresses the issue. So now the questions are why does GC clear the Edit: As you noted, I also saw the first GC click clears our material resource:
And the second click clears the storage resource:
So it appears the basic issue is that the GC is not doing a complete job. |
Updated MRP Instructions. Tested with 4.2.2-stable and 4.3-beta2.
The MRP provides three buttons which do the following:
If we click all three, then return to step 1, the array is empty, which causes other problems. |
From dotnet chat. You can join us there.
Please review and test the suggestions of using My response.
|
Another note from dotnet
So, I'm inclined to believe that this isn't an engine bug, it's by design. It's not our bug either. And the solution is to use the other functions suggested by the devs above. @TheOrioli Can you confirm their suggestions help your scenario? Whatever method is used, you want to ensure storage is flushed properly before it is reinstantiated. Or region_offsets is retained and replaced if not. |
I'm going to close this since 2 Godot contributor chat devs said it's by design and gave a different solution that is more proper for Godot C#. This isn't a Terrain3D issue, it was only revealed by our restructuring. It can be followed up on by Op's Godot engine report, though they'll likely say the same thing. We can reopen this if that issue reveals a change we need to make in the future. |
Terrain3D version
v0.9.2-dev
System information
Godot v4.2.2.stable.mono - Windows 10.0.19045 - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 2070 SUPER (NVIDIA; 31.0.15.5212) - AMD Ryzen 9 3900X 12-Core Processor (24 Threads)
Is the issue reproducable in the demo?
Not applicable
Issue description
I use Terrain3D with C# primarily. The previous version in my project was
0.9.0-beta
I keep a reference to the Terrain3DStorage resource in my scripts, and destroying levels and clearing references worked nicely.
In version
0.9.2-dev
built off f626dc1 even accessing the storage property through C# causes the garbage collector to completely clear all the terrain data down the line.I am writing this bug as a reference for now, currently I don't have the time to make a MRP, but I plan to get on that in a few days.
Specifically, the visuals seems fine, but physics collisions no longer get generated when loading the same storage again.
MRP
See #393 (comment)
The text was updated successfully, but these errors were encountered: