This repository has been archived on 2021-03-28. You can view files and clone it, but cannot push or open issues or pull requests.
formspec_anim/sscsm.lua

98 lines
2.8 KiB
Lua

--
-- formspec_anim SSCSM helper
--
-- Copyright © 2019 by luk3yx
-- License: https://git.minetest.land/luk3yx/formspec_anim/src/branch/master/LICENSE.md
--
local open_formname, open_formspec, elapsed, next_frame
local function cleanup()
open_formname, open_formspec, elapsed, next_frame = nil, nil, nil, nil
end
local function cmd(data)
minetest.run_server_chatcommand('formspec_anim', '\001' .. data)
end
local function send_formspec_input(formname, fields)
assert(not formname:find('\001', nil, true))
cmd(formname .. '\001' .. minetest.write_json(fields))
end
minetest.register_on_formspec_input(function(formname, fields)
if formname:sub(1, 14) ~= 'formspec_anim:' then return end
if fields.quit then
cleanup()
end
send_formspec_input(formname:sub(15), fields)
return true
end)
-- (Re)draw the formspec. This uses a primitive pattern that works with edge
-- cases because the formspec has been interpreted by formspec_ast on the
-- server.
-- Note that duration is in seconds here, it gets converted server-side.
local p = '(image%[[^;]+;[^;]+;)\\%[\001formspec_anim\001:([^,]+)([%+%.])' ..
'\\,([^,]+)\\,([^\001]*)\001'
local function redraw()
next_frame = math.huge
local formspec = open_formspec:gsub(p, function(prefix, count, one_shot,
duration, texture)
count, duration = tonumber(count), tonumber(duration)
local step = math.floor(elapsed / duration)
if one_shot == '.' then
-- One-shot
step = math.min(step + 1, count)
if step < count then
next_frame = math.min(next_frame, step * duration)
end
else
-- Loop
next_frame = math.min(next_frame, (step + 1) * duration)
step = (step % count) + 1
end
-- Numbers are casted to strings automatically.
return prefix .. texture .. step
end)
minetest.show_formspec('formspec_anim:' .. open_formname, formspec)
end
-- Draw the next frame when ready
minetest.register_globalstep(function(dtime)
if not open_formname then return end
elapsed = elapsed + dtime
if elapsed >= next_frame then
redraw()
end
end)
-- Handle formspec opens
local sscsm_msg_prefix = '\001FORMSPEC_ANIM\001'
minetest.register_on_receiving_chat_message(function(message)
if message:sub(1, #sscsm_msg_prefix) ~= sscsm_msg_prefix then
return
end
message = message:sub(#sscsm_msg_prefix + 1)
if message == '' then
cleanup()
return true
end
local s, e = message:find('\001', nil, true)
if not s or not e then return end
local formname = message:sub(1, s - 1)
if formname ~= open_formname then
elapsed = 0
open_formname = formname
end
open_formspec = message:sub(e + 1)
redraw()
return true
end)
cmd('OK')