🎮 Game
A particle system extension for s&box with custom emitters, force controllers, and model/line render attribute drivers. It adds donut, cylinder, sphere, box, ring, and point emitters, tornado and vortex forces, per-emitter and per-particle attribute evaluation, and editor helpers for playback control and phase driving. It reads material and shader attribute metadata from mounted files and drives SceneObjects for particle rendering.
🔧 Editor
An editor widget that adds a tool window to control ParticleEffectsManager components. It has play, pause, and restart controls, a time slider synced to the effect playback, and shows particle count and current time. It is a pure editor UI utility with no networking or file access.
🧪 Unit Test
Unit test project for ParticleSystemPlus. It sets up the s&box unit test environment, creates a Scene, pushes it, spawns a GameObject, and asserts the scene reports one GameObject. Uses Sandbox.Application.InitUnitTest in an assembly initializer.
🐞 Possible Bugs
Code/EmittersShapes/ConchplexCylinderEmitter.csrandom.z is clamped with reversed bounds (0.5f, -0.5f) so it always becomes 0.5, and clamping x/y to 0..randomXYNormal.x/y breaks for negative normals and collapses coordinates to 0, severely biasing spawn positions.
Code/EmittersShapes/ConchplexEmitterShape.csOnEnabled unconditionally sets target from GetInAncestorsOrSelf, overwriting any non-null override and making a user-assigned target impossible.
ITemporaryEffect.IsActive falls through to an unconditional false, so during the running window (started and not finished, no loops/bursts) it incorrectly reports inactive.
Emissions/ConchplexBurstEmission.csThe cycle-limit guard uses 'Cycles! < 0' which evaluates as 'Cycles < 0', so positive Cycles are never enforced and any negative value blocks emission immediately.
EmittersShapes/ConchplexCylinderEmitter.csClamp calls invert min and max in normal flow, for example random.z = random.z.Clamp(0.5f, -0.5f) and clamping x/y against possibly negative randomXYNormal, so components collapse to wrong bounds during emission.