Add transport registration to movement packets (WIP - awaiting server MOVEMENT updates)

- Added transport fields to MovementInfo struct (transportGuid, transportX/Y/Z/O, transportTime)
- Updated MovementPacket::build() to serialize transport data when ONTRANSPORT flag set
- Modified GameHandler::sendMovement() to include transport info when player on transport
- Fixed coordinate conversion for transport offsets (server↔canonical)
- Added transport tracking in both CREATE_OBJECT and MOVEMENT update handlers
- Connected M2Renderer to WMORenderer for hierarchical doodad transforms
- Server-authoritative transport movement (no client-side animation)

Issue: Server not sending MOVEMENT updates for transports, so they remain stationary.
Transports register successfully but don't animate without server position updates.
This commit is contained in:
Kelsi 2026-02-11 02:23:37 -08:00
parent f3f3b62880
commit 55a40fc3aa
8 changed files with 425 additions and 60 deletions

View file

@ -903,16 +903,10 @@ void Application::setupUICallbacks() {
// Register the transport with spawn position (prevents rendering at origin until server update)
transportManager->registerTransport(guid, wmoInstanceId, pathId, canonicalSpawnPos);
if (clientAnim) {
LOG_INFO("Transport registered - client-side animation enabled");
} else {
// Only call updateServerTransport if client animation is disabled
// This sets the exact spawn position for server-controlled transports
// Coordinates are already canonical (converted in game_handler.cpp)
glm::vec3 canonicalPos(x, y, z);
transportManager->updateServerTransport(guid, canonicalPos, orientation);
LOG_INFO("Transport registered - server-controlled movement");
}
// Server-authoritative movement - set initial position from spawn data
glm::vec3 canonicalPos(x, y, z);
transportManager->updateServerTransport(guid, canonicalPos, orientation);
LOG_INFO("Transport registered - server-authoritative movement");
});
// Transport move callback (online mode) - update transport gameobject positions
@ -1792,6 +1786,12 @@ void Application::loadOnlineWorldTerrain(uint32_t mapId, float x, float y, float
LOG_INFO("TransportManager connected to WMORenderer for online mode");
}
// Connect WMORenderer to M2Renderer (for hierarchical transforms: doodads following WMO parents)
if (renderer->getWMORenderer() && renderer->getM2Renderer()) {
renderer->getWMORenderer()->setM2Renderer(renderer->getM2Renderer());
LOG_INFO("WMORenderer connected to M2Renderer for hierarchical doodad transforms");
}
showProgress("Loading character model...", 0.05f);
// Build faction hostility map for this character's race
@ -2870,6 +2870,65 @@ void Application::spawnOnlineGameObject(uint64_t guid, uint32_t entry, uint32_t
LOG_INFO("Spawned gameobject WMO: guid=0x", std::hex, guid, std::dec,
" displayId=", displayId, " at (", x, ", ", y, ", ", z, ")");
// Spawn WMO doodads (chairs, furniture, etc.) as child M2 instances
// TODO: Re-enable after implementing deferred/background loading
// Currently disabled - spawning 134 doodads synchronously causes massive slowdown
bool isTransport = false;
if (gameHandler) {
std::string lowerModelPath = modelPath;
std::transform(lowerModelPath.begin(), lowerModelPath.end(), lowerModelPath.begin(),
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
isTransport = (lowerModelPath.find("transport") != std::string::npos);
}
auto* m2Renderer = renderer->getM2Renderer();
if (false && m2Renderer && isTransport) { // DISABLED - too slow
const auto* doodadTemplates = wmoRenderer->getDoodadTemplates(modelId);
if (doodadTemplates && !doodadTemplates->empty()) {
LOG_INFO("Spawning ", doodadTemplates->size(), " doodads for transport WMO instance ", instanceId);
int spawnedDoodads = 0;
for (const auto& doodadTemplate : *doodadTemplates) {
// Load M2 model (may be cached)
uint32_t doodadModelId = static_cast<uint32_t>(std::hash<std::string>{}(doodadTemplate.m2Path));
auto m2Data = assetManager->readFile(doodadTemplate.m2Path);
if (m2Data.empty()) continue;
pipeline::M2Model m2Model = pipeline::M2Loader::load(m2Data);
std::string skinPath = doodadTemplate.m2Path.substr(0, doodadTemplate.m2Path.size() - 3) + "00.skin";
std::vector<uint8_t> skinData = assetManager->readFile(skinPath);
if (!skinData.empty()) {
pipeline::M2Loader::loadSkin(skinData, m2Model);
}
if (!m2Model.isValid()) continue;
// Load model to renderer (cached if already loaded)
m2Renderer->loadModel(m2Model, doodadModelId);
// Create M2 instance at world origin (transform will be updated by WMO parent)
uint32_t m2InstanceId = m2Renderer->createInstance(doodadModelId, glm::vec3(0.0f), glm::vec3(0.0f), 1.0f);
if (m2InstanceId == 0) continue;
// Link doodad to WMO instance
wmoRenderer->addDoodadToInstance(instanceId, m2InstanceId, doodadTemplate.localTransform);
spawnedDoodads++;
}
if (spawnedDoodads > 0) {
LOG_INFO("Spawned ", spawnedDoodads, " doodads for transport WMO instance ", instanceId);
// Initial transform update to position doodads correctly
// (subsequent updates will happen automatically via setInstanceTransform)
glm::mat4 wmoTransform(1.0f);
wmoTransform = glm::translate(wmoTransform, renderPos);
wmoTransform = glm::rotate(wmoTransform, renderYaw, glm::vec3(0, 0, 1));
wmoRenderer->setInstanceTransform(instanceId, wmoTransform);
}
} else {
LOG_INFO("Transport WMO has no doodads or templates not available");
}
}
// Check if this is a transport and notify via special method
if (gameHandler) {
std::string lowerModelPath = modelPath;
@ -3285,6 +3344,12 @@ void Application::setupTestTransport() {
// Connect transport manager to WMO renderer
transportManager->setWMORenderer(wmoRenderer);
// Connect WMORenderer to M2Renderer (for hierarchical transforms: doodads following WMO parents)
if (renderer->getM2Renderer()) {
wmoRenderer->setM2Renderer(renderer->getM2Renderer());
LOG_INFO("WMORenderer connected to M2Renderer for test transport doodad transforms");
}
// Define a simple circular path around Stormwind harbor (canonical coordinates)
// These coordinates are approximate - adjust based on actual harbor layout
std::vector<glm::vec3> harborPath = {