Lunatic: prototypical editor binding.

git-svn-id: https://svn.eduke32.com/eduke32@3056 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
helixhorned 2012-10-07 15:25:52 +00:00
parent fb5d920408
commit 851c6b081d
9 changed files with 592 additions and 403 deletions

View file

@ -163,6 +163,8 @@ ifneq (0,$(LUNATIC))
else
LIBS+= -L/usr/local/lib -lluajit-5.1
endif
EDITOROBJS+= $(OBJ)/lunatic_m32.$o
GAMEOBJS+= $(OBJ)/lunatic.$o
GAMEOBJS+= $(OBJ)/../lpeg.$o # TEMP

View file

@ -49,6 +49,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "m32script.h"
#include "m32def.h"
#ifdef LUNATIC
# include "lunatic_m32.h"
#endif
#include "rev.h"
#ifdef _WIN32
@ -87,6 +91,10 @@ char **g_clipMapFiles = NULL;
int32_t g_clipMapFilesNum = 0;
#endif
#ifdef LUNATIC
Em_State *g_EmState;
#endif
#pragma pack(push,1)
sound_t g_sounds[MAXSOUNDS];
#pragma pack(pop)
@ -10492,6 +10500,21 @@ int32_t ExtInit(void)
MultiPskyInit();
#ifdef LUNATIC
g_EmState = Em_CreateState();
if (g_EmState)
{
i = Em_RunOnce(g_EmState, "defs_m32.ilua");
if (i)
{
initprintf("Lunatic: Error preparing global Lua state (code %d)\n", i);
Em_DestroyState(g_EmState);
g_EmState = NULL;
}
}
#endif
signal(SIGINT, m32script_interrupt_handler);
return rv;

View file

@ -6,95 +6,25 @@ _EDUKE32_LUNATIC = true
local ffi = require("ffi")
local ffiC = ffi.C
---=== Duke3D engine and game definitions ===---
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;
local string = string
local table = table
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;
--== First, load the definitions common to the game's and editor's Lua interface.
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;
const int16_t sectnum, statnum;
int16_t ang, owner, xvel, yvel, zvel;
int16_t lotag, hitag, extra;
} spritetype;
typedef struct {
const uint32_t mdanimtims;
const int16_t mdanimcur;
int16_t angoff, pitch, roll;
int32_t xoff, yoff, zoff;
uint8_t flags;
uint8_t xpanning, ypanning;
const uint8_t filler;
float alpha;
const int32_t _do_not_use1;
const int32_t _do_not_use2;
} spriteext_t;
typedef struct {
int32_t x, y, z;
} vec3_t;
typedef struct {
vec3_t pos;
int16_t sprite, wall, sect;
} hitdata_t;
typedef struct {
char r,g,b,f;
} palette_t;
#pragma pack(pop)
]]
local vec3_ct = ffi.typeof("vec3_t")
local hitdata_ct = ffi.typeof("hitdata_t")
---- engine data and functions ----
-- GLOBAL gv: provides access to C global *scalars* and safe functions
-- XXX: still exposes C library functions etc. contained in ffi.C.
-- Is this a problem?
-- The "gv" global will provide access to C global *scalars* and safe functions.
-- XXX: still exposes C library functions etc. contained in ffi.C, problem?
local gv_ = {
-- all non-scalars need to be explicitly listed here and access to them is
-- All non-scalars need to be explicitly listed here and access to them is
-- redirected to the dummy empty table...
}
local dummy_empty_table = {}
-- This is for declarations of arrays or pointers which should not be
-- accessible through the gv global.
-- accessible through the "gv" global. The "defs_common" module require will
-- use this function.
-- NOTE: don't declare multiple pointers on one line (like int32_t *a, *b;)!
local function decl(str)
function decl(str)
for varname in string.gmatch(str, "([%a_][%w_]*)[[(;]") do
-- print("protect "..varname)
gv_[varname] = dummy_empty_table
@ -103,86 +33,11 @@ local function decl(str)
ffi.cdef(str)
end
ffi.cdef[[int32_t engine_main_arrays_are_static, engine_v8;]]
-- load them!
local defs_c = require("defs_common")
-- NOTE TO SELF: This is not C, never EVER write
-- if (x)
-- when checking a C variable x for 'thuthiness'
if (ffiC.engine_main_arrays_are_static ~= 0) then
decl[[
sectortype sector[];
walltype wall[];
spritetype sprite[];
spriteext_t spriteext[];
]]
else
decl[[
sectortype *sector;
walltype *wall;
spritetype *sprite;
spriteext_t *spriteext;
]]
end
if (ffiC.engine_v8 == 0) then
-- V7
ffi.cdef[[
enum
{
MAXSECTORS = 1024,
MAXWALLS = 8192,
MAXSPRITES = 4096,
}
]]
else
-- V8
ffi.cdef[[
enum
{
MAXSECTORS = 4096,
MAXWALLS = 16384,
MAXSPRITES = 16384,
}
]]
end
ffi.cdef[[
enum {
MAXSTATUS = 1024,
MAXTILES = 30720,
MAXBUNCHES = 256,
CEILING = 0,
FLOOR = 1,
CLIPMASK0 = (1<<16)+1, // blocking
CLIPMASK1 = (256<<16)+64, // hittable
};
]]
ffi.cdef[[
const int16_t numsectors, numwalls;
const int32_t numyaxbunches;
const int32_t totalclock;
const int32_t xdim, ydim;
]]
decl[[
const int16_t headspritesect[MAXSECTORS+1], headspritestat[MAXSTATUS+1];
const int16_t prevspritesect[MAXSPRITES], prevspritestat[MAXSPRITES];
const int16_t nextspritesect[MAXSPRITES], nextspritestat[MAXSPRITES];
const int16_t headsectbunch[2][MAXBUNCHES], nextsectbunch[2][MAXSECTORS];
int16_t yax_getbunch(int16_t i, int16_t cf);
int32_t hitscan(const vec3_t *sv, int16_t sectnum, int32_t vx, int32_t vy, int32_t vz,
hitdata_t *hitinfo, uint32_t cliptype);
void rotatesprite(int32_t sx, int32_t sy, int32_t z, int16_t a, int16_t picnum,
int8_t dashade, char dapalnum, int32_t dastat,
int32_t cx1, int32_t cy1, int32_t cx2, int32_t cy2);
]]
---=== EDuke32 game definitions ===---
-- array -> element flattening inside structs,
-- e.g. int32_t a[4] --> int32_t _a0, _a1, _a2, _a3;
@ -546,12 +401,7 @@ double rand_jkiss_dbl(rng_jkiss_t *s);
void md4once(const unsigned char *block, unsigned int len, unsigned char digest[16]);
]]
ffi.cdef[[
int32_t ksqrt(uint32_t num);
]]
ffi.cdef "double gethitickms(void);"
-- XXX: "digest" --> dummy?
@ -567,9 +417,6 @@ local setmetatable = setmetatable
local setfenv = setfenv
local type = type
local string = string
local table = table
-- http://lua-users.org/wiki/SandBoxes says "potentially unsafe"
-- as it allows to see implementations of functions.
--local string_dump = string.dump
@ -967,46 +814,20 @@ end
-- error(..., 2) is to blame the caller and get its line numbers
-- set metatable and forbid setting it further
local function setmtonce(tab, mt)
mt.__metatable = true
return setmetatable(tab, mt)
end
local tmpmt = {
__index = function() error('dummy variable: read access forbidden', 2) end,
__newindex = function() error('dummy variable: write access forbidden', 2) end,
}
setmtonce(dummy_empty_table, tmpmt)
defs_c.setmtonce(dummy_empty_table, tmpmt)
gv = gv_
local tmpmt = {
__index = ffiC,
__newindex = function() error("cannot create new or write into existing fields of 'gv'", 2) end,
}
setmtonce(gv, tmpmt)
defs_c.setmtonce(gv, tmpmt)
---- indirect C array access ----
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', 2)
end,
__newindex = function(tab, key, val) error('cannot write directly to sector[] struct', 2) end,
}
sector = setmtonce({}, tmpmt)
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', 2)
end,
__newindex = function(tab, key, val) error('cannot write directly to wall[] struct', 2) end,
}
wall = setmtonce({}, tmpmt)
local tmpmt = {
__index = function(tab, key)
if (key >= 0 and key < ffiC.playerswhenstarted) then
@ -1017,126 +838,37 @@ local tmpmt = {
__newindex = function(tab, key, val) error('cannot write directly to player[] struct', 2) end,
}
player = setmtonce({}, tmpmt)
player = defs_c.setmtonce({}, tmpmt)
-- create a safe indirection for an 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', 2)
end,
__newindex = function(tab, key, val)
error('cannot write directly to '..name, 2)
end,
}
-- structs
sector = defs_c.sector;
wall = defs_c.wall;
sprite = defs_c.sprite
spriteext = defs_c.spriteext
return setmtonce(tab, tmpmt)
end
headspritesect = defs_c.headspritesect
headspritestat = defs_c.headspritestat
nextspritesect = defs_c.nextspritesect
nextspritestat = defs_c.nextspritestat
prevspritesect = defs_c.prevspritesect
prevspritestat = defs_c.prevspritestat
sprite = creategtab(ffiC.sprite, ffiC.MAXSPRITES, 'sprite[] struct')
spriteext = creategtab(ffiC.spriteext, ffiC.MAXSPRITES, 'spriteext[] struct')
headspritesect = creategtab(ffiC.headspritesect, ffiC.MAXSECTORS, 'headspritesect[]')
-- TODO: allow sprite freelist access via the status list for CON compatibility?
headspritestat = creategtab(ffiC.headspritestat, ffiC.MAXSTATUS, 'headspritestat[]')
nextspritesect = creategtab(ffiC.nextspritesect, ffiC.MAXSPRITES, 'nextspritesect[]')
nextspritestat = creategtab(ffiC.nextspritestat, ffiC.MAXSPRITES, 'nextspritestat[]')
prevspritesect = creategtab(ffiC.prevspritesect, ffiC.MAXSPRITES, 'prevspritesect[]')
prevspritestat = creategtab(ffiC.prevspritestat, ffiC.MAXSPRITES, 'prevspritestat[]')
actor = defs_c.creategtab(ffiC.actor, ffiC.MAXSPRITES, 'actor[]')
-- functions
spritesofsect = defs_c.spritesofsect
spritesofstat = defs_c.spritesofstat
sectorsofbunch = defs_c.sectorsofbunch
getbunch = defs_c.getbunch
hitscan = defs_c.hitscan
actor = creategtab(ffiC.actor, ffiC.MAXSPRITES, 'actor[]')
function TEMP_getvollev() -- REMOVE
return ffiC.ud.volume_number+1, ffiC.ud.level_number+1
end
---- 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 end
end
function spritesofsect(sect)
if (sect < 0 or sect >= ffiC.numsectors) then
error("passed invalid sectnum to spritesofsect iterator", 2)
end
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 end
end
function spritesofstat(stat)
if (stat < 0 or stat >= ffiC.MAXSTATUS) then
error("passed invalid statnum to spritesofstat iterator", 2)
end
return iter_spritesofstat, stat, -1
end
-- TROR iterators
local function iter_sectorsofbunch(cf, i)
if (i < 0) then
i = ffiC.headsectbunch[cf][-i-1];
else
i = ffiC.nextsectbunch[cf][i];
end
if (i >= 0) then return i end
end
function sectorsofbunch(bunchnum, cf)
if (bunchnum < 0 or bunchnum >= ffiC.numyaxbunches) then
error("passed invalid bunchnum to sectorsofbunch iterator", 2)
end
if (cf ~= 0 and cf ~= 1) then
error("passed invalid 'cf' to sectorsofbunch iterator, must be 0 or 1", 2)
end
return iter_sectorsofbunch, cf, -bunchnum-1
end
function getbunch(sectnum, cf)
if (sectnum < 0 or sectnum >= ffiC.numsectors) then
error('passed out-of-bounds sector number'..sectnum, 2)
end
if (cf ~= 0 and cf ~= 1) then
error("passed invalid 'cf' to getbunch, must be 0 or 1", 2)
end
return ffiC.yax_getbunch(sectnum, cf)
end
---=== Engine functions, wrapped for Lua convenience ===---
-- returns a hitdata_ct
function hitscan(x,y,z, sectnum, vx,vy,vz, cliptype)
if (sectnum < 0 or sectnum >= ffiC.numsectors) then
error('passed out-of-bounds sector number'..sectnum, 2)
end
local vec = vec3_ct(x,y,z)
local hitdata = hitdata_ct()
ffiC.hitscan(vec, sectnum, vx,vy,vz, hitdata, cliptype)
return hitdata
end
---=== Game variables ===---

