-- definitions of BUILD and game types for the Lunatic Interpreter -- INTERNAL! local ffi = require("ffi") ---- sector, wall, sprite ---- ffi.cdef[[ #pragma pack(push,1) typedef struct { const int16_t wallptr, wallnum; int32_t ceilingz, floorz; int16_t ceilingstat, floorstat; int16_t ceilingpicnum, ceilingheinum; int8_t ceilingshade; uint8_t ceilingpal, ceilingxpanning, ceilingypanning; int16_t floorpicnum, floorheinum; int8_t floorshade; uint8_t floorpal, floorxpanning, floorypanning; uint8_t visibility, filler; int16_t lotag, hitag, extra; } sectortype; typedef struct { int32_t x, y; const int16_t point2, nextwall, nextsector; int16_t cstat; int16_t picnum, overpicnum; int8_t shade; uint8_t pal, xrepeat, yrepeat, xpanning, ypanning; int16_t lotag, hitag, extra; } walltype; typedef struct { int32_t x, y, z; int16_t cstat, picnum; int8_t shade; uint8_t pal, clipdist, filler; uint8_t xrepeat, yrepeat; int8_t xoffset, yoffset; int16_t sectnum, statnum; int16_t ang, owner, xvel, yvel, zvel; int16_t lotag, hitag, extra; } spritetype; #pragma pack(pop) ]] ffi.cdef[[ sectortype *sector; walltype *wall; spritetype *sprite; const int16_t numsectors, numwalls; const int16_t headspritesect[16384+1], headspritestat[1024+1]; const int16_t prevspritesect[16384], prevspritestat[16384]; const int16_t nextspritesect[16384], nextspritestat[16384]; ]] ---- _G tweaks -- pull in only 'safe' stuff ---- local G_ = {} -- our soon-to-be global environment local oG = _G G_.coroutine = coroutine G_.assert = assert G_.tostring = tostring G_.tonumber = tonumber --rawget G_.xpcall = xpcall G_.ipairs = ipairs G_.print = print G_.pcall = pcall --gcinfo --DEPRECATED --module --setfenv --require --rawset --jit G_.bit = bit --package G_.error = error --debug --loadfile --rawequal --load G_.unpack = unpack G_.pairs = pairs G_.table = table G_._VERSION = _VERSION --newproxy --NOT STD? --collectgarbage --dofile G_.next = next G_.math = math --loadstring --_G G_.select = select G_.string = string G_.type = type --getmetatable --getfenv --setmetatable G_._G = G_ -- REMOVE this for release DBG_ = {} DBG_.loadstring = oG.loadstring ---- Set up restricted access to ffi.C from lunatic. ---- local ffiC = ffi.C local det = {} -- dummy empty table local tmpmt = { __index = function() error('dummy variable: read access forbidden') end, __newindex = function() error('dummy variable: write access forbidden') end, __metatable = true -- forbid setting the metatable } oG.setmetatable(det, tmpmt) -- GLOBAL gv: provides access to C global *scalars* gv = { -- all non-scalars need to be explicitly listed -- and access to them is redirected to the dummy -- empty table... this is somewhat ugly sector = det, wall = det, sprite = det, headspritesect = det, headspritestat = det, prevspritesect = det, prevspritestat = det, nextspritesect = det, nextspritestat = det, } local tmpmt = { __index = ffiC, __newindex = function() error("cannot create new fields in 'gv'") end, __metatable = true, } oG.setmetatable(gv, tmpmt) ---- indirect C array access ---- sector = {} local tmpmt = { __index = function(tab, key) if (key >= 0 and key < ffiC.numsectors) then return ffiC.sector[key] end error('out-of-bounds sector[] read access') end, __newindex = function(tab, key, val) error('cannot write to sector[] struct directly') end, __metatable = true, } oG.setmetatable(sector, tmpmt) wall = {} local tmpmt = { __index = function(tab, key) if (key >= 0 and key < ffiC.numwalls) then return ffiC.wall[key] end error('out-of-bounds wall[] read access') end, __newindex = function(tab, key, val) error('cannot write to wall[] struct directly') end, __metatable = true, } oG.setmetatable(wall, tmpmt) -- create a safe indirection for a ffi.C array local function creategtab(ctab, maxidx, name) local tab = {} local tmpmt = { __index = function(tab, key) if (key>=0 and key < maxidx) then return ctab[key] end error('out-of-bounds '..name..' read access') end, __newindex = function(tab, key, val) error('cannot write to '..name) end, __metatable = true, } oG.setmetatable(tab, tmpmt) return tab end sprite = creategtab(ffiC.sprite, 16384, 'sprite[] struct') headspritesect = creategtab(ffiC.headspritesect, 16384, 'headspritesect[]') headspritestat = creategtab(ffiC.headspritestat, 1024, 'headspritestat[]') nextspritesect = creategtab(ffiC.nextspritesect, 16384, 'nextspritesect[]') nextspritestat = creategtab(ffiC.nextspritestat, 16384, 'nextspritestat[]') prevspritesect = creategtab(ffiC.prevspritesect, 16384, 'prevspritesect[]') prevspritestat = creategtab(ffiC.prevspritestat, 16384, 'prevspritestat[]') ---- per-sector/per-statnum sprite iterators ---- local function iter_spritesofsect(sect, i) if (i < 0) then i = ffiC.headspritesect[sect] else i = ffiC.nextspritesect[i] end if (i >= 0) then return i, i end end function spritesofsect(sect) assert(sect >= 0 and sect < ffiC.numsectors, "passed invalid sectnum to spritesofsect iterator") return iter_spritesofsect, sect, -1 end local function iter_spritesofstat(stat, i) if (i < 0) then i = ffiC.headspritestat[stat] else i = ffiC.nextspritestat[i] end if (i >= 0) then return i, i end end function spritesofstat(stat) assert(stat >= 0 and stat < 1024, "passed invalid statnum to spritesofstat iterator") return iter_spritesofstat , stat, -1 end -- add new variables/functions living in the global environment G_.DBG_ = DBG_ -- REMOVE this for release G_.gv = gv G_.sector = sector G_.wall = wall G_.sprite = sprite G_.headspritesect = headspritesect G_.headspritestat = headspritestat G_.nextspritesect = nextspritesect G_.nextspritestat = nextspritestat G_.prevspritesect = prevspritesect G_.prevspritestat = prevspritestat G_.spritesofsect = spritesofsect G_.spritesofstat = spritesofstat -- change the environment of the running Lua thread to the table G_ setfenv(0, G_)