From 7378275c77aabb0a45972108dfbdeca063e47cd2 Mon Sep 17 00:00:00 2001 From: rtri Date: Tue, 14 Jul 2020 20:13:29 +0200 Subject: [PATCH] fix #6407 --- rts/Sim/Projectiles/Projectile.cpp | 1 - rts/Sim/Projectiles/Projectile.h | 1 - rts/Sim/Projectiles/ProjectileHandler.cpp | 166 +++++++++++++--------- rts/Sim/Projectiles/ProjectileHandler.h | 27 +++- 4 files changed, 125 insertions(+), 70 deletions(-) diff --git a/rts/Sim/Projectiles/Projectile.cpp b/rts/Sim/Projectiles/Projectile.cpp index a6f76b8367f..fe42741654a 100644 --- a/rts/Sim/Projectiles/Projectile.cpp +++ b/rts/Sim/Projectiles/Projectile.cpp @@ -26,7 +26,6 @@ CR_REG_METADATA(CProjectile, CR_MEMBER(checkCol), CR_MEMBER(ignoreWater), CR_MEMBER(deleteMe), - CR_IGNORED(callEvent), // we want the render event called for all projectiles CR_MEMBER(castShadow), CR_MEMBER(drawSorted), diff --git a/rts/Sim/Projectiles/Projectile.h b/rts/Sim/Projectiles/Projectile.h index a88ea06019c..2b8cd22383d 100644 --- a/rts/Sim/Projectiles/Projectile.h +++ b/rts/Sim/Projectiles/Projectile.h @@ -103,7 +103,6 @@ class CProjectile: public CExpGenSpawnable bool checkCol = true; bool ignoreWater = false; bool deleteMe = false; - bool callEvent = true; // do we need to call the ProjectileCreated event bool castShadow = false; bool drawSorted = true; diff --git a/rts/Sim/Projectiles/ProjectileHandler.cpp b/rts/Sim/Projectiles/ProjectileHandler.cpp index 60a7da1bec6..16523edcd32 100644 --- a/rts/Sim/Projectiles/ProjectileHandler.cpp +++ b/rts/Sim/Projectiles/ProjectileHandler.cpp @@ -86,6 +86,10 @@ void CProjectileHandler::Init() projectileMaps[false].clear(); projectileMaps[false].resize(8192, nullptr); #endif + createdProjectiles[false].clear(); + createdProjectiles[false].reserve(256); + createdProjectiles[ true].clear(); + createdProjectiles[ true].reserve(256); maxParticles = configHandler->GetInt("MaxParticles"); maxNanoParticles = configHandler->GetInt("MaxNanoParticles"); @@ -157,6 +161,9 @@ void CProjectileHandler::Kill() projectileMaps[ true].clear(); projectileMaps[false].clear(); + createdProjectiles[ true].clear(); + createdProjectiles[false].clear(); + CCollisionHandler::PrintStats(); } @@ -180,67 +187,14 @@ static void MAPPOS_SANITY_CHECK(const float3 v) } -void CProjectileHandler::UpdateProjectileContainer(bool synced) -{ - ProjectileContainer& pc = projectileContainers[synced]; - - // WARNING: - // we can't use iterators here because ProjectileCreated - // and ProjectileDestroyed events may add new projectiles - // to the container! - for (size_t i = 0; i < pc.size(); /*no-op*/) { - CProjectile* p = pc[i]; - - assert(p != nullptr); - assert(p->synced == synced); -#ifdef USING_CREG - assert(p->synced == !!(p->GetClass()->flags & creg::CF_Synced)); -#endif - - // creation - if (p->callEvent) { - if (synced || !UNSYNCED_PROJ_NOEVENT) - eventHandler.ProjectileCreated(p, p->GetAllyteamID()); - - eventHandler.RenderProjectileCreated(p); - p->callEvent = false; - } - - // deletion (FIXME: move outside of loop) - if (p->deleteMe) { - pc[i] = pc.back(); - pc.pop_back(); - - eventHandler.RenderProjectileDestroyed(p); - - if (synced) { - eventHandler.ProjectileDestroyed(p, p->GetAllyteamID()); - - projectileMaps[true][p->id] = nullptr; - freeProjectileIDs[true].push_back(p->id); - - ASSERT_SYNCED(p->pos); - ASSERT_SYNCED(p->id); - } else { - #if !UNSYNCED_PROJ_NOEVENT - eventHandler.ProjectileDestroyed(p, p->GetAllyteamID()); - - projectileMaps[false][p->id] = nullptr; - freeProjectileIDs[false].push_back(p->id); - #endif - } - - projMemPool.free(p); - continue; - } - - // neither - ++i; - } +void CProjectileHandler::UpdateProjectiles(bool synced) +{ SCOPED_TIMER("Sim::Projectiles::Update"); - // WARNING: same as above but for p->Update() + ProjectileContainer& pc = projectileContainers[synced]; + + // WARNING: can't use iterators here because p->Update() may add new projectiles to the container for (size_t i = 0; i < pc.size(); ++i) { CProjectile* p = pc[i]; assert(p != nullptr); @@ -265,7 +219,7 @@ static void UPDATE_PTR_CONTAINER(T& cont) { #endif size_t size = cont.size(); - for (unsigned int i = 0; i < size; /*no-op*/) { + for (size_t i = 0; i < size; /*no-op*/) { CGroundFlash*& gf = cont[i]; if (!gf->Update()) { @@ -295,7 +249,7 @@ static void UPDATE_REF_CONTAINER(T& cont) { #endif size_t size = cont.size(); - for (unsigned int i = 0; i < size; /*no-op*/) { + for (size_t i = 0; i < size; /*no-op*/) { auto& p = cont[i]; if (!p.Update()) { @@ -313,17 +267,96 @@ static void UPDATE_REF_CONTAINER(T& cont) { } + +void CProjectileHandler::CreateProjectiles(bool synced) +{ + auto& projs = createdProjectiles[synced]; + + // WARNING: ProjectileCreated can trigger AddProjectile + for (size_t i = 0, n = projs.size(); i < n; i = n, n = projs.size()) { + while (i < n) { + CreateProjectile(projs[i++]); + } + } + + projs.clear(); +} + +void CProjectileHandler::DestroyProjectiles(bool synced) +{ + ProjectileContainer& pc = projectileContainers[synced]; + + // WARNING: ProjectileDestroyed can trigger AddProjectile + for (size_t i = 0; i < pc.size(); /*no-op*/) { + CProjectile* p = pc[i]; + + assert(p != nullptr); + assert(p->synced == synced); +#ifdef USING_CREG + assert(p->synced == !!(p->GetClass()->flags & creg::CF_Synced)); +#endif + + // deletion + if (p->deleteMe) { + pc[i] = pc.back(); + pc.pop_back(); + + DestroyProjectile(p); + continue; + } + + ++i; + } +} + + + +void CProjectileHandler::CreateProjectile(CProjectile* p) +{ + if (p->synced || !UNSYNCED_PROJ_NOEVENT) + eventHandler.ProjectileCreated(p, p->GetAllyteamID()); + + eventHandler.RenderProjectileCreated(p); +} + +void CProjectileHandler::DestroyProjectile(CProjectile* p) +{ + eventHandler.RenderProjectileDestroyed(p); + + if (p->synced) { + eventHandler.ProjectileDestroyed(p, p->GetAllyteamID()); + + projectileMaps[true][p->id] = nullptr; + freeProjectileIDs[true].push_back(p->id); + + ASSERT_SYNCED(p->pos); + ASSERT_SYNCED(p->id); + } else { + #if !UNSYNCED_PROJ_NOEVENT + eventHandler.ProjectileDestroyed(p, p->GetAllyteamID()); + + projectileMaps[false][p->id] = nullptr; + freeProjectileIDs[false].push_back(p->id); + #endif + } + + projMemPool.free(p); +} + + + void CProjectileHandler::Update() { { SCOPED_TIMER("Sim::Projectiles"); - // particles - CheckCollisions(); // before :Update() to check if the particles move into stuff - UpdateProjectileContainer( true); - UpdateProjectileContainer(false); + // announce existence of projectiles created last frame to Lua, etc + CreateProjectiles(); + // check if any projectiles have collided since the previous update + CheckCollisions(); + DestroyProjectiles(); + UpdateProjectiles(); - // groundflashes UPDATE_PTR_CONTAINER(groundFlashes); // flying pieces; sort these every now and then @@ -362,7 +395,6 @@ void CProjectileHandler::AddProjectile(CProjectile* p) { // already initialized? assert(p->id < 0); - assert(p->callEvent); static constexpr decltype(&UnsyncedRandInt) rngFuncs[] = {&UnsyncedRandInt, &SyncedRandInt}; @@ -409,6 +441,8 @@ void CProjectileHandler::AddProjectile(CProjectile* p) if ((p->id) > (1 << 24)) LOG_L(L_WARNING, "[ProjectileHandler::%s] Lua %s projectile IDs are now out of range", __func__, (p->synced? "synced": "unsynced")); + createdProjectiles[p->synced].push_back(p); + if (!p->synced) return; diff --git a/rts/Sim/Projectiles/ProjectileHandler.h b/rts/Sim/Projectiles/ProjectileHandler.h index 1f3753f70d5..b1a2b45f553 100644 --- a/rts/Sim/Projectiles/ProjectileHandler.h +++ b/rts/Sim/Projectiles/ProjectileHandler.h @@ -61,7 +61,7 @@ class CProjectileHandler return std::min(1.0f, fract); } - int GetCurrentParticles() const; + int GetCurrentParticles() const; void AddProjectile(CProjectile* p); void AddGroundFlash(CGroundFlash* flash); @@ -98,8 +98,29 @@ class CProjectileHandler GroundFlashContainer groundFlashes; private: - void UpdateProjectileContainer(bool); + // event-notifiers + void CreateProjectile(CProjectile*); + void DestroyProjectile(CProjectile*); + + void CreateProjectiles(bool); + void CreateProjectiles() { + CreateProjectiles( true); + CreateProjectiles(false); + } + + void DestroyProjectiles(bool); + void DestroyProjectiles() { + DestroyProjectiles( true); + DestroyProjectiles(false); + } + void UpdateProjectiles(bool); + void UpdateProjectiles() { + UpdateProjectiles( true); + UpdateProjectiles(false); + } + +private: // [0] := available unsynced projectile ID's // [1] := available synced (weapon, piece) projectile ID's std::vector freeProjectileIDs[2]; @@ -107,6 +128,8 @@ class CProjectileHandler // [0] := ID ==> projectile* map for living unsynced projectiles // [1] := ID ==> projectile* map for living synced projectiles std::vector projectileMaps[2]; + + std::vector createdProjectiles[2]; };