View file

@ -0,0 +1,324 @@
-- This file contains LuaJIT definitions of stuff that's common to the game and
-- editor. The 'decl' is expected to be defined in the global environment.
local ffi = require("ffi")
local ffiC = ffi.C
local error = error
local setmetatable = setmetatable
local decl = decl
module(...)
--== Core engine structs ==--
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;
const int16_t sectnum, statnum;
int16_t ang, owner, xvel, yvel, zvel;
int16_t lotag, hitag, extra;
} spritetype;
typedef struct {
const uint32_t mdanimtims;
const int16_t mdanimcur;
int16_t angoff, pitch, roll;
int32_t xoff, yoff, zoff;
uint8_t flags;
uint8_t xpanning, ypanning;
const uint8_t filler;
float alpha;
const int32_t _do_not_use1;
const int32_t _do_not_use2;
} spriteext_t;
typedef struct {
int32_t x, y, z;
} vec3_t;
typedef struct {
vec3_t pos;
int16_t sprite, wall, sect;
} hitdata_t;
typedef struct {
char r,g,b,f;
} palette_t;
#pragma pack(pop)
]]
local vec3_ct = ffi.typeof("vec3_t")
local hitdata_ct = ffi.typeof("hitdata_t")
-- TODO: add 'const'
ffi.cdef[[int32_t engine_main_arrays_are_static, engine_v8;]]
--== Engine data and functions ==--
-- NOTE TO SELF: This is not C, never EVER write
-- if (x)
-- when checking a C variable x for 'thuthiness'
if (ffiC.engine_main_arrays_are_static ~= 0) then
decl[[
sectortype sector[];
walltype wall[];
spritetype sprite[];
spriteext_t spriteext[];
]]
else
decl[[
sectortype *sector;
walltype *wall;
spritetype *sprite;
spriteext_t *spriteext;
]]
end
if (ffiC.engine_v8 == 0) then
-- V7
ffi.cdef[[
enum
{
MAXSECTORS = 1024,
MAXWALLS = 8192,
MAXSPRITES = 4096,
}
]]
else
-- V8
ffi.cdef[[
enum
{
MAXSECTORS = 4096,
MAXWALLS = 16384,
MAXSPRITES = 16384,
}
]]
end
ffi.cdef[[
enum {
MAXSTATUS = 1024,
MAXTILES = 30720,
MAXBUNCHES = 256,
CEILING = 0,
FLOOR = 1,
CLIPMASK0 = (1<<16)+1, // blocking
CLIPMASK1 = (256<<16)+64, // hittable
};
]]
ffi.cdef[[
const int16_t numsectors, numwalls;
const int32_t numyaxbunches;
const int32_t totalclock;
const int32_t xdim, ydim;
]]
decl[[
const int16_t headspritesect[MAXSECTORS+1], headspritestat[MAXSTATUS+1];
const int16_t prevspritesect[MAXSPRITES], prevspritestat[MAXSPRITES];
const int16_t nextspritesect[MAXSPRITES], nextspritestat[MAXSPRITES];
const int16_t headsectbunch[2][MAXBUNCHES], nextsectbunch[2][MAXSECTORS];
int16_t yax_getbunch(int16_t i, int16_t cf);
int32_t hitscan(const vec3_t *sv, int16_t sectnum, int32_t vx, int32_t vy, int32_t vz,
hitdata_t *hitinfo, uint32_t cliptype);
void rotatesprite(int32_t sx, int32_t sy, int32_t z, int16_t a, int16_t picnum,
int8_t dashade, char dapalnum, int32_t dastat,
int32_t cx1, int32_t cy1, int32_t cx2, int32_t cy2);
]]
-- misc. functions
ffi.cdef[[
int32_t ksqrt(uint32_t num);
double gethitickms(void);
]]
---=== Restricted access to C variables from Lunatic ===---
-- set metatable and forbid setting it further
function setmtonce(tab, mt)
mt.__metatable = true
return setmetatable(tab, mt)
end
---- indirect C array access ----
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', 2)
end,
__newindex = function(tab, key, val) error('cannot write directly to sector[] struct', 2) end,
}
sector = setmtonce({}, tmpmt)
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', 2)
end,
__newindex = function(tab, key, val) error('cannot write directly to wall[] struct', 2) end,
}
wall = setmtonce({}, tmpmt)
-- create a safe indirection for an ffi.C array
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', 2)
end,
__newindex = function(tab, key, val)
error('cannot write directly to '..name, 2)
end,
}
return setmtonce(tab, tmpmt)
end
sprite = creategtab(ffiC.sprite, ffiC.MAXSPRITES, 'sprite[] struct')
spriteext = creategtab(ffiC.spriteext, ffiC.MAXSPRITES, 'spriteext[] struct')
headspritesect = creategtab(ffiC.headspritesect, ffiC.MAXSECTORS, 'headspritesect[]')
-- TODO: allow sprite freelist access via the status list for CON compatibility?
headspritestat = creategtab(ffiC.headspritestat, ffiC.MAXSTATUS, 'headspritestat[]')
nextspritesect = creategtab(ffiC.nextspritesect, ffiC.MAXSPRITES, 'nextspritesect[]')
nextspritestat = creategtab(ffiC.nextspritestat, ffiC.MAXSPRITES, 'nextspritestat[]')
prevspritesect = creategtab(ffiC.prevspritesect, ffiC.MAXSPRITES, 'prevspritesect[]')
prevspritestat = creategtab(ffiC.prevspritestat, ffiC.MAXSPRITES, '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 end
end
function spritesofsect(sect)
if (sect < 0 or sect >= ffiC.numsectors) then
error("passed invalid sectnum to spritesofsect iterator", 2)
end
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 end
end
function spritesofstat(stat)
if (stat < 0 or stat >= ffiC.MAXSTATUS) then
error("passed invalid statnum to spritesofstat iterator", 2)
end
return iter_spritesofstat, stat, -1
end
--== TROR iterators ==--
local function iter_sectorsofbunch(cf, i)
if (i < 0) then
i = ffiC.headsectbunch[cf][-i-1];
else
i = ffiC.nextsectbunch[cf][i];
end
if (i >= 0) then return i end
end
function sectorsofbunch(bunchnum, cf)
if (bunchnum < 0 or bunchnum >= ffiC.numyaxbunches) then
error("passed invalid bunchnum to sectorsofbunch iterator", 2)
end
if (cf ~= 0 and cf ~= 1) then
error("passed invalid 'cf' to sectorsofbunch iterator, must be 0 or 1", 2)
end
return iter_sectorsofbunch, cf, -bunchnum-1
end
function getbunch(sectnum, cf)
if (sectnum < 0 or sectnum >= ffiC.numsectors) then
error('passed out-of-bounds sector number'..sectnum, 2)
end
if (cf ~= 0 and cf ~= 1) then
error("passed invalid 'cf' to getbunch, must be 0 or 1", 2)
end
return ffiC.yax_getbunch(sectnum, cf)
end
---=== Engine functions, wrapped for Lua convenience ===---
-- returns a hitdata_ct
function hitscan(x,y,z, sectnum, vx,vy,vz, cliptype)
if (sectnum < 0 or sectnum >= ffiC.numsectors) then
error('passed out-of-bounds sector number'..sectnum, 2)
end
local vec = vec3_ct(x,y,z)
local hitdata = hitdata_ct()
ffiC.hitscan(vec, sectnum, vx,vy,vz, hitdata, cliptype)
return hitdata
end

View file

@ -0,0 +1,31 @@
-- INTERNAL
-- definitions of BUILD and game types for the Lunatic Interpreter
local ffi = require("ffi")
local ffiC = ffi.C
--== First, load the definitions common to the game's and editor's Lua interface.
decl = ffi.cdef
local defs_c = require("defs_common")
-- structs
sector = defs_c.sector;
wall = defs_c.wall;
sprite = defs_c.sprite
spriteext = defs_c.spriteext
headspritesect = defs_c.headspritesect
headspritestat = defs_c.headspritestat
nextspritesect = defs_c.nextspritesect
nextspritestat = defs_c.nextspritestat
prevspritesect = defs_c.prevspritesect
prevspritestat = defs_c.prevspritestat
-- functions
spritesofsect = defs_c.spritesofsect
spritesofstat = defs_c.spritesofstat
sectorsofbunch = defs_c.sectorsofbunch
getbunch = defs_c.getbunch
hitscan = defs_c.hitscan

View file

@ -11,7 +11,9 @@
#include "gameexec.h"
#include "gamedef.h" // EventNames[], MAXEVENTS
#include "lunatic.h"
#include "lunatic_priv.h"
// this serves two purposes:
// the values as booleans and the addresses as keys to the Lua registry
@ -86,16 +88,6 @@ void El_PrintTimes(void)
OSD_Printf(" },\n}\n");
}
static void check_and_register_function(lua_State *L, void *keyaddr)
{
luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushlightuserdata(L, keyaddr); // 3, push address
lua_pushvalue(L, -2); // 4, push copy of lua function
lua_settable(L, LUA_REGISTRYINDEX); // "registry[keyaddr] = <lua function>", pop 2
}
// 0: success, <0: failure
int32_t El_CreateState(El_State *estate, const char *name)
@ -119,12 +111,7 @@ int32_t El_CreateState(El_State *estate, const char *name)
luaopen_lpeg(L);
lua_pop(L, lua_gettop(L)); // pop off whatever lpeg leaves on the stack
// get debug.traceback
lua_getglobal(L, "debug");
lua_getfield(L, -1, "traceback");
Bassert(lua_isfunction(L, -1));
check_and_register_function(L, &debug_traceback_key);
lua_pop(L, 2);
setup_debug_traceback(L);
// create misc. global functions in the Lua state
lua_pushcfunction(L, SetEvent_luacf);
@ -157,88 +144,7 @@ void El_DestroyState(El_State *estate)
// 4: runtime error while executing lua file
int32_t El_RunOnce(El_State *estate, const char *fn)
{
int32_t fid, flen, i;
char *buf;
lua_State *const L = estate->L;
fid = kopen4load(fn, 0); // TODO: g_loadFromGroupOnly, kopen4loadfrommod ?
if (fid < 0)
return 1;
flen = kfilelength(fid);
if (flen == 0)
return 0; // empty script ...
buf = Bmalloc(flen+1);
if (!buf)
{
kclose(fid);
return -1;
}
i = kread(fid, buf, flen);
kclose(fid);
if (i != flen)
{
Bfree(buf);
return 2;
}
buf[flen] = 0;
// -- lua --
Bassert(lua_gettop(L)==0);
// get debug.traceback
lua_pushlightuserdata(L, &debug_traceback_key);
lua_gettable(L, LUA_REGISTRYINDEX);
Bassert(lua_isfunction(L, -1));
i = luaL_loadstring(L, buf);
Bassert(lua_gettop(L)==2);
Bfree(buf);
if (i == LUA_ERRMEM)
{
lua_pop(L, 2);
return -1;
}
if (i == LUA_ERRSYNTAX)
{
OSD_Printf("state \"%s\" syntax error: %s\n", estate->name,
lua_tostring(L, -1)); // get err msg
lua_pop(L, 2); // pop errmsg and debug.traceback
return 3;
}
// -- call the lua chunk! --
i = lua_pcall(L, 0, 0, -2);
Bassert(lua_gettop(L) == 1+!!i);
Bassert(i != LUA_ERRERR); // we expect debug.traceback not to fail
if (i == LUA_ERRMEM) // XXX: should be more sophisticated. Clean up stack? Do GC?
{
lua_pop(L, 2);
return -1;
}
if (i == LUA_ERRRUN)
{
Bassert(lua_type(L, -1)==LUA_TSTRING);
OSD_Printf("state \"%s\" runtime error: %s\n", estate->name,
lua_tostring(L, -1)); // get err msg
lua_pop(L, 2); // pop errmsg and debug.traceback
return 4;
}
lua_pop(L, 1);
return 0;
return lunatic_run_once(estate->L, fn, estate->name);
}

