mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-04 03:43:43 +00:00
feat(skills): end a dead caster's skill when a client reports it (CasterDead)
When a client gets EchoStartSkill (or SyncSkill) from a caster it sees as dead, aimed at another object, it logs "msgEchoStartSkill msgCasterDead" and sends CasterDead (120: optional i64Caster, optional uiSkillHandle) through that target (LWOSkillComponent::msgEchoStartSkill 0x00d5dc90). 303 live packets, the target nearly always the attacked player, the caster a spawned enemy; the next messages were mostly Die and SetStunned for the player. DLU dropped it. The server now ends that skill on the caster: its behaviors with that handle are dropped (end entries run, pending timers and syncs discarded, its projectiles removed), so a hit an enemy scheduled before dying does not land later. It only does so when the server also sees the caster as dead, so a client can't cancel a living enemy's attack. What live did with the message is inferred from the name and when it was sent. Check in game: kill an enemy in the middle of a slow or charged attack (e.g. a Maelstrom horseman or a spider queen add): its attack does not hit after it has died, and other enemies' attacks still hit normally. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -202,6 +202,23 @@ void SkillComponent::Reset() {
|
||||
this->m_managedBehaviors.clear();
|
||||
}
|
||||
|
||||
void SkillComponent::EndSkill(const uint32_t skillUid) {
|
||||
const auto [begin, end] = m_managedBehaviors.equal_range(skillUid);
|
||||
for (auto it = begin; it != end; ++it) {
|
||||
auto* const context = it->second;
|
||||
if (!context) continue;
|
||||
std::erase_if(m_managedProjectiles, [context](const ProjectileSyncEntry& projectile) { return projectile.context == context; });
|
||||
// End what the skill started, but drop its pending timers (Reset would run them now: a late hit)
|
||||
for (const auto& entry : context->endEntries) entry.behavior->End(context, entry.branchContext, entry.second);
|
||||
context->endEntries.clear();
|
||||
context->timerEntries.clear();
|
||||
context->syncEntries.clear();
|
||||
context->scheduledUpdates.clear();
|
||||
delete context;
|
||||
}
|
||||
m_managedBehaviors.erase(begin, end);
|
||||
}
|
||||
|
||||
void SkillComponent::Interrupt() {
|
||||
// TODO: need to check immunities on the destroyable component, but they aren't implemented
|
||||
auto* combat = m_Parent->GetComponent<BaseCombatAIComponent>();
|
||||
|
||||
Reference in New Issue
Block a user