Fix Deeprun Tram: visual movement, direction, and player riding

- Fix NULL renderer pointers by moving TransportManager connection after
  initializeRenderers for WMO-only maps
- Fix tram direction by negating DBC TransportAnimation X/Y local offsets
  before serverToCanonical conversion
- Implement client-side M2 transport boarding via proximity detection
  (server doesn't send transport attachment for trams)
- Use position-delta approach: player keeps normal movement while
  transport's frame-to-frame motion is applied on top
- Prevent server movement packets from clearing client-side M2 transport
  state (isClientM2Transport guard)
- Fix getPlayerWorldPosition for M2 transports: simple canonical addition
  instead of render-space matrix multiplication
This commit is contained in:
Kelsi 2026-03-06 23:01:11 -08:00
parent e001aaa2b6
commit f4c115ade9
5 changed files with 233 additions and 70 deletions

View file

@ -658,6 +658,9 @@ public:
playerTransportStickyTimer_ = 8.0f;
movementInfo.transportGuid = transportGuid;
}
void setPlayerTransportOffset(const glm::vec3& offset) {
playerTransportOffset_ = offset;
}
void clearPlayerTransport() {
if (playerTransportGuid_ != 0) {
playerTransportStickyGuid_ = playerTransportGuid_;

View file

@ -9,6 +9,7 @@
namespace wowee::rendering {
class WMORenderer;
class M2Renderer;
}
namespace wowee::pipeline {
@ -71,6 +72,7 @@ struct ActiveTransport {
float serverAngularVelocity;
bool hasServerVelocity;
bool allowBootstrapVelocity; // Disable DBC bootstrap when spawn/path mismatch is clearly invalid
bool isM2 = false; // True if rendered as M2 (not WMO), uses M2Renderer for transforms
};
class TransportManager {
@ -79,12 +81,14 @@ public:
~TransportManager();
void setWMORenderer(rendering::WMORenderer* renderer) { wmoRenderer_ = renderer; }
void setM2Renderer(rendering::M2Renderer* renderer) { m2Renderer_ = renderer; }
void update(float deltaTime);
void registerTransport(uint64_t guid, uint32_t wmoInstanceId, uint32_t pathId, const glm::vec3& spawnWorldPos, uint32_t entry = 0);
void unregisterTransport(uint64_t guid);
ActiveTransport* getTransport(uint64_t guid);
const std::unordered_map<uint64_t, ActiveTransport>& getTransports() const { return transports_; }
glm::vec3 getPlayerWorldPosition(uint64_t transportGuid, const glm::vec3& localOffset);
glm::mat4 getTransportInvTransform(uint64_t transportGuid);
@ -141,6 +145,7 @@ private:
std::unordered_map<uint32_t, TransportPath> paths_; // Indexed by transportEntry (pathId from TransportAnimation.dbc)
std::unordered_map<uint32_t, TransportPath> taxiPaths_; // Indexed by TaxiPath.dbc ID (world-coord paths for MO_TRANSPORT)
rendering::WMORenderer* wmoRenderer_ = nullptr;
rendering::M2Renderer* m2Renderer_ = nullptr;
bool clientSideAnimation_ = false; // DISABLED - use server positions instead of client prediction
float elapsedTime_ = 0.0f; // Total elapsed time (seconds)
};