Skip to content

Commit a995d48

Browse files
committed
Proof of concept for a hot-reload test case
1 parent 5910c0e commit a995d48

File tree

11 files changed

+232
-18
lines changed

11 files changed

+232
-18
lines changed

cmake/godotcpp.cmake

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,9 @@ function(godotcpp_options)
139139
#TODO compiledb_file
140140

141141
set(GODOTCPP_BUILD_PROFILE "" CACHE PATH "Path to a file containing a feature build profile")
142+
if(GODOTCPP_BUILD_PROFILE AND EXISTS "${GODOTCPP_BUILD_PROFILE}")
143+
set_property(SOURCE APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${GODOTCPP_BUILD_PROFILE}")
144+
endif()
142145

143146
set(GODOTCPP_USE_HOT_RELOAD "" CACHE BOOL "Enable the extra accounting required to support hot reload. (ON|OFF)")
144147

test/build_profile.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
"OS",
99
"TileMap",
1010
"TileSet",
11-
"Viewport"
11+
"Viewport",
12+
"Engine",
13+
"DirAccess",
14+
"EditorInterface",
15+
"GDExtensionManager"
1216
]
1317
}

test/project/example.gdextension

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
entry_symbol = "example_library_init"
44
compatibility_minimum = "4.1"
5+
reloadable = true
56

67
[libraries]
78

test/project/icon.png.import

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,19 @@ dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.cte
1818
compress/mode=0
1919
compress/high_quality=false
2020
compress/lossy_quality=0.7
21+
compress/uastc_level=0
22+
compress/rdo_quality_loss=0.0
2123
compress/hdr_compression=1
2224
compress/normal_map=0
2325
compress/channel_pack=0
2426
mipmaps/generate=false
2527
mipmaps/limit=-1
2628
roughness/mode=0
2729
roughness/src_normal=""
30+
process/channel_remap/red=0
31+
process/channel_remap/green=1
32+
process/channel_remap/blue=2
33+
process/channel_remap/alpha=3
2834
process/fix_alpha_border=true
2935
process/premult_alpha=false
3036
process/normal_map_invert_y=false

test/project/project.godot

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ config_version=5
1212

1313
config/name="GDExtension Test Project"
1414
run/main_scene="res://main.tscn"
15-
config/features=PackedStringArray("4.4")
15+
config/features=PackedStringArray("4.5")
1616
config/icon="res://icon.png"
1717

1818
[native_extensions]

test/project/reload.gd

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
@tool
2+
extends Example
3+
4+
func _on_custom_signal( _msg, _value ) -> void:
5+
print_rich("[color=green] ******** PASSED ******** [/color]")
6+
get_tree().quit(0)
7+
8+
9+
func _on_timeout():
10+
print_rich("[color=red] ******** FAILED ********[/color]")
11+
get_tree().quit(1)
12+
13+
14+
func _ready() -> void:
15+
# Dont quit if the reload test isnt specified on the command line.
16+
if not 'test_reload' in OS.get_cmdline_args(): return
17+
18+
print("gdscript:Reload Test is Enabled")
19+
# Connect to the custom signal of Example
20+
custom_signal.connect(_on_custom_signal)
21+
22+
# Start 5s watchdog timer
23+
var timer = get_tree().create_timer(10.0)
24+
timer.timeout.connect(_on_timeout)
25+
26+
print("Awaiting Custom Signal (with 10s timeout)")

test/project/reload.gd.uid

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
uid://c8v75k3p4pnjj

test/project/reload.tscn

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[gd_scene load_steps=2 format=3 uid="uid://b4wrd36npp8ov"]
2+
3+
[ext_resource type="Script" uid="uid://c8v75k3p4pnjj" path="res://reload.gd" id="1_icw2l"]
4+
5+
[node name="Reload" type="Example"]
6+
script = ExtResource("1_icw2l")

test/run-tests.ps1

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Define Godot executable (uses environment variable if set, else defaults to 'godot')
2+
$GODOT = if ($env:GODOT) { $env:GODOT } else { 'godot' }
3+
4+
$END_STRING = "==== TESTS FINISHED ===="
5+
$FAILURE_STRING = "******** FAILED ********"
6+
$HAS_FAILURE = 0
7+
8+
# Function to filter spam from output
9+
function Filter-Output {
10+
param([string[]]$Lines)
11+
$Lines | ForEach-Object { $_.TrimEnd() } | Where-Object {
12+
$_ -notmatch "Narrowing conversion" -and
13+
$_ -notmatch "at:\s+GDScript::reload" -and
14+
$_ -notmatch "\[\s*\d+%\s*\]" -and
15+
$_ -notmatch "first_scan_filesystem" -and
16+
$_ -notmatch "loading_editor_layout"
17+
}
18+
}
19+
20+
# Run Godot and capture output and exit code
21+
try {
22+
$OUTPUT = & $GODOT --path project --debug --headless --quit 2>&1
23+
$ERRCODE = $LASTEXITCODE
24+
}
25+
catch {
26+
$OUTPUT = $_.Exception.Message
27+
$ERRCODE = 1
28+
}
29+
30+
# Output the results
31+
Write-Output $OUTPUT
32+
Write-Output ""
33+
34+
# Check if tests completed
35+
if (-not ($OUTPUT -match [regex]::Escape($END_STRING))) {
36+
$HAS_FAILURE += 1
37+
}
38+
39+
# Check for test failures
40+
if ($OUTPUT -match [regex]::Escape($FAILURE_STRING)) {
41+
$HAS_FAILURE += 1
42+
}
43+
44+
# Lock file path (relative to project dir)
45+
$LOCK_PATH = "project/test_reload_lock"
46+
47+
# Delete lock file before reload test if it exists
48+
Remove-Item -Path $LOCK_PATH -Force -ErrorAction SilentlyContinue
49+
50+
# Run Godot and capture output and exit code
51+
try {
52+
$OUTPUT = & $GODOT -e --path project --scene reload.tscn --headless --debug test_reload 2>&1
53+
$ERRCODE = $LASTEXITCODE
54+
}
55+
catch {
56+
$OUTPUT = $_.Exception.Message
57+
$ERRCODE = 1
58+
}
59+
60+
# Filter and output the results
61+
$FilteredOutput = Filter-Output -Lines ($OUTPUT -split "`n")
62+
Write-Output ($FilteredOutput -join "`n")
63+
Write-Output ""
64+
65+
# Check for test failures
66+
if ($OUTPUT -match [regex]::Escape($FAILURE_STRING)) {
67+
$HAS_FAILURE += 1
68+
}
69+
70+
# Lock file path (relative to project dir)
71+
$LOCK_PATH = "project/test_reload_lock"
72+
73+
# Delete lock file before reload test if it exists
74+
Remove-Item -Path $LOCK_PATH -Force -ErrorAction SilentlyContinue
75+
76+
if ($HAS_FAILURE -gt 0 ){
77+
Write-Output "ERROR: Tests failed to complete"
78+
exit 1
79+
}
80+
81+
# Success!
82+
exit 0

test/src/example.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ void Example::_notification(int p_what) {
114114
rpc_config("test_rpc", opts);
115115
}
116116
//UtilityFunctions::print("Notification: ", String::num(p_what));
117+
if (p_what == NOTIFICATION_EXTENSION_RELOADED) {
118+
emit_custom_signal("NOTIFICATION_EXTENSION_RELOADED ", 0);
119+
}
117120
}
118121

119122
bool Example::_set(const StringName &p_name, const Variant &p_value) {

0 commit comments

Comments
 (0)