public void Execute(Entity ent, int index, [ReadOnly] ref PlayerShoot shoot,
                            [ReadOnly] ref Translation pos, [ReadOnly] ref Rotation rotation)
        {
            // getting the right TimePassed
            DynamicBuffer <TimePassed> buffer = data.timePassedBuffers[ent];
            TimePassed timePassed             = buffer[shoot.timeIdx];

            timePassed.time += data.dt;

            if (timePassed.time >= shoot.shotCooldown)
            {
                // get data to update the bubble with
                WaterShootData shootData = bubbleData[index];
                shootData.timeHeld              = math.min(timePassed.time - shoot.shotCooldown, maxChargeTime);
                shootData.maxChargeTime         = maxChargeTime;
                shootData.position              = pos.Value;
                shootData.initialScale          = shoot.initialScale;
                shootData.initialColliderRadius = shoot.initialColliderRadius;
                shootData.bullet   = shoot.bullet;
                shootData.topSpeed = bubbleBurstTopSpeed;

                if (data.shooting)
                {
                    // create a new bubble
                    if (shootData.state == WaterShootState.NotFired)
                    {
                        Entity bullet = data.CreateBullet(index, ref pos, ref rotation, shoot.bullet, 0);
                        data.commandBuffer.AddComponent(index, bullet,
                                                        new WaterShootIndex {
                            index = index
                        });
                        data.commandBuffer.AddComponent(index, bullet,
                                                        new Scale {
                            Value = .3f
                        });
                        shootData.state = WaterShootState.JustFired;
                    }
                    else
                    {
                        shootData.state = WaterShootState.Charging;
                    }
                }
                else
                {
                    timePassed.time = shoot.shotCooldown;

                    // bullet was updated last frame, so it exists and was charged,
                    // so create burst of bullets
                    if (shootData.state == WaterShootState.UpdatedCharging)
                    {
                        shootData.state = WaterShootState.Burst;
                    }
                }

                bubbleData[index] = shootData;
            }

            buffer[shoot.timeIdx] = timePassed;
        }
        public void Execute(Entity ent, int index, ref Translation pos, ref Scale scale,
                            [ReadOnly] ref WaterShootIndex waterIndex, ref PhysicsCollider collider,
                            ref BulletDamage damage)
        {
            WaterShootData data = bubbleData[waterIndex.index];

            // stick to player
            pos.Value = new float3(data.position.x, data.position.y + scale.Value,
                                   Constants.PLAYER_BULLET_HEIGHT);

            float progress    = math.sqrt(data.timeHeld);
            float scaleFactor = 1 + progress;

            // increase damage and size
            if (data.timeHeld != data.maxChargeTime)
            {
                scale.Value = data.initialScale * scaleFactor;
                unsafe {
                    if (collider.ColliderPtr->Type == ColliderType.Cylinder)
                    {
                        CylinderCollider *col = (CylinderCollider *)collider.ColliderPtr;
                        col->Radius = data.initialColliderRadius * scale.Value;
                    }
                }
                damage.damage = (int)(scaleFactor * math.pow(scaleFactor, .25)); // temporary

                if (data.state == WaterShootState.Charging)
                {
                    effectReqUtil.CreateParticleRequest(pos.Value,
                                                        EffectRequestSystem.ParticleType.WaterCharge);
                }
            }

            if (data.state == WaterShootState.Burst)
            {
                commandBuffer.DestroyEntity(index, ent);

                for (float angle = 0; angle < 2 * math.PI; angle += rnd.NextFloat(1 / (progress + 1), 1 / progress))
                {
                    CreateBurstLine(data.bullet, index, angle, pos.Value,
                                    data.topSpeed, (int)(progress * 2));
                }
            }
            else if (data.state == WaterShootState.NotFired)
            {
                commandBuffer.DestroyEntity(index, ent);
            }

            // notify shooter that bullet existed and was updated
            ++data.state;

            bubbleData[waterIndex.index] = data;
        }
        public void Execute(Entity ent, int index, [ReadOnly] ref PlayerShoot shoot)
        {
            WaterShootData waterData = bubbleData[index];

            // failed to update or bullet will not exist anymore, reset
            if (waterData.state != WaterShootState.UpdatedCharging && waterData.state != WaterShootState.NotFired &&
                waterData.state != WaterShootState.JustFired)
            {
                waterData.state = WaterShootState.NotFired;

                DynamicBuffer <TimePassed> buffer = data.timePassedBuffers[ent];
                TimePassed timePassed             = buffer[shoot.timeIdx];
                timePassed.time       = 0;
                buffer[shoot.timeIdx] = timePassed;
                bubbleData[index]     = waterData;
            }
        }