80 lines
5.5 KiB
Python
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 ↦}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')
|