tmodloader 1.4.4.9

using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
using Microsoft.Xna.Framework;
using Terraria.Audio;
using System;
using Terraria.DataStructures;

namespace ITD.Content.Items.Accessories.Movement.Jumps
{
    public class TwisterInABottle : ModItem
    {
        public override void SetDefaults()
        {
            Item.width = 28;
            Item.height = 24;
            Item.value = Item.sellPrice(gold: 2);
            Item.rare = ItemRarityID.White;
            Item.accessory = true;
        }

        public override void UpdateAccessory(Player player, bool hideVisual)
        {
            player.GetModPlayer<TwisterPlayer>().hasTwisterJump = true;
        }
    }

    public class TwisterPlayer : ModPlayer
    {

        public const int DamageInterval = 30;
        public const int TotalDamage = 70;
        public const int DamageDuration = 120;
        private int damageCounter = 0;
        public const int TwisterDuration = 60;
        public const float SpeedBoostMultiplier = 1.5f;
        public const float AccelerationRate = 0.05f;


        public bool hasTwisterJump;
        public bool canDoubleJump;
        public bool hasReleasedJumpButton;
        public bool isTwistering;
        public int twisterTimer;
        public int damageTimer;
        public int spinTimer;
        public int spinDirection = 1;
        public Vector2 jumpPosition;
        public float currentSpeedMultiplier = 1f;

        public override void ResetEffects() => hasTwisterJump = false;

        public override void PreUpdate()
        {
            HandleTwisterJump();
            UpdateTimers();
            if (isTwistering)
            {
                Player.direction = spinDirection;
                CreateTrail();
            }
        }

        public override void PostUpdate() => UpdateTwisterDust();

        public override void ModifyDrawInfo(ref PlayerDrawSet drawInfo)
        {
            if (isTwistering) drawInfo.drawPlayer.direction = spinDirection;
        }

        private void HandleTwisterJump()
        {
            if ((Player.velocity.Y == 0f || Player.sliding || Player.autoJump && Player.justJumped) && hasTwisterJump)
            {
                canDoubleJump = true;
                hasReleasedJumpButton = false;
            }

            if (!Player.controlJump && Player.velocity.Y != 0f && !hasReleasedJumpButton)
            {
                hasReleasedJumpButton = true;
            }

            if (canDoubleJump && hasTwisterJump && Player.controlJump && hasReleasedJumpButton && Player.velocity.Y != 0f)
            {
                StartTwister();
            }
            else if (isTwistering && Player.controlJump && twisterTimer > 0)
            {
                ContinueTwister();
            }
            else if (isTwistering)
            {
                EndTwister();
            }
        }

        private void StartTwister()
        {
            isTwistering = true;
            twisterTimer = TwisterDuration;
            damageTimer = DamageInterval;
            jumpPosition = Player.Bottom;
            Player.velocity.Y = -Player.jumpSpeed * Player.gravDir;
            Player.jump = Player.jumpHeight;
            spinTimer = 0;
            spinDirection = 1;
            currentSpeedMultiplier = 1f;
            canDoubleJump = false;
            hasReleasedJumpButton = false;
            damageCounter = 0;
            SoundEngine.PlaySound(SoundID.DoubleJump, Player.position);
        }

        private void ContinueTwister()
        {
            Player.velocity.Y = -Player.jumpSpeed * Player.gravDir;
            Player.fallStart = (int)(Player.position.Y / 16f);
            currentSpeedMultiplier = Math.Min(currentSpeedMultiplier + AccelerationRate, SpeedBoostMultiplier);
            ApplyHorizontalMovement();
            SpinPlayer();
        }

        private void EndTwister()
        {
            isTwistering = false;
            twisterTimer = 0;
        }

        private void ApplyHorizontalMovement()
        {
            if (Player.controlLeft)
                Player.velocity.X = -Player.maxRunSpeed * currentSpeedMultiplier;
            else if (Player.controlRight)
                Player.velocity.X = Player.maxRunSpeed * currentSpeedMultiplier;
        }

        private void SpinPlayer()
        {
            spinTimer++;
            if (spinTimer % 3 == 0)
            {
                Player.bodyFrame.Y = (Player.bodyFrame.Y + Player.bodyFrame.Height) % (Player.bodyFrame.Height * 20);
                Player.direction = spinDirection;
                spinDirection *= -1;
            }
        }

        private void UpdateTimers()
        {
            if (twisterTimer > 0)
            {
                twisterTimer--;
                Twister();
            }
            if (damageTimer > 0) damageTimer--;
        }

