mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-05-01 16:37:45 +00:00
wip: refactor encounter timeline stuff to only modify state objects, cache should now work as intended
- tldr: fast as fuck boi
This commit is contained in:
parent
025f57ce9b
commit
43f9254086
2 changed files with 153 additions and 96 deletions
|
@ -9,7 +9,7 @@
|
|||
|
||||
namespace Sapphire
|
||||
{
|
||||
bool EncounterTimeline::ConditionHp::isConditionMet( InstanceContentPtr pInstance, uint64_t time )
|
||||
bool EncounterTimeline::ConditionHp::isConditionMet( ConditionState& state, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const
|
||||
{
|
||||
auto pBNpc = pInstance->getActiveBNpcByLayoutId( layoutId );
|
||||
if( !pBNpc )
|
||||
|
@ -30,7 +30,7 @@ namespace Sapphire
|
|||
return false;
|
||||
};
|
||||
|
||||
bool EncounterTimeline::ConditionDirectorVar::isConditionMet( InstanceContentPtr pInstance, uint64_t time )
|
||||
bool EncounterTimeline::ConditionDirectorVar::isConditionMet( ConditionState& state, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const
|
||||
{
|
||||
// todo: use something other than InstanceContentPtr
|
||||
if( !pInstance )
|
||||
|
@ -54,7 +54,7 @@ namespace Sapphire
|
|||
return false;
|
||||
}
|
||||
|
||||
bool EncounterTimeline::ConditionCombatState::isConditionMet( InstanceContentPtr pInstance, uint64_t time )
|
||||
bool EncounterTimeline::ConditionCombatState::isConditionMet( ConditionState& state, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const
|
||||
{
|
||||
auto pBattleNpc = pInstance->getActiveBNpcByLayoutId( this->layoutId );
|
||||
|
||||
|
@ -78,27 +78,22 @@ namespace Sapphire
|
|||
return false;
|
||||
}
|
||||
|
||||
bool EncounterTimeline::ConditionEncounterTimeElapsed::isConditionMet( InstanceContentPtr pInstance, uint64_t time )
|
||||
bool EncounterTimeline::ConditionEncounterTimeElapsed::isConditionMet( ConditionState& state, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const
|
||||
{
|
||||
if( pInstance == nullptr )
|
||||
{
|
||||
// die idk
|
||||
return false;
|
||||
}
|
||||
|
||||
auto elapsed = time - pack.getStartTime();
|
||||
// todo: check encounter time
|
||||
return false;
|
||||
return elapsed >= this->duration;
|
||||
}
|
||||
|
||||
bool EncounterTimeline::ConditionBNpcFlags::isConditionMet( InstanceContentPtr pInstance, uint64_t time )
|
||||
bool EncounterTimeline::ConditionBNpcFlags::isConditionMet( ConditionState& state, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const
|
||||
{
|
||||
auto pBNpc = pInstance->getActiveBNpcByLayoutId( this->layoutId );
|
||||
return pBNpc && pBNpc->hasFlag( this->flags );
|
||||
}
|
||||
|
||||
void EncounterTimeline::Timepoint::update( InstanceContentPtr pInstance, uint64_t time )
|
||||
void EncounterTimeline::Timepoint::update( TimepointState& state, InstanceContentPtr pInstance, uint64_t time ) const
|
||||
{
|
||||
m_lastTick = time;
|
||||
state.m_lastTick = time;
|
||||
switch( m_type )
|
||||
{
|
||||
case TimepointDataType::Idle:
|
||||
|
@ -141,7 +136,7 @@ namespace Sapphire
|
|||
else
|
||||
{
|
||||
// if we are at the pos, stop waiting
|
||||
m_finished = true;
|
||||
state.m_finished = true;
|
||||
}
|
||||
pBNpc->setRot( pMoveToData->m_rot );
|
||||
}
|
||||
|
@ -237,7 +232,7 @@ namespace Sapphire
|
|||
}
|
||||
break;
|
||||
}
|
||||
m_finished = m_finished || m_executeTime + m_duration <= time;
|
||||
state.m_finished = state.m_finished || state.m_startTime + m_duration <= time;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -302,10 +297,10 @@ namespace Sapphire
|
|||
}
|
||||
*/
|
||||
|
||||
void EncounterTimeline::Timepoint::execute( InstanceContentPtr pInstance, uint64_t time )
|
||||
void EncounterTimeline::Timepoint::execute( TimepointState& state, InstanceContentPtr pInstance, uint64_t time ) const
|
||||
{
|
||||
m_executeTime = time;
|
||||
update( pInstance, time );
|
||||
state.m_startTime = time;
|
||||
update( state, pInstance, time );
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -719,7 +714,6 @@ namespace Sapphire
|
|||
|
||||
// build the condition
|
||||
PhaseConditionPtr pCondition;
|
||||
pCondition->m_description = description;
|
||||
switch( conditionId )
|
||||
{
|
||||
case ConditionId::HpPctLessThan:
|
||||
|
@ -755,7 +749,7 @@ namespace Sapphire
|
|||
default:
|
||||
break;
|
||||
}
|
||||
actor.m_phaseConditions.push_back( pCondition );
|
||||
actor.addPhaseCondition( pCondition );
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -19,6 +19,30 @@ namespace Sapphire
|
|||
public:
|
||||
// forwards
|
||||
class TimelineActor;
|
||||
class TimelinePack;
|
||||
|
||||
struct TimepointState
|
||||
{
|
||||
uint64_t m_startTime{ 0 };
|
||||
uint64_t m_lastTick{ 0 };
|
||||
bool m_finished{ false };
|
||||
};
|
||||
|
||||
struct ConditionState
|
||||
{
|
||||
uint64_t m_startTime{ 0 };
|
||||
bool m_loop{ false };
|
||||
bool m_completed{ false };
|
||||
|
||||
struct
|
||||
{
|
||||
uint64_t m_startTime{ 0 };
|
||||
uint64_t m_lastTimepointTime{ 0 };
|
||||
uint32_t m_lastTimepointIndex{ 0 };
|
||||
|
||||
std::vector< TimepointState > m_timepointStates;
|
||||
} m_phaseInfo;
|
||||
};
|
||||
|
||||
// EncounterFight::OnTick() { switch EncounterTimepointConditionId }
|
||||
enum class ConditionId : uint32_t
|
||||
|
@ -59,14 +83,18 @@ namespace Sapphire
|
|||
Idle,
|
||||
CastAction,
|
||||
MoveTo,
|
||||
|
||||
LogMessage,
|
||||
BattleTalk,
|
||||
|
||||
SetDirectorVar,
|
||||
SetDirectorVarLR,
|
||||
SetDirectorSeq,
|
||||
SetDirectorFlag,
|
||||
|
||||
AddStatusEffect,
|
||||
RemoveStatusEffect,
|
||||
|
||||
SetBNpcFlags,
|
||||
SetEObjState,
|
||||
SetBgm
|
||||
|
@ -320,12 +348,9 @@ namespace Sapphire
|
|||
public:
|
||||
TimepointDataType m_type;
|
||||
uint64_t m_duration{ 0 };
|
||||
uint64_t m_executeTime{ 0 };
|
||||
uint64_t m_lastTick{ 0 };
|
||||
TimepointOverrideFlags m_overrideFlags;
|
||||
TimepointDataPtr m_pData;
|
||||
std::string m_description;
|
||||
bool m_finished{ false };
|
||||
|
||||
// todo: repeatable?
|
||||
|
||||
|
@ -334,27 +359,27 @@ namespace Sapphire
|
|||
return m_pData;
|
||||
}
|
||||
|
||||
bool canExecute( uint64_t elapsed )
|
||||
bool canExecute( TimepointState& state, uint64_t elapsed ) const
|
||||
{
|
||||
return m_executeTime == 0; // & &m_duration <= elapsed;
|
||||
return state.m_startTime == 0; // & &m_duration <= elapsed;
|
||||
}
|
||||
|
||||
bool finished( uint64_t time )
|
||||
bool finished( TimepointState& state, uint64_t time ) const
|
||||
{
|
||||
return m_executeTime + m_duration <= time || m_finished;
|
||||
return state.m_startTime + m_duration <= time || state.m_finished;
|
||||
}
|
||||
|
||||
void reset()
|
||||
void reset( TimepointState& state ) const
|
||||
{
|
||||
m_executeTime = 0;
|
||||
m_lastTick = 0;
|
||||
m_finished = false;
|
||||
state.m_startTime = 0;
|
||||
state.m_lastTick = 0;
|
||||
state.m_finished = false;
|
||||
}
|
||||
|
||||
void from_json( const nlohmann::json& json, const std::unordered_map< std::string, TimelineActor >& actors, uint32_t selfLayoutId );
|
||||
// todo: separate execute/update into onStart and onTick?
|
||||
void update( InstanceContentPtr pInstance, uint64_t time );
|
||||
void execute( InstanceContentPtr pInstance, uint64_t time );
|
||||
void update( TimepointState& state, InstanceContentPtr pInstance, uint64_t time ) const;
|
||||
void execute( TimepointState& state, InstanceContentPtr pInstance, uint64_t time ) const;
|
||||
};
|
||||
|
||||
class Phase :
|
||||
|
@ -366,52 +391,65 @@ namespace Sapphire
|
|||
|
||||
std::string m_name;
|
||||
std::vector< Timepoint > m_timepoints;
|
||||
uint32_t m_lastTimepointIndex{ 0 };
|
||||
uint64_t m_startTime{ 0 };
|
||||
uint64_t m_lastTimepointTime{ 0 };
|
||||
|
||||
std::queue< Timepoint > m_executed;
|
||||
|
||||
// todo: i wrote this very sleep deprived, ensure it is actually sane
|
||||
void execute( InstanceContentPtr pInstance, uint64_t time )
|
||||
void execute( ConditionState& state, InstanceContentPtr pInstance, uint64_t time ) const
|
||||
{
|
||||
if( m_startTime == 0 )
|
||||
m_startTime = time;
|
||||
if( m_lastTimepointTime == 0 )
|
||||
m_lastTimepointTime = time;
|
||||
if( state.m_startTime == 0 )
|
||||
state.m_startTime = time;
|
||||
if( state.m_phaseInfo.m_startTime == 0 )
|
||||
state.m_phaseInfo.m_startTime = time;
|
||||
if( state.m_phaseInfo.m_lastTimepointTime == 0 )
|
||||
state.m_phaseInfo.m_lastTimepointTime = time;
|
||||
|
||||
for( auto i = m_lastTimepointIndex; i < m_timepoints.size(); )
|
||||
for( auto i = state.m_phaseInfo.m_lastTimepointIndex; i < m_timepoints.size(); )
|
||||
{
|
||||
uint64_t phaseElapsed = time - m_startTime;
|
||||
uint64_t timepointElapsed = time - m_lastTimepointTime;
|
||||
uint64_t phaseElapsed = time - state.m_phaseInfo.m_startTime;
|
||||
uint64_t timepointElapsed = time - state.m_phaseInfo.m_lastTimepointTime;
|
||||
|
||||
auto& tpState = state.m_phaseInfo.m_timepointStates[ i ];
|
||||
auto& timepoint = m_timepoints[ i ];
|
||||
if( timepoint.canExecute( timepointElapsed ) )
|
||||
if( timepoint.canExecute( tpState, timepointElapsed ) )
|
||||
{
|
||||
timepoint.execute( pInstance, time );
|
||||
m_lastTimepointTime = time;
|
||||
m_executed.push( timepoint );
|
||||
timepoint.execute( tpState, pInstance, time );
|
||||
state.m_phaseInfo.m_lastTimepointTime = time;
|
||||
}
|
||||
else if( !timepoint.finished( timepointElapsed ) )
|
||||
else if( !timepoint.finished( tpState, timepointElapsed ) )
|
||||
{
|
||||
timepoint.update( pInstance, time );
|
||||
timepoint.update( tpState, pInstance, time );
|
||||
}
|
||||
|
||||
if( timepoint.finished( timepointElapsed ) )
|
||||
if( timepoint.finished( tpState, timepointElapsed ) )
|
||||
{
|
||||
timepoint.reset();
|
||||
m_lastTimepointIndex = i;
|
||||
timepoint.reset( tpState );
|
||||
// make sure this timepoint isnt run again unless phase loops
|
||||
++i;
|
||||
state.m_phaseInfo.m_lastTimepointIndex = i;
|
||||
|
||||
if( i == m_timepoints.size() )
|
||||
{
|
||||
state.m_phaseInfo.m_lastTimepointIndex++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool completed()
|
||||
void reset( ConditionState& state ) const
|
||||
{
|
||||
return m_timepoints.size() == 0;
|
||||
state.m_phaseInfo.m_startTime = 0;
|
||||
state.m_phaseInfo.m_lastTimepointIndex = 0;
|
||||
state.m_phaseInfo.m_lastTimepointTime = 0;
|
||||
|
||||
state.m_phaseInfo.m_timepointStates.clear();
|
||||
for( auto i = 0; i < m_timepoints.size(); ++i )
|
||||
state.m_phaseInfo.m_timepointStates.push_back( {} );
|
||||
}
|
||||
|
||||
bool completed( ConditionState& state ) const
|
||||
{
|
||||
return state.m_phaseInfo.m_lastTimepointIndex > m_timepoints.size();
|
||||
}
|
||||
};
|
||||
using PhasePtr = std::shared_ptr< Phase >;
|
||||
|
@ -419,14 +457,13 @@ namespace Sapphire
|
|||
class PhaseCondition :
|
||||
public std::enable_shared_from_this< PhaseCondition >
|
||||
{
|
||||
public:
|
||||
protected:
|
||||
ConditionId m_conditionId{ 0 };
|
||||
Phase m_phase;
|
||||
bool m_loop{ false };
|
||||
uint64_t m_startTime{ 0 };
|
||||
uint32_t m_cooldown{ 0 };
|
||||
std::string m_description;
|
||||
|
||||
uint32_t m_cooldown{ 0 };
|
||||
bool m_loop{ false };
|
||||
public:
|
||||
PhaseCondition() {}
|
||||
~PhaseCondition() {}
|
||||
|
||||
|
@ -436,45 +473,47 @@ namespace Sapphire
|
|||
this->m_loop = json.at( "loop" ).get< bool >();
|
||||
//this->m_cooldown = json.at( "cooldown" ).get< uint32_t >();
|
||||
this->m_phase = phase;
|
||||
this->m_description = json.at( "description" ).get< std::string >();
|
||||
}
|
||||
|
||||
void execute( InstanceContentPtr pInstance, uint64_t time )
|
||||
void execute( ConditionState& state, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const
|
||||
{
|
||||
m_startTime = time;
|
||||
m_phase.execute( pInstance, time );
|
||||
state.m_startTime = time;
|
||||
m_phase.execute( state, pInstance, time );
|
||||
};
|
||||
|
||||
void update( InstanceContentPtr pInstance, uint64_t time )
|
||||
void update( ConditionState& state, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const
|
||||
{
|
||||
m_phase.execute( pInstance, time );
|
||||
m_phase.execute( state, pInstance, time );
|
||||
}
|
||||
|
||||
void reset()
|
||||
void reset( ConditionState& state ) const
|
||||
{
|
||||
m_startTime = 0;
|
||||
state.m_startTime = 0;
|
||||
m_phase.reset( state );
|
||||
}
|
||||
|
||||
bool inProgress()
|
||||
bool inProgress( ConditionState& state ) const
|
||||
{
|
||||
return m_startTime != 0;
|
||||
return state.m_startTime != 0;
|
||||
}
|
||||
|
||||
bool completed()
|
||||
bool completed( ConditionState& state ) const
|
||||
{
|
||||
return m_phase.completed();
|
||||
return m_phase.completed( state );
|
||||
}
|
||||
|
||||
bool isLoopable()
|
||||
bool isLoopable() const
|
||||
{
|
||||
return m_loop;
|
||||
}
|
||||
|
||||
bool loopReady( uint64_t time )
|
||||
bool loopReady( ConditionState& state, uint64_t time ) const
|
||||
{
|
||||
return m_phase.completed() && m_loop && ( m_startTime + m_cooldown <= time );
|
||||
return m_phase.completed( state ) && m_loop && ( state.m_startTime + m_cooldown <= time );
|
||||
}
|
||||
|
||||
virtual bool isConditionMet( InstanceContentPtr pInstance, uint64_t time )
|
||||
virtual bool isConditionMet( ConditionState& state, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const
|
||||
{
|
||||
return false;
|
||||
};
|
||||
|
@ -484,54 +523,78 @@ namespace Sapphire
|
|||
|
||||
class TimelineActor
|
||||
{
|
||||
protected:
|
||||
std::vector< PhaseConditionPtr > m_phaseConditions;
|
||||
std::queue< PhaseConditionPtr > m_phaseHistory;
|
||||
std::vector< ConditionState > m_conditionStates;
|
||||
public:
|
||||
uint32_t m_layoutId{ 0 };
|
||||
uint32_t m_hp{ 0 };
|
||||
std::string m_name;
|
||||
|
||||
std::vector< PhaseConditionPtr > m_phaseConditions;
|
||||
std::queue< PhaseConditionPtr > m_phaseHistory;
|
||||
void addPhaseCondition( PhaseConditionPtr pCondition )
|
||||
{
|
||||
m_phaseConditions.push_back( pCondition );
|
||||
m_conditionStates.push_back( {} );
|
||||
}
|
||||
|
||||
void update( InstanceContentPtr pInstance, uint64_t time )
|
||||
// todo: make this sane and pass info down
|
||||
void update( InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time )
|
||||
{
|
||||
// todo: handle auto attacks and make it so they dont fire during boss intermission phases
|
||||
// todo: handle interrupts
|
||||
for( const auto& pCondition : m_phaseConditions )
|
||||
for( auto i = 0; i < m_phaseConditions.size(); ++i )
|
||||
{
|
||||
if( pCondition->completed() )
|
||||
const auto& pCondition = m_phaseConditions[ i ];
|
||||
auto& state = m_conditionStates[ i ];
|
||||
|
||||
if( pCondition->completed( state ) )
|
||||
{
|
||||
if( pCondition->isLoopable() )
|
||||
{
|
||||
if( pCondition->loopReady( time ) )
|
||||
pCondition->reset();
|
||||
if( pCondition->loopReady( state, time ) )
|
||||
pCondition->reset( state );
|
||||
}
|
||||
}
|
||||
else if( pCondition->inProgress() )
|
||||
else if( pCondition->inProgress( state ) )
|
||||
{
|
||||
pCondition->update( pInstance, time );
|
||||
pCondition->update( state, pInstance, pack, time );
|
||||
}
|
||||
else if( pCondition->isConditionMet( pInstance, time ) )
|
||||
else if( pCondition->isConditionMet( state, pInstance, pack, time ) )
|
||||
{
|
||||
pCondition->execute( pInstance, time );
|
||||
pCondition->execute( state, pInstance, pack, time );
|
||||
m_phaseHistory.push( pCondition );
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// todo: actually handle solo stuff properly (or tie to zone director/content director at least)
|
||||
class TimelinePack
|
||||
{
|
||||
TimelinePackType m_type{TimelinePackType::Solo};
|
||||
std::vector< TimelineActor > m_actors;
|
||||
std::string m_name;
|
||||
|
||||
uint64_t m_startTime{ 0 };
|
||||
public:
|
||||
TimelinePack() { }
|
||||
TimelinePack( TimelinePackType type ) : m_type( type ) {}
|
||||
|
||||
void setStartTime( uint64_t time )
|
||||
{
|
||||
m_startTime = time;
|
||||
}
|
||||
|
||||
uint64_t getStartTime() const
|
||||
{
|
||||
return m_startTime;
|
||||
}
|
||||
|
||||
void update( InstanceContentPtr pInstance, uint64_t time )
|
||||
{
|
||||
for( auto& actor : m_actors )
|
||||
actor.update( pInstance, time );
|
||||
actor.update( pInstance, *this, time );
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -554,7 +617,7 @@ namespace Sapphire
|
|||
void from_json( nlohmann::json& json, Phase& phase, ConditionId conditionId,
|
||||
const std::unordered_map< std::string, TimelineActor >& actors );
|
||||
|
||||
bool isConditionMet( InstanceContentPtr pInstance, uint64_t time ) override;
|
||||
bool isConditionMet( ConditionState& state, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const override;
|
||||
};
|
||||
|
||||
class ConditionDirectorVar : PhaseCondition
|
||||
|
@ -572,7 +635,7 @@ namespace Sapphire
|
|||
} param;
|
||||
|
||||
void from_json( nlohmann::json& json, Phase& phase, ConditionId conditionId );
|
||||
bool isConditionMet( InstanceContentPtr pInstance, uint64_t time ) override;
|
||||
bool isConditionMet( ConditionState& state, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const override;
|
||||
};
|
||||
|
||||
class ConditionEncounterTimeElapsed : PhaseCondition
|
||||
|
@ -581,7 +644,7 @@ namespace Sapphire
|
|||
uint64_t duration;
|
||||
|
||||
void from_json( nlohmann::json& json, Phase& phase, ConditionId conditionId );
|
||||
bool isConditionMet( InstanceContentPtr pInstance, uint64_t time ) override;
|
||||
bool isConditionMet( ConditionState& state, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const override;
|
||||
};
|
||||
|
||||
class ConditionCombatState : PhaseCondition
|
||||
|
@ -591,7 +654,7 @@ namespace Sapphire
|
|||
CombatStateType combatState;
|
||||
|
||||
void from_json( nlohmann::json& json, Phase& phase, ConditionId conditionId, const std::unordered_map< std::string, TimelineActor >& actors );
|
||||
bool isConditionMet( InstanceContentPtr pInstance, uint64_t time ) override;
|
||||
bool isConditionMet( ConditionState& state, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const override;
|
||||
};
|
||||
|
||||
class ConditionBNpcFlags : PhaseCondition
|
||||
|
@ -601,7 +664,7 @@ namespace Sapphire
|
|||
uint32_t flags;
|
||||
|
||||
void from_json( nlohmann::json& json, Phase& phase, ConditionId conditionId, const std::unordered_map< std::string, TimelineActor >& actors );
|
||||
bool isConditionMet( InstanceContentPtr pInstance, uint64_t time ) override;
|
||||
bool isConditionMet( ConditionState& state, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const override;
|
||||
};
|
||||
|
||||
public:
|
||||
|
|
Loading…
Add table
Reference in a new issue