Files
shadow-over-bishkek001/src/Character.h
T

174 lines
8.3 KiB
C++

#pragma once
#include "CharacterState.h"
#include "BoneAnimatedModelNew.h"
#include "render/Renderer.h"
#include "render/TextureManager.h"
#include "SparkEmitter.h"
#include <functional>
#include <memory>
#include <map>
#include <string>
#include <cstdint>
#include <vector>
#include <unordered_map>
#include <utility>
#include <chrono>
#include "dialogue/TranslationDatabase.h"
#include "AudioPlayerAsync.h"
namespace FRG {
class TextRenderer;
class IGameServer;
class Character {
public:
Character(IGameServer& server, std::string locationId, std::string entityId)
: gameServer_(server), locationId_(std::move(locationId)),
entityId_(std::move(entityId)) {}
const std::string& entityId() const { return entityId_; }
void bindToLocation(std::string locationId) { locationId_ = std::move(locationId); }
// The aliasing shared_ptr keeps the owning GameSnapshot alive for as long
// as the returned CharacterState is being read.
std::shared_ptr<const CharacterState> stateSnapshot() const;
static constexpr float kAttackRange = 1.25f;
// ---- Asset loading ----
void loadAnimation(AnimationState animState, const std::string& filename, const std::string& zipFile = "");
void loadBinaryAnimation(AnimationState animState, const std::string& filename, const std::string& zipFile = "");
// Assigns a texture to a specific mesh by name.
void setTexture(const std::string& meshName, std::shared_ptr<Texture> texture);
// Assigns one texture to every mesh in every loaded animation. Call AFTER loading animations.
void setTexture(std::shared_ptr<FRG::Texture> texture);
// Creates a fully-loaded Character from a CharacterState (including its creationInfo).
// Loads all animations, textures, and weapon mesh/texture from the paths stored in creationInfo.
static std::unique_ptr<Character> createFromState(
const CharacterState& initialState, IGameServer& server,
const std::string& locationId, const std::string& entityId,
Renderer& renderer, const char* zipFile);
// ---- Per-frame update ----
// Applies authoritative animation state to runtime resources and consumes
// presentation-only events emitted by CharacterState::update.
void update(int64_t deltaMs, const CharacterUpdateEvents* events = nullptr);
// ---- Damage ----
void presentDamage(float hp, float maxHp, const Vec3fp& attackDirection,
const std::string& attackerId);
// ---- Spark setup ----
void setupHitSparks(std::shared_ptr<Texture> sparkTexture);
void prepareHitSparksForDraw(const Eigen::Matrix4f& cameraViewMatrix);
// ---- HUD overlays ----
void drawName(TextRenderer& textRenderer,
const Eigen::Matrix4f& cameraViewMatrix,
const Eigen::Matrix4f& projectionMatrix);
void drawPlayerName(TextRenderer& textRenderer,
const Eigen::Matrix4f& cameraViewMatrix,
const Eigen::Matrix4f& projectionMatrix,
const std::string& displayName);
void drawHealthBar(Renderer& renderer,
const Eigen::Matrix4f& cameraViewMatrix,
const Eigen::Matrix4f& projectionMatrix);
// ---- Draw passes ----
void draw(Renderer& renderer);
void drawShadowDepth(Renderer& renderer);
void drawWithShadow(Renderer& renderer, const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const Eigen::Vector3f& lightDirCamera);
void drawNight(Renderer& renderer,
const float* pointLightPosEye, const float* pointLightDirEye,
const float* pointLightColors, int pointLightCount,
const float* pointLightWorldXZ, const float* pointLightLimitXZ,
const Eigen::Matrix4f& cameraViewInverse,
const float* ambientColor, const float* fogColor);
void drawNightWithShadow(Renderer& renderer,
const float* plPosEye, const float* plDirEye, const float* plColors, int plCount,
const float* plWorldXZ, const float* plLimitXZ,
const Eigen::Matrix4f& cameraViewInverse,
const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex,
const float* ambientColor, const float* fogColor);
// ---- Query helpers (read immutable snapshots) ----
bool isMoving() const;
Eigen::Vector3f renderPosition() const;
float getHp() const;
// ---- Weapon rendering data (initialized from state.creationInfo by createFromState) ----
VertexRenderStruct weaponMesh;
std::shared_ptr<Texture> weaponTexture;
Eigen::Matrix3f weaponInitialRotation = Eigen::Matrix3f::Identity();
Eigen::Vector3f weaponInitialPosition = Eigen::Vector3f::Zero();
std::string weaponAttachBoneName = "RightHand";
SparkEmitter hitSparkEmitter;
AudioPlayerAsync* audioPlayer = nullptr;
static Dialogue::TranslationDatabase nameTranslations;
private:
friend class Game;
friend class Location;
friend class ScriptEngine;
friend class LocationEditor;
friend class PathVisualization;
IGameServer& gameServer_;
std::string locationId_;
std::string entityId_;
std::function<void()> onDeathAnimComplete;
std::function<void(float, float, const std::string&)> onHpChanged;
std::map<AnimationState, BoneAnimationDataNew> animations;
VertexRenderStruct modelMutable;
VertexRenderStruct healthBarMesh;
std::unordered_map<std::string, std::shared_ptr<Texture>> meshTextures;
struct PresentationSample {
Eigen::Vector3f position = Eigen::Vector3f::Zero();
float facingAngle = 0.0f;
float animationFrame = 0.0f;
AnimationState currentState = AnimationState::STAND;
bool enabled = true;
};
PresentationSample previousPresentationSample_;
PresentationSample currentPresentationSample_;
std::chrono::steady_clock::time_point lastPresentationUpdate_;
bool hasPresentationSample_ = false;
AnimationState resolveActiveState(const CharacterState& state) const;
CharacterState interpolatedState(const CharacterState& state) const;
void updateAnimationForRender(const CharacterState& state);
bool prepareGpuSkinning(const CharacterState& state);
void drawAttachedWeapon(Renderer& renderer, const CharacterState& state);
void drawGpuSkinning(Renderer& renderer, const CharacterState& state);
void drawShadowDepthGpuSkinning(Renderer& renderer, const CharacterState& state);
void drawShadowDepthCpu(Renderer& renderer, const CharacterState& state);
void drawGpuSkinningWithShadow(Renderer& renderer, const CharacterState& state, const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const Eigen::Vector3f& lightDirCamera);
void drawCpuWithShadow(Renderer& renderer, const CharacterState& state, const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const Eigen::Vector3f& lightDirCamera);
void drawNightGpuSkinning(Renderer& renderer,
const CharacterState& state,
const float* plPosEye, const float* plDirEye, const float* plColors, int plCount,
const float* plWorldXZ, const float* plLimitXZ, const Eigen::Matrix4f& cameraViewInverse,
const float* ambientColor, const float* fogColor);
void drawNightCpu(Renderer& renderer,
const CharacterState& state,
const float* plPosEye, const float* plDirEye, const float* plColors, int plCount,
const float* plWorldXZ, const float* plLimitXZ, const Eigen::Matrix4f& cameraViewInverse,
const float* ambientColor, const float* fogColor);
void drawNightGpuSkinningWithShadow(Renderer& renderer,
const CharacterState& state,
const float* plPosEye, const float* plDirEye, const float* plColors, int plCount,
const float* plWorldXZ, const float* plLimitXZ, const Eigen::Matrix4f& cameraViewInverse,
const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const float* ambientColor, const float* fogColor);
void drawNightCpuWithShadow(Renderer& renderer,
const CharacterState& state,
const float* plPosEye, const float* plDirEye, const float* plColors, int plCount,
const float* plWorldXZ, const float* plLimitXZ, const Eigen::Matrix4f& cameraViewInverse,
const Eigen::Matrix4f& lightFromCamera, GLuint shadowMapTex, const float* ambientColor, const float* fogColor);
};
} // namespace FRG