Lunatic: replace DukePlayer_t set-member methods with metatable magic.

So that members needing it are checked when they're assigned to using the
usual syntax. What kind of check to perform (sector, player, ... x whether
negative values are allowed) is written in a declarative fashion inside the
C declaration.

Also, make Lunatic's MAXQUOTES be C's OBITQUOTEINDEX and bound-check an
access of sprite[p->wackedbyplayer] in the C code.

git-svn-id: https://svn.eduke32.com/eduke32@3653 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
helixhorned 2013-04-07 15:20:41 +00:00
parent fb41d91a50
commit bbdc035335
7 changed files with 88 additions and 77 deletions

View file

@ -20,7 +20,11 @@ MAXEVENTS = 95 -- KEEPINSYNC with EVENT_* list
MAXSOUNDS = 4096
-- KEEPINSYNC quotes.h
MAXQUOTES = 16384
-- For Lunatic, MAXQUOTES is OBITQUOTEINDEX because starting from that index
-- are obituary and suicide quotes which are passed as *format strings* to
-- sprintf() in C.
MAXQUOTES = 16384-128
MAXQUOTELEN = 128
local STR = {
@ -516,17 +520,17 @@ local PlayerLabels = {
oang = PL".oang",
angvel = PL".angvel",
cursectnum = { PL".cursectnum", PL":set_cursectnum(%%s)" },
cursectnum = PL".cursectnum",
look_ang = PL".look_ang",
last_extra = PL".last_extra",
subweapon = PL".subweapon",
max_ammo_amount = PL".max_ammo_amount[%s]" ,
ammo_amount = PL".ammo_amount[%s]" ,
max_ammo_amount = PL".max_ammo_amount[%s]",
ammo_amount = PL".ammo_amount[%s]",
-- NOTE: no direct access for .inv_amount (but see end)
wackedbyactor = { PL".wackedbyactor", PL":set_wackedbyactor(%%s)" },
wackedbyactor = PL".wackedbyactor",
pyoff = PL".pyoff",
opyoff = PL".opyoff",
@ -541,7 +545,7 @@ local PlayerLabels = {
airleft = PL".airleft",
fta = PL".fta",
ftq = { PL".ftq", PL":set_ftq(%%s)" },
ftq = PL".ftq",
access_wallnum = { PL".access_wallnum" },
access_spritenum = { PL".access_spritenum" },
@ -559,7 +563,7 @@ local PlayerLabels = {
random_club_frame = PL".random_club_frame",
one_eighty_count = PL".one_eighty_count",
dummyplayersprite = { PL".dummyplayersprite", PL":set_dummyplayersprite(%%s)" },
dummyplayersprite = PL".dummyplayersprite",
extra_extra8 = PL".extra_extra8",
actorsqu = PL".actorsqu",
@ -568,7 +572,7 @@ local PlayerLabels = {
last_pissed_time = PL".last_pissed_time",
weaprecs = PL".weaprecs[%s]" ,
weaprecs = PL".weaprecs[%s]",
weapon_sway = PL".weapon_sway",
crack_time = PL".crack_time",
@ -649,12 +653,12 @@ local PlayerLabels = {
loogcnt = PL".loogcnt",
scream_voice = PL".scream_voice",
last_weapon = { PL".last_weapon", PL":set_last_weapon(%%s)" },
last_weapon = PL".last_weapon",
cheat_phase = PL".cheat_phase",
weapon_pos = PL".weapon_pos",
wantweaponfire = { PL".wantweaponfire" },
wantweaponfire = PL".wantweaponfire",
curr_weapon = { PL".curr_weapon", PL":set_curr_weapon(%%s)" },
curr_weapon = PL".curr_weapon",
palette = PL".palette",

View file

@ -1130,7 +1130,7 @@ end
function _endofgame(pli, timebeforeexit)
player[pli].timebeforeexit = timebeforeexit
player[pli]:set_customexitsound(-1)
player[pli].customexitsound = -1
ffiC.ud.eog = 1
end

View file

@ -210,28 +210,29 @@ __attribute__((packed)) struct {
int16_t sbs, sound_pitch;
int16_t ang, oang, angvel;
const int16_t cursectnum;
const<S> int16_t cursectnum;
int16_t look_ang, last_extra, subweapon;
int16_x_MAX_WEAPONS max_ammo_amount;
int16_x_MAX_WEAPONS ammo_amount;
int16_x_GET_MAX inv_amount;
const int16_t wackedbyactor;
const<I-> int16_t wackedbyactor;
int16_t pyoff, opyoff;
int16_t horiz, horizoff, ohoriz, ohorizoff;
const int16_t newowner;
int16_t jumping_counter, airleft;
int16_t fta;
const int16_t ftq, access_wallnum, access_spritenum;
const<Q> int16_t ftq;
const int16_t access_wallnum, access_spritenum;
int16_t got_access, weapon_ang, visibility;
int16_t somethingonplayer, on_crane;
const int16_t i;
const int16_t one_parallax_sectnum;
int16_t random_club_frame, one_eighty_count;
const int16_t dummyplayersprite;
const<I-> int16_t dummyplayersprite;
int16_t extra_extra8;
int16_t actorsqu, timebeforeexit;
const int16_t customexitsound;
const<X-> int16_t customexitsound;
int16_t last_pissed_time;
int16_x_MAX_WEAPONS weaprecs;
@ -248,7 +249,7 @@ __attribute__((packed)) struct {
const uint8_t weapreccnt;
uint8_t aim_mode, auto_aim, weaponswitch, movement_lock, team;
uint8_t tipincs, hbomb_hold_delay;
const uint8_t frag_ps;
const<P> uint8_t frag_ps;
uint8_t kickback_pic;
uint8_t gm;
@ -278,9 +279,10 @@ __attribute__((packed)) struct {
uint8_t walking_snd_toggle, palookup, hard_landing, fist_incs;
int8_t numloogs, loogcnt, scream_voice;
const int8_t last_weapon;
const<W-> int8_t last_weapon;
int8_t cheat_phase, weapon_pos;
const int8_t wantweaponfire, curr_weapon;
const<W-> int8_t wantweaponfire;
const<W> int8_t curr_weapon;
uint8_t palette;
palette_t _pals;
@ -337,15 +339,44 @@ local function ma_replace_array(typestr, neltstr)
return table.concat(strtab)
end
-- Converts a template struct definition to an external one, in which arrays
-- have been substituted by randomly named scalar fields.
local function mangle_arrays(structstr)
ma_count = 0
-- NOTE: regexp only works for non-nested arrays and for one array per line.
return (string.gsub(structstr, "const%s+([%w_]+)[^\n]+%[([%w_]+)%];", ma_replace_array))
---=== Protection of scalars in (currently only) DukePlayer_t struct. ===---
-- This is more convenient than writing dozens of set-member methods.
local prot_scalar_chkfunc = {
S = check_sector_idx,
I = check_sprite_idx,
P = bcheck.player_idx,
W = check_weapon_idx,
X = check_sound_idx,
Q = bcheck.quote_idx,
}
local DukePlayer_prot_allowneg = {} -- [<member name>] = true if setting <0 allowed
local DukePlayer_prot_chkfunc = {} -- [<member name>] = <checking function>
local function ma_replace_scalar(what, typestr, membname)
DukePlayer_prot_chkfunc[membname] = assert(prot_scalar_chkfunc[what:sub(1,1)])
DukePlayer_prot_allowneg[membname] = (what:sub(2)=="-")
return ma_replace_array(typestr, 1)
end
--print(mangle_arrays(ACTOR_STRUCT))
-- Converts a template struct definition to an external one, in which arrays
-- have been substituted by randomly named scalar fields.
-- <also_scalars>: also handle protected scalars like "const<W-> ..." etc.
local function mangle_arrays(structstr, also_scalars)
ma_count = 0
-- NOTE: regexp only works for non-nested arrays and for one array per line.
structstr = structstr:gsub("const%s+([%w_]+)[^\n]+%[([%w_]+)%];", ma_replace_array)
if (also_scalars) then
-- One protected scalar per line, too.
structstr = structstr:gsub("const<(.-)>%s+([%w_]-)%s+([%w_]-);", ma_replace_scalar)
end
return structstr
end
--print(mangle_arrays(DUKEPLAYER_STRUCT, true))
--- default defines etc.
local con_lang = require("con_lang")
@ -365,7 +396,7 @@ typedef
actor_t;
typedef
]].. mangle_arrays(DUKEPLAYER_STRUCT) ..[[
]].. mangle_arrays(DUKEPLAYER_STRUCT, true) ..[[
DukePlayer_t;
typedef __attribute__((packed)) struct {
@ -963,7 +994,7 @@ ffi.metatype("actor_t", actor_mt)
local weapondata_mt = {
__index = function(wd, member)
-- Handle protected members that are renamed (e.g. shoots/_shoots).
return ffi.cast(weapondata_ptr_ct, wd)[member]
return ffi.cast(weapondata_ptr_ct, wd)[0][member]
end,
__newindex = function(wd, member, val)
@ -986,7 +1017,7 @@ local weapondata_mt = {
end
end
ffi.cast(weapondata_ptr_ct, wd)[member] = val
ffi.cast(weapondata_ptr_ct, wd)[0][member] = val
end,
}
ffi.metatype("weapondata_t", weapondata_mt)
@ -1007,50 +1038,6 @@ ffi.metatype("weaponaccess_t", weaponaccess_mt)
local player_mt = {
__index = {
--- Getters/setters
set_curr_weapon = function(p, weap)
check_weapon_idx(weap)
ffi.cast(player_ptr_ct, p).curr_weapon = weap
end,
set_last_weapon = function(p, weap)
if (not (weap < 0)) then
check_weapon_idx(weap)
end
ffi.cast(player_ptr_ct, p).last_weapon = weap
end,
set_ftq = function(p, ftq)
bcheck.quote_idx(ftq)
ffi.cast(player_ptr_ct, p).ftq = ftq
end,
set_cursectnum = function(p, sectnum)
check_sector_idx(sectnum)
ffi.cast(player_ptr_ct, p).cursectnum = sectnum
end,
set_customexitsound = function(p, soundnum)
if (not (soundnum < 0)) then
check_sound_idx(soundnum)
end
ffi.cast(player_ptr_ct, p).customexitsound = soundnum
end,
set_dummyplayersprite = function(p, spritenum)
if (not (spritenum < 0)) then
check_sprite_idx(spritenum)
end
ffi.cast(player_ptr_ct, p).dummyplayersprite = spritenum
end,
set_wackedbyactor = function(p, spritenum)
if (not (spritenum < 0)) then
check_sprite_idx(spritenum)
end
ffi.cast(player_ptr_ct, p).wackedbyactor = spritenum
end,
-- CON-like addammo/addweapon, but without the non-local control flow
-- (returns true if weapon's ammo was at the max. instead).
addammo = con._addammo,
@ -1099,12 +1086,27 @@ local player_mt = {
pals.r, pals.g, pals.b = r, g, b
end,
},
__newindex = function(p, key, val)
-- Write access to protected player members.
local allowneg = DukePlayer_prot_allowneg[key]
assert(type(allowneg)=="boolean")
if (allowneg==false or not (val < 0)) then
DukePlayer_prot_chkfunc[key](val)
end
ffi.cast(player_ptr_ct, p)[key] = val
end,
}
local function player_index_index(p, key)
if (key=="_input") then
return ffiC.g_player[p.weapon._p].sync[0]
end
-- Read access to protected player members.
return ffi.cast(player_ptr_ct, p)[0][key]
end
setmtonce(player_mt.__index, { __index = player_index_index })

View file

@ -166,8 +166,9 @@ struct {
}]]
-- Converts a template struct definition to an internal, unrestricted one.
-- NOTE: "[^ ]*" for const decorations in defs.ilua.
function strip_const(structstr)
return (string.gsub(structstr, "const ", ""));
return (string.gsub(structstr, "const[^ ]* ", ""));
end
-- NOTE for FFI definitions: we're compiling EDuke32 with -funsigned-char, so

View file

@ -190,6 +190,10 @@ checkfail("gv.g_sizes_of=nil; print(gv.g_sizes_of[0])", "write access forbidden"
checkfail("gv.cam.sect=-1", "invalid sector number")
checkfail("local flag=gv.SFLAG_NULL", "missing declaration")
player[0].wackedbyactor = -1 -- should succeed
checkfail("player[0].curr_weapon = -1", "Invalid weapon ID")
player[0].curr_weapon = 1
printf('ceilingbunch of sector 0: %d', getbunch(0, gv.CEILING))
gameevent(gv.EVENT_JUMP,

View file

@ -3570,7 +3570,7 @@ void P_FragPlayer(int32_t snum)
if (actor[p->i].picnum != APLAYERTOP)
{
p->fraggedself++;
if (A_CheckEnemyTile(sprite[p->wackedbyactor].picnum))
if ((unsigned)p->wackedbyactor < MAXTILES && A_CheckEnemyTile(sprite[p->wackedbyactor].picnum))
Bsprintf(tempbuf,ScriptQuotes[OBITQUOTEINDEX+(krand()%g_numObituaries)],"A monster",&g_player[snum].user_name[0]);
else if (actor[p->i].picnum == NUKEBUTTON)
Bsprintf(tempbuf,"^02%s^02 tried to leave",&g_player[snum].user_name[0]);

View file

@ -161,7 +161,7 @@ typedef struct {
// * int16_t --> int8_t
// * char --> int8_t
// Need to carefully think about implications!
// TODO: rearrange this is the opportunity arises!
// TODO: rearrange this if the opportunity arises!
// KEEPINSYNC lunatic/defs.ilua
typedef struct {
vec3_t pos, opos, vel, npos;