Godot 4.4 beta 4 hot-reloading not working.
Godot version
Godot 4.4 beta 4
godot-cpp version
master
System information
Fedora Kinoite 41
Issue description
After compiling any part of the code, every public code to show in Godot gui, disappear.
In Cmake I tried this:
set(GODOT_COMPILE_FLAGS "${GODOT_COMPILE_FLAGS} -fno-omit-frame-pointer -O0 -DHOT_RELOAD_ENABLED -DDEBUG_ENABLED -DDEBUG_METHODS_ENABLED")
tried this:
set(GODOT_ENABLE_HOT_RELOAD ON CACHE INTERNAL "Enable hot reloading support")
set(GODOT_CPP_SYSTEM_HEADERS ON CACHE INTERNAL "Generate system headers")
#set(GODOT_CPP_WARNING_AS_ERROR OFF CACHE INTERNAL "Treat warnings as errors")
set(GENERATE_TEMPLATE_GET_NODE ON CACHE INTERNAL "Get template node")
set(FLOAT_PRECISION "${PRECISION}" CACHE INTERNAL "Library precision")
set(GODOT_CUSTOM_API_FILE "${EXTENSION_FILE}" CACHE INTERNAL "Extension api file")
and this.
reloadable = true
I tried this with 4.3 and 4.4 beta 1,2,3 and 4
Steps to reproduce
Launch Godot, edit some part of the code, compile and disappears every public code and not showing in godot GUI.
Before:
After:
Minimal reproduction project
Could happen with a new project.
Thanks for the report!
However, I'm not sure how much headway we'll be able to make without an MRP. I've relatively recently tested hot reload with Godot 4.3 and it was working, although, that was with scons. Based on your description it sounds like you're doing what you need to do for hot reload with cmake, but something must not be right if it works for me, but not for you.
Could you share which version of godot-cpp you're using?
We did at one point have an issue with the cmake configuration missing something needed for hot reload, but that should be fixed now.
I am using the master branch, I downloaded yesterday to test the godot beta 4.4.
Could you share your compile flags ?
The correct variable is GODOT_USE_HOT_RELOAD, not GODOT_ENABLE_HOT_RELOAD.
GODOT_USE_HOT_RELOAD
Mmm same result, not working. Also noticed that.
Before Compile:
- Then, edit any part of my code, no matter if is "Collectable".
- In Clion press the button to compile, but before finish, switch to godot, the changes not showing.
- If I switch back to CLion, then back to godot, the info disappears.
If this still doesn't work, you will have to upload an example project for anyone to be able to help you with this issue.
In Clion press the button to compile, but before finish, switch to godot, the changes not showing.
Godot editor reloads GDExtension only on focus, i.e. if you open the editor before the compilation finishes, and compilation finishes when you're in the editor, you will not see the changes. You have to re-focus the editor. I opened an issue for that a while ago https://github.com/godotengine/godot-proposals/issues/11684
If I switch back to CLion, then back to godot, the info disappears.
This means your hot reload is working. I'm not very sure what your issue is right now.
If I switch back to CLion, then back to godot, the info disappears.
This means your hot reload is working. I'm not very sure what your issue is right now.
For example, at start I set the Lv of the collectable:
// header
private:
int m_lv { };
public:
auto GetLv( ) const -> int;
auto SetLv(int val) -> void;
// Source
ClassDB::bind_method(D_METHOD("GetLv"), &Collectable::GetLv);
ClassDB::bind_method(D_METHOD("SetLv", "val"), &Collectable::SetLv);
ClassDB::add_property("Collectable", PropertyInfo(Variant::INT, "lv"), "SetLv", "GetLv");
Compile and shows the info in godot, perfect.
Then I want to work with this class, Adding methods, working with the process method, or just add other attribute,
// header
private:
int m_lv { };
bool m_isActive {}; // <--- Just an example
Or If I edit any part of the project, for example, the player.cpp file. The Lv info that showed in Godot, disappear.
Edit: The cmake file, is a mess, because I am trying many things.
Upload all project sources, not just those 2 files. Create a small example project, if you don't want to share your sources.
The problem is that your node becomes just Area2D instead of your class. I can't tell you the reason for that without seeing sources.
The problem is that your node becomes just Area2D instead of your class. I can't tell you the reason for that without seeing sources.
I am making a new project.
The problem is that your node becomes just Area2D instead of your class.
I don't get it.
class Collectable : public Area2D, public IObject {
GDCLASS(Collectable, Area2D)
I don't get it.
Inspect the ~project.godot~ scene file and find your node and see what is its type before and after it disappears.
In project.godot I have nothing about that, in the tscn where is the "Collectable" I found this:
[node name="Collectable" parent="Spawns/Collectables" index="0" instance=ExtResource("5_301qf")]
In the project.godot
config_version
application
...
display
...
input
...
layer_names
...
rendering
...
This is a new project. I am coding with CLion and the cmake is a mess.
Just to try:
- Open Godot with this project, to show the main scene: Collectable, and will show Lv.
- Enter to src/src/Game/Collectable.cpp, at like 77, just duplicate the line and compile.
- In godot, the Lv attribute will disappear.
Edit: I am using Fedora Kinoite and launching CLion and Godot 4.4 beta 4 from a Distrobox.
I can't build your project. There are too many dependencies, and some are non-existent, like godot-cpp.
I'm not on Linux, so I can't just run your build. I'd suggest you create a very small MRP without any dependencies, just a plain CMakeLists.txt with add_library and some cpp/h sources.
I am making a new project.
About the godot-cpp, in the cmake,
Change: ../../last-godot-cpp/ to the godot-cpp location
So I've built your project, and modified the Lv value to Lv1, and in Godot I see Lv1. So everything seems to be working for me.
However, I'm getting some corruption messages in the log, not sure where it's coming from. Maybe this is due to how you're using CMake, which is quite wrong. You shouldn't be linking *.a files manually and specifying includes with target_include_directories. To link godot-cpp all you have to do is
add_library(${PROJECT_NAME} MODULE main.cpp)
add_subdirectory(godot-cpp)
target_link_libraries(${PROJECT_NAME} godot-cpp::template_debug)
This way your project will build godot-cpp and correctly link your target to it.
So I've built your project, and modified the Lv value to Lv1, and in Godot I see Lv1. So everything seems to be working for me. However, I'm getting some corruption messages in the log, not sure where it's coming from. Maybe this is due to how you're using CMake, which is quite wrong. You shouldn't be linking
*.afiles manually and specifying includes withtarget_include_directories. To link godot-cpp all you have to do isadd_library(${PROJECT_NAME} MODULE main.cpp) add_subdirectory(godot-cpp) target_link_libraries(${PROJECT_NAME} godot-cpp::template_debug)This way your project will build godot-cpp and correctly link your target to it.
I am using the previous CMake version that godot-cpp in the directory test.
And trying to setup godot-cpp as subdirectory shows this errors:
Auto-detected 16 CPU cores available for build parallelism.
-- If not already cached, setting CMAKE_MSVC_RUNTIME_LIBRARY.
For more information please read godot-cpp/cmake/windows.cmake
Using cores, You can override it at configure time by using -j <n> or --parallel <n> on the build command.
eg. cmake --build . -j 7 ...
-- GODOT_GDEXTENSION_API_FILE = '../../last-godot-cpp/gdextension//extension_api.json'
Traceback (most recent call last):
File "<string>", line 1, in <module>
from binding_generator import print_file_list;print_file_list( api_filepath='../../last-godot-cpp/gdextension//extension_api.json', output_dir='/home/cris/Workspace/Godot/godot_game/src/cmake-build-debug/last-godot-cpp', headers=True, sources=True)
~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/cris/Workspace/Godot/godot_game/src/last-godot-cpp/binding_generator.py", line 274, in print_file_list
print(*get_file_list(api_filepath, output_dir, headers, sources), sep=";", end=None)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/cris/Workspace/Godot/godot_game/src/last-godot-cpp/binding_generator.py", line 202, in get_file_list
with open(api_filepath, encoding="utf-8") as api_file:
~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: '../../last-godot-cpp/gdextension//extension_api.json'
CMake Error at last-godot-cpp/cmake/GodotCPPModule.cmake:76 (message):
File List Generation Failed
Call Stack (most recent call first):
last-godot-cpp/cmake/godotcpp.cmake:244 (binding_generator_get_file_list)
last-godot-cpp/CMakeLists.txt:52 (godotcpp_generate)
-- Configuring incomplete, errors occurred!
So I've built your project, and modified the Lv value to Lv1, and in Godot I see Lv1. So everything seems to be working for me. However, I'm getting some corruption messages in the log, not sure where it's coming from. Maybe this is due to how you're using CMake, which is quite wrong. You shouldn't be linking
*.afiles manually and specifying includes withtarget_include_directories. To link godot-cpp all you have to do isadd_library(${PROJECT_NAME} MODULE main.cpp) add_subdirectory(godot-cpp) target_link_libraries(${PROJECT_NAME} godot-cpp::template_debug)This way your project will build godot-cpp and correctly link your target to it.
Could you share how did you setup that miniproject to work with hotreloading ?
Here's the minimal CMakeLists.txt that will go with your project. You just need to put in place godot-cpp and configure the *.gdextension file.
cmake_minimum_required(VERSION 3.28.2)
project(godot-cpp-test)
set(GODOT_USE_HOT_RELOAD ON)
add_subdirectory(godot-cpp)
add_library(${PROJECT_NAME} MODULE)
target_link_libraries(${PROJECT_NAME} godot-cpp::template_debug)
target_sources(${PROJECT_NAME} PRIVATE
${PROJECT_SOURCE_DIR}/Collectable.cpp
${PROJECT_SOURCE_DIR}/Collectable.hpp
${PROJECT_SOURCE_DIR}/register_types.cpp
${PROJECT_SOURCE_DIR}/register_types.h
)
Thank you. I made it :D
But I discover something:
After playing around with the hot-reloading feature, I discovered:
If I use GDREGISTER_RUNTIME_CLASS(Collectable); works hot-reloading. But, if I use GDREGISTER_CLASS(Collectable) To enable again the hot reloading, I have to delete the .godot folder from my project to check everything again.
GDREGISTER_RUNTIME_CLASS(Collectable); // This works with Hot-Reloading
// GDREGISTER_CLASS(Collectable); // This disables hot-reloading.
Note: I am testing with godot 4.4 beta 4
Yeah, I'm not sure about the GDREGISTER_RUNTIME_CLASS vs GDREGISTER_CLASS situation. Maybe you should open a separate issue for that. But I'm glad you got it working in the end.
Yeah, I'm not sure about the
GDREGISTER_RUNTIME_CLASSvsGDREGISTER_CLASSsituation. Maybe you should open a separate issue for that. But I'm glad you got it working in the end.
Almost, because I closed godot, and open again and if I try to modify something, removes everything, like this:
I have to delete the .godot folder to again.
Why don't you just use GDREGISTER_RUNTIME_CLASS if it works for you?
The reason I think why it's failing is because GDREGISTER_CLASS runs your nodes in the editor, and when you rebuild the project, it destroys those objects and calls their destructors, which is where it probably crashes. I saw you had some code for connecting the signal in the constructor (which I think you should be using _ready for), but I don't think you were disconnecting the signal, which would be the reason for the crash.
Mmm... After playing with a new empty project with CMake. This was not the issue:
GDREGISTER_RUNTIME_CLASS(Collectable); // This works with Hot-Reloading
// GDREGISTER_CLASS(Collectable); // This disables hot-reloading.
Working with this new project, adding one by one my original code, godot stop working with hot-reloading when I start working with SQLiteCpp.
@chriztheanvill: Thanks for sharing your project!
Working with this new project, adding one by one my original code, godot stop working with hot-reloading when I start working with SQLiteCpp.
So, you're saying that without SQLiteCpp, reloading works fine, but as soon as you add SQLiteCpp, then reloading doesn't work?
It could be that there is something in SQLiteCpp that makes the unloading of your extensions not succeed, which would cause the subsequent reloading to fail.
This is something we've encountered a couple times, for example: on MacOS, using any thread_local variable will prevent unloading from succeeding. Or, if using GCC, building without -fno-gnu-unique will break unloading.
Are you using GCC? I don't know how Conan builds end up coming together, but is it possible the SQLiteCpp files are built without -fno-gnu-unique? Or, cmake configuration should be adding that, but I don't know if it'll make it into the SQLiteCpp build.
@chriztheanvill: Thanks for sharing your project!
Working with this new project, adding one by one my original code, godot stop working with hot-reloading when I start working with SQLiteCpp.
So, you're saying that without SQLiteCpp, reloading works fine, but as soon as you add SQLiteCpp, then reloading doesn't work?
It could be that there is something in SQLiteCpp that makes the unloading of your extensions not succeed, which would cause the subsequent reloading to fail.
This is something we've encountered a couple times, for example: on MacOS, using any
thread_localvariable will prevent unloading from succeeding. Or, if using GCC, building without-fno-gnu-uniquewill break unloading.Are you using GCC? I don't know how Conan builds end up coming together, but is it possible the SQLiteCpp files are built without
-fno-gnu-unique? Or, cmake configuration should be adding that, but I don't know if it'll make it into the SQLiteCpp build.
Hi.
I am still playing with Godot + CMake with Conan, and yes, looks like Godot do not like SqliteCpp.
void SInventory::_enter_tree( ) {
UtilityFunctions::print("SInventory::_enter_tree( )");
SQLite::Database db("data.db", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE);
std::string qGetStoreItems { "SELECT * FROM StoreItems" };
SQLite::Statement qItemsStore(db, qGetStoreItems);
while (qItemsStore.executeStep( )) {
int storeItemsID = qItemsStore.getColumn(0).getInt( );
int storeItemsType = qItemsStore.getColumn(1).getInt( );
SQLite::Statement qlistItems(
db,
"SELECT * FROM ListItems "
"WHERE id = ?"
"AND type = ?"
);
qlistItems.bind(1, storeItemsID);
qlistItems.bind(2, storeItemsType);
qlistItems.executeStep( );
std::string name = qlistItems.getColumn(1).getString( );
DataItem* item = memnew(DataItem);
item->set_name(name.c_str( ));
m_inventory.push_back(item); // m_inventory is an Array from godot::cpp
}
}
About -fno-gnu-unique in my previous cmake config, yes, if I did not use it, the hot-reloading not works. But in this really really small cmake config, even without enabling -fno-gnu-unique or GODOT_USE_HOT_RELOAD the hot-reloading works ( Yes, I enabled -fno-gnu-unique and GODOT_USE_HOT_RELOAD in this cmake).
The funny thing is:
- Close godot.
- Erase the .godot of the project.
- Compile the project with the SqliteCpp code.
- Open godot and everything works excellent. IF I close godot and open again, the hot-reloading stop working, I need to erase again the .godot folder to hot-reloading work.