310 lines
6.4 KiB
Lua
310 lines
6.4 KiB
Lua
--[[
|
|
This file is part of Ice Lua Components.
|
|
|
|
Ice Lua Components is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Ice Lua Components is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with Ice Lua Components. If not, see <http://www.gnu.org/licenses/>.
|
|
]]
|
|
|
|
-- Simple, not necessarily secure sandbox.
|
|
-- More like a VM.
|
|
sandbox = {}
|
|
|
|
do
|
|
|
|
local sb_counter = 1
|
|
local sb_list = {}
|
|
local sb_aux = {}
|
|
local sb_ctl = {}
|
|
local sb_current = ""
|
|
|
|
local sb_wrap_fetch = loadfile("pkg/base/sandbox/fetch.lua")(sb_list, sb_aux, sb_ctl)
|
|
local sb_wrap_audio = loadfile("pkg/base/sandbox/wav.lua")(sb_list, sb_aux, sb_ctl)
|
|
local sb_wrap_gfx = loadfile("pkg/base/sandbox/gfx.lua")(sb_list, sb_aux, sb_ctl)
|
|
|
|
local function table_dup(S)
|
|
if S == nil then return nil end
|
|
|
|
local D = {}
|
|
local k, v
|
|
|
|
for k, v in pairs(S) do
|
|
if type(v) == "table" then
|
|
D[k] = table_dup(v)
|
|
else
|
|
D[k] = v
|
|
end
|
|
end
|
|
|
|
return D
|
|
end
|
|
|
|
-- Creates a new sandbox with a given name.
|
|
-- Returns actual name in case of collision.
|
|
function sandbox.new(name, fname, ...)
|
|
-- Pick a name
|
|
if sb_list[name] then
|
|
while sb_list[name.."-"..sb_counter] do
|
|
sb_counter = sb_counter + 1
|
|
end
|
|
|
|
name = name.."-"..sb_counter
|
|
sb_counter = sb_counter + 1
|
|
end
|
|
|
|
print("Creating sandbox \""..name.."\"")
|
|
|
|
-- Create new environment
|
|
local SG = {}
|
|
SG._G = SG
|
|
sb_list[name] = SG
|
|
sb_aux[name] = {}
|
|
|
|
sb_aux[name].tick_enabled = true
|
|
|
|
-- Copy some builtins
|
|
SG.coroutine = coroutine
|
|
SG.string = string
|
|
SG.math = math
|
|
SG.table = table
|
|
|
|
SG.assert = assert
|
|
SG.collectgarbage = collectgarbage
|
|
SG.error = error
|
|
SG.getmetatable = getmetatable
|
|
SG.ipairs = ipairs
|
|
SG.next = next
|
|
SG.pairs = pairs
|
|
SG.pcall = pcall
|
|
SG.print = print
|
|
SG.rawequal = rawequal
|
|
SG.rawget = rawget
|
|
SG.rawset = rawset
|
|
SG.select = select
|
|
SG.setfenv = setfenv
|
|
SG.setmetatable = setmetatable
|
|
SG.tonumber = tonumber
|
|
SG.tostring = tostring
|
|
SG.type = type
|
|
SG.unpack = unpack
|
|
SG._VERSION = _VERSION
|
|
SG.xpcall = xpcall
|
|
|
|
-- Copy main things
|
|
setfenv(table_dup, _G)
|
|
SG.client = table_dup(client)
|
|
SG.common = table_dup(common)
|
|
SG.server = table_dup(server)
|
|
SG.sandbox = table_dup(sandbox)
|
|
|
|
-- Remove hooks
|
|
local k,v
|
|
local clsv = (SG.client or SG.server)
|
|
for k,v in pairs(clsv) do
|
|
if k:sub(1,5) == "hook_" then
|
|
clsv[k] = nil
|
|
end
|
|
end
|
|
|
|
-- Enable wrappers
|
|
sb_wrap_fetch(sb_list, sb_aux, sb_ctl, name)
|
|
sb_wrap_audio(sb_list, sb_aux, sb_ctl, name)
|
|
sb_wrap_gfx(sb_list, sb_aux, sb_ctl, name)
|
|
|
|
function SG.getfenv(f)
|
|
local ret = getfenv(f)
|
|
|
|
if ret == _G then
|
|
ret = SG
|
|
end
|
|
|
|
return ret
|
|
end
|
|
|
|
function SG.sandbox.this()
|
|
return name
|
|
end
|
|
|
|
-- Do file
|
|
-- Return name
|
|
return name, (SG.loadfile(fname))(...)
|
|
end
|
|
|
|
-- Kills a sandbox.
|
|
function sandbox.kill(name)
|
|
if not sb_list[name] then
|
|
error("nonexistant sandbox \""..tostring(name).."\"")
|
|
end
|
|
|
|
if client then
|
|
sb_ctl.gfx_kill(name)
|
|
end
|
|
|
|
sb_list[name] = nil
|
|
sb_aux[name] = nil
|
|
end
|
|
|
|
if client then
|
|
function client.hook_tick(...)
|
|
local k, v
|
|
local hadf = false
|
|
local retacc = 1
|
|
local kill_list = {}
|
|
for k, v in pairs(sb_list) do
|
|
if sb_aux[k].tick_enabled then
|
|
local f = v.client.hook_tick
|
|
if f then
|
|
hadf = true
|
|
sb_ctl.gfx_api_push(k)
|
|
retacc = math.min(retacc, f(...))
|
|
sb_ctl.gfx_api_pop()
|
|
else
|
|
kill_list[1+#kill_list] = k
|
|
end
|
|
end
|
|
end
|
|
|
|
for k, v in pairs(kill_list) do
|
|
print("Killing sandbox \""..tostring(v).."\"")
|
|
sandbox.kill(v)
|
|
end
|
|
|
|
if not hadf then
|
|
client.hook_tick = nil
|
|
end
|
|
sb_ctl.gfx_api_prerender()
|
|
|
|
return retacc
|
|
end
|
|
|
|
function client.hook_key(...)
|
|
if not sb_list[sb_ctl.gfx_select] then return end
|
|
local f = sb_list[sb_ctl.gfx_select].client.hook_key
|
|
if f then
|
|
sb_ctl.gfx_api_push(sb_ctl.gfx_select)
|
|
f(...)
|
|
sb_ctl.gfx_api_pop()
|
|
end
|
|
sb_ctl.gfx_api_prerender()
|
|
end
|
|
|
|
function client.hook_text(...)
|
|
if not sb_list[sb_ctl.gfx_select] then return end
|
|
local f = sb_list[sb_ctl.gfx_select].client.hook_text
|
|
if f then
|
|
sb_ctl.gfx_api_push(sb_ctl.gfx_select)
|
|
f(...)
|
|
sb_ctl.gfx_api_pop()
|
|
end
|
|
sb_ctl.gfx_api_prerender()
|
|
end
|
|
|
|
function client.hook_mouse_button(...)
|
|
if not sb_list[sb_ctl.gfx_select] then return end
|
|
local f = sb_list[sb_ctl.gfx_select].client.hook_mouse_button
|
|
if f then
|
|
sb_ctl.gfx_api_push(sb_ctl.gfx_select)
|
|
f(...)
|
|
sb_ctl.gfx_api_pop()
|
|
end
|
|
sb_ctl.gfx_api_prerender()
|
|
end
|
|
|
|
function client.hook_mouse_motion(...)
|
|
if not sb_list[sb_ctl.gfx_select] then return end
|
|
local f = sb_list[sb_ctl.gfx_select].client.hook_mouse_motion
|
|
if f then
|
|
sb_ctl.gfx_api_push(sb_ctl.gfx_select)
|
|
f(...)
|
|
sb_ctl.gfx_api_pop()
|
|
end
|
|
sb_ctl.gfx_api_prerender()
|
|
end
|
|
|
|
function client.hook_render(...)
|
|
if not sb_list[sb_ctl.gfx_select] then return end
|
|
local f = sb_list[sb_ctl.gfx_select].client.hook_render
|
|
|
|
if f then
|
|
sb_ctl.gfx_api_push(sb_ctl.gfx_select)
|
|
f(...)
|
|
sb_ctl.gfx_api_pop()
|
|
end
|
|
sb_ctl.gfx_api_prerender()
|
|
end
|
|
|
|
function client.hook_kick(...)
|
|
local k, v
|
|
for k, v in pairs(sb_list) do
|
|
local f = v.client.hook_kick
|
|
if f then
|
|
f(...)
|
|
end
|
|
end
|
|
end
|
|
|
|
elseif server then
|
|
function server.hook_tick(...)
|
|
local k, v
|
|
local hadf = false
|
|
local retacc = 1
|
|
for k, v in pairs(sb_list) do
|
|
if sb_aux[k].tick_enabled then
|
|
local f = v.server.hook_tick
|
|
if f then
|
|
hadf = true
|
|
retacc = math.min(retacc, f(...))
|
|
end
|
|
end
|
|
end
|
|
|
|
if not hadf then
|
|
server.hook_tick = nil
|
|
end
|
|
end
|
|
|
|
function server.hook_file(...)
|
|
local f = sb_list[sb_current].server.hook_file
|
|
if f then
|
|
return f(...)
|
|
end
|
|
end
|
|
|
|
function server.hook_connect(...)
|
|
local f = sb_list[sb_current].server.hook_connect
|
|
if f then
|
|
return f(...)
|
|
end
|
|
end
|
|
|
|
function server.hook_disconnect(...)
|
|
local f = sb_list[sb_current].server.hook_disconnect
|
|
if f then
|
|
return f(...)
|
|
end
|
|
end
|
|
end
|
|
|
|
sb_current = "root" -- TO BE PHASED OUT
|
|
|
|
end
|
|
|
|
-- Do initial sandbox
|
|
if client then
|
|
sandbox.new("root", "pkg/base/main_client.lua", ...)
|
|
elseif server then
|
|
sandbox.new("root", "pkg/base/main_server.lua", ...)
|
|
else
|
|
error("Cannot determine if client or server!")
|
|
end
|
|
|