mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-23 07:40:14 +00:00
Add property-based mount animation discovery and procedural lean
Mount Animation System: - Property-based jump animation discovery using sequence metadata - Chain linkage scoring (nextAnimation/aliasNext) for accurate detection - Correct loop detection: flags & 0x01 == 0 means looping - Avoids brake/stop animations via blendTime penalties - Works on any mount model without hardcoded animation IDs Mount Physics: - Physics-based jump height: vz = sqrt(2 * g * h) - Configurable MOUNT_JUMP_HEIGHT constant (1.0m default) - Procedural lean into turns for ground mounts - Smooth roll based on turn rate (±14° max, 6x/sec blend) Audio Improvements: - State-machine driven mount sounds (jump, land, rear-up) - Semantic sound methods (no animation ID dependencies) - Debug logging for missing sound files Bug Fixes: - Fixed mount animation sequencing (JumpStart → JumpLoop → JumpEnd) - Fixed animation loop flag interpretation (0x20 vs 0x21) - Rider bone attachment working correctly during all mount actions
This commit is contained in:
parent
3c783d1845
commit
c623fcef51
16 changed files with 1083 additions and 145 deletions
|
|
@ -67,6 +67,7 @@ public:
|
|||
bool isGrounded() const { return grounded; }
|
||||
bool isJumping() const { return !grounded && verticalVelocity > 0.0f; }
|
||||
bool isFalling() const { return !grounded && verticalVelocity <= 0.0f; }
|
||||
bool isJumpKeyPressed() const { return jumpBufferTimer > 0.0f; }
|
||||
bool isSprinting() const;
|
||||
bool isMovingForward() const { return moveForwardActive; }
|
||||
bool isMovingBackward() const { return moveBackwardActive; }
|
||||
|
|
@ -92,6 +93,9 @@ public:
|
|||
void setFacingYaw(float yaw) { facingYaw = yaw; } // For taxi/scripted movement
|
||||
void clearMovementInputs();
|
||||
|
||||
// Trigger mount jump (applies vertical velocity for physics hop)
|
||||
void triggerMountJump();
|
||||
|
||||
// For first-person player hiding
|
||||
void setCharacterRenderer(class CharacterRenderer* cr, uint32_t playerId) {
|
||||
characterRenderer = cr;
|
||||
|
|
@ -168,6 +172,16 @@ private:
|
|||
std::optional<float> cachedCamWmoFloor;
|
||||
bool hasCachedCamFloor = false;
|
||||
|
||||
// Cached floor height queries (update every 5 frames or 2 unit movement)
|
||||
glm::vec3 lastFloorQueryPos = glm::vec3(0.0f);
|
||||
std::optional<float> cachedFloorHeight;
|
||||
int floorQueryFrameCounter = 0;
|
||||
static constexpr float FLOOR_QUERY_DISTANCE_THRESHOLD = 2.0f; // Increased from 1.0
|
||||
static constexpr int FLOOR_QUERY_FRAME_INTERVAL = 5; // Increased from 3
|
||||
|
||||
// Helper to get cached floor height (reduces expensive queries)
|
||||
std::optional<float> getCachedFloorHeight(float x, float y, float z);
|
||||
|
||||
// Swimming
|
||||
bool swimming = false;
|
||||
bool wasSwimming = false;
|
||||
|
|
@ -212,6 +226,13 @@ private:
|
|||
static constexpr float WOW_TURN_SPEED = 180.0f; // Keyboard turn deg/sec
|
||||
static constexpr float WOW_GRAVITY = -19.29f;
|
||||
static constexpr float WOW_JUMP_VELOCITY = 7.96f;
|
||||
static constexpr float MOUNT_GRAVITY = -18.0f; // Snappy WoW-feel jump
|
||||
static constexpr float MOUNT_JUMP_HEIGHT = 1.0f; // Desired jump height in meters
|
||||
|
||||
// Computed jump velocity using vz = sqrt(2 * g * h)
|
||||
static inline float getMountJumpVelocity() {
|
||||
return std::sqrt(2.0f * std::abs(MOUNT_GRAVITY) * MOUNT_JUMP_HEIGHT);
|
||||
}
|
||||
|
||||
// Server-driven run speed override (0 = use default WOW_RUN_SPEED)
|
||||
float runSpeedOverride_ = 0.0f;
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ public:
|
|||
|
||||
void playAnimation(uint32_t instanceId, uint32_t animationId, bool loop = true);
|
||||
|
||||
void update(float deltaTime);
|
||||
void update(float deltaTime, const glm::vec3& cameraPos = glm::vec3(0.0f));
|
||||
|
||||
void render(const Camera& camera, const glm::mat4& view, const glm::mat4& projection);
|
||||
void renderShadow(const glm::mat4& lightSpaceMatrix);
|
||||
|
|
@ -74,6 +74,9 @@ public:
|
|||
bool getInstanceModelName(uint32_t instanceId, std::string& modelName) const;
|
||||
bool getInstanceBounds(uint32_t instanceId, glm::vec3& outCenter, float& outRadius) const;
|
||||
|
||||
/** Debug: Log all available animations for an instance */
|
||||
void dumpAnimations(uint32_t instanceId) const;
|
||||
|
||||
/** Attach a weapon model to a character instance at the given attachment point. */
|
||||
bool attachWeapon(uint32_t charInstanceId, uint32_t attachmentId,
|
||||
const pipeline::M2Model& weaponModel, uint32_t weaponModelId,
|
||||
|
|
@ -82,6 +85,15 @@ public:
|
|||
/** Detach a weapon from the given attachment point. */
|
||||
void detachWeapon(uint32_t charInstanceId, uint32_t attachmentId);
|
||||
|
||||
/** Get the world-space transform of an attachment point on an instance.
|
||||
* Used for mount seats, weapon positions, etc.
|
||||
* @param instanceId The character/mount instance
|
||||
* @param attachmentId The attachment point ID (0=Mount, 1=RightHand, 2=LeftHand, etc.)
|
||||
* @param outTransform The resulting world-space transform matrix
|
||||
* @return true if attachment found and matrix computed
|
||||
*/
|
||||
bool getAttachmentTransform(uint32_t instanceId, uint32_t attachmentId, glm::mat4& outTransform);
|
||||
|
||||
size_t getInstanceCount() const { return instances.size(); }
|
||||
|
||||
void setFog(const glm::vec3& color, float start, float end) {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace wowee {
|
||||
namespace core { class Window; }
|
||||
namespace game { class World; class ZoneManager; }
|
||||
namespace game { class World; class ZoneManager; class GameHandler; }
|
||||
namespace audio { class MusicManager; class FootstepManager; class ActivitySoundManager; class MountSoundManager; class NpcVoiceManager; class AmbientSoundManager; class UiSoundManager; class CombatSoundManager; class SpellSoundManager; class MovementSoundManager; enum class FootstepSurface : uint8_t; enum class VoiceType; }
|
||||
namespace pipeline { class AssetManager; }
|
||||
|
||||
|
|
@ -27,6 +27,7 @@ class Clouds;
|
|||
class LensFlare;
|
||||
class Weather;
|
||||
class LightingManager;
|
||||
class SkySystem;
|
||||
class SwimEffects;
|
||||
class MountDust;
|
||||
class CharacterRenderer;
|
||||
|
|
@ -47,7 +48,7 @@ public:
|
|||
void beginFrame();
|
||||
void endFrame();
|
||||
|
||||
void renderWorld(game::World* world);
|
||||
void renderWorld(game::World* world, game::GameHandler* gameHandler = nullptr);
|
||||
|
||||
/**
|
||||
* Update renderer (camera, etc.)
|
||||
|
|
@ -108,6 +109,7 @@ public:
|
|||
M2Renderer* getM2Renderer() const { return m2Renderer.get(); }
|
||||
Minimap* getMinimap() const { return minimap.get(); }
|
||||
QuestMarkerRenderer* getQuestMarkerRenderer() const { return questMarkerRenderer.get(); }
|
||||
SkySystem* getSkySystem() const { return skySystem.get(); }
|
||||
const std::string& getCurrentZoneName() const { return currentZoneName; }
|
||||
|
||||
// Third-person character follow
|
||||
|
|
@ -176,6 +178,7 @@ private:
|
|||
std::unique_ptr<LensFlare> lensFlare;
|
||||
std::unique_ptr<Weather> weather;
|
||||
std::unique_ptr<LightingManager> lightingManager;
|
||||
std::unique_ptr<SkySystem> skySystem; // Coordinator for sky rendering
|
||||
std::unique_ptr<SwimEffects> swimEffects;
|
||||
std::unique_ptr<MountDust> mountDust;
|
||||
std::unique_ptr<CharacterRenderer> characterRenderer;
|
||||
|
|
@ -302,10 +305,27 @@ private:
|
|||
uint32_t equippedWeaponInvType_ = 0;
|
||||
|
||||
// Mount state
|
||||
// Mount animation capabilities (discovered at mount time, varies per model)
|
||||
struct MountAnimSet {
|
||||
uint32_t jumpStart = 0; // Jump start animation
|
||||
uint32_t jumpLoop = 0; // Jump airborne loop
|
||||
uint32_t jumpEnd = 0; // Jump landing
|
||||
uint32_t rearUp = 0; // Rear-up / special flourish
|
||||
uint32_t run = 0; // Run animation (discovered, don't assume)
|
||||
uint32_t stand = 0; // Stand animation (discovered)
|
||||
};
|
||||
|
||||
enum class MountAction { None, Jump, RearUp };
|
||||
|
||||
uint32_t mountInstanceId_ = 0;
|
||||
float mountHeightOffset_ = 0.0f;
|
||||
float mountPitch_ = 0.0f; // Up/down tilt (radians)
|
||||
float mountRoll_ = 0.0f; // Left/right banking (radians)
|
||||
float prevMountYaw_ = 0.0f; // Previous yaw for turn rate calculation (procedural lean)
|
||||
float lastDeltaTime_ = 0.0f; // Cached for use in updateCharacterAnimation()
|
||||
MountAction mountAction_ = MountAction::None; // Current mount action (jump/rear-up)
|
||||
uint32_t mountActionPhase_ = 0; // 0=start, 1=loop, 2=end (for jump chaining)
|
||||
MountAnimSet mountAnims_; // Cached animation IDs for current mount
|
||||
bool taxiFlight_ = false;
|
||||
|
||||
bool terrainEnabled = true;
|
||||
|
|
|
|||
|
|
@ -282,8 +282,8 @@ private:
|
|||
|
||||
// Streaming parameters
|
||||
bool streamingEnabled = true;
|
||||
int loadRadius = 8; // Load tiles within this radius (17x17 grid)
|
||||
int unloadRadius = 12; // Unload tiles beyond this radius
|
||||
int loadRadius = 4; // Load tiles within this radius (9x9 grid = 81 tiles)
|
||||
int unloadRadius = 7; // Unload tiles beyond this radius
|
||||
float updateInterval = 0.033f; // Check streaming every 33ms (~30 fps)
|
||||
float timeSinceLastUpdate = 0.0f;
|
||||
|
||||
|
|
@ -326,6 +326,17 @@ private:
|
|||
|
||||
// Dedup set for WMO placements across tile boundaries (prevents rendering Stormwind 16x)
|
||||
std::unordered_set<uint32_t> placedWmoIds;
|
||||
|
||||
// Progressive M2 upload queue (spread heavy uploads across frames)
|
||||
struct PendingM2Upload {
|
||||
uint32_t modelId;
|
||||
pipeline::M2Model model;
|
||||
std::string path;
|
||||
};
|
||||
std::queue<PendingM2Upload> m2UploadQueue_;
|
||||
static constexpr int MAX_M2_UPLOADS_PER_FRAME = 5; // Upload up to 5 models per frame
|
||||
|
||||
void processM2UploadQueue();
|
||||
};
|
||||
|
||||
} // namespace rendering
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue