45 lines
2.5 KiB
Python
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.')
|