sandbox API, hopefully i didn't break anything

This commit is contained in:
Ben Russell (300178622) 2015-02-14 12:26:47 +13:00
parent 65337536d2
commit 6aa85e359c
11 changed files with 772 additions and 0 deletions

View File

@ -135,6 +135,9 @@ function fastload_analyse_client()
state.e.pcall = pcall
state.e.pairs = pairs
state.e.ipairs = ipairs
-- Tell it there's a sandbox
state.e.sandbox = {}
-- client.wav_play_local/global
function state.e.client.wav_play_local(...) return 1 end

View File

@ -15,10 +15,16 @@
along with Ice Lua Components. If not, see <http://www.gnu.org/licenses/>.
]]
SANDBOX_CLIENT = true
if common.version.num < 8388608 then
error("You need Iceball version 0.2 or later to connect to this server.")
end
if SANDBOX_CLIENT and not sandbox then
return (loadfile("pkg/base/sandbox/main.lua"))(...)
end
if common.mk_compat_disable then
common.mk_compat_disable()
client.mk_set_title("Iceball")
@ -155,6 +161,7 @@ do
local last_keepalive = common.time()
function load_screen_fetch(ftype, fname)
if string.sub(fname, 1,6) == "clsave" then return client.fetch_block(ftype, fname) end
--if true then return client.fetch_block(ftype, fname) end
if widgets ~= nil then
scene = gui_create_scene(w, h)
img_loading_width, img_loading_height = client.img_get_dims(img_loading)

View File

@ -15,10 +15,16 @@
along with Ice Lua Components. If not, see <http://www.gnu.org/licenses/>.
]]
SANDBOX_SERVER = false
if common.version.num < 8388608 then
error("You need Iceball version 0.2 or later to run this code.")
end
if SANDBOX_SERVER and not sandbox then
return (loadfile("pkg/base/sandbox/main.lua"))(...)
end
dofile("pkg/base/lib_fastload.lua")
-- UDP port test.

View File

