mirror of
https://github.com/isledecomp/isle-portable.git
synced 2026-05-02 02:23:56 +00:00
- Move TickHostSessions outside m_inIsleWorld gate so the host can coordinate animations from any world - Load animation catalog early in HandleCreate so the host can coordinate before entering the ISLE world - Use network-reported positions for remote player location detection instead of requiring spawned ROIs - Always erase sessions at launch — the host's job ends when the animation starts; clients play and complete independently - Replace BroadcastAnimComplete with locally-driven completion callbacks: host generates eventId at launch, clients cache completion JSON at start time, fire it when ScenePlayer finishes - Make StopAnimation only do local cleanup (stop playback, cancel own interest, reset coordinator) without destroying the session host, so other players' sessions survive world transitions - Broadcast state=0 in ResetAnimationState for full teardown paths (shutdown, reconnect, host migration) so clients aren't left with stale session state
81 lines
2.4 KiB
C++
81 lines
2.4 KiB
C++
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <map>
|
|
#include <vector>
|
|
|
|
namespace Multiplayer::Animation
|
|
{
|
|
|
|
class Catalog;
|
|
struct CatalogEntry;
|
|
enum class CoordinationState : uint8_t;
|
|
|
|
struct SessionSlot {
|
|
uint32_t peerId; // 0 = unfilled
|
|
int8_t charIndex; // g_actorInfoInit index, or -1 for spectator
|
|
|
|
bool IsSpectator() const { return IsSpectatorCharIndex(charIndex); }
|
|
static bool IsSpectatorCharIndex(int8_t p_charIndex) { return p_charIndex < 0; }
|
|
};
|
|
|
|
struct AnimSession {
|
|
uint16_t animIndex;
|
|
CoordinationState state;
|
|
std::vector<SessionSlot> slots;
|
|
uint32_t countdownEndTime; // SDL_GetTicks timestamp when countdown expires
|
|
};
|
|
|
|
class SessionHost {
|
|
public:
|
|
void SetCatalog(const Catalog* p_catalog);
|
|
|
|
bool HandleInterest(
|
|
uint32_t p_peerId,
|
|
uint16_t p_animIndex,
|
|
uint8_t p_displayActorIndex,
|
|
std::vector<uint16_t>& p_changedAnims
|
|
);
|
|
bool HandleCancel(uint32_t p_peerId, std::vector<uint16_t>& p_changedAnims);
|
|
bool HandlePlayerRemoved(uint32_t p_peerId, std::vector<uint16_t>& p_changedAnims);
|
|
|
|
// Returns animIndices of all sessions ready to play
|
|
std::vector<uint16_t> Tick(uint32_t p_now);
|
|
|
|
void StartCountdown(uint16_t p_animIndex);
|
|
void RevertCountdown(uint16_t p_animIndex);
|
|
|
|
void Reset();
|
|
void EraseSession(uint16_t p_animIndex);
|
|
|
|
const AnimSession* FindSession(uint16_t p_animIndex) const;
|
|
const std::map<uint16_t, AnimSession>& GetSessions() const;
|
|
bool AreAllSlotsFilled(uint16_t p_animIndex) const;
|
|
|
|
static uint16_t ComputeCountdownMs(const AnimSession& p_session, uint32_t p_now);
|
|
|
|
// Reconstruct slot charIndex assignments from CatalogEntry::performerMask.
|
|
// Same iteration order as CreateSession — deterministic across all clients.
|
|
static std::vector<int8_t> ComputeSlotCharIndices(const CatalogEntry* p_entry);
|
|
|
|
bool HasCountdownSession() const;
|
|
|
|
private:
|
|
AnimSession CreateSession(const CatalogEntry* p_entry, uint16_t p_animIndex);
|
|
bool TryAssignSlot(AnimSession& p_session, uint32_t p_peerId, int8_t p_charIndex);
|
|
bool AllSlotsFilled(const AnimSession& p_session) const;
|
|
void RemovePlayerFromAllSessions(uint32_t p_peerId, std::vector<uint16_t>& p_changedAnims);
|
|
void RemovePlayerFromSessions(
|
|
uint32_t p_peerId,
|
|
bool p_includePlayingSessions,
|
|
std::vector<uint16_t>& p_changedAnims
|
|
);
|
|
|
|
const Catalog* m_catalog = nullptr;
|
|
std::map<uint16_t, AnimSession> m_sessions;
|
|
|
|
static const uint32_t COUNTDOWN_DURATION_MS = 4000;
|
|
};
|
|
|
|
} // namespace Multiplayer::Animation
|