-
-
Notifications
You must be signed in to change notification settings - Fork 189
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #653 from godot-rust/bugfix/hot-reload-panic
Fix hot-reload panic on Linux
- Loading branch information
Showing
24 changed files
with
706 additions
and
209 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
res://rust.gdextension |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
list=Array[Dictionary]([]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[gd_scene format=3 uid="uid://da7eiv1notj7j"] | ||
|
||
[node name="Reloadable" type="Reloadable"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
; Engine configuration file. | ||
; It's best edited using the editor UI and not directly, | ||
; since the parameters that go here are not all obvious. | ||
; | ||
; Format: | ||
; [section] ; section goes between [] | ||
; param=value ; assign values to parameters | ||
|
||
config_version=5 | ||
|
||
[application] | ||
|
||
config/name="hot-reload" | ||
config/features=PackedStringArray("4.3", "Forward Plus") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
[configuration] | ||
entry_symbol = "gdext_rust_init" | ||
compatibility_minimum = 4.1 | ||
reloadable = true | ||
|
||
[libraries] | ||
linux.debug.x86_64 = "res://../../../target/debug/libhot_reload.so" | ||
linux.release.x86_64 = "res://../../../target/release/libhot_reload.so" | ||
windows.debug.x86_64 = "res://../../../target/debug/hot_reload.dll" | ||
windows.release.x86_64 = "res://../../../target/release/hot_reload.dll" | ||
macos.debug = "res://../../../target/debug/libhot_reload.dylib" | ||
macos.release = "res://../../../target/release/libhot_reload.dylib" | ||
macos.debug.arm64 = "res://../../../target/debug/libhot_reload.dylib" | ||
macos.release.arm64 = "res://../../../target/release/libhot_reload.dylib" | ||
web.debug.wasm32 = "res://../../../target/wasm32-unknown-emscripten/debug/hot_reload.wasm" | ||
web.release.wasm32 = "res://../../../target/wasm32-unknown-emscripten/release/hot_reload.wasm" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
[gd_scene load_steps=2 format=3 uid="uid://da7eiv1notj7j"] | ||
|
||
[ext_resource type="Script" path="res://test/ReloadTest.gd" id="1_6hpr0"] | ||
|
||
[node name="MainScene" type="Node"] | ||
script = ExtResource("1_6hpr0") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
# Copyright (c) godot-rust; Bromeon and contributors. | ||
# This Source Code Form is subject to the terms of the Mozilla Public | ||
# License, v. 2.0. If a copy of the MPL was not distributed with this | ||
# file, You can obtain one at https://mozilla.org/MPL/2.0/. | ||
|
||
# Note: This file is not part of the example, but a script used for gdext integration tests. | ||
# You can safely ignore it. | ||
|
||
@tool | ||
extends Node | ||
|
||
var udp := PacketPeerUDP.new() | ||
var thread := Thread.new() | ||
var extension_name: String | ||
|
||
|
||
func _ready() -> void: | ||
print("[GDScript] Start...") | ||
|
||
var r = Reloadable.new() | ||
var num = r.get_number() | ||
r.free() | ||
|
||
print("[GDScript] Sanity check: initial number is ", num) | ||
|
||
var extensions = GDExtensionManager.get_loaded_extensions() | ||
if extensions.size() == 1: | ||
extension_name = extensions[0] | ||
else: | ||
fail(str("Must have 1 extension, has: ", extensions)) | ||
return | ||
|
||
udp.bind(1337) | ||
print("[GDScript] ReloadTest ready to receive...") | ||
|
||
send_udp() | ||
|
||
|
||
func send_udp(): | ||
# Attempt to bind the UDP socket to any available port for sending. | ||
# You can specify a port number instead of 0 if you need to bind to a specific port. | ||
var out_udp = PacketPeerUDP.new() | ||
|
||
# Set the destination address and port for the message | ||
if out_udp.set_dest_address("127.0.0.1", 1338) != OK: | ||
fail("Failed to set destination address") | ||
return | ||
|
||
if out_udp.put_packet("ready".to_utf8_buffer()) != OK: | ||
fail("Failed to send packet") | ||
return | ||
|
||
print("[GDScript] Packet sent successfully") | ||
out_udp.close() | ||
|
||
|
||
func _exit_tree() -> void: | ||
print("[GDScript] ReloadTest exit.") | ||
udp.close() | ||
|
||
|
||
func _process(delta: float) -> void: | ||
if udp.get_available_packet_count() == 0: | ||
return | ||
|
||
var packet = udp.get_packet().get_string_from_ascii() | ||
print("[GDScript] Received UDP packet [", packet.length(), "]: ", packet) | ||
|
||
if not _hot_reload(): | ||
return | ||
|
||
var r = Reloadable.new() | ||
var num = r.get_number() | ||
r.free() | ||
|
||
if num == 777: | ||
print("[GDScript] Successful hot-reload! Exit...") | ||
get_tree().quit(0) | ||
else: | ||
fail(str("Number was not updated correctly (is ", num, ")")) | ||
return | ||
|
||
|
||
func _hot_reload(): | ||
# TODO sometimes fails because .so is not found | ||
var status = GDExtensionManager.reload_extension(extension_name) | ||
if status != OK: | ||
fail(str("Failed to reload extension: ", status)) | ||
return false | ||
|
||
return true | ||
|
||
|
||
func fail(s: String) -> void: | ||
print("::error::[GDScript] ", s) # GitHub Action syntax | ||
get_tree().quit(1) | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
[docks] | ||
|
||
dock_3_selected_tab_idx=0 | ||
dock_4_selected_tab_idx=0 | ||
dock_5_selected_tab_idx=0 | ||
dock_floating={} | ||
dock_bottom=[] | ||
dock_split_2=0 | ||
dock_split_3=0 | ||
dock_hsplit_1=0 | ||
dock_hsplit_2=270 | ||
dock_hsplit_3=-270 | ||
dock_hsplit_4=0 | ||
dock_filesystem_h_split_offset=240 | ||
dock_filesystem_v_split_offset=0 | ||
dock_filesystem_display_mode=0 | ||
dock_filesystem_file_sort=0 | ||
dock_filesystem_file_list_display_mode=1 | ||
dock_filesystem_selected_paths=PackedStringArray("res://MainScene.tscn") | ||
dock_filesystem_uncollapsed_paths=PackedStringArray("Favorites", "res://") | ||
dock_3="Scene,Import" | ||
dock_4="FileSystem" | ||
dock_5="Inspector,Node,History" | ||
|
||
[EditorNode] | ||
|
||
open_scenes=PackedStringArray("res://MainScene.tscn") | ||
current_scene="res://MainScene.tscn" | ||
center_split_offset=0 | ||
selected_default_debugger_tab_idx=0 | ||
selected_main_editor_idx=1 | ||
|
||
[ScriptEditor] | ||
|
||
open_scripts=["res://test/ReloadTest.gd"] | ||
selected_script="res://test/ReloadTest.gd" | ||
open_help=[] | ||
script_split_offset=70 | ||
list_split_offset=0 | ||
zoom_factor=1.0 | ||
|
||
[ShaderEditor] | ||
|
||
open_shaders=[] | ||
split_offset=0 | ||
selected_shader="" | ||
text_shader_zoom_factor=1.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
# Copyright (c) godot-rust; Bromeon and contributors. | ||
# This Source Code Form is subject to the terms of the Mozilla Public | ||
# License, v. 2.0. If a copy of the MPL was not distributed with this | ||
# file, You can obtain one at https://mozilla.org/MPL/2.0/. | ||
|
||
# Python code because it runs outside the engine, and portably sending UDP in bash is cumbersome. | ||
|
||
import select | ||
import socket | ||
import sys | ||
|
||
|
||
def replace_line(file_path: str): | ||
with open(file_path, 'r') as file: | ||
lines = file.readlines() | ||
|
||
replaced = 0 | ||
with open(file_path, 'w') as file: | ||
for line in lines: | ||
if line.strip() == 'fn get_number(&self) -> i64 { 100 }': | ||
file.write(line.replace('100', '777')) | ||
replaced += 1 | ||
else: | ||
file.write(line) | ||
|
||
if replaced == 0: | ||
print("[Python] ERROR: Line not found in file.") | ||
return False | ||
else: | ||
return True | ||
|
||
|
||
def send_udp(): | ||
msg = bytes("reload", "utf-8") | ||
udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | ||
udp.sendto(msg, ("localhost", 1337)) | ||
return True | ||
|
||
|
||
def receive_udp() -> bool: | ||
timeout = 20 | ||
udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | ||
udp.bind(("localhost", 1338)) | ||
|
||
ready = select.select([udp], [], [], 20) | ||
if ready[0]: | ||
# If data is ready, receive it (max 1024 bytes) | ||
data, addr = udp.recvfrom(1024) | ||
print(f"[Python] Await ready; received from {addr}: {data}") | ||
return True | ||
else: | ||
# If no data arrives within the timeout, exit with code 1 | ||
print(f"[Python] ERROR: Await timeout: no packet within {timeout} seconds.") | ||
return False | ||
|
||
|
||
# ----------------------------------------------------------------------------------------------------------------------------------------------- | ||
# Main | ||
|
||
if len(sys.argv) != 2: | ||
print(f"Usage: {sys.argv[0]} [replace|notify]") | ||
sys.exit(2) | ||
|
||
# Get the command from the command line | ||
command = sys.argv[1] | ||
|
||
# Dispatch based on the command | ||
if command == 'await': | ||
print("[Python] Await Godot to be ready...") | ||
ok = receive_udp() | ||
elif command == 'replace': | ||
print("[Python] Replace source code...") | ||
ok = replace_line("../../rust/src/lib.rs") | ||
elif command == 'notify': | ||
print("[Python] Notify Godot about change...") | ||
ok = send_udp() | ||
else: | ||
print("[Python] ERROR: Invalid command.") | ||
sys.exit(2) | ||
|
||
if not ok: | ||
sys.exit(1) | ||
|
||
print("[Python] Done.") |
Oops, something went wrong.