Skip to content

Commit

Permalink
fix #6407
Browse files Browse the repository at this point in the history
  • Loading branch information
rtri committed Jul 14, 2020
1 parent 4b0ec54 commit 7378275
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 70 deletions.
1 change: 0 additions & 1 deletion rts/Sim/Projectiles/Projectile.cpp
Expand Up @@ -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),
Expand Down
1 change: 0 additions & 1 deletion rts/Sim/Projectiles/Projectile.h
Expand Up @@ -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;
Expand Down
166 changes: 100 additions & 66 deletions rts/Sim/Projectiles/ProjectileHandler.cpp
Expand Up @@ -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");
Expand Down Expand Up @@ -157,6 +161,9 @@ void CProjectileHandler::Kill()
projectileMaps[ true].clear();
projectileMaps[false].clear();

createdProjectiles[ true].clear();
createdProjectiles[false].clear();

CCollisionHandler::PrintStats();
}

Expand All @@ -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);
Expand All @@ -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()) {
Expand Down Expand Up @@ -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()) {
Expand All @@ -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
Expand Down Expand Up @@ -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};

Expand Down Expand Up @@ -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;

Expand Down
27 changes: 25 additions & 2 deletions rts/Sim/Projectiles/ProjectileHandler.h
Expand Up @@ -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);
Expand Down Expand Up @@ -98,15 +98,38 @@ 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<int> freeProjectileIDs[2];

// [0] := ID ==> projectile* map for living unsynced projectiles
// [1] := ID ==> projectile* map for living synced projectiles
std::vector<CProjectile*> projectileMaps[2];

std::vector<CProjectile*> createdProjectiles[2];
};


Expand Down

0 comments on commit 7378275

Please sign in to comment.