Files
Viano-Core/tests/clientless/test_group_flight_mount.py
T

80 lines
5.5 KiB
Python

"""Run native mount admission and stationary-flight publication adapters."""
from pathlib import Path
import subprocess
import tempfile
root=Path(__file__).resolve().parents[2]
s=(root/'src/server/game/World/ClientlessFlightMgr.cpp').read_text()
def method(sig):
a=s.index(sig);b=s.index('{',a);e=b+1;n=1
while n:
n+=(s[e]=='{')-(s[e]=='}');e+=1
return s[a:e]
code=r'''
#include <algorithm>
#include <cassert>
#include <vector>
using uint32=unsigned;using uint8=unsigned char;
constexpr int MAP_COMMON=0,UNIT_STATE_CASTING=1,MOUNT_CAPABILITY_FLAG_FLYING=1,SPELL_AURA_MOUNTED=1,SPELL_CAST_OK=0;
constexpr int MOVEMENTFLAG_FLYING=1,UNIT_FIELD_BYTES_1=1,UNIT_BYTES_1_OFFSET_ANIM_TIER=1,SMSG_MOVE_UPDATE=1;
enum class AnimTier:uint8{Ground=0,Fly=3};
struct Position{void Relocate(Position const&){}};
struct Map{struct Entry{int MapType=MAP_COMMON;}entry;Entry*GetEntry(){return &entry;}}map;
struct Guid{unsigned GetCounter(){return 49;}};
struct WorldPacket{explicit WorldPacket(int){}};
namespace GameTime{unsigned GetGameTimeMS(){return 100;}}
struct Player{
bool alive=true,combat=false,teleport=false,transport=false,taxi=false,falling=false,water=false,outdoors=true,mounted=true,fly=false,casting=false,learned=true;
unsigned flags=0,tier=0,stops=0,updates=0,animations=0,removals=0,casts=0;int castResult=SPELL_CAST_OK;
struct Capability{unsigned Flags=MOUNT_CAPABILITY_FLAG_FLYING;}capability;
struct{Guid guid;Position pos;unsigned time=0;}m_movementInfo;
bool IsAlive(){return alive;}bool IsInCombat(){return combat;}bool IsBeingTeleported(){return teleport;}bool GetTransport(){return transport;}bool IsInFlight(){return taxi;}
bool IsFalling(){return falling;}bool IsInWater(){return water;}bool IsOutdoors(){return outdoors;}Map*GetMap(){return &map;}bool IsMounted(){return mounted;}bool CanFly(){return fly;}
bool HasUnitState(int){return casting;}unsigned GetZoneId(){return 1519;}Guid GetGUID(){return {};}
bool HasSpell(unsigned){return learned;}Capability*GetMountCapability(unsigned){return &capability;}
void StopMoving(){++stops;}void RemoveAurasByType(int){++removals;mounted=false;}
int CastSpell(Player*,unsigned spell,bool triggered){assert(spell==123&&!triggered);++casts;return castResult;}
bool HasUnitMovementFlag(int flag){return flags&flag;}void AddUnitMovementFlag(int flag){flags|=flag;}
unsigned GetByteValue(int,int){return tier;}void SetAnimTier(AnimTier t){tier=unsigned(t);++animations;}
Position GetPosition(){return {};}void WriteMovementInfo(WorldPacket&){assert(flags&MOVEMENTFLAG_FLYING);}
void SendMessageToSet(WorldPacket*,bool){++updates;}
};
struct Battlefield{bool allowed=true;bool CanFlyIn(){return allowed;}}battle;
struct BattleMgr{Battlefield*GetBattlefieldToZoneId(Map*,unsigned){return &battle;}}battleMgr;auto sBattlefieldMgr=&battleMgr;
struct Profile{struct Mount{unsigned DisplayId,Weight;};std::vector<Mount>FlightMounts{{123,1}};}profile;
struct Lua{Profile*GetAdventureProfile(unsigned){return &profile;}void DismountGroundMount(Player*,char const*){}}lua;auto sClientlessLuaEngine=&lua;
struct Travel{unsigned cancels=0;void CancelTravel(unsigned){++cancels;}}travel;auto sClientlessTravelMgr=&travel;
struct SpellMgr{void*GetSpellInfo(unsigned){return nullptr;}}spells;auto sSpellMgr=&spells;
unsigned FlightType(void*){return 1;}unsigned urand(unsigned low,unsigned){return low;}
struct ClientlessFlightMgr{struct Record{bool Moving=false;};bool enabled=true;
bool Enabled(Player*){return enabled;}bool PrepareFollowingMount(Player*);void HoldFollowing(Player*,Record&);
};
'''+method('bool ClientlessFlightMgr::PrepareFollowingMount(')+method('void ClientlessFlightMgr::HoldFollowing(')+r'''
int main(){
ClientlessFlightMgr m;Player p;
assert(m.PrepareFollowingMount(&p)&&p.casts==1&&p.removals==1&&travel.cancels==1);
p.mounted=p.fly=true;assert(!m.PrepareFollowingMount(&p)&&p.casts==1); // retain native flight mount
p.fly=false;p.casting=true;assert(m.PrepareFollowingMount(&p)&&p.casts==1);p.casting=false;
p.combat=true;assert(!m.PrepareFollowingMount(&p));p.combat=false;
p.outdoors=false;assert(!m.PrepareFollowingMount(&p));p.outdoors=true;
p.transport=true;assert(!m.PrepareFollowingMount(&p));p.transport=false;
p.taxi=true;assert(!m.PrepareFollowingMount(&p));p.taxi=false;
p.falling=true;assert(!m.PrepareFollowingMount(&p));p.falling=false;
p.water=true;assert(!m.PrepareFollowingMount(&p));p.water=false;
battle.allowed=false;assert(!m.PrepareFollowingMount(&p));battle.allowed=true;
p.learned=false;assert(!m.PrepareFollowingMount(&p));p.learned=true;
p.capability.Flags=0;assert(!m.PrepareFollowingMount(&p));p.capability.Flags=1;
profile.FlightMounts[0].Weight=0;assert(!m.PrepareFollowingMount(&p));profile.FlightMounts[0].Weight=1;
p.castResult=1;assert(!m.PrepareFollowingMount(&p));
ClientlessFlightMgr::Record r;r.Moving=true;
auto stops=p.stops;m.HoldFollowing(&p,r);
assert(!r.Moving&&p.stops==stops+1&&p.flags==MOVEMENTFLAG_FLYING&&p.tier==unsigned(AnimTier::Fly)&&p.updates==1);
m.HoldFollowing(&p,r);assert(p.updates==1&&p.stops==stops+1&&p.animations==1); // no idle packet flood
p.tier=0;m.HoldFollowing(&p,r);assert(p.updates==2&&p.animations==2); // restore interrupted animation
}
'''
with tempfile.TemporaryDirectory() as d:
p=Path(d);(p/'test.cpp').write_text(code)
subprocess.run(['c++','-std=c++17',str(p/'test.cpp'),'-o',str(p/'test')],check=True)
subprocess.run([str(p/'test')],check=True)
print('Group flight mount: native admission, mount retention, casting wait, rejected capabilities, stationary flight animation and bounded publication passed')