Files
Viano-Core/tests/clientless/test_clientless_damage_notifications.py
T
Nico c0c799c4b6
GCC PCH / build (push) Canceled after 0s
clang PCH / build (push) Canceled after 0s
Add AdventureBot combat reactions, training and corpse recovery
2026-10-27 23:17:05 +01:00

45 lines
2.5 KiB
Python

"""Execute the production map-worker damage enqueue concurrently, without pointers."""
from pathlib import Path
import subprocess,tempfile
root=Path(__file__).resolve().parents[2]
s=(root/'src/server/game/World/ClientlessPlayerMgr.cpp').read_text()
a=s.index('void ClientlessPlayerMgr::DamageTaken(');b=s.index('{',a);e=b+1;depth=1
while depth:depth+=(s[e]=='{')-(s[e]=='}');e+=1
code=r'''
#include <cassert>
#include <deque>
#include <unordered_map>
#include <mutex>
#include <thread>
#include <vector>
using uint32=unsigned;
struct ObjectGuid{unsigned id;unsigned GetCounter(){return id;}};
struct Unit{ObjectGuid guid;ObjectGuid GetGUID(){return guid;}};
struct Session{bool clientless=true;bool IsClientless(){return clientless;}};
struct Player:Unit{Session session;Session* GetSession(){return &session;}};
struct ClientlessPlayerMgr{
struct DamageNotice{ObjectGuid Attacker;uint32 Damage;};
std::mutex _damageMutex;std::unordered_map<uint32,std::deque<DamageNotice>> _damageNotices;
void DamageTaken(Player*,Unit*,uint32);
};
'''+s[a:e]+r'''
int main(){
ClientlessPlayerMgr mgr;std::vector<Player> players(16);std::vector<std::thread> threads;
for(unsigned i=0;i<players.size();++i){players[i].guid={i+1};threads.emplace_back([&,i]{for(unsigned n=1;n<=1000;++n){Unit attacker{{n}};mgr.DamageTaken(&players[i],&attacker,n);}});}
for(auto& t:threads)t.join();
assert(mgr._damageNotices.size()==16);
for(unsigned i=1;i<=16;++i){auto const&q=mgr._damageNotices[i];assert(q.size()==1000);for(unsigned n=1;n<=1000;++n)assert(q[n-1].Attacker.id==n && q[n-1].Damage==n);}
Player ordinary;ordinary.guid={100};ordinary.session.clientless=false;Unit attacker{{100}};
mgr.DamageTaken(&ordinary,&attacker,100);assert(!mgr._damageNotices.count(100));
ordinary.session.clientless=true;mgr.DamageTaken(&ordinary,&attacker,0);mgr.DamageTaken(&ordinary,nullptr,100);assert(!mgr._damageNotices.count(100));
}
'''
with tempfile.TemporaryDirectory() as d:
p=Path(d);(p/'test.cpp').write_text(code)
subprocess.run(['g++','-std=c++17','-pthread',str(p/'test.cpp'),'-o',str(p/'test')],check=True)
subprocess.run([str(p/'test')],check=True)
unit=(root/'src/server/game/Entities/Unit/Unit.cpp').read_text();start=unit.index('uint32 Unit::DealDamage(')
hook=unit.index('sClientlessPlayerMgr->DamageTaken(',start)
assert unit.index('GetCommandStatus(CHEAT_GOD)',start)<unit.index('victim->ModifyHealth(-(int32)damage);',start)<hook
print('Production damage handoff: 16 concurrent map-worker writers, ordered GUID-only events, clientless-only/positive damage gates and post-health notification passed.')