Add native transport recording and execution with grid lifecycle handling, clientless teleport acknowledgements, and regression tests. Support targeted same-map portal imports and preserve disabled taxi nodes. Document live transport and portal verification and the remaining portal inventory.
84 lines
3.7 KiB
Python
84 lines
3.7 KiB
Python
"""Exercise the actual portal handler/ACK/destination checks with Core doubles."""
|
|
from pathlib import Path
|
|
import subprocess
|
|
import tempfile
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
source = (ROOT / "src/server/game/World/ClientlessActionExecutorMgr.cpp").read_text()
|
|
start = source.index(" WorldPacket areaTriggerPacket(CMSG_AREATRIGGER, 4);")
|
|
end = source.index(" record.Status.State = ClientlessActionExecutionState::Moving;", start)
|
|
fragment = source[start:end]
|
|
assert "same-map portal transition is not supported" not in source
|
|
|
|
harness = r'''
|
|
#include <cassert>
|
|
#include <cmath>
|
|
#include <string>
|
|
#define TC_LOG_WARN(...) ((void)0)
|
|
enum class ClientlessActionExecutionState { Idle, Failed, Moving };
|
|
constexpr int CMSG_AREATRIGGER=1;
|
|
struct WorldPacket { WorldPacket(int,int){} void operator<<(int){} };
|
|
struct Player;
|
|
struct Session {
|
|
Player* p;
|
|
int accepted=0,ackCount=0;
|
|
bool clientless=true,ackWorks=true;
|
|
void HandleAreaTriggerOpcode(WorldPacket&);
|
|
void CompleteClientlessTeleport();
|
|
bool IsClientless() { return clientless; }
|
|
};
|
|
struct Player {
|
|
int map=1; float x=8393,y=1003,z=30;
|
|
bool pending=false,world=true;
|
|
Session session{this};
|
|
bool IsBeingTeleported() { return pending; }
|
|
bool IsBeingTeleportedFar() { return pending&&map==0; }
|
|
bool IsInWorld() { return world; }
|
|
int GetMapId() { return map; }
|
|
float GetPositionX() { return x; } float GetPositionY() { return y; } float GetPositionZ() { return z; }
|
|
Session* GetSession() { return &session; }
|
|
};
|
|
struct Teleport { int target_mapId=1; float target_X=9946,target_Y=2612,target_Z=1316; } destination;
|
|
void Session::HandleAreaTriggerOpcode(WorldPacket&) { if (accepted) p->pending=true; }
|
|
void Session::CompleteClientlessTeleport() {
|
|
++ackCount;
|
|
if (!ackWorks) return;
|
|
p->pending=false;p->map=destination.target_mapId;
|
|
p->x=destination.target_X;p->y=destination.target_Y;p->z=destination.target_Z;
|
|
}
|
|
struct Record {
|
|
struct {ClientlessActionExecutionState State=ClientlessActionExecutionState::Idle; std::string Detail,TargetName;} Status;
|
|
bool Active=true;
|
|
} record;
|
|
struct {int EdgeDatabaseId=1;std::string NodeKey="portal_at_542_target";} step;
|
|
bool transfer(Player* player) {
|
|
int triggerId=542,characterGuid=26;
|
|
auto teleport=&destination;
|
|
'''
|
|
harness += fragment
|
|
harness += r'''
|
|
return true;
|
|
}
|
|
int main() {
|
|
Player denied;
|
|
assert(!transfer(&denied)&&!record.Active&&record.Status.State==ClientlessActionExecutionState::Failed);
|
|
Player near;near.session.accepted=1;record={};
|
|
assert(transfer(&near)&&near.session.ackCount==1&&near.map==1&&near.x==9946&&!near.pending);
|
|
Player far;far.map=0;far.session.accepted=1;record={};
|
|
assert(transfer(&far)&&far.session.ackCount==1&&far.map==1&&!far.pending);
|
|
Player pending;pending.session.accepted=1;pending.session.ackWorks=false;record={};
|
|
assert(!transfer(&pending)&&pending.pending&&!record.Active);
|
|
Player network;network.session.accepted=1;network.session.clientless=false;record={};
|
|
assert(!transfer(&network)&&!record.Active);
|
|
Player wrongMap;wrongMap.map=0;record={};assert(!transfer(&wrongMap));
|
|
Player alreadyAtTarget;alreadyAtTarget.x=destination.target_X;alreadyAtTarget.y=destination.target_Y;alreadyAtTarget.z=destination.target_Z;
|
|
record={};assert(transfer(&alreadyAtTarget)); // destination reached independently is valid
|
|
}
|
|
'''
|
|
with tempfile.TemporaryDirectory(prefix="vcore-portal-test-") as folder:
|
|
cpp, binary = Path(folder) / "test.cpp", Path(folder) / "test"
|
|
cpp.write_text(harness)
|
|
subprocess.run(["c++", "-std=c++17", str(cpp), "-o", str(binary)], check=True)
|
|
subprocess.run([str(binary)], check=True)
|
|
print("Portal near/far ACK and denied same-map transfer regressions passed.")
|