Signal and Time API
This commit is contained in:
@@ -798,6 +798,197 @@ var HTML_CONTENT_ADD_REMOVE = """<head>
|
|||||||
""".to_utf8_buffer()
|
""".to_utf8_buffer()
|
||||||
|
|
||||||
var HTML_CONTENT = """<head>
|
var HTML_CONTENT = """<head>
|
||||||
|
<title>Signal API Demo</title>
|
||||||
|
<icon src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/cf/Lua-Logo.svg/256px-Lua-Logo.svg.png">
|
||||||
|
<meta name="theme-color" content="#8b5cf6">
|
||||||
|
<meta name="description" content="Demonstrating the new Signal API with custom events">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body { bg-[#f8fafc] p-6 }
|
||||||
|
h1 { text-[#8b5cf6] text-3xl font-bold text-center }
|
||||||
|
h2 { text-[#6d28d9] text-xl font-semibold }
|
||||||
|
.container { bg-[#ffffff] p-6 rounded-lg shadow-lg max-w-4xl mx-auto }
|
||||||
|
.button-group { flex gap-3 justify-center items-center flex-wrap }
|
||||||
|
.signal-button { px-4 py-2 rounded-lg font-medium cursor-pointer transition-colors }
|
||||||
|
.fire-btn { bg-[#10b981] text-white hover:bg-[#059669] }
|
||||||
|
.connect-btn { bg-[#3b82f6] text-white hover:bg-[#2563eb] }
|
||||||
|
.disconnect-btn { bg-[#ef4444] text-white hover:bg-[#dc2626] }
|
||||||
|
.log-area { bg-[#f1f5f9] p-4 rounded-lg min-h-32 font-mono text-sm }
|
||||||
|
.status-display { bg-[#ddd6fe] p-3 rounded-md text-[#5b21b6] font-mono }
|
||||||
|
.info-box { bg-[#fef3c7] border border-[#f59e0b] p-4 rounded-lg }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
-- Create custom signals
|
||||||
|
local mySignal = Signal.new()
|
||||||
|
local dataSignal = Signal.new()
|
||||||
|
local userActionSignal = Signal.new()
|
||||||
|
|
||||||
|
-- Get UI elements
|
||||||
|
local logArea = gurt.select('#log-area')
|
||||||
|
local statusDisplay = gurt.select('#status-display')
|
||||||
|
local connectBtn = gurt.select('#connect-btn')
|
||||||
|
local disconnectBtn = gurt.select('#disconnect-btn')
|
||||||
|
local fireBtn = gurt.select('#fire-btn')
|
||||||
|
local fireDataBtn = gurt.select('#fire-data-btn')
|
||||||
|
local clearLogBtn = gurt.select('#clear-log-btn')
|
||||||
|
|
||||||
|
gurt.log('Signal API demo script started.')
|
||||||
|
|
||||||
|
local logMessages = {}
|
||||||
|
local connectionCount = 0
|
||||||
|
local activeConnections = {}
|
||||||
|
|
||||||
|
-- Function to add message to log
|
||||||
|
local function addLog(message)
|
||||||
|
table.insert(logMessages, Time.format(Time.now(), '%H:%M:%S') .. ' - ' .. message)
|
||||||
|
if #logMessages > 20 then
|
||||||
|
table.remove(logMessages, 1)
|
||||||
|
end
|
||||||
|
logArea.text = table.concat(logMessages, '\\n')
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Function to update status
|
||||||
|
local function updateStatus()
|
||||||
|
statusDisplay.text = 'Active Connections: ' .. #activeConnections .. '\\nTotal Events Fired: ' .. connectionCount
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Signal handlers
|
||||||
|
local function onMySignal(arg1, arg2)
|
||||||
|
addLog('mySignal fired with args: ' .. (arg1 or 'nil') .. ', ' .. (arg2 or 'nil'))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function onDataSignal(data)
|
||||||
|
addLog('dataSignal received: ' .. table.tostring(data))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function onUserAction(action, timestamp)
|
||||||
|
addLog('userActionSignal: ' .. action .. ' at ' .. timestamp)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Connect button
|
||||||
|
connectBtn:on('click', function()
|
||||||
|
-- Connect multiple handlers to demonstrate multiple connections
|
||||||
|
local conn1 = mySignal:connect(onMySignal)
|
||||||
|
local conn2 = dataSignal:connect(onDataSignal)
|
||||||
|
local conn3 = userActionSignal:connect(onUserAction)
|
||||||
|
|
||||||
|
table.insert(activeConnections, conn1)
|
||||||
|
table.insert(activeConnections, conn2)
|
||||||
|
table.insert(activeConnections, conn3)
|
||||||
|
|
||||||
|
addLog('Connected 3 signal handlers')
|
||||||
|
updateStatus()
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Disconnect button
|
||||||
|
disconnectBtn:on('click', function()
|
||||||
|
for i = 1, #activeConnections do
|
||||||
|
activeConnections[i]:disconnect()
|
||||||
|
end
|
||||||
|
activeConnections = {}
|
||||||
|
addLog('Disconnected all signal handlers')
|
||||||
|
updateStatus()
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Fire simple signal
|
||||||
|
fireBtn:on('click', function()
|
||||||
|
mySignal:fire('Hello', 123)
|
||||||
|
connectionCount = connectionCount + 1
|
||||||
|
addLog('Fired mySignal with two arguments')
|
||||||
|
updateStatus()
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Fire data signal
|
||||||
|
fireDataBtn:on('click', function()
|
||||||
|
local sampleData = {
|
||||||
|
user = 'Alice',
|
||||||
|
score = math.random(100, 999),
|
||||||
|
items = {'sword', 'shield', 'potion'}
|
||||||
|
}
|
||||||
|
dataSignal:fire(sampleData)
|
||||||
|
connectionCount = connectionCount + 1
|
||||||
|
addLog('Fired dataSignal with complex data')
|
||||||
|
updateStatus()
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Fire user action signal
|
||||||
|
gurt.body:on('keypress', function(keyInfo)
|
||||||
|
if #activeConnections > 0 then
|
||||||
|
userActionSignal:fire('keypress: ' .. keyInfo.key, Time.format(Time.now(), '%H:%M:%S'))
|
||||||
|
connectionCount = connectionCount + 1
|
||||||
|
updateStatus()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Clear log button
|
||||||
|
clearLogBtn:on('click', function()
|
||||||
|
logMessages = {}
|
||||||
|
logArea.text = 'Log cleared.'
|
||||||
|
addLog('Log area cleared')
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Initialize with some sample connections
|
||||||
|
local initialConn = mySignal:connect(function(a, b)
|
||||||
|
addLog('Initial handler triggered with: ' .. (a or 'nil') .. ', ' .. (b or 'nil'))
|
||||||
|
end)
|
||||||
|
table.insert(activeConnections, initialConn)
|
||||||
|
|
||||||
|
addLog('Signal API demo initialized')
|
||||||
|
addLog('Try connecting handlers and firing signals!')
|
||||||
|
addLog('Press any key to trigger userActionSignal (when connected)')
|
||||||
|
updateStatus()
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>🔔 Signal API Demo</h1>
|
||||||
|
|
||||||
|
<div style="container mt-6">
|
||||||
|
<div style="info-box mb-6">
|
||||||
|
<p><strong>Signal API Usage Example:</strong></p>
|
||||||
|
<p><code>local mySignal = Signal.new()</code></p>
|
||||||
|
<p><code>mySignal:connect(function(arg1, arg2) print("Event fired with: ", arg1, arg2) end)</code></p>
|
||||||
|
<p><code>mySignal:fire("Hello", 123)</code></p>
|
||||||
|
<p><code>connection:disconnect()</code></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Controls</h2>
|
||||||
|
<div style="button-group mb-6">
|
||||||
|
<button id="connect-btn" style="signal-button connect-btn">🔗 Connect Handlers</button>
|
||||||
|
<button id="disconnect-btn" style="signal-button disconnect-btn">❌ Disconnect All</button>
|
||||||
|
<button id="fire-btn" style="signal-button fire-btn">🔔 Fire Simple Signal</button>
|
||||||
|
<button id="fire-data-btn" style="signal-button fire-btn">📊 Fire Data Signal</button>
|
||||||
|
<button id="clear-log-btn" style="signal-button">🧹 Clear Log</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Status</h2>
|
||||||
|
<div style="status-display mb-6">
|
||||||
|
<pre id="status-display">Loading status...</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Event Log</h2>
|
||||||
|
<div style="log-area mb-6">
|
||||||
|
<pre id="log-area">Initializing...</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="bg-[#e0f2fe] p-4 rounded-lg">
|
||||||
|
<h3 style="text-[#0277bd] font-semibold mb-2">Signal API Features:</h3>
|
||||||
|
<ul style="text-[#01579b] space-y-1">
|
||||||
|
<li><strong>Signal.new():</strong> Creates a new signal object</li>
|
||||||
|
<li><strong>signal:connect(callback):</strong> Connects a callback function and returns a connection object</li>
|
||||||
|
<li><strong>signal:fire(...):</strong> Fires the signal with optional arguments</li>
|
||||||
|
<li><strong>connection:disconnect():</strong> Disconnects a specific connection</li>
|
||||||
|
<li><strong>signal:disconnect():</strong> Disconnects all connections from the signal</li>
|
||||||
|
<li><strong>Multiple Connections:</strong> One signal can have multiple connected callbacks</li>
|
||||||
|
<li><strong>Argument Passing:</strong> Signals can pass multiple arguments to connected callbacks</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
""".to_utf8_buffer()
|
||||||
|
|
||||||
|
var HTML_CONTENTa = """<head>
|
||||||
<title>Button getAttribute/setAttribute Demo</title>
|
<title>Button getAttribute/setAttribute Demo</title>
|
||||||
<icon src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/cf/Lua-Logo.svg/256px-Lua-Logo.svg.png">
|
<icon src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/cf/Lua-Logo.svg/256px-Lua-Logo.svg.png">
|
||||||
<meta name="theme-color" content="#3b82f6">
|
<meta name="theme-color" content="#3b82f6">
|
||||||
|
|||||||
@@ -27,6 +27,12 @@ static func setup_gurt_api(vm: LuauVM, lua_api, dom_parser: HTMLParser) -> void:
|
|||||||
vm.lua_setfield(-2, "tostring")
|
vm.lua_setfield(-2, "tostring")
|
||||||
vm.lua_pop(1) # Pop table from stack
|
vm.lua_pop(1) # Pop table from stack
|
||||||
|
|
||||||
|
# Setup Signal API
|
||||||
|
LuaSignalUtils.setup_signal_api(vm)
|
||||||
|
|
||||||
|
# Setup Time API
|
||||||
|
LuaTimeUtils.setup_time_api(vm)
|
||||||
|
|
||||||
vm.lua_newtable()
|
vm.lua_newtable()
|
||||||
|
|
||||||
vm.lua_pushcallable(LuaPrintUtils.lua_print, "gurt.log")
|
vm.lua_pushcallable(LuaPrintUtils.lua_print, "gurt.log")
|
||||||
|
|||||||
223
flumi/Scripts/Utils/Lua/Signal.gd
Normal file
223
flumi/Scripts/Utils/Lua/Signal.gd
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
class_name LuaSignalUtils
|
||||||
|
extends RefCounted
|
||||||
|
|
||||||
|
# Signal API for Lua - provides custom signal functionality
|
||||||
|
# Usage: local mySignal = Signal.new(), mySignal:connect(callback), mySignal:fire(args...)
|
||||||
|
|
||||||
|
class LuaSignal:
|
||||||
|
var connections: Array[Dictionary] = []
|
||||||
|
var next_connection_id: int = 1
|
||||||
|
var signal_table_ref: int = -1
|
||||||
|
|
||||||
|
func connect_callback(callback_ref: int, vm: LuauVM) -> int:
|
||||||
|
var connection_id = next_connection_id
|
||||||
|
next_connection_id += 1
|
||||||
|
|
||||||
|
var connection = {
|
||||||
|
"id": connection_id,
|
||||||
|
"callback_ref": callback_ref,
|
||||||
|
"vm": vm
|
||||||
|
}
|
||||||
|
connections.append(connection)
|
||||||
|
return connection_id
|
||||||
|
|
||||||
|
func disconnect_callback(connection_id: int, vm: LuauVM) -> void:
|
||||||
|
for i in range(connections.size() - 1, -1, -1):
|
||||||
|
var connection = connections[i]
|
||||||
|
if connection.id == connection_id:
|
||||||
|
# Clean up the Lua reference from custom storage
|
||||||
|
vm.lua_pushstring("SIGNAL_CALLBACKS")
|
||||||
|
vm.lua_rawget(vm.LUA_REGISTRYINDEX)
|
||||||
|
vm.lua_pushinteger(connection.callback_ref)
|
||||||
|
vm.lua_pushnil()
|
||||||
|
vm.lua_rawset(-3) # Set callbacks[callback_ref] = nil
|
||||||
|
vm.lua_pop(1) # Pop callbacks table
|
||||||
|
connections.remove_at(i)
|
||||||
|
break
|
||||||
|
|
||||||
|
func disconnect_all(vm: LuauVM) -> void:
|
||||||
|
# Clean up all Lua references from custom storage
|
||||||
|
vm.lua_pushstring("SIGNAL_CALLBACKS")
|
||||||
|
vm.lua_rawget(vm.LUA_REGISTRYINDEX)
|
||||||
|
for connection in connections:
|
||||||
|
vm.lua_pushinteger(connection.callback_ref)
|
||||||
|
vm.lua_pushnil()
|
||||||
|
vm.lua_rawset(-3) # Set callbacks[callback_ref] = nil
|
||||||
|
vm.lua_pop(1) # Pop callbacks table
|
||||||
|
connections.clear()
|
||||||
|
|
||||||
|
func fire_signal(args: Array, signal_table_ref: int = -1) -> void:
|
||||||
|
for connection in connections:
|
||||||
|
var vm = connection.vm as LuauVM
|
||||||
|
# Get the callback function from our custom storage
|
||||||
|
vm.lua_pushstring("SIGNAL_CALLBACKS")
|
||||||
|
vm.lua_rawget(vm.LUA_REGISTRYINDEX)
|
||||||
|
vm.lua_pushinteger(connection.callback_ref)
|
||||||
|
vm.lua_rawget(-2)
|
||||||
|
if vm.lua_isfunction(-1):
|
||||||
|
# Push the arguments directly (don't pass self)
|
||||||
|
for arg in args:
|
||||||
|
vm.lua_pushvariant(arg)
|
||||||
|
|
||||||
|
# Call the function
|
||||||
|
if vm.lua_pcall(args.size(), 0, 0) != vm.LUA_OK:
|
||||||
|
print("GURT ERROR in Signal callback: ", vm.lua_tostring(-1))
|
||||||
|
vm.lua_pop(1)
|
||||||
|
# Pop the callbacks table
|
||||||
|
vm.lua_pop(1)
|
||||||
|
else:
|
||||||
|
vm.lua_pop(2) # Pop both the non-function and the callbacks table
|
||||||
|
|
||||||
|
static var signals_registry: Dictionary = {}
|
||||||
|
static var next_signal_id: int = 1
|
||||||
|
static var next_callback_ref: int = 1
|
||||||
|
|
||||||
|
# Signal.new() constructor
|
||||||
|
static func signal_new_handler(vm: LuauVM) -> int:
|
||||||
|
var signal_id = next_signal_id
|
||||||
|
next_signal_id += 1
|
||||||
|
|
||||||
|
var lua_signal = LuaSignal.new()
|
||||||
|
signals_registry[signal_id] = lua_signal
|
||||||
|
|
||||||
|
# Create the signal table
|
||||||
|
vm.lua_newtable()
|
||||||
|
vm.lua_pushinteger(signal_id)
|
||||||
|
vm.lua_setfield(-2, "_signal_id")
|
||||||
|
|
||||||
|
# Store a reference to this signal table for : syntax
|
||||||
|
vm.lua_pushvalue(-1) # Duplicate the signal table
|
||||||
|
var signal_table_ref = vm.luaL_ref(vm.LUA_REGISTRYINDEX)
|
||||||
|
lua_signal.signal_table_ref = signal_table_ref
|
||||||
|
|
||||||
|
# Add methods
|
||||||
|
vm.lua_pushcallable(signal_connect_handler, "signal:connect")
|
||||||
|
vm.lua_setfield(-2, "connect")
|
||||||
|
|
||||||
|
vm.lua_pushcallable(signal_fire_handler, "signal:fire")
|
||||||
|
vm.lua_setfield(-2, "fire")
|
||||||
|
|
||||||
|
vm.lua_pushcallable(signal_disconnect_handler, "signal:disconnect")
|
||||||
|
vm.lua_setfield(-2, "disconnect")
|
||||||
|
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# signal:connect(callback) method
|
||||||
|
static func signal_connect_handler(vm: LuauVM) -> int:
|
||||||
|
vm.luaL_checktype(1, vm.LUA_TTABLE)
|
||||||
|
vm.luaL_checktype(2, vm.LUA_TFUNCTION)
|
||||||
|
|
||||||
|
# Get signal ID
|
||||||
|
vm.lua_getfield(1, "_signal_id")
|
||||||
|
var signal_id: int = vm.lua_tointeger(-1)
|
||||||
|
vm.lua_pop(1)
|
||||||
|
|
||||||
|
var lua_signal = signals_registry.get(signal_id) as LuaSignal
|
||||||
|
if not lua_signal:
|
||||||
|
vm.lua_pushnil()
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# Store callback in a custom registry table instead of using luaL_ref
|
||||||
|
# Get or create our custom callback storage table
|
||||||
|
vm.lua_pushstring("SIGNAL_CALLBACKS")
|
||||||
|
vm.lua_rawget(vm.LUA_REGISTRYINDEX)
|
||||||
|
if vm.lua_isnil(-1):
|
||||||
|
vm.lua_pop(1) # Pop nil
|
||||||
|
vm.lua_newtable() # Create new table
|
||||||
|
vm.lua_pushstring("SIGNAL_CALLBACKS")
|
||||||
|
vm.lua_pushvalue(-2) # Duplicate the table
|
||||||
|
vm.lua_rawset(vm.LUA_REGISTRYINDEX) # Set SIGNAL_CALLBACKS = table
|
||||||
|
|
||||||
|
# Now store the callback function
|
||||||
|
var callback_ref = next_callback_ref
|
||||||
|
next_callback_ref += 1
|
||||||
|
|
||||||
|
vm.lua_pushinteger(callback_ref) # Key
|
||||||
|
vm.lua_pushvalue(2) # Value (the callback function)
|
||||||
|
vm.lua_rawset(-3) # Set callbacks[callback_ref] = function
|
||||||
|
|
||||||
|
vm.lua_pop(1) # Pop the callbacks table
|
||||||
|
|
||||||
|
# Connect the callback
|
||||||
|
var connection_id = lua_signal.connect_callback(callback_ref, vm)
|
||||||
|
|
||||||
|
# Return connection object
|
||||||
|
vm.lua_newtable()
|
||||||
|
vm.lua_pushinteger(connection_id)
|
||||||
|
vm.lua_setfield(-2, "_connection_id")
|
||||||
|
vm.lua_pushinteger(signal_id)
|
||||||
|
vm.lua_setfield(-2, "_signal_id")
|
||||||
|
|
||||||
|
vm.lua_pushcallable(connection_disconnect_handler, "connection:disconnect")
|
||||||
|
vm.lua_setfield(-2, "disconnect")
|
||||||
|
|
||||||
|
return 1
|
||||||
|
|
||||||
|
# signal:fire(...) method
|
||||||
|
static func signal_fire_handler(vm: LuauVM) -> int:
|
||||||
|
vm.luaL_checktype(1, vm.LUA_TTABLE)
|
||||||
|
|
||||||
|
# Get signal ID
|
||||||
|
vm.lua_getfield(1, "_signal_id")
|
||||||
|
var signal_id: int = vm.lua_tointeger(-1)
|
||||||
|
vm.lua_pop(1)
|
||||||
|
|
||||||
|
var lua_signal = signals_registry.get(signal_id) as LuaSignal
|
||||||
|
if not lua_signal:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# Collect arguments (everything after the signal table)
|
||||||
|
var args: Array = []
|
||||||
|
var arg_count = vm.lua_gettop() - 1 # Subtract 1 for the signal table itself
|
||||||
|
for i in range(2, arg_count + 2): # Start from index 2 (after signal table)
|
||||||
|
args.append(vm.lua_tovariant(i))
|
||||||
|
|
||||||
|
# Fire the signal with the signal table reference
|
||||||
|
lua_signal.fire_signal(args, lua_signal.signal_table_ref)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# signal:disconnect() method - disconnects all connections
|
||||||
|
static func signal_disconnect_handler(vm: LuauVM) -> int:
|
||||||
|
vm.luaL_checktype(1, vm.LUA_TTABLE)
|
||||||
|
|
||||||
|
# Get signal ID
|
||||||
|
vm.lua_getfield(1, "_signal_id")
|
||||||
|
var signal_id: int = vm.lua_tointeger(-1)
|
||||||
|
vm.lua_pop(1)
|
||||||
|
|
||||||
|
var lua_signal = signals_registry.get(signal_id) as LuaSignal
|
||||||
|
if lua_signal:
|
||||||
|
lua_signal.disconnect_all(vm)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# connection:disconnect() method - disconnects specific connection
|
||||||
|
static func connection_disconnect_handler(vm: LuauVM) -> int:
|
||||||
|
vm.luaL_checktype(1, vm.LUA_TTABLE)
|
||||||
|
|
||||||
|
# Get connection ID and signal ID
|
||||||
|
vm.lua_getfield(1, "_connection_id")
|
||||||
|
var connection_id: int = vm.lua_tointeger(-1)
|
||||||
|
vm.lua_pop(1)
|
||||||
|
|
||||||
|
vm.lua_getfield(1, "_signal_id")
|
||||||
|
var signal_id: int = vm.lua_tointeger(-1)
|
||||||
|
vm.lua_pop(1)
|
||||||
|
|
||||||
|
var lua_signal = signals_registry.get(signal_id) as LuaSignal
|
||||||
|
if lua_signal:
|
||||||
|
lua_signal.disconnect_callback(connection_id, vm)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
static func setup_signal_api(vm: LuauVM) -> void:
|
||||||
|
# Create Signal table
|
||||||
|
vm.lua_newtable()
|
||||||
|
|
||||||
|
# Add Signal.new constructor
|
||||||
|
vm.lua_pushcallable(signal_new_handler, "Signal.new")
|
||||||
|
vm.lua_setfield(-2, "new")
|
||||||
|
|
||||||
|
# Set as global Signal
|
||||||
|
vm.lua_setglobal("Signal")
|
||||||
1
flumi/Scripts/Utils/Lua/Signal.gd.uid
Normal file
1
flumi/Scripts/Utils/Lua/Signal.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://drb1qy7epbtwe
|
||||||
244
flumi/Scripts/Utils/Lua/Time.gd
Normal file
244
flumi/Scripts/Utils/Lua/Time.gd
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
class_name LuaTimeUtils
|
||||||
|
extends RefCounted
|
||||||
|
|
||||||
|
static func time_now_handler(vm: LuauVM) -> int:
|
||||||
|
var current_time = Time.get_unix_time_from_system()
|
||||||
|
vm.lua_pushnumber(current_time)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
static func time_format_handler(vm: LuauVM) -> int:
|
||||||
|
var format_string: String = "%H:%M:%S"
|
||||||
|
var datetime: Dictionary
|
||||||
|
|
||||||
|
if vm.lua_gettop() >= 1 and vm.lua_isnumber(1):
|
||||||
|
var timestamp: float = vm.lua_tonumber(1)
|
||||||
|
|
||||||
|
var local_now_dict = Time.get_datetime_dict_from_system(false)
|
||||||
|
var utc_now_dict = Time.get_datetime_dict_from_system(true)
|
||||||
|
var offset_seconds = Time.get_unix_time_from_datetime_dict(local_now_dict) - Time.get_unix_time_from_datetime_dict(utc_now_dict)
|
||||||
|
|
||||||
|
datetime = Time.get_datetime_dict_from_unix_time(int(timestamp) + offset_seconds)
|
||||||
|
else:
|
||||||
|
datetime = Time.get_datetime_dict_from_system(false)
|
||||||
|
|
||||||
|
if vm.lua_gettop() >= 2 and vm.lua_isstring(2):
|
||||||
|
format_string = vm.lua_tostring(2)
|
||||||
|
|
||||||
|
var formatted_time = format_datetime(datetime, format_string)
|
||||||
|
|
||||||
|
vm.lua_pushstring(formatted_time)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
static func time_date_handler(vm: LuauVM) -> int:
|
||||||
|
var datetime: Dictionary
|
||||||
|
|
||||||
|
if vm.lua_gettop() >= 1 and vm.lua_isnumber(1):
|
||||||
|
var timestamp = vm.lua_tonumber(1)
|
||||||
|
|
||||||
|
var local_now_dict = Time.get_datetime_dict_from_system(false)
|
||||||
|
var utc_now_dict = Time.get_datetime_dict_from_system(true)
|
||||||
|
var offset_seconds = Time.get_unix_time_from_datetime_dict(local_now_dict) - Time.get_unix_time_from_datetime_dict(utc_now_dict)
|
||||||
|
|
||||||
|
datetime = Time.get_datetime_dict_from_unix_time(int(timestamp) + offset_seconds)
|
||||||
|
else:
|
||||||
|
datetime = Time.get_datetime_dict_from_system(false)
|
||||||
|
|
||||||
|
vm.lua_newtable()
|
||||||
|
vm.lua_pushinteger(datetime.year)
|
||||||
|
vm.lua_setfield(-2, "year")
|
||||||
|
vm.lua_pushinteger(datetime.month)
|
||||||
|
vm.lua_setfield(-2, "month")
|
||||||
|
vm.lua_pushinteger(datetime.day)
|
||||||
|
vm.lua_setfield(-2, "day")
|
||||||
|
vm.lua_pushinteger(datetime.hour)
|
||||||
|
vm.lua_setfield(-2, "hour")
|
||||||
|
vm.lua_pushinteger(datetime.minute)
|
||||||
|
vm.lua_setfield(-2, "minute")
|
||||||
|
vm.lua_pushinteger(datetime.second)
|
||||||
|
vm.lua_setfield(-2, "second")
|
||||||
|
vm.lua_pushinteger(datetime.weekday)
|
||||||
|
vm.lua_setfield(-2, "weekday")
|
||||||
|
|
||||||
|
return 1
|
||||||
|
|
||||||
|
static func time_sleep_handler(vm: LuauVM) -> int:
|
||||||
|
vm.luaL_checknumber(1)
|
||||||
|
var seconds = vm.lua_tonumber(1)
|
||||||
|
var milliseconds = int(seconds * 1000)
|
||||||
|
|
||||||
|
# TODO: implement a proper sleep function
|
||||||
|
|
||||||
|
vm.lua_pushnumber(seconds)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
static func time_benchmark_handler(vm: LuauVM) -> int:
|
||||||
|
vm.luaL_checktype(1, vm.LUA_TFUNCTION)
|
||||||
|
|
||||||
|
var start_time = Time.get_ticks_msec()
|
||||||
|
|
||||||
|
vm.lua_pushvalue(1)
|
||||||
|
if vm.lua_pcall(0, 0, 0) != vm.LUA_OK:
|
||||||
|
var error_msg = vm.lua_tostring(-1)
|
||||||
|
vm.lua_pop(1)
|
||||||
|
|
||||||
|
var end_time = Time.get_ticks_msec()
|
||||||
|
var elapsed_ms = end_time - start_time
|
||||||
|
|
||||||
|
vm.lua_pushnumber(elapsed_ms / 1000.0)
|
||||||
|
vm.lua_pushstring("Error: " + error_msg)
|
||||||
|
return 2
|
||||||
|
|
||||||
|
var end_time = Time.get_ticks_msec()
|
||||||
|
var elapsed_ms = end_time - start_time
|
||||||
|
|
||||||
|
vm.lua_pushnumber(elapsed_ms / 1000.0)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
static func time_timer_handler(vm: LuauVM) -> int:
|
||||||
|
var start_time = Time.get_ticks_msec()
|
||||||
|
|
||||||
|
vm.lua_newtable()
|
||||||
|
vm.lua_pushnumber(start_time)
|
||||||
|
vm.lua_setfield(-2, "_start_time")
|
||||||
|
|
||||||
|
vm.lua_pushcallable(timer_elapsed_handler, "timer:elapsed")
|
||||||
|
vm.lua_setfield(-2, "elapsed")
|
||||||
|
|
||||||
|
vm.lua_pushcallable(timer_reset_handler, "timer:reset")
|
||||||
|
vm.lua_setfield(-2, "reset")
|
||||||
|
|
||||||
|
return 1
|
||||||
|
|
||||||
|
static func timer_elapsed_handler(vm: LuauVM) -> int:
|
||||||
|
vm.luaL_checktype(1, vm.LUA_TTABLE)
|
||||||
|
|
||||||
|
vm.lua_getfield(1, "_start_time")
|
||||||
|
var start_time = vm.lua_tonumber(-1)
|
||||||
|
vm.lua_pop(1)
|
||||||
|
|
||||||
|
var current_time = Time.get_ticks_msec()
|
||||||
|
var elapsed = (current_time - start_time) / 1000.0
|
||||||
|
|
||||||
|
vm.lua_pushnumber(elapsed)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
static func timer_reset_handler(vm: LuauVM) -> int:
|
||||||
|
vm.luaL_checktype(1, vm.LUA_TTABLE)
|
||||||
|
|
||||||
|
var current_time = Time.get_ticks_msec()
|
||||||
|
vm.lua_pushnumber(current_time)
|
||||||
|
vm.lua_setfield(1, "_start_time")
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
static func time_delay_handler(vm: LuauVM) -> int:
|
||||||
|
vm.luaL_checknumber(1)
|
||||||
|
var seconds = vm.lua_tonumber(1)
|
||||||
|
var end_time = Time.get_ticks_msec() + (seconds * 1000)
|
||||||
|
|
||||||
|
vm.lua_newtable()
|
||||||
|
vm.lua_pushnumber(end_time)
|
||||||
|
vm.lua_setfield(-2, "_end_time")
|
||||||
|
|
||||||
|
vm.lua_pushcallable(delay_is_complete_handler, "delay:complete")
|
||||||
|
vm.lua_setfield(-2, "complete")
|
||||||
|
|
||||||
|
vm.lua_pushcallable(delay_remaining_handler, "delay:remaining")
|
||||||
|
vm.lua_setfield(-2, "remaining")
|
||||||
|
|
||||||
|
return 1
|
||||||
|
|
||||||
|
static func delay_is_complete_handler(vm: LuauVM) -> int:
|
||||||
|
vm.luaL_checktype(1, vm.LUA_TTABLE)
|
||||||
|
|
||||||
|
vm.lua_getfield(1, "_end_time")
|
||||||
|
var end_time = vm.lua_tonumber(-1)
|
||||||
|
vm.lua_pop(1)
|
||||||
|
|
||||||
|
var current_time = Time.get_ticks_msec()
|
||||||
|
var is_complete = current_time >= end_time
|
||||||
|
|
||||||
|
vm.lua_pushboolean(is_complete)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
static func delay_remaining_handler(vm: LuauVM) -> int:
|
||||||
|
vm.luaL_checktype(1, vm.LUA_TTABLE)
|
||||||
|
|
||||||
|
vm.lua_getfield(1, "_end_time")
|
||||||
|
var end_time = vm.lua_tonumber(-1)
|
||||||
|
vm.lua_pop(1)
|
||||||
|
|
||||||
|
var current_time = Time.get_ticks_msec()
|
||||||
|
var remaining = max(0.0, (end_time - current_time) / 1000.0)
|
||||||
|
|
||||||
|
vm.lua_pushnumber(remaining)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
static func format_datetime(datetime: Dictionary, format_string: String) -> String:
|
||||||
|
var result = format_string
|
||||||
|
|
||||||
|
var local_datetime = datetime
|
||||||
|
if not local_datetime.has("weekday"):
|
||||||
|
var unix_time = Time.get_unix_time_from_datetime_dict(local_datetime)
|
||||||
|
local_datetime = Time.get_datetime_dict_from_unix_time(unix_time)
|
||||||
|
|
||||||
|
var ampm = ""
|
||||||
|
var hour12 = local_datetime.hour
|
||||||
|
if local_datetime.hour >= 12:
|
||||||
|
ampm = "pm"
|
||||||
|
if local_datetime.hour > 12:
|
||||||
|
hour12 = local_datetime.hour - 12
|
||||||
|
else:
|
||||||
|
ampm = "am"
|
||||||
|
if local_datetime.hour == 0:
|
||||||
|
hour12 = 12
|
||||||
|
|
||||||
|
result = result.replace("%Y", "%04d" % local_datetime.year)
|
||||||
|
result = result.replace("%y", "%02d" % (local_datetime.year % 100))
|
||||||
|
result = result.replace("%m", "%02d" % local_datetime.month)
|
||||||
|
result = result.replace("%d", "%02d" % local_datetime.day)
|
||||||
|
result = result.replace("%H", "%02d" % local_datetime.hour)
|
||||||
|
result = result.replace("%I", "%02d" % hour12)
|
||||||
|
result = result.replace("%M", "%02d" % local_datetime.minute)
|
||||||
|
result = result.replace("%S", "%02d" % local_datetime.second)
|
||||||
|
result = result.replace("%p", ampm)
|
||||||
|
|
||||||
|
var weekday_names = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
|
||||||
|
var weekday_abbrev = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
|
||||||
|
if local_datetime.weekday >= 0 and local_datetime.weekday <= 6:
|
||||||
|
result = result.replace("%A", weekday_names[local_datetime.weekday])
|
||||||
|
result = result.replace("%a", weekday_abbrev[local_datetime.weekday])
|
||||||
|
|
||||||
|
var month_names = ["January", "February", "March", "April", "May", "June","July", "August", "September", "October", "November", "December"]
|
||||||
|
var month_abbrev = ["Jan", "Feb", "Mar", "Apr", "May", "Jun","Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
|
||||||
|
if local_datetime.month >= 1 and local_datetime.month <= 12:
|
||||||
|
result = result.replace("%B", month_names[local_datetime.month - 1])
|
||||||
|
result = result.replace("%b", month_abbrev[local_datetime.month - 1])
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
static func setup_time_api(vm: LuauVM) -> void:
|
||||||
|
vm.lua_newtable()
|
||||||
|
|
||||||
|
vm.lua_pushcallable(time_now_handler, "Time.now")
|
||||||
|
vm.lua_setfield(-2, "now")
|
||||||
|
|
||||||
|
vm.lua_pushcallable(time_format_handler, "Time.format")
|
||||||
|
vm.lua_setfield(-2, "format")
|
||||||
|
|
||||||
|
vm.lua_pushcallable(time_date_handler, "Time.date")
|
||||||
|
vm.lua_setfield(-2, "date")
|
||||||
|
|
||||||
|
vm.lua_pushcallable(time_sleep_handler, "Time.sleep")
|
||||||
|
vm.lua_setfield(-2, "sleep")
|
||||||
|
|
||||||
|
vm.lua_pushcallable(time_benchmark_handler, "Time.benchmark")
|
||||||
|
vm.lua_setfield(-2, "benchmark")
|
||||||
|
|
||||||
|
vm.lua_pushcallable(time_timer_handler, "Time.timer")
|
||||||
|
vm.lua_setfield(-2, "timer")
|
||||||
|
|
||||||
|
vm.lua_pushcallable(time_delay_handler, "Time.delay")
|
||||||
|
vm.lua_setfield(-2, "delay")
|
||||||
|
|
||||||
|
vm.lua_setglobal("Time")
|
||||||
1
flumi/Scripts/Utils/Lua/Time.gd.uid
Normal file
1
flumi/Scripts/Utils/Lua/Time.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://ntey7mujnbo6
|
||||||
Reference in New Issue
Block a user