godot-cpp icon indicating copy to clipboard operation
godot-cpp copied to clipboard

Godot 4.4 beta 4 hot-reloading not working.

Open chriztheanvill opened this issue 10 months ago • 39 comments

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:

Image

After:

Image

Minimal reproduction project

Could happen with a new project.

chriztheanvill avatar Feb 20 '25 07:02 chriztheanvill

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.

dsnopek avatar Feb 20 '25 13:02 dsnopek

I am using the master branch, I downloaded yesterday to test the godot beta 4.4.

Could you share your compile flags ?

chriztheanvill avatar Feb 20 '25 20:02 chriztheanvill

The correct variable is GODOT_USE_HOT_RELOAD, not GODOT_ENABLE_HOT_RELOAD.

ghuser404 avatar Feb 20 '25 21:02 ghuser404

GODOT_USE_HOT_RELOAD

Mmm same result, not working. Also noticed that.

Before Compile:

Image

  • 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.

Image

  • If I switch back to CLion, then back to godot, the info disappears.

Image

chriztheanvill avatar Feb 20 '25 21:02 chriztheanvill

Image

Image

chriztheanvill avatar Feb 20 '25 21:02 chriztheanvill

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.

ghuser404 avatar Feb 20 '25 22:02 ghuser404

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

ghuser404 avatar Feb 20 '25 22:02 ghuser404

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.

ghuser404 avatar Feb 20 '25 22:02 ghuser404

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.

CMakeLists.txt conanfile.txt

chriztheanvill avatar Feb 20 '25 22:02 chriztheanvill

Upload all project sources, not just those 2 files. Create a small example project, if you don't want to share your sources.

ghuser404 avatar Feb 20 '25 22:02 ghuser404

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.

ghuser404 avatar Feb 20 '25 22:02 ghuser404

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)

chriztheanvill avatar Feb 20 '25 22:02 chriztheanvill

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.

ghuser404 avatar Feb 20 '25 22:02 ghuser404

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
    ...

chriztheanvill avatar Feb 20 '25 22:02 chriztheanvill

godot_game.zip

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.

chriztheanvill avatar Feb 20 '25 23:02 chriztheanvill

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.

ghuser404 avatar Feb 21 '25 00:02 ghuser404

I am making a new project.

About the godot-cpp, in the cmake,

Image

Change: ../../last-godot-cpp/ to the godot-cpp location

chriztheanvill avatar Feb 21 '25 00:02 chriztheanvill

godot_game.zip

This has no dependencies.

Image

chriztheanvill avatar Feb 21 '25 00:02 chriztheanvill

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.

ghuser404 avatar Feb 21 '25 01:02 ghuser404

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.

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!

chriztheanvill avatar Feb 21 '25 02:02 chriztheanvill

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.

Could you share how did you setup that miniproject to work with hotreloading ?

chriztheanvill avatar Feb 21 '25 05:02 chriztheanvill

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
)

ghuser404 avatar Feb 21 '25 06:02 ghuser404

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

chriztheanvill avatar Feb 21 '25 08:02 chriztheanvill

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.

ghuser404 avatar Feb 21 '25 08:02 ghuser404

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.

Almost, because I closed godot, and open again and if I try to modify something, removes everything, like this:

Image

I have to delete the .godot folder to again.

chriztheanvill avatar Feb 21 '25 08:02 chriztheanvill

Why don't you just use GDREGISTER_RUNTIME_CLASS if it works for you?

ghuser404 avatar Feb 21 '25 09:02 ghuser404

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.

ghuser404 avatar Feb 21 '25 09:02 ghuser404

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 avatar Feb 22 '25 16:02 chriztheanvill

@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.

dsnopek avatar Feb 24 '25 15:02 dsnopek

@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.

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.

chriztheanvill avatar Feb 24 '25 21:02 chriztheanvill