diff --git a/src/client/particles.cpp b/src/client/particles.cpp index 5411cc820..7b86e8a68 100644 --- a/src/client/particles.cpp +++ b/src/client/particles.cpp @@ -31,6 +31,10 @@ ClientParticleTexture::ClientParticleTexture(const ServerParticleTexture& p, ITe tex = p; // note: getTextureForMesh not needed here because we don't use texture filtering ref = tsrc->getTexture(p.string); + + // Try to show another texture to indicate a code issue. + if (!ref) + ref = tsrc->getTexture("no_texture.png"); } /* @@ -455,14 +459,17 @@ void ParticleSpawner::spawnParticle(ClientEnvironment *env, float radius, } else { if (m_texpool.size() == 0) return; - texture = ClientParticleTexRef(m_texpool[m_texpool.size() == 1 ? 0 - : myrand_range(0, m_texpool.size()-1)]); + texture = ClientParticleTexRef(m_texpool[myrand_range(0, m_texpool.size() - 1)]); texpos = v2f(0.0f, 0.0f); texsize = v2f(1.0f, 1.0f); if (texture.tex->animated) pp.animation = texture.tex->animation; } + // Same guard as in `CE_SPAWN_PARTICLE` + if (!texture.ref) + return; + // synchronize animation length with particle life if desired if (pp.animation.type != TAT_NONE) { // FIXME: this should be moved into a TileAnimationParams class method @@ -786,7 +793,8 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, Client *client, const ParticleSpawnerParameters &p = *event->add_particlespawner.p; - // texture pool + // There can be multiple textures, e.g. for time-based animations + // Look up all required textures in `ITextureSource` to retrieve an `ITexture`. std::vector texpool; if (!p.texpool.empty()) { size_t txpsz = p.texpool.size(); diff --git a/src/noise.cpp b/src/noise.cpp index 347780b1a..fb6ee074d 100644 --- a/src/noise.cpp +++ b/src/noise.cpp @@ -83,6 +83,9 @@ u32 PcgRandom::range(u32 bound) if (bound == 0) return next(); + if (bound == 1) + return 0; + /* This is an optimization of the expression: 0x100000000ull % bound