142 lines
6.4 KiB
Python
142 lines
6.4 KiB
Python
"""Run with python3 after installing lupa; no live server or database involved."""
|
|
from pathlib import Path
|
|
from lupa import LuaRuntime
|
|
|
|
lua = LuaRuntime()
|
|
setup='''
|
|
rows={{10,"Dead",1,0,"dead",2},{11,"Zaku",1,1,"active",5},
|
|
{12,"Fresh",2,0,"reserve",2},{13,"Human",3,0,"active",1},
|
|
{14,"Wronglevel",2,0,"reserve",2}}
|
|
players={}; writes={}; removed={}; values={}; events={}; deaths=0
|
|
function player(guid,name,account,level,dead)
|
|
local p={guid=guid,name=name,account=account,level=level,dead=dead}
|
|
function p:GetGUIDLow() return self.guid end
|
|
function p:GetName() return self.name end
|
|
function p:GetAccountId() return self.account end
|
|
function p:GetLevel() return self.level end
|
|
function p:GetClass() return self.class or 1 end
|
|
function p:GetRace() return self.race or 2 end
|
|
function p:IsDead() return self.dead end
|
|
players[name]=p; return p
|
|
end
|
|
function AuthDBQuery(sql)
|
|
if string.find(sql,"azerothai_realm_rules",1,true) then return {GetUInt32=function()return mode or 1 end} end
|
|
if string.find(sql,'SELECT id FROM account',1,true) then
|
|
if string.find(sql,'id=99 ',1,true) then return nil end
|
|
return {GetUInt32=function() return 2 end}
|
|
end
|
|
if string.find(sql,"SELECT guid,name,account_id FROM azerothai_lifecycle WHERE state='dead'",1,true) then return nil end
|
|
local q={i=1}
|
|
function q:GetUInt32(n) return rows[self.i][n+1] end
|
|
function q:GetString(n) return rows[self.i][n+1] end
|
|
function q:NextRow() self.i=self.i+1;return self.i<=#rows end
|
|
return q
|
|
end
|
|
function CharDBQuery(sql) return {GetUInt32=function() return 0 end} end
|
|
function AuthDBExecute(sql) table.insert(writes,sql) end
|
|
mgr={}
|
|
function mgr:Remove(p) table.insert(removed,p.guid);players[p.name]=nil end
|
|
function mgr:SetValue(guid,key,value) values[guid..key]=value end
|
|
function mgr:GetValue(guid,key) return values[guid..key] or 0 end
|
|
function GetRandomPlayerbotMgr() return mgr end
|
|
function GetPlayerByName(name) return players[name] end
|
|
function GetPlayersInWorld() return players end
|
|
function RegisterPlayerEvent(id,fn) events[id]=fn end
|
|
function CreateLuaEvent(fn) tick=fn end
|
|
function PrintError(text) end
|
|
function PrintInfo(text) end
|
|
function AzerothAIEmitPermanentDeath(p) deaths=deaths+1 end
|
|
function AzerothAIEmitPlayerSnapshot(name) end
|
|
player(10,"Dead",1,80,false)
|
|
player(11,"Zaku",1,7,true)
|
|
player(12,"Fresh",2,1,false)
|
|
-- A mismatched account must never be managed, even if the GUID/name matches.
|
|
player(13,"Human",99,20,true)
|
|
player(14,"Wronglevel",2,55,false)
|
|
'''
|
|
lua.execute(setup)
|
|
lua.execute((Path(__file__).parents[1] / 'ale/azerothai_lifecycle.lua').read_text())
|
|
lua.execute('''
|
|
assert(#removed==1 and removed[1]==10)
|
|
assert(values['10logout']==1 and values['10add']==0)
|
|
assert(players.Zaku and players.Human)
|
|
assert(deaths==0)
|
|
tick();assert(not players.Wronglevel)
|
|
local fresh=players.Fresh
|
|
events[8](8,nil,fresh);events[8](8,nil,fresh);events[6](6,nil,fresh)
|
|
assert(deaths==1,'Repeated death events must be idempotent')
|
|
tick();assert(not players.Fresh and values['12logout']==1)
|
|
events[8](8,nil,players.Zaku);events[8](8,nil,players.Human)
|
|
assert(deaths==1 and players.Zaku and players.Human)
|
|
local before=#writes;tick();assert(#writes==before,'No per-second database churn')
|
|
-- A retired identity accidentally logged in again must be evicted.
|
|
player(10,'Dead',1,80,false);tick();assert(not players.Dead)
|
|
player(15,'Factorynew',2,1,false);tick();assert(players.Factorynew)
|
|
player(16,'Realhuman',99,1,true);tick();assert(players.Realhuman)
|
|
assert(deaths==1)
|
|
events[8](8,nil,players.Factorynew);tick();assert(not players.Factorynew)
|
|
assert(deaths==2)
|
|
local fast=player(17,'Fastlearner',2,1,false)
|
|
events[3](3,fast);fast.level=2;tick();assert(players.Fastlearner)
|
|
''')
|
|
balanced=LuaRuntime()
|
|
balanced.execute(setup)
|
|
balanced.execute('''
|
|
players={};rows={}
|
|
for i=1,25 do
|
|
rows[#rows+1]={100+i,'Horde'..i,2,0,'active',2}
|
|
player(100+i,'Horde'..i,2,5,false)
|
|
end
|
|
rows[#rows+1]={201,'Alliancefresh',2,0,'reserve',1}
|
|
rows[#rows+1]={202,'Hordefresh',2,0,'reserve',2}
|
|
player(201,'Alliancefresh',2,1,false)
|
|
player(202,'Hordefresh',2,1,false)
|
|
''')
|
|
balanced.execute((Path(__file__).parents[1] / 'ale/azerothai_lifecycle.lua').read_text())
|
|
balanced.execute('''
|
|
assert(players.Alliancefresh,'Underrepresented faction must fill its vacancy')
|
|
assert(not players.Hordefresh,'Do not exceed 25 members of a faction')
|
|
assert(values['202logout']==1)
|
|
assert(deaths==0,'Faction deferral is not a death')
|
|
''')
|
|
returning=LuaRuntime()
|
|
returning.execute(setup)
|
|
returning.execute("""
|
|
players={};rows={}
|
|
for i=1,26 do
|
|
rows[#rows+1]={100+i,'Horde'..i,2,0,'active',2}
|
|
player(100+i,'Horde'..i,2,5,false)
|
|
end
|
|
rows[#rows+1]={999,'Zaku',2,1,'active',2}
|
|
player(999,'Zaku',2,7,false)
|
|
""")
|
|
returning.execute((Path(__file__).parents[1] / 'ale/azerothai_lifecycle.lua').read_text())
|
|
returning.execute("""
|
|
local n=0;for _ in pairs(players) do n=n+1 end
|
|
assert(n==25 and players.Zaku,'Returning population must obey faction cap and protect Zaku')
|
|
assert(deaths==0,'Holding returning residents offline must not retire them')
|
|
assert(values['125logout']==1 and values['126logout']==1)
|
|
""")
|
|
dk=LuaRuntime()
|
|
dk.execute(setup)
|
|
dk.execute("""
|
|
players={};rows={{201,'AllianceDK',2,0,'reserve',1},{202,'HordeDK',2,0,'reserve',2}}
|
|
local a=player(201,'AllianceDK',2,55,false);a.class=6;a.race=1
|
|
local h=player(202,'HordeDK',2,55,false);h.class=6
|
|
""")
|
|
dk.execute((Path(__file__).parents[1] / 'ale/azerothai_lifecycle.lua').read_text())
|
|
dk.execute("""
|
|
assert(players.AllianceDK and players.HordeDK)
|
|
local entries=0
|
|
for _,q in pairs(writes) do if string.find(q,'entry_level=55',1,true) then entries=entries+1 end end
|
|
assert(entries==2,'Death Knights must be audited at level 55')
|
|
events[8](8,nil,players.HordeDK);tick();assert(not players.HordeDK and deaths==1)
|
|
""")
|
|
print('PASS: retirement, protection, level-1 entry, replay safety, and 25/25 faction balancing')
|
|
|
|
normal=LuaRuntime();normal.execute(setup)
|
|
normal.execute("mode=0;players={};rows={};for i=1,25 do rows[#rows+1]={100+i,'Resident'..i,2,0,'active',2};player(100+i,'Resident'..i,2,5,i==1) end;rows[#rows+1]={200,'Reserve',2,0,'reserve',2};player(200,'Reserve',2,1,false)")
|
|
normal.execute((Path(__file__).parents[1]/'ale/azerothai_lifecycle.lua').read_text())
|
|
normal.execute("events[8](8,nil,players.Resident1);tick();assert(players.Resident1 and deaths==0);assert(not players.Reserve,'Recoverable death must retain its population slot');local n=0;for _ in pairs(players)do n=n+1 end;assert(n==25)")
|
|
print('Normal resurrection mode preserves identity and reserves the dead resident population slot')
|