onNextFrame

This commit is contained in:
Face
2025-09-11 17:30:28 +03:00
parent a51223250f
commit eddf0f370c
6 changed files with 69 additions and 17 deletions

View File

@@ -58,4 +58,17 @@ local clean = string.trim(messy)
trace.log('"' .. clean .. '"') -- "Hello World"
```
This is particularly useful for debugging and logging complex data structures.
### onNextFrame(callback)
Schedules a function to execute on the next frame render cycle. This helps sync your code with Godot's render pipeline, eliminating stuff like flickering.
```lua
local canvas = gurt.select("#my-canvas")
local ctx = canvas:withContext("2d")
onNextFrame(function()
local x = math.random(0, canvas.width - 100)
local y = math.random(0, canvas.height - 100)
ctx:fillRect(x, y, 100, 100, "#ff0000")
end)
```

View File

@@ -9,7 +9,7 @@ var draw_commands: Array = []
var context_2d: CanvasContext2D = null
var context_shader: CanvasContextShader = null
var pending_redraw: bool = false
var max_draw_commands: int = 1000
var max_draw_commands: int = 10000
class CanvasContext2D:
var canvas: HTMLCanvas

View File

@@ -9,16 +9,32 @@ static var batch_timer: SceneTreeTimer = null
static func emit_canvas_operation(lua_api: LuaAPI, operation: Dictionary) -> void:
var element_id = operation.get("element_id", "")
if not pending_operations.has(element_id):
pending_operations[element_id] = []
# SUPER HACKY WAY TO FIX ODD ERRORS DESPITE EXISTING CHECKS
if element_id == "":
return
pending_operations[element_id].append(operation)
var safe_element_id = str(element_id)
var ops_array = pending_operations.get(safe_element_id, null)
if not batch_timer or batch_timer.time_left <= 0:
if ops_array == null or not (ops_array is Array):
ops_array = []
pending_operations[safe_element_id] = ops_array
ops_array.append(operation)
var should_create_timer = false
if batch_timer == null or not is_instance_valid(batch_timer):
should_create_timer = true
else:
if batch_timer.time_left <= 0:
should_create_timer = true
if should_create_timer:
var scene_tree = lua_api.get_tree() if lua_api else Engine.get_main_loop()
if scene_tree:
batch_timer = scene_tree.create_timer(0.001) # 1ms batch window
batch_timer.timeout.connect(_flush_pending_operations.bind(lua_api))
# END HACKY WAY
static func _flush_pending_operations(lua_api: LuaAPI) -> void:
if not lua_api or not lua_api.is_inside_tree():

View File

@@ -406,9 +406,41 @@ func _setup_additional_lua_apis():
LuaDownloadUtils.setup_download_api(lua_vm)
LuaCrumbsUtils.setup_crumbs_api(lua_vm)
LuaRegexUtils.setup_regex_api(lua_vm)
lua_vm.lua_pushcallable(_onNextFrame_handler, "onNextFrame")
lua_vm.lua_setglobal("onNextFrame")
LuaURLUtils.setup_url_api(lua_vm)
Trace.setup_trace_api(lua_vm)
func _onNextFrame_handler(vm: LuauVM) -> int:
vm.luaL_checktype(1, vm.LUA_TFUNCTION)
vm.lua_pushstring("THREADED_CALLBACKS")
vm.lua_rawget(vm.LUA_REGISTRYINDEX)
if vm.lua_isnil(-1):
vm.lua_pop(1)
vm.lua_newtable()
vm.lua_pushstring("THREADED_CALLBACKS")
vm.lua_pushvalue(-2)
vm.lua_rawset(vm.LUA_REGISTRYINDEX)
var callback_ref = lua_api.next_callback_ref
lua_api.next_callback_ref += 1
vm.lua_pushinteger(callback_ref)
vm.lua_pushvalue(1)
vm.lua_rawset(-3)
vm.lua_pop(1)
# Schedule callback execution on next frame
var scene_tree = Engine.get_main_loop() as SceneTree
if scene_tree:
var frame_callback = func():
execute_callback_async(callback_ref, [])
scene_tree.process_frame.connect(frame_callback, CONNECT_ONE_SHOT)
return 0
func _table_tostring_handler(vm: LuauVM) -> int:
vm.luaL_checktype(1, vm.LUA_TTABLE)
var table_string = LuaPrintUtils.table_to_string(vm, 1)

View File

@@ -124,6 +124,8 @@ class WebSocketWrapper:
# Call the function
var result = vm.lua_pcall(1, 0, 0)
if result != vm.LUA_OK:
var error_msg = vm.lua_tostring(-1)
print("WebSocket event error: ", error_msg)
vm.lua_pop(1)
else:
vm.lua_pop(1) # Pop the non-function value

View File

@@ -114,17 +114,6 @@
addLog('WebSocket API demo ready')
end)
messageInput:on('keypress', function(e)
if e.key == 'Enter' and socket and connected then
local message = messageInput.text
if message and message ~= '' then
socket:send(message)
addLog('📤 Sent: ' .. message)
messageInput.text = ''
end
end
end)
updateStatus('Disconnected', 'disconnected')
addLog('WebSocket API demo ready')
addLog('Enter a WebSocket URL and click Connect to start!')