View file

@ -0,0 +1,35 @@
/* The Lunatic Interpreter, part of EDuke32/Mapster32 */
#include <stdint.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include "lunatic_m32.h"
#include "lunatic_priv.h"
Em_State *Em_CreateState(void)
{
lua_State *L = luaL_newstate();
if (L == NULL)
return NULL;
luaL_openlibs(L);
setup_debug_traceback(L);
return L;
}
// -1: alloc failure
// 0: success
// 1: didn't find file
// 2: couldn't read whole file
// 3: syntax error in lua file
// 4: runtime error while executing lua file
int32_t Em_RunOnce(Em_State *L, const char *fn)
{
return lunatic_run_once(L, fn, "test");
}

View file

@ -0,0 +1,19 @@
#ifndef EDUKE32_LUNATIC_M32_H_
#define EDUKE32_LUNATIC_M32_H_
#include <lua.h>
typedef lua_State Em_State;
Em_State *Em_CreateState(void);
static inline void Em_DestroyState(Em_State *L)
{
lua_close(L);
}
int32_t Em_RunOnce(Em_State *L, const char *fn);
#endif

View file

@ -0,0 +1,117 @@
/* Private, game/editor-common Lunatic routines. */
#include <lua.h>
#include <lauxlib.h>
#include "cache1d.h"
#include "osd.h"
// Lua-registry key for debug.traceback
static uint8_t debug_traceback_key;
static void check_and_register_function(lua_State *L, void *regkeyaddr)
{
luaL_checktype(L, -1, LUA_TFUNCTION);
lua_pushlightuserdata(L, regkeyaddr); // 3, push address
lua_pushvalue(L, -2); // 4, push copy of lua function
lua_settable(L, LUA_REGISTRYINDEX); // "registry[regkeyaddr] = <lua function>", pop 2
}
static void setup_debug_traceback(lua_State *L)
{
// get debug.traceback
lua_getglobal(L, "debug");
lua_getfield(L, -1, "traceback");
Bassert(lua_isfunction(L, -1));
check_and_register_function(L, &debug_traceback_key);
lua_pop(L, 2);
}
static int32_t lunatic_run_once(lua_State *L, const char *fn, const char *statename)
{
int32_t fid, flen, i;
char *buf;
fid = kopen4load(fn, 0); // TODO: g_loadFromGroupOnly, kopen4loadfrommod ?
if (fid < 0)
return 1;
flen = kfilelength(fid);
if (flen == 0)
return 0; // empty script ...
buf = Bmalloc(flen+1);
if (!buf)
{
kclose(fid);
return -1;
}
i = kread(fid, buf, flen);
kclose(fid);
if (i != flen)
{
Bfree(buf);
return 2;
}
buf[flen] = 0;
// -- lua --
Bassert(lua_gettop(L)==0);
// get debug.traceback
lua_pushlightuserdata(L, &debug_traceback_key);
lua_gettable(L, LUA_REGISTRYINDEX);
Bassert(lua_isfunction(L, -1));
i = luaL_loadstring(L, buf);
Bassert(lua_gettop(L)==2);
Bfree(buf);
if (i == LUA_ERRMEM)
{
lua_pop(L, 2);
return -1;
}
if (i == LUA_ERRSYNTAX)
{
OSD_Printf("state \"%s\" syntax error: %s\n", statename,
lua_tostring(L, -1)); // get err msg
lua_pop(L, 2); // pop errmsg and debug.traceback
return 3;
}
// -- call the lua chunk! --
i = lua_pcall(L, 0, 0, -2);
Bassert(lua_gettop(L) == 1+!!i);
Bassert(i != LUA_ERRERR); // we expect debug.traceback not to fail
if (i == LUA_ERRMEM) // XXX: should be more sophisticated. Clean up stack? Do GC?
{
lua_pop(L, 2);
return -1;
}
if (i == LUA_ERRRUN)
{
int32_t stringp = (lua_type(L, -1)==LUA_TSTRING);
// get error message if possible
OSD_Printf("state \"%s\" runtime error: %s\n", statename,
stringp ? lua_tostring(L, -1) : "??? (errmsg not a string)");
lua_pop(L, 2); // pop errmsg and debug.traceback
return 4;
}
lua_pop(L, 1);
return 0;
}