        private void CreateTrail()
        {
            if (Main.rand.NextBool(2))
            {
                Vector2 position = Player.Center + new Vector2(Main.rand.NextFloat(-10f, 10f), Main.rand.NextFloat(-20f, 20f));
                Vector2 velocity = Player.velocity * -0.2f + Main.rand.NextVector2Circular(1f, 1f);
                Color color = Color.Lerp(Color.White, Color.Cyan, Main.rand.NextFloat(0.7f));

                Dust dust = Dust.NewDustPerfect(
                    position,
                    DustID.Cloud,
                    velocity,
                    0,
                    color,
                    Main.rand.NextFloat(0.5f, 1f)
                );

                dust.noGravity = true;
                dust.fadeIn = Main.rand.NextFloat(0.8f, 1.2f);
            }
        }

        private void Twister()
        {
            float progress = (float)twisterTimer / TwisterDuration;
            for (int i = 0; i < 10; i++) CreateTwisterDust(progress);
        }

        private void CreateTwisterDust(float progress)
        {
            float angle = Main.rand.NextFloat() * MathHelper.TwoPi;
            float radius = Main.rand.NextFloat(20f, 60f);
            float height = Main.rand.NextFloat(-120f, 40f) * progress;

            Vector2 offset = new Vector2((float)Math.Cos(angle) * radius, height);
            Vector2 position = jumpPosition + offset;
            Vector2 velocity = new Vector2(-offset.X * Main.rand.NextFloat(0.03f, 0.07f), Main.rand.NextFloat(0.5f, 2.5f));

            int dustType = Main.rand.NextBool(3) ? DustID.Cloud : DustID.Smoke;
            Color dustColor = Color.Lerp(Color.White, Color.LightBlue, Main.rand.NextFloat(0.7f));

            Dust dust = Dust.NewDustPerfect(
                position,
                dustType,
                velocity,
                0,
                dustColor * progress,
                Main.rand.NextFloat(0.8f, 1.8f) * progress
            );

            dust.noGravity = true;
            dust.fadeIn = Main.rand.NextFloat(0.8f, 1.2f) * progress;

            dust.customData = new TwisterDustData
            {
                InitialPosition = position,
                Angle = angle,
                Radius = radius,
                RotationSpeed = Main.rand.NextFloat(0.08f, 0.12f),
                CreationTime = Main.GameUpdateCount,
                NextDamageTime = Main.GameUpdateCount
            };

            DamageEnemy(dust.position);
        }

        private void UpdateTwisterDust()
        {
            for (int i = 0; i < Main.maxDust; i++)
            {
                Dust dust = Main.dust[i];
                if (dust.active && (dust.type == DustID.Cloud || dust.type == DustID.Smoke) && dust.customData is TwisterDustData data)
                {
                    UpdateDustPosition(dust, data);
                    FadeDust(dust);

                    if (Main.GameUpdateCount >= data.NextDamageTime && damageCounter < DamageDuration)
                    {
                        DamageEnemy(dust.position);
                        data.NextDamageTime = Main.GameUpdateCount + DamageInterval;
                        damageCounter += DamageInterval;
                    }
                }
            }
        }

        private void UpdateDustPosition(Dust dust, TwisterDustData data)
        {
            data.Angle += data.RotationSpeed;
            Vector2 newOffset = new Vector2(
                (float)Math.Cos(data.Angle) * data.Radius,
                dust.position.Y - jumpPosition.Y + dust.velocity.Y
            );
            dust.position = jumpPosition + newOffset + Main.rand.NextVector2Circular(1f, 1f);
        }

        private void FadeDust(Dust dust)
        {
            dust.scale *= 0.98f;
            if (dust.scale <= 0.1f || dust.position.Y > jumpPosition.Y + 170f)
            {
                dust.active = false;
            }
        }

        private void DamageEnemy(Vector2 position)
        {
            for (int i = 0; i < Main.maxNPCs; i++)
            {
                NPC npc = Main.npc[i];
                if (npc.active && !npc.friendly && Vector2.Distance(npc.Center, position) < 10f)
                {
                    ApplyDamage(npc);
                    break;
                }
            }
        }

        private void ApplyDamage(NPC npc)
        {
            int direction = npc.Center.X < Player.Center.X ? -1 : 1;
            int damage = TotalDamage / (DamageDuration / DamageInterval);
            Player.ApplyDamageToNPC(npc, damage, 2f, direction, crit: false);
        }

        private class TwisterDustData
        {
            public Vector2 InitialPosition;
            public float Angle;
            public float Radius;
            public float RotationSpeed;
            public uint CreationTime;
            public uint NextDamageTime;
        }
    }
}


can you change the logic adding the double jump, make it use something similar to:

using ExampleMod.Content.Tiles.Furniture;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using Terraria;
using Terraria.Enums;
using Terraria.ID;
using Terraria.ModLoader;

