Lunatic: export C functions that may call into CON events using the Lua C API.

We must not call these functions using the FFI, since the Lua state is
considered locked across such calls.

git-svn-id: https://svn.eduke32.com/eduke32@3520 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
helixhorned 2013-02-24 16:05:47 +00:00
parent b1320d0ab5
commit c66b891a38
6 changed files with 155 additions and 57 deletions

View file

@ -752,8 +752,7 @@ dead:
else vm.g_sp->shade += (sector[vm.g_sp->sectnum].floorshade-vm.g_sp->shade)>>1;
}
// NOTE: Used from Lunatic
void P_AddWeaponMaybeSwitch(DukePlayer_t *ps, int32_t weap)
static void P_AddWeaponMaybeSwitch(DukePlayer_t *ps, int32_t weap)
{
if ((ps->weaponswitch & 1) && (ps->weaponswitch & 4))
{
@ -784,7 +783,12 @@ void P_AddWeaponMaybeSwitch(DukePlayer_t *ps, int32_t weap)
P_AddWeaponNoSwitch(ps, weap);
}
#if !defined LUNATIC
#if defined LUNATIC
void P_AddWeaponMaybeSwitchI(int32_t snum, int32_t weap)
{
P_AddWeaponMaybeSwitch(g_player[snum].ps, weap);
}
#else
static void P_AddWeaponAmmoCommon(DukePlayer_t *ps, int32_t weap, int32_t amount)
{
P_AddAmmo(weap, ps, amount);

View file

@ -4,6 +4,9 @@ local require = require
local ffi = require("ffi")
local ffiC = ffi.C
-- Lua C API functions, this comes from El_PushCFunctions() in lunatic_game.c.
local CF = CF
local bit = require("bit")
local io = require("io")
local math = require("math")
@ -149,6 +152,13 @@ local function krandand(mask)
return bit.band(ffiC.krand(), mask)
end
local function check_isnumber(...)
local vals = {...}
for i=1,#vals do
assert(type(vals[i])=="number")
end
end
-- Lunatic's "insertsprite" is a wrapper around the game "A_InsertSprite", not
-- the engine "insertsprite".
--
@ -187,20 +197,21 @@ function insertsprite(tab_or_tilenum, ...)
check_tile_idx(tilenum)
check_sector_idx(sectnum)
check_isnumber(shade, xrepeat, yrepeat, ang, xvel, zvel, owner)
if (statnum >= ffiC.MAXSTATUS) then
if (statnum >= ffiC.MAXSTATUS+0ULL) then
error("invalid 'statnum' argument to insertsprite: must be a status number (0 .. MAXSTATUS-1)", 2)
end
return ffiC.A_InsertSprite(sectnum, pos.x, pos.y, pos.z, tilenum,
shade, xrepeat, yrepeat, ang, xvel, zvel,
owner, statnum)
return CF.A_InsertSprite(sectnum, pos.x, pos.y, pos.z, tilenum,
shade, xrepeat, yrepeat, ang, xvel, zvel,
owner, statnum)
end
-- INTERNAL USE ONLY.
function _addtodelqueue(spritenum)
check_sprite_idx(spritenum)
ffiC.A_AddToDeleteQueue(spritenum)
CF.A_AddToDeleteQueue(spritenum)
end
-- This corresponds to the first (spawn from parent sprite) form of A_Spawn().
@ -212,9 +223,9 @@ function spawn(parentspritenum, tilenum, addtodelqueue)
return -1
end
local i = ffiC.A_Spawn(parentspritenum, tilenum)
local i = CF.A_Spawn(parentspritenum, tilenum)
if (addtodelqueue) then
ffiC.A_AddToDeleteQueue(i)
CF.A_AddToDeleteQueue(i)
end
return i
end
@ -222,7 +233,7 @@ end
-- This is the second A_Spawn() form. INTERNAL USE ONLY.
function _spawnexisting(spritenum)
check_sprite_idx(spritenum)
return ffiC.A_Spawn(-1, spritenum)
return CF.A_Spawn(-1, spritenum)
end
-- A_SpawnMultiple clone
@ -247,7 +258,7 @@ function _shoot(i, tilenum, zvel)
zvel = zvel and int16_st(zvel).s or 0x80000000 -- SHOOT_HARDCODED_ZVEL
return ffiC.A_ShootWithZvel(i, tilenum, zvel)
return CF.A_ShootWithZvel(i, tilenum, zvel)
end
function isenemytile(tilenum)
@ -418,7 +429,7 @@ local function P_AddWeaponAmmoCommon(ps, weap, amount)
P_AddAmmo(ps, weap, amount)
if (ps.curr_weapon==ffiC.KNEE_WEAPON and ps:have_weapon(weap)) then
ffiC.P_AddWeaponMaybeSwitch(ps, weap);
CF.P_AddWeaponMaybeSwitchI(ps.weapon._p, weap);
end
end
@ -808,7 +819,7 @@ end
function _A_Shoot(i, atwith)
check_sprite_idx(i)
check_tile_idx(atwith)
return ffiC.A_ShootWithZvel(i, atwith, 0x80000000) -- SHOOT_HARDCODED_ZVEL
return CF.A_ShootWithZvel(i, atwith, 0x80000000) -- SHOOT_HARDCODED_ZVEL
end
function _A_IncurDamage(sn)
@ -818,7 +829,7 @@ end
function _VM_FallSprite(i)
check_sprite_idx(i)
ffiC.VM_FallSprite(i)
CF.VM_FallSprite(i)
end
function _sizeto(i, xr, yr)
@ -835,7 +846,7 @@ end
function _A_Spawn(j, pn)
local bound_check = sector[sprite[j].sectnum] -- two in one whack
check_tile_idx(pn)
return ffiC.A_Spawn(j, pn)
return CF.A_Spawn(j, pn)
end
function _pstomp(ps, i)
@ -864,8 +875,8 @@ function _pkick(ps, spr)
end
function _VM_ResetPlayer2(snum)
local bound_check = player[snum]
return (ffiC.VM_ResetPlayer2(snum)~=0)
check_player_idx(snum)
return (CF.VM_ResetPlayer2(snum)~=0)
end
local PALBITS = { [0]=1, [21]=2, [23]=4 }
@ -933,7 +944,8 @@ function _selectnextinv(ps)
end
function _checkavailweapon(pli)
ffiC.P_CheckWeapon(player[pli])
check_player_idx(pli)
CF.P_CheckWeaponI(pli)
end
function _addphealth(ps, aci, hlthadd)
@ -991,7 +1003,7 @@ function _addweapon(ps, weap, amount)
end
if (not ps:have_weapon(weap)) then
ffiC.P_AddWeaponMaybeSwitch(ps, weap);
CF.P_AddWeaponMaybeSwitchI(ps.weapon._p, weap);
elseif (have_ammo_at_max(ps, weap)) then
return true
end
@ -1001,7 +1013,8 @@ end
function _A_RadiusDamage(i, r, hp1, hp2, hp3, hp4)
check_sprite_idx(i)
ffiC.A_RadiusDamage(i, r, hp1, hp2, hp3, hp4)
check_isnumber(r, hp1, hp2, hp3, hp4)
CF.A_RadiusDamage(i, r, hp1, hp2, hp3, hp4)
end
function _testkey(pli, synckey)
@ -1045,7 +1058,7 @@ function _operate(spritenum)
return
end
end
ffiC.G_OperateSectors(tag.sector, spritenum)
CF.G_OperateSectors(tag.sector, spritenum)
end
end
end
@ -1056,21 +1069,22 @@ end
function _operatesectors(sectnum, spritenum)
check_sector_idx(sectnum)
check_sprite_idx(spritenum) -- XXX: -1 permissible under certain circumstances?
ffiC.G_OperateSectors(sectnum, spritenum)
CF.G_OperateSectors(sectnum, spritenum)
end
function _operateactivators(tag, playernum)
check_player_idx(playernum)
-- NOTE: passing oob playernum would be safe because G_OperateActivators
-- bound-checks it
ffiC.G_OperateActivators(tag, playernum)
assert(type(tag)=="number")
CF.G_OperateActivators(tag, playernum)
end
function _activatebysector(sectnum, spritenum)
local didit = false
for i in spriteofsect(sectnum) do
if (sprite[i].picnum==D.ACTIVATOR) then
ffiC.G_OperateActivators(sprite[i].lotag, -1)
CF.G_OperateActivators(sprite[i].lotag, -1)
end
end
if (didit) then
@ -1463,7 +1477,7 @@ function _sound(aci, sndidx)
-- A_PlaySound() returns early if the sound index is oob, but IMO it's good
-- style to throw an error instead of silently failing.
check_sound_idx(sndidx)
ffiC.A_PlaySound(sndidx, aci)
CF.A_PlaySound(sndidx, aci)
end
function _globalsound(pli, sndidx)

View file

@ -520,26 +520,12 @@ const int32_t g_currentMenu;
uint16_t g_earthquakeTime;
char CheatKeys[2];
// Functions marked with 'EVENT' may call events.
// http://www.freelists.org/post/luajit/intermitten-lua-pcall-crash-on-x86-64-linux,1
// Must not have functions here that may call events directly or
// indirectly. See lunatic_game.c.
int32_t A_IncurDamage(int32_t sn); // not bound-checked!
void P_AddWeaponMaybeSwitch(DukePlayer_t *ps, int32_t weap); // EVENT
void P_CheckWeapon(DukePlayer_t *p); // EVENT
int32_t A_ShootWithZvel(int32_t i, int32_t atwith, int32_t override_zvel); // EVENT
int32_t A_Spawn(int32_t j, int32_t pn); // EVENT
void VM_FallSprite(int32_t i); // EVENT
int32_t VM_ResetPlayer2(int32_t snum); // EVENT
void A_RadiusDamage(int32_t i, int32_t r, int32_t, int32_t, int32_t, int32_t); // EVENT
void G_OperateSectors(int32_t sn, int32_t ii); // EVENT
void G_OperateActivators(int32_t low,int32_t snum); // EVENT
int32_t G_CheckActivatorMotion(int32_t lotag);
int32_t A_Dodge(spritetype *s);
// EVENT:
int32_t A_InsertSprite(int32_t whatsect,int32_t s_x,int32_t s_y,int32_t s_z,int32_t s_pn,int32_t s_s,
int32_t s_xr,int32_t s_yr,int32_t s_a,int32_t s_ve,int32_t s_zv,int32_t s_ow,int32_t s_ss);
int32_t A_Spawn(int32_t j, int32_t pn); // EVENT
void A_AddToDeleteQueue(int32_t i); // EVENT
int32_t A_MoveSprite(int32_t spritenum, const vec3_t *change, uint32_t cliptype);
void P_DoQuote(int32_t q, DukePlayer_t *p);
void G_AddUserQuote(const char *daquote);
@ -554,7 +540,6 @@ int32_t G_StartTrack(int32_t level);
const char *KB_ScanCodeToString(uint8_t scancode);
int32_t A_CheckAnySoundPlaying(int32_t i);
int32_t A_PlaySound(uint32_t num, int32_t i); // EVENT
int32_t S_CheckSoundPlaying(int32_t i, int32_t num);
void S_StopEnvSound(int32_t num, int32_t i);
int32_t FX_StopAllSounds(void);

View file

@ -133,21 +133,8 @@ rand_jkiss_dbl;
md4once;
A_IncurDamage;
P_AddWeaponMaybeSwitch;
P_CheckWeapon;
A_ShootWithZvel;
A_IncurDamage;
A_Spawn;
VM_FallSprite;
VM_ResetPlayer2;
A_RadiusDamage;
G_OperateSectors;
G_OperateActivators;
G_CheckActivatorMotion;
A_Dodge;
A_InsertSprite;
A_Spawn;
A_AddToDeleteQueue;
A_MoveSprite;
P_DoQuote;
G_AddUserQuote;
@ -161,7 +148,6 @@ G_StartTrack;
KB_ScanCodeToString;
A_CheckAnySoundPlaying;
A_PlaySound;
S_CheckSoundPlaying;
S_StopEnvSound;
FX_StopAllSounds;

View file

@ -221,6 +221,106 @@ static int our_traceback_CF(lua_State *L)
return 1;
}
////// Lua C-API interfaces for C game functions that may call events.
// http://www.freelists.org/post/luajit/intermitten-lua-pcall-crash-on-x86-64-linux,1
// Some of these are duplicate declarations:
extern void P_AddWeaponMaybeSwitchI(int32_t snum, int32_t weap);
extern void P_CheckWeaponI(int32_t snum);
extern int32_t A_ShootWithZvel(int32_t i, int32_t atwith, int32_t override_zvel);
extern int32_t A_Spawn(int32_t j, int32_t pn);
extern void VM_FallSprite(int32_t i);
extern int32_t VM_ResetPlayer2(int32_t snum);
extern void A_RadiusDamage(int32_t i, int32_t r, int32_t, int32_t, int32_t, int32_t);
extern void G_OperateSectors(int32_t sn, int32_t ii);
extern void G_OperateActivators(int32_t low,int32_t snum);
extern int32_t A_InsertSprite(int32_t whatsect,int32_t s_x,int32_t s_y,int32_t s_z,int32_t s_pn,int32_t s_s,
int32_t s_xr,int32_t s_yr,int32_t s_a,int32_t s_ve,int32_t s_zv,int32_t s_ow,int32_t s_ss);
extern void A_AddToDeleteQueue(int32_t i);
extern int32_t A_PlaySound(uint32_t num, int32_t i);
#define LARG(index) lua_tointeger(L, index)
#define ONE_ARG LARG(1)
#define TWO_ARGS LARG(1), LARG(2)
#define THREE_ARGS LARG(1), LARG(2), LARG(3)
#define CALL_WITH_RET(Name, ...) \
int32_t ret = Name(__VA_ARGS__); \
lua_pushinteger(L, ret); \
return 1
#define CALL_WITHOUT_RET(Name, ...) \
Name(__VA_ARGS__); \
return 0
#define DEFINE_RET_CFUNC(Name, ...) \
static int32_t Name##_CF(lua_State *L) \
{ \
CALL_WITH_RET(Name, __VA_ARGS__); \
}
#define DEFINE_VOID_CFUNC(Name, ...) \
static int32_t Name##_CF(lua_State *L) \
{ \
CALL_WITHOUT_RET(Name, __VA_ARGS__); \
}
// NOTE: player struct -> player index -> player struct ugliness because
// pointers to FFI cdata apparently can't be reliably passed via lua_getpointer().
// Not to mention that lua_getpointer() returns _const_ void*.
DEFINE_VOID_CFUNC(P_AddWeaponMaybeSwitchI, TWO_ARGS)
DEFINE_VOID_CFUNC(P_CheckWeaponI, ONE_ARG)
DEFINE_RET_CFUNC(A_ShootWithZvel, THREE_ARGS)
DEFINE_RET_CFUNC(A_Spawn, TWO_ARGS)
DEFINE_VOID_CFUNC(VM_FallSprite, ONE_ARG)
DEFINE_RET_CFUNC(VM_ResetPlayer2, ONE_ARG)
DEFINE_VOID_CFUNC(A_RadiusDamage, LARG(1), LARG(2), LARG(3), LARG(4), LARG(5), LARG(6))
DEFINE_VOID_CFUNC(G_OperateSectors, TWO_ARGS)
DEFINE_VOID_CFUNC(G_OperateActivators, TWO_ARGS)
DEFINE_RET_CFUNC(A_InsertSprite, LARG(1), LARG(2), LARG(3), LARG(4), LARG(5), LARG(6),
LARG(7), LARG(8), LARG(9), LARG(10), LARG(11), LARG(12), LARG(13))
DEFINE_VOID_CFUNC(A_AddToDeleteQueue, ONE_ARG)
DEFINE_RET_CFUNC(A_PlaySound, TWO_ARGS)
#define CFUNC_REG(Name) { #Name, Name##_CF }
struct { const char *name; lua_CFunction func; } cfuncs[] =
{
CFUNC_REG(P_AddWeaponMaybeSwitchI),
CFUNC_REG(P_CheckWeaponI),
CFUNC_REG(A_ShootWithZvel),
CFUNC_REG(A_Spawn),
CFUNC_REG(VM_FallSprite),
CFUNC_REG(VM_ResetPlayer2),
CFUNC_REG(A_RadiusDamage),
CFUNC_REG(G_OperateSectors),
CFUNC_REG(G_OperateActivators),
CFUNC_REG(A_InsertSprite),
CFUNC_REG(A_Spawn),
CFUNC_REG(A_AddToDeleteQueue),
CFUNC_REG(A_PlaySound),
};
// Creates a global table "CF" containing the functions from cfuncs[].
static void El_PushCFunctions(lua_State *L)
{
int32_t i;
lua_newtable(L);
for (i=0; i<(signed)sizeof(cfuncs)/(signed)sizeof(cfuncs[0]); i++)
{
lua_pushstring(L, cfuncs[i].name);
lua_pushcfunction(L, cfuncs[i].func);
lua_settable(L, -3);
}
lua_setglobal(L, "CF");
}
//////
static void El_StateSetup(lua_State *L)
{
luaopen_lpeg(L);
@ -232,6 +332,8 @@ static void El_StateSetup(lua_State *L)
lua_pushcfunction(L, SetActor_CF);
lua_setglobal(L, "gameactor_internal");
El_PushCFunctions(L);
Bassert(lua_gettop(L)==0);
// This is for engine-side Lua:

View file

@ -3302,6 +3302,13 @@ void P_CheckWeapon(DukePlayer_t *p)
P_ChangeWeapon(p, weapon);
}
#ifdef LUNATIC
void P_CheckWeaponI(int32_t snum)
{
P_CheckWeapon(g_player[snum].ps);
}
#endif
static void P_CheckTouchDamage(DukePlayer_t *p, int32_t obj)
{
if ((obj = VM_OnEvent(EVENT_CHECKTOUCHDAMAGE, p->i, sprite[p->i].yvel, -1, obj)) == -1)