mirror of
https://github.com/ZDoom/Raze.git
synced 2024-12-15 15:11:41 +00:00
1606c17a77
- add LuaJIT's 'v' module printing trace info - translator: fix game function name definitions - revert math.fmod -> math.modf, they are different! - disable JIT compilation for a function we're getting strange crashes with - Make some of DukePlayer_t's members 'bool' on the Lua side. It's way too easy to write something like "ps.jetpack_on" where "ps.jetpack_on~=0" was meant. [Background: Kyle873 observed that Duke was always floating.] - Error out if looping in our_module(). I find this behavior more logical than returning true. - fix a couple of missed FORBID variables git-svn-id: https://svn.eduke32.com/eduke32@3530 1a8010ca-5511-0410-912e-c29ae57300e0
481 lines
15 KiB
Text
481 lines
15 KiB
Text
-- test script for ELua/Lunatic Interpreter
|
|
|
|
--do return end
|
|
|
|
-- error=nil -- must not affect "require"
|
|
local string = require("string")
|
|
local bit = require("bit")
|
|
local math = require("math")
|
|
|
|
local pcall = pcall
|
|
local DBG_ = DBG_
|
|
|
|
print('---=== ELua Test script ===---')
|
|
|
|
local function printf(fmt, ...)
|
|
print(string.format(fmt, ...))
|
|
end
|
|
|
|
local function checkfail(funcstr, expectedmsg)
|
|
local status, errmsg = pcall(DBG_.loadstring(funcstr))
|
|
if (status) then
|
|
print('^21ERROR:^O '..funcstr.." DIDN'T fail")
|
|
else
|
|
if (expectedmsg==nil or string.find(errmsg, expectedmsg, 1, true)) then
|
|
print("^11SUCCESS:^O "..funcstr.." failed: "..errmsg)
|
|
else
|
|
-- XXX: beginning with "^10" is counted as error in OSD_Printf()
|
|
print("^10ERROR*:^O "..funcstr.." failed: "..errmsg..
|
|
", but expected error message was: "..expectedmsg)
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
---- check serialization ----
|
|
gamevar("ourvar")
|
|
gamevar("ourvar2")
|
|
|
|
-- test nans, infs, precision, subnorms, booleans
|
|
ourvar2 = { "asd"; 0/0, 1/0, -1/0, 0.12345678901234567, 1e-314, true }
|
|
ourvar = { ourvar2; 1, 2, 3, "qwe"; [true]=0, [false]=1 }
|
|
ourvar[#ourvar+1] = ourvar;
|
|
|
|
local gvstr = DBG_.serializeGamevars()
|
|
ourvar = -1
|
|
|
|
print("========== attempting to load string: ==========")
|
|
print(gvstr)
|
|
print("---------- (end string to load) ----------")
|
|
|
|
-- XXX: need to think about fully restoring state
|
|
DBG_.loadGamevarsString(gvstr)
|
|
print("ourvar[4]="..ourvar[4])
|
|
|
|
|
|
local i
|
|
|
|
print('tweaking sector pals')
|
|
print('numsectors: ' .. gv.numsectors .. ' of ' .. gv.MAXSECTORS)
|
|
|
|
---[[
|
|
for i = 0, gv.numsectors/2 do
|
|
sector[i].floorpal = 1;
|
|
sector[i].ceilingpal = 2;
|
|
end
|
|
|
|
local vol, lev = gv.currentEpisode()+1, gv.currentLevel()+1
|
|
printf('volume=%d, level=%d', vol, lev)
|
|
|
|
if (vol==1 and lev==1) then -- E1L1
|
|
print('tweaking some sprites 2')
|
|
i = 562
|
|
spriteext[i].alpha = 0.5;
|
|
sprite[i].cstat = bit.bor(sprite[i].cstat, 2+512);
|
|
spriteext[i].pitch = 128;
|
|
spriteext[i].roll = 256;
|
|
|
|
for spr in spritesofsect(307) do -- some fence sprites in E1L1
|
|
printf('spr %d', spr)
|
|
sprite[spr].pal = 6
|
|
end
|
|
|
|
--this is a problem
|
|
--actor = {}
|
|
actor[562].flags = bit.bor(actor[562].flags, 2); -- pal 6 with goggles on front SEENINE
|
|
end
|
|
|
|
--[[
|
|
-- TODO: better API for all TROR things?
|
|
if (vol==1 and lev==8) then
|
|
print('tweaking bunch 1');
|
|
-- trueror1.map
|
|
for i in sectorsofbunch(1, gv.CEILING) do
|
|
sector[i].ceilingz = sector[i].ceilingz - 3*1024;
|
|
end
|
|
for i in sectorsofbunch(1, gv.FLOOR) do
|
|
sector[i].floorz = sector[i].floorz - 3*1024;
|
|
end
|
|
end
|
|
--]]
|
|
|
|
local unsafe = pcall(function() string.UNSAFE=true; end)
|
|
|
|
--]]
|
|
--tostring = nil -- REMEMBER
|
|
--DBG_.printkv('_G in test.elua', _G)
|
|
|
|
-- direct gv array access forbidden
|
|
checkfail('gv.sprite[0].yrepeat = 100', "access forbidden")
|
|
|
|
-- indexing struct array with non-numeric type
|
|
checkfail('local i = sprite["qwe"]') -- this will produce an error inside the sprite metatable
|
|
|
|
checkfail('print(sprite[100000].ceilingpal)', "out-of-bounds sprite[] read access")
|
|
|
|
checkfail('print(gv.sprite[0])', "access forbidden")
|
|
|
|
-- set metatable forbidden
|
|
checkfail('setmetatable(sprite, {})', "attempt to read undeclared variable 'setmetatable'")
|
|
|
|
-- OOB write access.
|
|
-- Note that indexing ("reading") sector fails, even if the user wants to
|
|
-- assign to a sector member. Potentially confusing error message.
|
|
checkfail('sector[-1].ceilingpal = 4', "out-of-bounds sector[] read access")
|
|
|
|
-- wallnum member is read-only
|
|
checkfail('sector[0].wallnum = 0', "attempt to write to constant location") -- this comes from LJ/FFI
|
|
|
|
-- gv.numsectors is read-only
|
|
checkfail('gv.numsectors = 4', "write access forbidden")
|
|
|
|
-- cannot create new fields in 'gv'
|
|
checkfail('gv.QWE = 4', "write access forbidden")
|
|
|
|
-- direct sector write access forbidden
|
|
checkfail('sector[4] = sector[6]', "cannot write directly to sector[]")
|
|
|
|
-- that would be horrible...
|
|
checkfail('sprite._nextspritesect[4] = -666', "cannot write directly to nextspritesect[]")
|
|
|
|
-- we're indexing a plain array!
|
|
checkfail('print(sprite._nextspritesect[4].whatfield)', "attempt to index a number value")
|
|
|
|
-- creating new keys forbidden... handled by LuaJit
|
|
checkfail('wall[4].QWE = 123', "has no member named 'QWE'")
|
|
|
|
-- our 'require' has only safe stuff
|
|
--checkfail("require('os')")
|
|
|
|
-- we must declare globals with 'gamevar'
|
|
checkfail("new_global = 345", "attempt to write to undeclared variable 'new_global'")
|
|
|
|
-- can't redefine constants in 'gv'
|
|
checkfail('gv.CEILING = 3', "write access forbidden")
|
|
|
|
-- string.dump is unavailable
|
|
checkfail('local s=require[[string]]; local tmp=s.dump(gameevent)',
|
|
"attempt to call field 'dump' (a nil value)")
|
|
|
|
if (not unsafe) then
|
|
-- changing base module tables is disallowed
|
|
checkfail('local s=require[[string]]; s.format=nil', "modifying base module table forbidden")
|
|
else
|
|
print('WARNING: RUNNING WITH UNPROTECTED BASE MODULES')
|
|
end
|
|
|
|
print('')
|
|
-- This is problematic, even though pretty much every access will yield a
|
|
-- "missing declaration" error.
|
|
-- See http://luajit.org/ext_ffi_api.html#ffi_C about what stuff ffi.C contains.
|
|
checkfail('gv.luaJIT_setmode(nil, 0, 0)', "missing declaration for symbol 'luaJIT_setmode'")
|
|
|
|
checkfail('gv.luaJIT_BC_con_lang', "attempt to call a nil value")
|
|
checkfail('gv.yax_getbunch(0,0)', "access forbidden")
|
|
checkfail('gv.gethitickms = nil', "write access forbidden")
|
|
|
|
-- actor[].t_data[] is not accessible for now
|
|
checkfail('local i = actor[0].t_data[15]', "has no member named 't_data'")
|
|
|
|
-- no pointer arithmetic!
|
|
checkfail('local spr = sprite[0]; local x=spr+1', "attempt to perform arithmetic on")
|
|
|
|
checkfail('gameactor(1680, 0)', "invalid last argument to gameactor: must be a function")
|
|
|
|
checkfail("do local bt=require'bittest'; bt.QWE=1; end", "modifying module table forbidden")
|
|
-- the cdata returned by player[] can't be made into a pointer!
|
|
checkfail("do local pl=player[0]; i=pl[1]; end")
|
|
checkfail("do local ud=gv.ud.camerasprite; end", "access forbidden") -- test for proper decl()
|
|
checkfail("sprite[0]:set_picnum(-10)", "invalid tile number")
|
|
checkfail("gv.g_sizes_of=nil; print(gv.g_sizes_of[0])", "write access forbidden")
|
|
checkfail("gv.cam.sect=-1", "invalid sector number")
|
|
|
|
printf('ceilingbunch of sector 0: %d', getbunch(0, gv.CEILING))
|
|
|
|
gameevent(gv.EVENT_JUMP,
|
|
function(actori, playeri, dist)
|
|
printf("jump i=%d p=%d d=%d", actori, playeri, dist)
|
|
error("greetings from EVENT_JUMP")
|
|
end
|
|
)
|
|
|
|
gameevent("PROCESSINPUT",
|
|
-- Input test.
|
|
-- NOTE: I don't think that exposing g_player[].sync (aka "input") is a good idea...
|
|
function(actori, playeri, dist)
|
|
local IB = player.INPUT_BITS
|
|
local input = player[playeri]._input
|
|
if (bit.band(input.bits, IB.JUMP) ~= 0) then
|
|
print("JUMPED")
|
|
-- ... because for example this doesn't work
|
|
-- (P_HandleSharedKeys, where the JETPACK bit is tested, runs
|
|
-- before P_ProcessInput):
|
|
input.bits = bit.bor(input.bits, IB.JETPACK)
|
|
end
|
|
end
|
|
)
|
|
|
|
-- test event chaining
|
|
gameevent("JUMP",
|
|
function(actori, playeri, dist)
|
|
local ps = player[playeri]
|
|
print("I'm first!")
|
|
-- DBG_.oom()
|
|
ps.weapon.PISTOL.shoots = 2605 -- RPG
|
|
ps.weapon[gv.PISTOL_WEAPON].firesound = 351 -- thunder
|
|
|
|
-- XXX: provide either named constants or methods?
|
|
ps.pipebombControl = 2
|
|
ps.tripbombControl = 2
|
|
|
|
-- Test of INTERNAL member _pals.
|
|
-- NOTE: setting colors partially is bad! E.g. after an item is
|
|
-- picked up, col[0] and col[1] remain and tint everything greenish.
|
|
ps._pals.col[2] = 20
|
|
ps._pals.f = 30
|
|
end
|
|
)
|
|
|
|
gameevent(gv.EVENT_ENTERLEVEL,
|
|
function()
|
|
if (gv._DEBUG_LUNATIC) then
|
|
DBG_.testmembread()
|
|
end
|
|
|
|
-- NOTE: times are for helixhorned (Core2Duo 3GHz)
|
|
local i
|
|
local N = 1e6
|
|
local t = gv.gethitickms()
|
|
|
|
for i=3,N do
|
|
gv.gethitickms()
|
|
end
|
|
|
|
t = gv.gethitickms()-t
|
|
|
|
-- x86_64: 35ns/call, x86: 280 ns/call
|
|
-- Windows 32-bit: about 1 us/call?
|
|
printf("%d gethitickms() calls took %.03f ms (%.03f us/call)",
|
|
N, t, (t*1000)/N)
|
|
|
|
local sum=0
|
|
t = gv.gethitickms()
|
|
for i=1,N do sum = sum+gv.ksqrt(i) end
|
|
t = gv.gethitickms()-t
|
|
-- x86_64: 14ns/call
|
|
printf("%d ksqrt() calls took %.03f ms (%.03f us/call) [sum=%f]",
|
|
N, t, (t*1000)/N, sum)
|
|
|
|
sum=0
|
|
t = gv.gethitickms()
|
|
for i=1,N do sum = sum+math.sqrt(i) end
|
|
t = gv.gethitickms()-t
|
|
-- x86_64: 7ns/call
|
|
printf("%d math.sqrt() calls took %.03f ms (%.03f us/call) [sum=%f]",
|
|
N, t, (t*1000)/N, sum)
|
|
|
|
printf("sqrt(0xffffffff) = %f(ksqrt) %f(math.sqrt)",
|
|
gv.ksqrt(0xffffffff), math.sqrt(0xffffffff))
|
|
|
|
local pl = player[0]
|
|
pl.max_ammo_amount[gv.RPG_WEAPON] = 17
|
|
pl:give_weapon(gv.RPG_WEAPON)
|
|
pl.ammo_amount[gv.RPG_WEAPON] = 54
|
|
|
|
-- MORTER2 from test/weaponvars.con
|
|
player[0].weapon.SHOTGUN.shoots = 1653
|
|
local proj = projectile[1653]
|
|
proj.drop = 0
|
|
proj:set_trail(2329) -- SMALLSMOKE
|
|
|
|
t = gv.gethitickms()
|
|
local N=1
|
|
for n=1,N do
|
|
for i=0,gv.MAXSPRITES-1 do
|
|
sprite[i].filler = 1
|
|
end
|
|
for i=gv.MAXSPRITES-1,0,-1 do
|
|
sprite[i].shade = 1
|
|
end
|
|
for i=0,gv.MAXSPRITES-1 do
|
|
sprite[i].xoffset = 0
|
|
end
|
|
for i=gv.MAXSPRITES-1,0,-1 do
|
|
sprite[i].yoffset = 1
|
|
end
|
|
end
|
|
t = gv.gethitickms()-t
|
|
printf("%d x four 0..MAXSPRITES-1 iterations took %.03f us per outer iteration", N, (1000*t)/N)
|
|
-- Results on x86:
|
|
-- N=1: 480-1000 us (too large variance)
|
|
-- N=10: 190-210 us * 10 = 1.9-2.1 ms
|
|
-- N=100: about 160 us * 100 = about 16 ms
|
|
|
|
-- Make the DUKECAR in E1L1 into a zombie actor (temporarily)
|
|
if (sprite[24].picnum==2491) then
|
|
sprite.changestat(24, gv.STAT_ZOMBIEACTOR)
|
|
end
|
|
|
|
checkfail("gameevent('GAME', function() print('qwe') end)",
|
|
"must be called from top level")
|
|
end
|
|
)
|
|
|
|
local geom = require "geom"
|
|
|
|
gameevent("LOADACTOR", function(i)
|
|
local spr = sprite[i]
|
|
if (i==614 and spr.picnum==930) then
|
|
-- "police line" ribbon in E1L1
|
|
-- clear the hitag so that it doesn't spawn as FALLER from premap
|
|
spr.hitag = 0
|
|
end
|
|
end)
|
|
|
|
gameactor(930, 1, function(i) -- "police line" ribbon
|
|
local spr = sprite[i]
|
|
local r = math.random
|
|
local d = 20
|
|
local v = geom.tovec3(spr) + geom.vec3(r(-d,d), r(-d,d))
|
|
spr:setpos(v)
|
|
end)
|
|
|
|
local stat = require("stat")
|
|
local hs = stat.new()
|
|
|
|
local con = require("con")
|
|
local AC, MV = con.AC, con.MV
|
|
con.action("TROOPSTAND",0,1,5,1,1)
|
|
con.action("TROOPFLINTCH", 50, 1, 1, 1, 6)
|
|
con.move("SHRUNKVELS", 32)
|
|
con.ai("AITEMP", AC.TROOPFLINTCH, MV.SHRUNKVELS, 0) -- TODO: test
|
|
-- This should work as well. In fact, it's exactly the same, but I prefer the
|
|
-- above version for clarity. NOTE: we'll need to think whether it's OK to
|
|
-- redefine composites (moves/actions/ais) during gameplay (probably not).
|
|
-- Or will we allow only one definition per label ever?
|
|
con.ai("AITEMP", "TROOPFLINTCH", "SHRUNKVELS", 0)
|
|
|
|
local TROOPSTRENGTH = 30
|
|
|
|
gameactor(1680, TROOPSTRENGTH, "TROOPSTAND", -- LIZTROOP
|
|
function(i, playeri, dist)
|
|
spriteext[i]:make_animated()
|
|
|
|
sprite[i].pal = math.random(32)
|
|
-- sprite[i].ang = bit.band(sprite[i].ang-20, 2047)
|
|
|
|
local spr = sprite[i]
|
|
|
|
local t = gv.gethitickms()
|
|
local hit = hitscan(spr, spr.sectnum, 10, 10, 0, gv.CLIPMASK0)
|
|
|
|
hs:add(1000*(gv.gethitickms()-t))
|
|
|
|
if (hs.n == 300) then
|
|
printf("hitscan: %s", hs:getstatstr())
|
|
hs:reset()
|
|
error("greetings from LIZTROOP actor")
|
|
end
|
|
|
|
if (dist < 4096) then
|
|
-- Duke Vader / Anakin Nukewalker?
|
|
actor[i]:set_action("TROOPFLINTCH")
|
|
actor[i]:set_move("SHRUNKVELS")
|
|
|
|
if (dist < 1024) then
|
|
con.killit()
|
|
end
|
|
end
|
|
end
|
|
)
|
|
|
|
gameevent("DISPLAYROOMS",
|
|
function()
|
|
local cam = gv.cam
|
|
cam.pos.z = cam.pos.z + 64*16*math.sin(gv.totalclock/30)
|
|
|
|
local ps = player[0]
|
|
if (ps.cursectnum >= 0) then
|
|
local hit = sector[ps.cursectnum]:zrangeat(cam.pos)
|
|
if (gv.totalclock%200==0) then
|
|
printf("hit %s %d at z=%d, %s %d at z=%d",
|
|
hit.c.spritep and "sprite" or "sector", hit.c.num, hit.c.z,
|
|
hit.f.spritep and "sprite" or "sector", hit.f.num, hit.f.z)
|
|
end
|
|
end
|
|
end
|
|
)
|
|
|
|
gameevent("DISPLAYREST", function()
|
|
for i=0,10 do
|
|
for j=1,100 do
|
|
con._gametext(2822, j, i, 12, 0, 0, 16, 0,0,gv.xdim,gv.ydim,8192)
|
|
end
|
|
end
|
|
end)
|
|
|
|
local CS = sprite.CSTAT
|
|
|
|
gameevent("ANIMATESPRITES",
|
|
function(aci)
|
|
local tspr = atsprite[aci]
|
|
if (tspr:getspr().picnum==1680) then
|
|
local tspr2 = tspr:dup()
|
|
if (tspr2) then
|
|
tspr2.x = tspr2.x + 512*math.cos(gv.totalclock/60)
|
|
tspr2.y = tspr2.y + 512*math.sin(gv.totalclock/60)
|
|
tspr2:set_cstat_bits(CS.TRANSLUCENT_BOTH_BITS)
|
|
end
|
|
end
|
|
end)
|
|
|
|
printf("EVENT_INIT = %d", gv.EVENT_INIT) -- tests default defines
|
|
|
|
local bittest = require "bittest"
|
|
bittest.sieve()
|
|
|
|
require("test/test_geom")
|
|
require("test/test_rotspr")
|
|
|
|
do
|
|
-- Test ksin vs. sinb
|
|
local xmath = require "xmath"
|
|
local sum = 0
|
|
|
|
local N = 1000
|
|
local t = gv.gethitickms()
|
|
for i=0,N*2048-1 do
|
|
sum = sum+xmath.ksin(i)
|
|
end
|
|
t = gv.gethitickms()-t
|
|
sum = sum*1e12
|
|
printf("ksin: sum*1e12=%.03f, %.03fus per 0-2047 cycle", sum, t)
|
|
|
|
sum = 0
|
|
local t = gv.gethitickms()
|
|
for i=0,N*2048-1 do
|
|
sum = sum+xmath.sinb(i)
|
|
end
|
|
t = gv.gethitickms()-t
|
|
sum = sum*1e12
|
|
printf("sinb: sum*1e12=%.03f, %.03fus per 0-2047 cycle", sum, t)
|
|
|
|
-- Results (helixhorned x86):
|
|
-- ksin: sum*1e12=0.000, 3.801us per 0-2047 cycle
|
|
-- sinb: sum*1e12=0.052, 2.886us per 0-2047 cycle
|
|
end
|
|
|
|
print('---=== END TEST SCRIPT ===---')
|
|
|
|
--[[
|
|
function check_sector_idx()
|
|
error("bla")
|
|
end
|
|
spritesofsect(0)
|
|
--]]
|
|
|
|
--DBG_.oom()
|
|
|
|
-- This will complain about wrong usage of 'error'. In particular,
|
|
-- the nil must not propagate to C!
|
|
error(nil)
|