@ -588,6 +588,12 @@ network.sys_handle_c2s(PKT_PLR_OFFER, "bbz", nwdec_plrset(function (neth, cli, p
plr.wpn = weapons[wpn](plr)
if plr.team ~= tidx then
plr.set_health_damage(0, 0xFF800000, plr.name.." changed teams", nil)
if not teams[tidx] then
print("HACK ATTEMPT from neth "..tostring(neth))
server.net_kick(neth, "Hack attempt")
return
end
print(plr, tidx, teams[tidx])
net_broadcast(nil, common.net_pack("BIz", PKT_CHAT_ADD_TEXT, 0xFF800000,
"* Player "..plr.name.." has joined the "..teams[tidx].name.." team"))
elseif plr.weapon ~= wpn then

View File

@ -20,6 +20,7 @@ MODE_NUB_KICKONJOIN = false
-- skins allowed
SKIN_ENABLE_SRC = {"pmf", "kv6", "tga", "png", "wav", "it"}
--SKIN_ENABLE_SRC = {}
SKIN_ENABLE = {}
do
local i

150
pkg/base/sandbox/fetch.lua Normal file
View File

@ -0,0 +1,150 @@
--[[
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/>.
]]
-- Wrappers for fetching stuff.
do
return function(sb_list, sb_aux, sb_ctl, name)
local SG = sb_list[name]
-- Set up function wrapper
local function wrapfn(f)
setfenv(f, SG)
end
local s_fetch_start = common.fetch_start
local s_fetch_poll = common.fetch_poll
local s_fetch_block = common.fetch_block
local fetch_last_ftype = nil
local fetch_last_fname = nil
function SG.common.fetch_start(ftype, fname)
local obj = s_fetch_start(ftype, fname)
if obj ~= true and obj ~= nil then
if ftype == "lua" and obj ~= nil then
wrapfn(obj)
end
end
fetch_last_ftype = nil
fetch_last_fname = nil
if obj == true then
fetch_last_ftype = ftype
fetch_last_fname = fname
end
return obj
end
function SG.common.fetch_poll()
local oldmap = common.map_get()
sb_ctl.gfx_api_prerender()
local function ff(obj, ...)
if obj ~= false then
if fetch_last_ftype == "lua" and obj ~= nil then
wrapfn(obj)
end
fetch_last_ftype = nil
fetch_last_fname = nil
end
sb_ctl.gfx_api_postrender(name)
return obj, ...
end
return ff(s_fetch_poll())
end
function SG.common.fetch_block(ftype, fname)
local fetch_start = common.fetch_start
local fetch_poll = common.fetch_poll
common.fetch_start = SG.common.fetch_start
common.fetch_poll = SG.common.fetch_poll
--print("BLOCK", ftype, fname)
local obj = s_fetch_block(ftype, fname)
if ftype == "lua" and obj ~= nil then
wrapfn(obj)
end
--print("BLOCK END", ftype, fname, obj)
common.fetch_start = fetch_start
common.fetch_poll = fetch_poll
return obj
end
function SG.loadstring(...)
local f = loadstring(...)
wrapfn(f)
return f
end
function SG.loadfile(...)
return SG.common.fetch_block("lua", ...)
end
function SG.dofile(...)
return SG.loadfile(...)()
end
-- mirrors
if client then
SG.client.fetch_block = SG.common.fetch_block
SG.client.fetch_start = SG.common.fetch_start
SG.client.fetch_poll = SG.common.fetch_poll
end
if server then
SG.server.fetch_block = SG.common.fetch_block
SG.server.fetch_start = SG.common.fetch_start
SG.server.fetch_poll = SG.common.fetch_poll
end
-- other things that are basically fetch_block
function SG.common.bin_load(...) return SG.common.fetch_block("bin", ...) end
function SG.common.json_load(...) return SG.common.fetch_block("json", ...) end
function SG.common.wav_load(...) return SG.common.fetch_block("wav", ...) end
function SG.common.mus_load_it(...) return SG.common.fetch_block("it", ...) end
function SG.common.model_load_pmf(...) return SG.common.fetch_block("pmf", ...) end
function SG.common.map_load(fname, fmt)
if fmt == nil or fmt == "auto" then
fmt = "map"
end
return SG.common.fetch_block(fmt, fname)
end
function SG.common.img_load(fname, fmt)
print("IMG!", fmt, fname)
local img = SG.common.fetch_block(fmt or "tga", fname)
print("IMG!", img)
if not img then return nil, nil, nil end
return img, common.img_get_dims(img)
end
-- more aliases
if client then
SG.client.img_load = SG.common.img_load
end
end
end

175
pkg/base/sandbox/gfx.lua Normal file
View File

@ -0,0 +1,175 @@
--[[
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/>.
]]
-- Wrappers for graphical stuff. Also handles input.
do
local sb_list, sb_aux, sb_ctl = ...
sb_ctl.gfx_select = "root"
sb_ctl.gfx_map_stack = {idx = 0}
-- Select sandbox to use for graphics and input.
function sandbox.gfx_select(name)
if not sb_list[name] then
error("invalid VM \""..tostring(name).."\" for gfx_select")
end
sb_ctl.gfx_select = name
client.mouse_lock_set(sb_aux[name].gfx_mouse_grab)
client.mouse_visible_set(sb_aux[name].gfx_mouse_vis)
local l = sb_aux[name].gfx_map_fog
client.map_fog_set(l[1], l[2], l[3], l[4])
end
-- INTERNAL API: Begin / end of hooks
function sb_ctl.gfx_api_push(name)
local map = nil
if sb_aux[name] then
map = sb_aux[name].gfx_map
end
sb_ctl.gfx_map_stack.idx = sb_ctl.gfx_map_stack.idx + 1
sb_ctl.gfx_map_stack[sb_ctl.gfx_map_stack.idx] = {name, common.map_get()}
common.map_set(map)
end
function sb_ctl.gfx_api_pop()
local name = sb_ctl.gfx_map_stack[sb_ctl.gfx_map_stack.idx][1]
if sb_aux[name] then
sb_aux[name].gfx_map = common.map_get()
end
common.map_set(sb_ctl.gfx_map_stack[sb_ctl.gfx_map_stack.idx][2])
sb_ctl.gfx_map_stack[sb_ctl.gfx_map_stack.idx] = nil
sb_ctl.gfx_map_stack.idx = sb_ctl.gfx_map_stack.idx - 1
end
function sb_ctl.gfx_api_prerender()
local map = nil
if sb_aux[sb_ctl.gfx_select] then
map = sb_aux[sb_ctl.gfx_select].gfx_map
end
common.map_set(map)
end
function sb_ctl.gfx_api_postrender(name)
local map = nil
if sb_aux[name] then
map = sb_aux[name].gfx_map
end
common.map_set(map)
end
function sb_ctl.gfx_kill(name)
if name == sb_ctl.gfx_select then
-- TODO: properly return to parent
if name ~= "root" then
sandbox.gfx_select("root")
end
end
end
return function(sb_list, sb_aux, sb_ctl, name)
local SG = sb_list[name]
sb_aux[name].gfx_mouse_vis = true
sb_aux[name].gfx_mouse_grab = false
sb_aux[name].gfx_map_fog = {208, 224, 255, 60.0}
sb_aux[name].gfx_map = map
if client then
local s_img_blit = SG.client.img_blit
function SG.client.img_blit(...)
if sb_ctl.gfx_select == name then
return s_img_blit(...)
end
end
local s_va_render_global = SG.client.va_render_global
function SG.client.va_render_global(...)
if sb_ctl.gfx_select == name then
return s_va_render_global(...)
end
end
local s_va_render_local = SG.client.va_render_local
function SG.client.va_render_local(...)
if sb_ctl.gfx_select == name then
return s_va_render_local(...)
end
end
local s_model_render_bone_global = SG.client.model_render_bone_global
function SG.client.model_render_bone_global(...)
if sb_ctl.gfx_select == name then
return s_model_render_bone_global(...)
end
end
local s_model_render_bone_local = SG.client.model_render_bone_local
function SG.client.model_render_bone_local(...)
if sb_ctl.gfx_select == name then
return s_model_render_bone_local(...)
end
end
local s_mouse_lock_set = SG.client.mouse_lock_set
function SG.client.mouse_lock_set(state)
sb_aux[name].gfx_mouse_grab = state
if sb_ctl.gfx_select == name then
return s_mouse_lock_set(state)
end
end
local s_mouse_visible_set = SG.client.mouse_visible_set
function SG.client.mouse_visible_set(state)
sb_aux[name].gfx_mouse_vis = state
if sb_ctl.gfx_select == name then
return s_mouse_visible_set(state)
end
end
local s_map_set = SG.common.map_set
function SG.common.map_set(map)
print("map", name, map)
sb_aux[name].gfx_map = map
return s_map_set(map)
end
SG.client.map_set = SG.common.map_set
local s_map_fog_set = SG.client.map_fog_set
function SG.client.map_fog_set(r, g, b, dist)
sb_aux[name].gfx_map_fog = {r, g, b, dist}
if sb_ctl.gfx_select == name then
return s_map_fog_set(r, g, b, dist)
end
end
local s_map_fog_get = SG.client.map_fog_get
function SG.client.map_fog_get()
if sb_ctl.gfx_select == name then
return s_map_fog_get()
else
local l = sb_aux[name].gfx_map_fog
return l[1], l[2], l[3], l[4]
end
end
end
end
end

282
pkg/base/sandbox/main.lua Normal file
View File

@ -0,0 +1,282 @@
--[[
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.string = string
SG.math = math
SG.table = table
SG.assert = assert
SG.collectgarbage = collectgarbage
SG.error = error
SG.getfenv = getfenv
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)
-- 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()
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_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

87
pkg/base/sandbox/wav.lua Normal file
View File

@ -0,0 +1,87 @@
--[[
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/>.
]]
-- Wrappers for the audio system.
do
return function (sb_list, sb_aux, sb_ctl, name)
local SG = sb_list[name]
sb_aux[name].mus_ref = nil
sb_aux[name].mus_order = 0
sb_aux[name].mus_row = 0
sb_aux[name].mus_vol = 1.0
sb_aux[name].wav_enabled = true --(name == "root")
sb_aux[name].wav_cube_size = 1.0
if client then
function SG.client.wav_cube_size(size)
sb_aux[name].wav_cube_size = size
if sb_aux[name].wav_enabled then
return client.wav_cube_size(size)
end
end
function SG.client.wav_play_global(...)
if sb_aux[name].wav_enabled then
return client.wav_play_global(...)
end
return nil
end
function SG.client.wav_play_local(...)
if sb_aux[name].wav_enabled then
return client.wav_play_local(...)
end
return nil
end
function SG.client.mus_play(mus, order, row)
order = order or 0
row = row or 0
sb_aux[name].mus_ref = mus
sb_aux[name].mus_order = order
sb_aux[name].mus_row = row
if sb_aux[name].wav_enabled then
return client.mus_play(mus, order, row)
end
end
function SG.client.mus_stop()
sb_aux[name].mus_ref = nil
sb_aux[name].mus_order = 0
sb_aux[name].mus_row = 0
if sb_aux[name].wav_enabled then
return client.mus_stop()
end
end
function SG.client.mus_vol_set(vol)
sb_aux[name].mus_vol = vol
if sb_aux[name].wav_enabled then
return client.mus_vol_set(vol)
end
end
end
end
end

3
pkg/br/snake/mod.json Normal file
View File

@ -0,0 +1,3 @@
{
"load_client": ["mod_sandbox.lua"]
}

View File

@ -0,0 +1,52 @@
--[[
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 test of the sandbox API.
local super = new_player
function new_player(...)
local this = super(...)
local s_create_hud = this.create_hud
local function f_create_hud(...)
local ret = s_create_hud(...)
local s_chat_on_return = this.typing_text.on_return
function this.typing_text.on_return(...)
if this.typing_text.text == "/snake" then
local snake = sandbox.new("snake", "pkg/br/snake/main_client.lua")
sandbox.gfx_select(snake)
this.typing_text.text = ""
end
return s_chat_on_return(...)
end
end
function this.create_hud(...)
local ret = s_create_hud(...)
f_create_hud(...)
return ret
end
if this.scene then
f_create_hud(...)
end
return this
end