namespace ExampleMod.Content.Items.Accessories
{
	// Showcases a basic extra jump
	public class ExampleExtraJumpAccessory : ModItem
	{
		public override void SetDefaults() {
			Item.DefaultToAccessory(20, 26);
			Item.SetShopValues(ItemRarityColor.Green2, Item.buyPrice(silver: 50));
		}

		public override void UpdateAccessory(Player player, bool hideVisual) {
			player.GetJumpState<SimpleExtraJump>().Enable();
		}

		public override void AddRecipes() {
			CreateRecipe()
				.AddIngredient<ExampleItem>(20)
				.AddTile<ExampleWorkbench>()
				.Register();
		}
	}

	public class SimpleExtraJump : ExtraJump
	{
		public override Position GetDefaultPosition() => new After(BlizzardInABottle);

		public override IEnumerable<Position> GetModdedConstraints() {
			// By default, modded extra jumps set to be between two vanilla extra jumps (via After and Before) are ordered in load order.
			// This hook allows you to organize where this extra jump is located relative to other modded extra jumps that are also
			// placed between the same two vanilla extra jumps.
			yield return new Before(ModContent.GetInstance<MultipleUseExtraJump>());
		}

		public override float GetDurationMultiplier(Player player) {
			// Use this hook to set the duration of the extra jump
			// The XML summary for this hook mentions the values used by the vanilla extra jumps
			return 2.25f;
		}

		public override void UpdateHorizontalSpeeds(Player player) {
			// Use this hook to modify "player.runAcceleration" and "player.maxRunSpeed"
			// The XML summary for this hook mentions the values used by the vanilla extra jumps
			player.runAcceleration *= 1.75f;
			player.maxRunSpeed *= 2f;
		}

		public override void OnStarted(Player player, ref bool playSound) {
			// Use this hook to trigger effects that should appear at the start of the extra jump
			// This example mimics the logic for spawning the puff of smoke from the Cloud in a Bottle
			int offsetY = player.height;
			if (player.gravDir == -1f)
				offsetY = 0;

			offsetY -= 16;

			for (int i = 0; i < 10; i++) {
				Dust dust = Dust.NewDustDirect(player.position + new Vector2(-34f, offsetY), 102, 32, DustID.Cloud, -player.velocity.X * 0.5f, player.velocity.Y * 0.5f, 100, Color.Gray, 1.5f);
				dust.velocity = dust.velocity * 0.5f - player.velocity * new Vector2(0.1f, 0.3f);
			}

			SpawnCloudPoof(player, player.Top + new Vector2(-16f, offsetY));
			SpawnCloudPoof(player, player.position + new Vector2(-36f, offsetY));
			SpawnCloudPoof(player, player.TopRight + new Vector2(4f, offsetY));
		}

		private static void SpawnCloudPoof(Player player, Vector2 position) {
			Gore gore = Gore.NewGoreDirect(player.GetSource_FromThis(), position, -player.velocity, Main.rand.Next(11, 14));
			gore.velocity.X = gore.velocity.X * 0.1f - player.velocity.X * 0.1f;
			gore.velocity.Y = gore.velocity.Y * 0.1f - player.velocity.Y * 0.05f;
		}

		public override void ShowVisuals(Player player) {
			// Use this hook to trigger effects that should appear throughout the duration of the extra jump
			// This example mimics the logic for spawning the dust from the Blizzard in a Bottle
			int offsetY = player.height - 6;
			if (player.gravDir == -1f)
				offsetY = 6;

			Vector2 spawnPos = new Vector2(player.position.X, player.position.Y + offsetY);

			for (int i = 0; i < 2; i++) {
				SpawnBlizzardDust(player, spawnPos, 0.1f, i == 0 ? -0.07f : -0.13f);
			}

			for (int i = 0; i < 3; i++) {
				SpawnBlizzardDust(player, spawnPos, 0.6f, 0.8f);
			}

			for (int i = 0; i < 3; i++) {
				SpawnBlizzardDust(player, spawnPos, 0.6f, -0.8f);
			}
		}

		private static void SpawnBlizzardDust(Player player, Vector2 spawnPos, float dustVelocityMultiplier, float playerVelocityMultiplier) {
			Dust dust = Dust.NewDustDirect(spawnPos, player.width, 12, DustID.Snow, player.velocity.X * 0.3f, player.velocity.Y * 0.3f, newColor: Color.Gray);
			dust.fadeIn = 1.5f;
			dust.velocity *= dustVelocityMultiplier;
			dust.velocity += player.velocity * playerVelocityMultiplier;
			dust.noGravity = true;
			dust.noLight = true;
		}
	}
}