voxelcore/res/scripts/classes.lua
2026-09-22 02:17:53 +03:00

404 lines
14 KiB
Lua

local Camera = {__index={
get_pos=function(self) return cameras.get_pos(self.cid) end,
set_pos=function(self, v) return cameras.set_pos(self.cid, v) end,
get_name=function(self) return cameras.name(self.cid) end,
get_index=function(self) return self.cid end,
get_rot=function(self) return cameras.get_rot(self.cid) end,
set_rot=function(self, m) return cameras.set_rot(self.cid, m) end,
get_zoom=function(self) return cameras.get_zoom(self.cid) end,
set_zoom=function(self, f) return cameras.set_zoom(self.cid, f) end,
get_fov=function(self) return cameras.get_fov(self.cid) end,
set_fov=function(self, f) return cameras.set_fov(self.cid, f) end,
is_perspective=function(self) return cameras.is_perspective(self.cid) end,
set_perspective=function(self, b) return cameras.set_perspective(self.cid, b) end,
is_flipped=function(self) return cameras.is_flipped(self.cid) end,
set_flipped=function(self, b) return cameras.set_flipped(self.cid, b) end,
get_front=function(self) return cameras.get_front(self.cid) end,
get_right=function(self) return cameras.get_right(self.cid) end,
get_up=function(self) return cameras.get_up(self.cid) end,
look_at=function(self, v, f) return cameras.look_at(self.cid, v, f) end,
}}
local wrappers = {}
cameras.get = function(name)
if type(name) == 'number' then
return cameras.get(cameras.name(name))
end
local wrapper = wrappers[name]
if wrapper ~= nil then
return wrapper
end
local cid = cameras.index(name)
wrapper = setmetatable({cid=cid}, Camera)
wrappers[name] = wrapper
return wrapper
end
local Socket = {__index={
send=function(self, ...) return network.__send(self.id, ...) end,
recv=function(self, ...) return network.__recv(self.id, ...) end,
peek=function(self, ...) return network.__peek(self.id, ...) end,
recv_async=function(self, length, usetable)
while self:is_alive() do
local available = self:available()
if available >= length then
return self:recv(length, usetable)
end
coroutine.yield()
end
return self:recv(length, usetable)
end,
peek_async=function(self, length, usetable)
while self:is_alive() do
local available = self:available()
if available >= length then
return self:peek(length, usetable)
end
coroutine.yield()
end
return self:peek(length, usetable)
end,
as_stream=network.__as_stream,
close=function(self) return network.__close(self.id) end,
available=function(self) return network.__available(self.id) or 0 end,
is_alive=function(self) return network.__is_alive(self.id) end,
is_connected=function(self) return network.__is_connected(self.id) end,
get_address=function(self) return network.__get_address(self.id) end,
set_nodelay=function(self, nodelay) return network.__set_nodelay(self.id, nodelay or false) end,
is_nodelay=function(self) return network.__is_nodelay(self.id) end,
}}
local WriteableSocket = {__index={
send=function(self, ...) return network.__send(self.id, ...) end,
close=function(self) return network.__close(self.id) end,
is_open=function(self) return network.__is_alive(self.id) end,
get_address=function(self) return network.__get_address(self.id) end,
}}
local ServerSocket = {__index={
close=function(self) return network.__closeserver(self.id) end,
is_open=function(self) return network.__is_serveropen(self.id) end,
get_port=function(self) return network.__get_serverport(self.id) end,
}}
local DatagramServerSocket = {__index={
close=function(self) return network.__closeserver(self.id) end,
is_open=function(self) return network.__is_serveropen(self.id) end,
get_port=function(self) return network.__get_serverport(self.id) end,
send=function(self, ...) return network.__udp_server_send_to(self.id, ...) end
}}
local _tcp_server_callbacks = {}
local _tcp_client_callbacks = {}
local _tcp_client_error_callbacks = {}
local _udp_server_callbacks = {}
local _udp_client_datagram_callbacks = {}
local _udp_client_open_callbacks = {}
local _http_response_callbacks = {}
local http_request = network.__request
local open_tcp = network.__open_tcp
local open_udp = network.__open_udp
local connect_tcp = network.__connect_tcp
local connect_udp = network.__connect_udp
local http_open = network.__http_open
local http_respond = network.__http_respond
network.__request = nil
network.__open_tcp = nil
network.__open_udp = nil
network.__connect_tcp = nil
network.__connect_udp = nil
network.__http_open = nil
network.__http_respond = nil
local function request(url, params)
local id = http_request(url, params)
if params.on_response then
_http_response_callbacks[id] = params.on_response
end
end
network.request = request
network.get = function(url, callback, errorCallback, headers)
return request(url, {
method = "GET",
headers = headers,
on_response = function(response)
if response.status / 100 == 2 then
return callback(response.body)
else
return errorCallback(response.status, response.body)
end
end,
on_error = function(response)
errorCallback(response.status, response.body)
end,
follow_location = true,
})
end
network.get_binary = function(url, callback, errorCallback, headers)
return request(url, {
method = "GET",
headers = headers,
on_response = callback and (function (response)
if response.status / 100 == 2 then
return callback(Bytearray(response.body))
else
return errorCallback(response.status, response.body)
end
end),
follow_location = true,
})
end
network.post = function(url, body, callback, errorCallback, headers)
return request(url, {
method = "POST",
headers = table.extend({
"Content-Type: application/json"
}, headers or {}),
body = body,
on_response = function(response)
if response.status / 100 == 2 then
return callback(Bytearray(response.body))
else
return errorCallback(response.status, response.body)
end
end,
follow_location = true,
})
end
network.tcp_open = function (port, handler)
local socket = setmetatable({id=open_tcp(port)}, ServerSocket)
_tcp_server_callbacks[socket.id] = function(id)
handler(setmetatable({id=id}, Socket))
end
return socket
end
network.tcp_connect = function(address, port, callback, errorCallback)
local socket = setmetatable({id=0}, Socket)
socket.id = connect_tcp(address, port)
_tcp_client_callbacks[socket.id] = function() callback(socket) end
if errorCallback then
_tcp_client_error_callbacks[socket.id] = function(message) errorCallback(socket, message) end
end
return socket
end
network.udp_open = function (port, datagramHandler)
if type(datagramHandler) ~= 'function' then
error "udp server cannot be opened without datagram handler"
end
local socket = setmetatable({id=open_udp(port)}, DatagramServerSocket)
_udp_server_callbacks[socket.id] = function(address, port, data)
datagramHandler(address, port, data, socket)
end
return socket
end
network.udp_connect = function (address, port, datagramHandler, openCallback)
if type(datagramHandler) ~= 'function' then
error "udp client socket cannot be opened without datagram handler"
end
local socket = setmetatable({id=0}, WriteableSocket)
socket.id = connect_udp(address, port)
_udp_client_datagram_callbacks[socket.id] = datagramHandler
if openCallback then
_udp_client_open_callbacks[socket.id] = function()
openCallback(socket)
end
end
return socket
end
local _http_server_handlers = {}
local HttpRequest = {__index={
respond=function(self, status, body, headers)
if self.responded then
return
end
self.responded = true
http_respond(self.server_id, self.id, status or 200, headers or {}, body or "")
end,
json=function(self)
return json.parse(self.body)
end,
}}
network.http_open = function(port, handler, timeout_ms)
if handler == nil then
error "http server cannot be opened without a request handler"
end
local socket = setmetatable({id=http_open(port, timeout_ms or 60000)}, ServerSocket)
_http_server_handlers[socket.id] = handler
return socket
end
network.http_json = function(data, status, headers)
return {
status = status or 200,
headers = table.extend({"Content-Type: application/json"}, headers or {}),
body = json.tostring(data)
}
end
local function path_to_pattern(path)
local pattern = string.pattern_safe(path):gsub(":([%w_]+)", "([^/]+)")
return "^"..pattern.."$"
end
local Router = {}
Router.__index = Router
network.http_router = function()
return setmetatable({routes={}}, Router)
end
function Router:route(method, path, handler)
table.insert(self.routes, {
method = method:upper(),
pattern = path_to_pattern(path),
handler = handler
})
return self
end
function Router:get(path, handler) return self:route("GET", path, handler) end
function Router:post(path, handler) return self:route("POST", path, handler) end
function Router:put(path, handler) return self:route("PUT", path, handler) end
function Router:delete(path, handler) return self:route("DELETE", path, handler) end
function Router:patch(path, handler) return self:route("PATCH", path, handler) end
function Router.__call(self, request)
for _, route in ipairs(self.routes) do
if route.method == request.method then
local params = {request.path:match(route.pattern)}
if params[1] ~= nil or request.path:match(route.pattern) then
return route.handler(request, unpack(params))
end
end
end
return {status=404, headers={"Content-Type: text/plain"}, body="Not Found"}
end
local function clean(iterable, checkFun, ...)
local tables = { ... }
for id, _ in pairs(iterable) do
if not checkFun(id) then
for i = 1, #tables do
tables[i][id] = nil
end
end
end
end
network.__process_events = function()
if not network.is_available() then
return
end
local CLIENT_CONNECTED = 1
local CONNECTED_TO_SERVER = 2
local DATAGRAM = 3
local RESPONSE = 4
local CONNECTION_ERROR = 5
local HTTP_REQUEST = 6
local ON_SERVER = 1
local ON_CLIENT = 2
local cleaned = false
local events = network.__pull_events()
for i, event in ipairs(events) do
local etype, sid, cid, addr, port, side, data = unpack(event)
if etype == CLIENT_CONNECTED then
local callback = _tcp_server_callbacks[sid]
if callback then
callback(cid)
end
elseif etype == CONNECTED_TO_SERVER then
local callback = _tcp_client_callbacks[cid] or _udp_client_open_callbacks[cid]
if callback then
callback()
end
elseif etype == CONNECTION_ERROR then
local callback = _tcp_client_error_callbacks[cid]
if callback then
callback(addr)
end
elseif etype == DATAGRAM then
if side == ON_CLIENT then
local callback = _udp_client_datagram_callbacks[cid]
if callback then
callback(data)
end
elseif side == ON_SERVER then
local callback = _udp_server_callbacks[sid]
if callback then
callback(addr, port, data)
end
end
elseif etype == RESPONSE then
local callback = _http_response_callbacks[event[3]]
_http_response_callbacks[event[3]] = nil
if callback then
callback(event[4])
end
elseif etype == HTTP_REQUEST then
local handler = _http_server_handlers[sid]
if handler then
local request = setmetatable({
id = cid,
server_id = sid,
method = addr,
path = port,
query = side,
headers = data,
body = event[8],
remote_addr = event[9],
remote_port = event[10],
responded = false,
}, HttpRequest)
local ok, result = pcall(handler, request)
if not request.responded then
if ok and type(result) == 'table' then
request:respond(result.status, result.body, result.headers)
elseif ok then
request:respond(204)
else
request:respond(500, tostring(result), {"Content-Type: text/plain"})
end
end
end
end
-- remove dead servers
if not cleaned then
clean(_tcp_server_callbacks, network.__is_serveropen, _tcp_server_callbacks)
clean(_tcp_client_callbacks, network.__is_alive, _tcp_client_callbacks)
clean(_udp_server_callbacks, network.__is_serveropen, _udp_server_callbacks)
clean(_udp_client_datagram_callbacks, network.__is_alive, _udp_client_open_callbacks, _udp_client_datagram_callbacks)
clean(_http_server_handlers, network.__is_serveropen, _http_server_handlers)
cleaned = true
end
end
end